#!/bin/bash
# vim:tabstop=3:expandtab:shiftwidth=3

GitCommand=$(echo `basename $0` | sed 's/^git[-]//')
if [ "$GitCommand" != "push" ]
then
   oPthIde='^___|^__all_reachables$|^__all_remotes$'
else
   oPthIde='^___'
fi

######################### Automatic option processing #########################
#                                                                             #
#  Variables in lowecase, starting with _ are processed as options.           #
#  Only the first character can be Upper-case ;-)                             #
#  Checking [ "$__switch" = "yes" ] will be a switch; "yes" is ON "" is OFF   #
#  Checking [ ${#__values} -gt 0 ]  will be an array with values              #
#                                                                             #
###############################################################################

# No _option_processor, al arguments are passed (for what it brings ;-) )

# Store original $* arguments
aRGs="$*"

# Collect VAL opts
vALo="$(grep -v '^#' $BASH_SOURCE | tr '$' '\n' | grep '^{#_[_a-zA-Z][_a-z]\?'|\
        sed 's|^{#\([_a-zA-Z]\+\)[^_a-z].*|\1|' | sort -u)"
nOTy="$(sed -e 's/$/$/' -e 's/\s/$|^/g' -e 's/^/^/' <<< "$(echo $vALo)")"
yESo="$(grep -v '^#' $BASH_SOURCE | tr '$' '\n' | grep '^_[_a-zA-Z][_a-z]\?' |\
        sed 's|^\([_a-zA-Z]\+\)[^_a-z].*|\1|' | grep -E -v "$nOTy" | sort -u)"

# Get the -[-] options into _[_] vars
while [ "${1:0:1}" = '-' ]
do
   opT="$(sed 's|=.*||' <<< "$1")"
   oPT="$(sed 's|-|_|g' <<< "$opT")"
   if grep -q "^${oPT}\$" <<< "$yESo"
   then
      eval "$oPT=yes" 2> /dev/null
   elif grep -q "^${oPT}\$" <<< "$vALo"
   then
      iSvAL="$(grep "^${opT}=" <<< "$1" | sed "s|^${opT}=||")"
      if [ ${#iSvAL} -eq 0 ] && [ $# -gt 0 ]
      then
         shift
         eval "$oPT[\${#${oPT}[@]}]='$1'" 2> /dev/null
      else
         eval "$oPT[\${#${oPT}[@]}]='$iSvAL'" 2> /dev/null
      fi
   fi
   unset opT oPT iSvAL
   shift
done # processing the options, __have_fun

# Simple help example with showing the options
if [ "$__help" = "yes" ] || [ "$_h" = "yes" ]
then
   (
   oPThELP="$(sort <<< "$yESo" ; \
              grep -v '^$' <<< "$vALo" |sort|sed 's|$|[=]VALUE|')"
   echo
   echo "  Usage: $(basename $BASH_SOURCE) [EXTRA_OPTS] [OPTS] [ARGS]"
   echo
   (sort <<< "$yESo" ; grep -v '^$' <<< "$vALo" |sort|sed 's|$|[=]VALUE|') | \
   grep -Ev "$oPthIde" | sed -e 's|_|-|g' -e 's|^|   |' # hide --- opts + indent
   echo
   )
   exit 0
fi

# Main

# Get vars
eval "$(grep '^#[^#=[:space:]]\+=[^=[:space:]]\+$' $HOME/.git-skip \
             2> /dev/null | sed 's|^#||')"

if [ "$GitCommand" = "" ]
then
   echo "! [ERROR] git command not found in the script name" >&2
   exit 1
fi

# setup ssh_askpass cache for push and pull
if ( [ "$GitCommand" = "pull" ] || [ "$GitCommand" = "push" ] ) && \
   [ "$GIT_ASKPASS" != "" ] && [ -r $GIT_ASKPASS ] && \
   grep -qw ssh_askpass $GIT_ASKPASS
then
   # setup ssh_askpass cache vars (single input)
   $(ssh_askpass --exports | grep -w SSH_ASKPASS_CACHE)
fi

# Add EDITOR var if not set (missing -m will be caught by the EDITOR)
if [ "$EDITOR" = "" ]
then
   EDITOR=vi
   export EDITOR
fi

# Setup dry-run var
unset Run
if [ "$___dry_run" = "yes" ]
then
   Run=(echo '<skipped>')
fi

# From ~/
cd $HOME

EgrepSkip="$(awk '/^[^#]/{print $1}' .git-skip 2> /dev/null | tr '\n' '|' | sed -e 's/|$/$/' -e 's/|/$|^/g' -e 's/^/^/')"
for R in $(find . -xdev -name .git -type d 2> /dev/null | sed -e 's,/.git$,,' -e 's,^[.][/]*,,')
do
   if [ "$EgrepSkip" != "" ] && echo "$R" | egrep -q "$EgrepSkip"
   then
      echo "Skipping $(echo "$R" | sed 's,^, ~/,')"
   else
      (
         if ! cd "$R"
         then
            echo "! [WARNING] Unable to run: cd ~/$R"
         else
            echo "# git repo $(pwd | sed "s,^$HOME,~,")"
            if [ "$GitCommand" = "push" ] && \
               ( [ "$__all_reachables" ] || [ "$__all_remotes" ] )

            then
               if [ "$__all_remotes" ] || [ ${#UNREACHABLES} -eq 0 ]
               then
                  UnReachable='^$'
               else
                  UnReachable="$(sed 's~,~|~g' <<< "$UNREACHABLES")"
               fi
               for Remote in $(git remote | sort -r | grep -Ev "$UnReachable")
               do
                  echo "# Remote: $Remote"
                  ${Run[@]} git $GitCommand $Remote
                  [ ${#PUSH_SLEEP} -ne 0 ] && sleep $PUSH_SLEEP
               done
            else
               ${Run[@]} git $GitCommand $*
               if grep -q '^pu' <<< "$GitCommand"
               then
                  [ ${#PUSH_SLEEP} -ne 0 ] && sleep $PUSH_SLEEP
               fi
            fi
         fi
      )
   fi
done
