From: martin f. krafft Date: Tue, 2 Aug 2011 14:50:07 +0000 (+0200) Subject: import first prototype X-Git-Url: https://git.madduck.net/code/topgit-ng.git/commitdiff_plain/dc58ec49df849ec1aef6929cd40c759a6018e056?hp=34bbe7c33ac672f2fc80f639277f9ba750a3d957 import first prototype --- diff --git a/tg-datastore b/tg-datastore new file mode 100755 index 0000000..e9ce139 --- /dev/null +++ b/tg-datastore @@ -0,0 +1,47 @@ +#!/bin/sh +set -eu + +. ${0%/*}/tg-datastore.inc + +info() { printf "I: $@\n" >&2; } + +case "$1" in + add) + # tg-datastore add var=val var2=val2 ... + # only add to HEAD + shift + info "returns non-zero if there is already a datastore on HEAD." + info "adding the following data to the datastore of HEAD:" + for pair in "$@"; do + info " ${pair%%=*}: ${pair#*=}\n" + printf "${pair%%=*}: ${pair#*=}\n" + done | tg_ds_add_data || die "E: HEAD already has a datastore" + ;; + remove) + # removes from HEAD + info "always returns zero, even if there was nothing to remove." + tg_ds_remove_data + ;; + list) + # $2 is the commit + info "returns non-zero if no datastore found at given commit." + info "prints contents of datastore otherwise." + tg_ds_list_data "${2:-HEAD}" + ;; + get) + # get parameter $2 from $3 (default HEAD) + info "prints the value of the parameter stored in the given commit." + info "prints nothing if the commit has a datastore but without the parameter." + info "returns non-zero if there is no datastore." + tg_ds_get_value "$2" ${3:-HEAD} + ;; + find) + # search for parameter $2 by backtracking from $3 (default HEAD) + info "prints the value of the parameter, or empty if parameter is not found." + info "returns non-zero if no datastore was found." + tg_ds_find_value "$2" ${3:-HEAD} + ;; + *) + echo "Usage: ${0##*/} [ add var=val... | remove | list | get var [commit] | find var [commit] ]" + ;; +esac diff --git a/tg-datastore-pcommits.inc b/tg-datastore-pcommits.inc new file mode 100644 index 0000000..f03ede5 --- /dev/null +++ b/tg-datastore-pcommits.inc @@ -0,0 +1,85 @@ +_get_empty_treeref() +{ + git mktree $timestamp + committer "$author" + x-topgit-data-node yes + + TopGit data node + + This commit is used internally by TopGit. Please just ignore it. + + TopGit data follow: + $(cat) + _commit_data +} + +_append_parentref_to_HEAD() +{ + local parent; parent="$1" + local ref; ref=$(git cat-file commit HEAD | + sed -e "/^parent/aparent ${parent}" | + git hash-object -t commit -w --stdin) + git update-ref HEAD $ref +} + +_remove_parentref_from_HEAD() +{ + local parent; parent="$1" + local ref; ref=$(git cat-file commit HEAD | + grep -v "^parent ${parent}" | + git hash-object -t commit -w --stdin) + git update-ref HEAD $ref +} + +# returns 0 if $1 is a valid TopGit pcommit +_is_pcommit() +{ + local pcommit; pcommit="$1" + git cat-file commit $pcommit | grep -q '^x-topgit-data-node yes$' +} + +# returns the ref of the pcommit attached to $1 +# returns 1 when none is found +_find_pcommit() +{ + local commit; commit="$1" + local parentnr; parentnr=1 + + while :; do + ref=$(tg_ds_resolve_commit "${commit}^${parentnr}") || break + _is_pcommit "$ref" && printf "$ref\n" && return 0 + parentnr=$(($parentnr + 1)) + done + return 1 +} + +# expects data on stdin and adds to HEAD +tg_ds_add_data() +{ + local author; author=$(git cat-file commit HEAD | sed -rne 's,^author ,,p') + _append_parentref_to_HEAD $(_make_pcommit "$author") +} + +# removes data from HEAD +tg_ds_remove_data() +{ + local pcommit; pcommit=$(_find_pcommit HEAD) || return # no error + _remove_parentref_from_HEAD $pcommit +} + +# lists data on a given commit +tg_ds_list_data() +{ + local commit; commit="${1:-HEAD}" + ref=$(tg_ds_resolve_commit $commit) || die "tg_ds_list_data: invalid commit: $commit" + local pcommit; pcommit=$(_find_pcommit $commit) || return 1 + git cat-file commit $pcommit | sed -e '0,/^TopGit data follow:$/d' +} diff --git a/tg-datastore.inc b/tg-datastore.inc new file mode 100644 index 0000000..d79f159 --- /dev/null +++ b/tg-datastore.inc @@ -0,0 +1,45 @@ +die() +{ + printf "E: $@\n" >&2 + exit 1 +} + +tg_ds_resolve_commit() +{ + git rev-parse --verify $1 2>/dev/null +} + +. ${0%/*}/tg-datastore-pcommits.inc + +tg_ds_get_value() +{ + local name; name="${1:-}" + local commit; commit="${2:-HEAD}" + + [ -z "$1" ] && die 'tg_ds_get_value: missing first argument (name)' + tg_ds_resolve_commit $commit >/dev/null || die "tg_ds_get_value: invalid commit: $commit" + + local data; data=$(tg_ds_list_data "$commit") || return 1 + printf "$data\n" | sed -rne "s,^${name}: *,,p" +} + +tg_ds_find_value() +{ + local name; name="${1:-}" + local commit; commit="${2:-HEAD}" + + [ -z "$1" ] && die 'tg_ds_find_value: missing first argument (name)' + ref=$(tg_ds_resolve_commit $commit) || die "tg_ds_find_value: invalid commit: $commit" + + while :; do + if [ "$name" = commitref ]; then + tg_ds_list_data "$commit" >/dev/null && printf "$ref\n" && return 0 + else + tg_ds_get_value "$name" $commit && return 0 + fi + commit="${commit}^" + ref=$(tg_ds_resolve_commit "${commit}") || break + done + + return 1 +}