This adds general functions to get the list of all offending branches for a given one. Either which depends on the given branch (fan-in) or all dependencies (fan-out). Two simple users are provided which just lists the names or generates dot input. Signed-off-by: Bert Wesarg <bert.wesarg@xxxxxxxxxxxxxx> --- tg.sh | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 170 insertions(+), 0 deletions(-) diff --git a/tg.sh b/tg.sh index 3718702..926b31b 100644 tg.sh --- a/tg.sh +++ b/tg.sh @@ -351,6 +351,176 @@ setup_pager() trap "exec >&-; rm \"$_pager_fifo\"; rmdir \"$_pager_fifo_dir\"; wait" EXIT } +# traverse_fan_out(for_each_name, for_each_dep, name, head_deps) +# +# traverse the dependencies of @name in bfs order and call @for_each_name +# on each dep (i.e. node) and @for_each_dep on all dependencies (i.e. edge) +# with source and dest as arguments. +# +# @name' needs to be a TopGit controlled branch +# +# @head_deps specifies where to take the .topdeps from for the HEAD branch +# empty - from the committed tree +# '(i)' - from the index +# '(w)' - from the working dir +# +traverse_fan_out() +{ + local for_each_name=$1 + local for_each_dep=$2 + local name=$3 + local head_deps=$4 || : + local deps_src + local head="$(git symbolic-ref HEAD | sed 's#^refs/\(heads\|top-bases\)/##')" || : + + branchq="$(mktemp -t tg-fan-out.XXXXXX)" + allbranches="$(mktemp -t -d tg-fan-out-all.XXXXXX)" + trap "rm -rf \"$branchq\" \"$allbranches\"" 0 + + # fill queue with root name + echo "$name" > "$branchq" + + while [ -s "$branchq" ]; do + # dequeue + { + read name + cat > "$branchq.headless" + } < "$branchq" + mv -f "$branchq.headless" "$branchq" + + # eval name + eval "$for_each_name \"$name\"" + + # don't travers non-tgish branches + ref_exists "refs/top-bases/$name" || + continue + + deps_src=$name + # select .topdeps source for HEAD branch + [ "x$name" = "x$head" -a -n "$head_deps" ] && + deps_src=$head_deps + + old_IFS="$IFS" + IFS="" + cat_file "$deps_src:.topdeps" | + while read dep; do + + # eval dep + eval "$for_each_dep \"$name\" \"$dep\"" + + [ -d "$allbranches/$dep" ] || { + mkdir -p "$allbranches/$dep" + echo "$dep" >> "$branchq" + } + done + IFS="$old_IFS" + + done +} + +_graph_dep_edge() +{ + printf "\t\"%s\" -> \"%s\";\n" "$1" "$2" +} + +# prints the fan-out as a dot graph with edges +graph_fan_out() +{ + printf "digraph G {\n" + + traverse_fan_out : _graph_dep_edge "$1" $2 + + printf "}\n" +} + +# prints the fan-out as name per line +list_fan_out() +{ + traverse_fan_out echo : "$1" $2 +} + +# traverse_fan_in(for_each_name, for_each_dep, name, head_deps) +# +# traverse all branches which depends on @name in bfs order and call +# @for_each_name on each (i.e. node) and @for_each_dep on all dependencies +# (i.e. edge) with source and dest as arguments. +# +# @name' needs not to be a TopGit controlled branch +# +# @head_deps specifies where to take the .topdeps from for the HEAD branch +# empty - from the committed tree +# '(i)' - from the index +# '(w)' - from the working dir +# +traverse_fan_in() +{ + local for_each_name=$1 + local for_each_dep=$2 + local name=$3 + local head_deps=$4 || : + local deps_src + local head="$(git symbolic-ref HEAD | sed 's#^refs/\(heads\|top-bases\)/##')" || : + + branchq="$(mktemp -t tg-fan-in.XXXXXX)" + allbranches="$(mktemp -t -d tg-fan-in-all.XXXXXX)" + trap "rm -rf \"$branchq\" \"$allbranches\"" 0 + + echo "$name" > "$branchq" + + while [ -s "$branchq" ]; do + # dequeue + { + read name + cat > "$branchq.headless" + } < "$branchq" + mv -f "$branchq.headless" "$branchq" + + [ ! -d "$allbranches/$name" ] || + continue; + mkdir -p "$allbranches/$name" + + # eval branch + eval "$for_each_name \"$name\"" + + old_IFS="$IFS" + IFS="" + git for-each-ref --format='%(refname)' refs/top-bases | + while read ref; do + parent="${ref#refs/top-bases/}" + + deps_src=$parent + # select branch/index/worktree for HEAD branch + [ "x$parent" = "x$head" -a -n "$head_deps" ] && + deps_src=$head_deps + cat_file "$deps_src:.topdeps" | fgrep -qx "$name" || + continue + + # eval dep + eval "$for_each_dep \"$parent\" \"$name\"" + + echo "$parent" >> "$branchq" + done + IFS="$old_IFS" + + done +} + +# prints the fan-in as a dot graph with edges +graph_fan_in() +{ + printf "digraph G {\n" + + traverse_fan_in : _graph_dep_edge "$1" $2 + + printf "}\n" +} + +# prints the fan-in as name per line +list_fan_in() +{ + traverse_fan_in echo : "$1" $2 +} + ## Startup [ -d "@cmddir@" ] || -- tg: (ff59ac7..) bw/fan-in-out (depends on: master) -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html