## functions ## {{{1 ## assert ## {{{2 assert() { "$@" || die "assertion failed: $*" } ## authorinfo ## {{{2 authorinfo() { # XXX: implement parsing .ubergit/author personfromcommit "$1" "author" "AUTHOR" } ## base ## {{{2 base() { assert is_topic "$1" git cat-file blob "$1:.ubergit/base" \ | sed -e 's/ *#.*//; /^$/d' } ## commitenv ## {{{2 commitenv() { local commit commit="$1"; shift eval env $(authorinfo "$commit") $(committerinfo "$commit") "$(sq "$@")" } ## commiterinfo ## {{{2 committerinfo() { assert is_topic "$1" personfromcommit "$1" "committer" "COMMITTER" } ## debug ## {{{2 debug() { echo -- "$*" > /dev/tty } ## deps ## {{{2 deps() { assert test "$#" = "1" assert is_sha1 "$1" if is_topic "$1"; then local base deplines base="$(base "$1")" # this removes the final newline git cat-file blob "$base:.ubergit/deps" | sed -e 's/ *#.*//; /^$/d' fi } ## die ## {{{2 die() { printf "fatal: %s\n" "$*" >&2 exit 1 } ## export_rev_chk ## {{{2 export_rev_chk() { assert is_sha1 "$1" eval test -z "\$exported_$1" } ## export_rev_cmd ## {{{2 export_rev_cmd() { local deps parent exported assert is_sha1 "$1" # XXX: is this portable? deps="$(printf "%s" "$(deps "$1")" | tr '\012' ' ')" case "$deps" in "") eval "exported_$1=$1" return ;; *" "*) # >1 dependency parent="$(printf "exported base for $1\n" \ | commitenv "$1" git commit-tree "$(pretty_tree "$(base "$1")")" $(set -f; for p in $deps; do eval printf "%s" "\" -p \$exported_$p\""; done))" ;; *) # single dependency parent=$(eval printf "\$exported_$deps") ;; esac exported="$(msg "$1" | git stripspace | commitenv "$1" git commit-tree "$(pretty_tree "$1")" -p "$parent" )" eval "exported_$1=$exported" } ## export_rev ## {{{2 export_rev() { local ref assert is_sha1 "$1" ref="$1" recurse_deps export_rev_cmd export_rev_chk "$ref" eval echo "\$exported_$ref" } ## is_sha1 ## {{{2 is_sha1() { assert test "$#" = 1 git rev-parse -q --verify "$1" >/dev/null && test "$(git rev-parse --verify "$1")" = "$1" } ## is_ugbase ## {{{2 is_base() { rev_has_file "$1" ".ubergit/deps" } ## is_topic ## {{{2 is_topic() { rev_has_file "$1" ".ubergit/base" } ## is_ugish ## {{{2 is_ugish() { rev_has_file "$1" ".ubergit/" } ## msg ## {{{2 msg() { # XXX: encoding of msg file? Assume encoding of commit? assert test "$#" = 1 assert is_topic "$1" git cat-file blob "$1:.ubergit/msg" } ## personfromcommit ## {{{2 # personfromcommit [author|committer] [AUTHOR|COMMITTER] personfromcommit() { # inspired by git's get_author_ident_from_commit local encoding script encoding="$(git config i18n.commitencoding || echo UTF-8)" script=" /^$2 /{ s/'/'\\\\''/g # quote single quotes h s/^$2 \\([^<]*\\) <[^>]*> .*$/GIT_$3_NAME='\\1'/p g s/^$2 [^<]* <\\([^>]*\\)> .*$/GIT_$3_EMAIL='\\1'/p g s/^$2 [^<]* <[^>]*> \\(.*\\)$/GIT_$3_DATE='\\1'/p q } /^\$/q " git show -s --pretty=raw --encoding="$encoding" "$1" -- | sed -n -e "$script" } ## pretty_tree ## {{{2 pretty_tree() { git ls-tree --full-tree "$1" \ | awk -F ' ' '$2 != ".ubergit"' \ | git mktree } ## recurse_deps ## {{{2 ## recurse_deps recurse_deps() { local recdep_cmd recdep_recchk recdep recdep_cmd="$1"; shift recdep_recchk="$1"; shift if is_topic "$1" && "$recdep_recchk" "$@"; then for recdep in $(deps "$1"); do debug "recurse: patch=$1, dep=$recdep" recurse_deps "$recdep_cmd" "$recdep_recchk" "$recdep" "$@" || return "$?" done fi "$recdep_cmd" "$@" } ## rev_has_file ## {{{2 rev_has_file() { git ls-tree --full-tree --name-only "$1" "$2" | grep . > /dev/null } ## rev_verify ## {{{2 rev_verify() { git rev-parse --verify -q "$1" >/dev/null } ## sq ## {{{2 sq() { # depends on git >= v1.6.4-rc0~24^2~22 git rev-parse --sq-quote "$@" } ## option parsing ## {{{1 if test -n "$UG_OPTIONS_SPEC"; then eval "$(printf "%s\n" "$UG_OPTIONS_SPEC" | git rev-parse --parseopt --keep-dashdash --stop-at-non-option -- "$@" || echo "exit '$?'")" fi