#!/bin/bash
# YummyYummySourceControl - Simple and convenient Git wrapper
#
# Copyright (C) 2007 Tim Janik <[email protected]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# If you have not received a copy of the GNU General Public License
# along with this program, see: http://www.gnu.org/licenses/

#set -e # exit on errors
#set -x # show commands

VERSION=YummyYummySourceControl-0.5

# setup
SETBOLD=true ; SETNORM=true ; COLOR= ; OUT=cat ; YYHELP=

# perform wildcard string matches
function match() {
       pattern="$1"
       searchtext="$2"
       case "$searchtext" in
       $pattern) return 0 ;; # $pattern must be unquoted to allow *?[]
       esac
       return 1
}

# configure for terminals with ANSI color escapes
TAB=$'\t'       # joe(1) syntax highlighting is broken for $''
test -t 1 && match $'*\e[31m*' "`tput setaf 1 2>/dev/null`" && {
       SETBOLD=echo\ -ne\ '\e[1m' ; SETNORM=echo\ -ne\ '\e[0m'
       BOLD=$'\e[1m'; GREEN=$'\e[32m'; TURK=$'\e[36m'; NORM=$'\e[0m';
       COLOR=--color ; OUT=less\ -R
       #' # work around syntax highlighting in old joe(1) versions wrg $''
       # we hardcode ANSI escapes directly because less -R can only deal with \e[*m
}

# find repository
match '*/yyhelp*' "/$0" && YYHELP=1     # no repo required
gitdir="$(git-rev-parse --git-dir 2>/dev/null)"
if test -f "$gitdir/HEAD" ; then
       githead="$gitdir/`git-symbolic-ref -q HEAD || echo HEAD`"; test -e "$githead" || githead=
       gitprefix="$(git-rev-parse --show-prefix)" ; test -z "$gitprefix" && gitprefix=. # no subdir support if GIT_DIR is set
elif ! test "$YYHELP" ; then
       echo "`basename \"$0\"`: No repository" >&2 ; exit 9
fi

# GIT commands
case "/$0" in
*/yyadd)        exec git-update-index --add -- "$@" ;;
*/yyblame)      test -z "$*" && exec yyhelp
               git-blame -- "$@" | {
                 test -n "$COLOR" &&
                   sed "/^[^()]\+(Not Committed Yet\b/{ s/^\([^()]\+\)(\([^()]\+\))\(.*\)/$GREEN\1$TURK(\2)$GREEN\3$NORM/; p; d };
                                                      s/^\([^()]\+\)(\([^()]\+\))/$BOLD\1$NORM$TURK(\2)$NORM/" \
                   || cat ; } | $OUT ;;
*/yybranch)     test -z "$*" && exec yyhelp
               test "x$1" = "x-f" && exec git-branch -f "$2"
               test -n "$1"       && exec git-branch    "$1" ;;
*/yybranchdel)  test -z "$*" && exec yyhelp
               test "x$1" = "x-f" && exec git-branch -D "$2"
               test "x$1" = "x-D" && exec git-branch -D "$2"
               test -n "$1"       && exec git-branch -d "$1" ;;
*/yyChangeLog)  test -n "$*" && exec yyhelp
               git-log --pretty='format:%ad %an       # %H (%cn)%n%n%s%n%n%b' |
               sed 's/^/       /;s/^   //;/^[         ]*<unknown>$/d' | $OUT ;;
*/yycommit)     cg-commit -- "$@" && test "true" = "`git-config --bool yyhelp.auto-push-commits`" && yypushpull ;;
*/yydiff)       git-update-index --refresh > /dev/null
               git-diff-index -r -m -C -p $COLOR HEAD -- "$@" | $OUT ;;
*/yygc)         test -n "$*" && exec yyhelp
               exec git-gc --prune ;;
*/yyinfo)       test -n "$*" && exec yyhelp
               REPO="`cd \"$gitdir/..\" && basename \"$(pwd)\" `"
               REPODIR="`git-rev-parse --show-cdup`" ; test -z "$REPODIR" && REPODIR=.
               URL="`git-config --get remote.origin.url`"; test -z "$URL" && URL="`cat $gitdir/remotes/origin 2>/dev/null | sed -n '/^URL: /{s/^URL: //;p;q}'`"
               SVNURL="`git-config --get svn-remote.svn.url`";
               test -z "$URL" -a -r "$gitdir/branches/origin" && URL="`cat $gitdir/branches/origin`" # cogito location
               test -z "$URL" && URL="`cd \"$gitdir\" && pwd`" # no url, must be local
               OC="`git-rev-parse --verify origin 2>/dev/null`"; test -n "$OC" && OC="`date -d \"$(git-log -n1 --pretty=format:%cD $OC)\" '+%F %T %z'` # $OC"
               HC="`git-rev-parse --verify HEAD   2>/dev/null`"; test -n "$HC" && HC="`date -d \"$(git-log -n1 --pretty=format:%cD $HC)\" '+%F %T %z'` # $HC"
               true                    && echo "GIT-Repo: $REPO"
               true                    && echo "URL:      $URL"
               test -n "$SVNURL"       && echo "SVN:      $SVNURL"
               true                    && echo "Path:     $REPODIR"
               test -n "$HC"           && echo "HEAD:     $HC"
               test -n "$OC"           && echo "Origin:   $OC"
               ;;
*/yylsbranches) test -n "$*" && exec yyhelp
               exec git-branch $COLOR ;;
*/yylstags)     test -n "$*" && exec yyhelp
               exec git-tag -l '.*' ;;
*/yypull)       exec git-pull ;;
*/yypushpull)   test -n "$*" && exec yyhelp
               git-push && git-pull || exit $? ;;
*/yyremove)     exec git-update-index --force-remove -- "$@" ;;
*/yyreset)      test -n "$*" && exec yyhelp
               exec git-checkout -f HEAD ;;
*/yyrestore)    git-ls-tree -r HEAD -- "$@" | git-update-index --index-info # resurrect deleted
               exec git-checkout-index -f -u -- "$@" ;;
*/yystatus)     test -z "$*" || match '-[tuc]' "$*" || exec yyhelp
               git-update-index --refresh > /dev/null  # update stat info
               ! match '*-[tc]*' "$*" &&       # list unknown files
                 git-ls-files --others --directory --exclude-from=$gitdir/info/exclude --exclude-per-directory=.gitignore |
                   { test " $*" != " -u" && sed 's,^,?  ,' || sed 's,/$,,' ; }
               test " $*" != " -u" && {        # list non-unknown files
                 if test -z "$githead" ; then  # empty history, list new files
                   git-ls-files | sed 's/^/A  /'
                 else                          # list known files, path-relative
                   test -s "$gitdir/commit-ignore" && commitignore="$gitdir/commit-ignore" || commitignore=
                   git-diff-index --name-status --no-renames HEAD . | while IFS="$TAB" read -r mode file ; do
                     case "$mode" in
                     D)        test -n "$(git-diff-files -- "$file")" && mode=! ;;
                     M)        test -n "$commitignore" && fgrep -qx "$file" "$commitignore" && mode=n ;;
                     esac
                     echo "$mode  ${file#$gitprefix}"
                   done
                 fi
               } | { test " $*" != " -c" && cat || sed 's/^[^ ]  \([^ ].*\)/* \1:/' ; } ;;
*/yytag)        (set -e && test -n "$*" && test -z "$3" && ! match "* -*" " $*" ) || exec yyhelp
               test -n "$2" && exec git-tag "$1" "$2"
               exec git-tag "$1" ;;
*/yytagdel)     test -z "$*" && exec yyhelp
               match "* -*" " $*" && exec yyhelp
               exec git-tag -d "$1" ;;
*/yyuncommit)   test -n "$*" && exec yyhelp
               exec git-reset --soft HEAD~1 ;;
*/yyview)       test -n "$*" && exec yyhelp
               exec gitk --all -d ;;
*/yywarp)       test -z "$*" && exec yyhelp
               exec git-checkout "$1" ;;
*)              test "$YYHELP" || { echo "`basename \"$0\"`: No such command" >&2 ; exit 9 ; } ;;
esac
test "$YYHELP" || exit 0 # successful command execution

YYHELP_ALIASES="yyadd yyblame yybranch yybranchdel yyChangeLog yycommit yydiff yygc yyinfo
               yylsbranches yylstags yypull yypushpull yyremove yyreset yyrestore yystatus
               yytag yytagdel yyuncommit yyview yywarp"

test "x$1" = "x--install-aliases" && {
       git --version | egrep '^git version (1\.[5-9]\.|[2-9]\.)' -q ||
                                          { echo "$0: failed to install: missing git >= 1.5.0" >&2 ; exit 2 ; }
       test -x ./yyhelp                || { echo "$0: failed to install: missing ./yyhelp" >&2 ; exit 2 ; }
       test -x /bin/bash               || { echo "$0: failed to install: missing /bin/bash" >&2 ; exit 2 ; }
       cg --help >/dev/null 2>&1       || { echo "$0: failed to install: missing cogito" >&2 ; exit 2 ; }
       set -e
       for i in $YYHELP_ALIASES ; do
               test -L $i || ln -vs yyhelp $i
       done
       exit 0
}
test "x$1" = "x--uninstall-aliases" && {
       set -e
       for i in $YYHELP_ALIASES ; do
               test -L $i && rm -vf $i
       done
       exit 0
}

# BACKGROUND
# The prefix 'yy' was choosen to allow conflict free shell completion.
# YummyYummySourceControl was started only after cogito was announced to be
# halted. It is meant to not depend on cogito one day, albeit that's not yet
# possible.

{       # yyhelp
       echo -e 'YummyYummySourceControl                                 YummyYummySourceControl'
       echo
       #       0\t911234567892123456789312345678941234567895123456789612345678971234567898
       $SETBOLD
       echo -e 'NAME'
       $SETNORM
       echo -e '\tYummyYummySourceControl - Simple and convenient Git wrapper'
       echo
       $SETBOLD
       echo -e 'SYNOPSIS'
       $SETNORM
       echo -e '\tyyadd          [FILES...] - add files to git repository'
       echo -e '\tyyblame        [FILES...] - annotate file source code'
       echo -e '\tyybranch    [-f] <branch> - add branch (forcable)'
       echo -e '\tyybranchdel [-f] <branch> - delete branch (forcable)'
       echo -e '\tyyChangeLog               - show git log in ChangeLog style'
       echo -e '\tyycommit       [FILES...] - commit current working tree'
       echo -e '\tyydiff         [FILES...] - show committable differences in'
       echo -e '\t                            working tree'
       echo -e '\tyygc                      - repack and prune repository'
       echo -e '\tyyhelp                    - display yy* help information'
       echo -e '\tyyinfo                    - display repository information'
       echo -e '\tyylsbranches              - list branches'
       echo -e '\tyylstags                  - list tags'
       echo -e '\tyypull                    - pull upstream sources'
       echo -e '\tyypushpull                - push & pull upstream sources'
       echo -e '\tyyremove       [FILES...] - remove files from git repository'
       echo -e '\tyyreset                   - reset (revert to HEAD) all files in the tree'
       echo -e '\tyyrestore      [FILES...] - forcefully recheckout specific files'
       echo -e '\tyystatus       [-t|-u|-c] - display working tree status'
       echo -e '\t                            -t: trim unknown; -u: show unknown;'
       echo -e '\t                            -c: trim and use commit message style'
       echo -e '\tyytag    <tag> [revision] - add tag'
       echo -e '\tyytagdel <tag>            - delete tag'
       echo -e '\tyyuncommit                - undo the last commit (must be unpushed)'
       echo -e '\tyyview                    - browse & navigate the history'
       echo -e '\tyywarp           <branch> - checkout new branch'
       echo
       $SETBOLD
       echo -e 'DESCRIPTION'
       $SETNORM
       echo -e '\tYummyYummySourceControl is a shallow wrapper around the myriads of'
       echo -e '\tcommands and options offered by the Git(7) revision control system.'
       echo -e '\tThe scope of this wrapper is confined to a farily basic set of actions'
       echo -e '\taround source control management, such as adding/removing/modifying'
       echo -e '\tfiles and the simplest forms of tag and branch handling.'
       echo
       $SETBOLD
       echo -e 'CONFIGURATION'
       $SETNORM
       echo -e "\tThe yycommit command can be configured to automatically issue"
       echo -e "\tyypushpull after successful commits with the following option:"
       echo -e "\t\tgit-config yyhelp.auto-push-commits true"
       echo
       $SETBOLD
       echo -e 'INSTALLATION'
       $SETNORM
       echo -e '\tTo install YummyYummySourceControl, copy yyhelp into a bin/ directory'
       echo -e '\tfrom $PATH and invoke: ./yyhelp --install-aliases'
       echo
       $SETBOLD
       echo -e 'HISTORY'
       $SETNORM
       echo -e "\tYummyYummySourceControl was created as a very shallow wrapper around"
       echo -e "\tgit-* tool option variants, to simplify the common use cases."
       echo -e "\tDepending on programming habits, YummyYummySourceControl may or may"
       echo -e "\tnot suit a developers daily needs. It is in any case not meant as a"
       echo -e "\tfull replacement for the git interface (there is e.g. no yyclone) and"
       echo -e "\tsubject to change."
       echo
       VERSIONSTRING___________FIXED=`printf '%-30s' "$VERSION"`
       echo -e "$VERSIONSTRING___________FIXED                          YummyYummySourceControl"
} | $OUT
exit 0