tg-summary.sh: awksome accelerate --list --verbosely
[topgit/pro.git] / tg-summary.sh
blob71fdc1cfde3ad277869375ecabd4f1fc42e2f4a1
1 #!/bin/sh
2 # TopGit - A different patch queue manager
3 # Copyright (C) Petr Baudis <pasky@suse.cz> 2008
4 # Copyright (C) Kyle J. McKay <mackyle@gmail.com> 2015,2016,2017
5 # All rights reserved.
6 # GPLv2
8 terse=
9 graphviz=
10 sort=
11 deps=
12 depsonly=
13 rdeps=
14 head_from=
15 branches=
16 head=
17 heads=
18 headsindep=
19 headsonly=
20 exclude=
21 tgish=
22 withdeps=
23 verbose=0
25 ## Parse options
27 usage()
29 echo "Usage: ${tgname:-tg} [...] summary [-t | --list | --heads[-only] | --sort | --deps[-only] | --rdeps | --graphviz] [-i | -w] [--tgish-only] [--with[out]-deps] [--exclude branch]... [--all | branch...]" >&2
30 exit 1
33 while [ -n "$1" ]; do
34 arg="$1"
35 case "$arg" in
36 -i|-w)
37 [ -z "$head_from" ] || die "-i and -w are mutually exclusive"
38 head_from="$arg";;
39 -t|--list|-l|--terse)
40 terse=1;;
41 -v|--verbose)
42 verbose=1;;
43 --heads|--topgit-heads)
44 heads=1
45 headsindep=;;
46 --heads-independent)
47 heads=1
48 headsindep=1;;
49 --heads-only)
50 headsonly=1;;
51 --with-deps)
52 head=HEAD
53 withdeps=1;;
54 --without-deps|--no-with-deps)
55 head=HEAD
56 withdeps=0;;
57 --graphviz)
58 graphviz=1;;
59 --sort)
60 sort=1;;
61 --deps)
62 deps=1;;
63 --tgish-only)
64 tgish=1;;
65 --deps-only)
66 head=HEAD
67 depsonly=1;;
68 --rdeps)
69 head=HEAD
70 rdeps=1;;
71 --all)
72 break;;
73 --exclude=*)
74 [ -n "${1#--exclude=}" ] || die "--exclude= requires a branch name"
75 exclude="$exclude ${1#--exclude=}";;
76 --exclude)
77 shift
78 [ -n "$1" -a "$1" != "--all" ] || die "--exclude requires a branch name"
79 exclude="$exclude $1";;
80 -*)
81 usage;;
83 break;;
84 esac
85 shift
86 done
87 [ $# -eq 0 ] || defwithdeps=1
88 [ -z "$exclude" ] || exclude="$exclude "
89 doingall=
90 if [ "$1" = "--all" ]; then
91 [ -z "$withdeps" ] || die "mutually exclusive options given"
92 [ $# -eq 1 ] || usage
93 shift
94 head=
95 defwithdeps=
96 doingall=1
98 [ "$heads$rdeps" != "11" ] || head=
99 [ $# -ne 0 -o -z "$head" ] || set -- "$head"
101 [ "$terse$heads$headsonly$graphviz$sort$deps$depsonly" = "" ] ||
102 [ "$terse$heads$headsonly$graphviz$sort$deps$depsonly$rdeps" = "1" ] ||
103 [ "$terse$heads$headsonly$graphviz$sort$deps$depsonly$rdeps" = "11" -a "$heads$rdeps" = "11" ] ||
104 die "mutually exclusive options given"
105 [ -z "$withdeps" -o -z "$rdeps$depsonly$heads$headsonly" ] ||
106 die "mutually exclusive options given"
108 for b; do
109 [ "$b" != "--all" ] || usage
110 branches="$branches $(verify_topgit_branch "$b")"
111 done
113 get_branch_list()
115 if [ -n "$branches" ]; then
116 if [ -n "$1" ]; then
117 printf '%s\n' $branches | sort -u
118 else
119 printf '%s\n' $branches
121 else
122 non_annihilated_branches
126 show_heads_independent()
128 topics="$(get_temp topics)"
129 get_branch_list | sed -e 's,^\(.*\)$,refs/heads/\1 \1,' |
130 git cat-file --batch-check='%(objectname) %(rest)' |
131 sort -u -b -k1,1 >"$topics"
132 git merge-base --independent $(cut -d ' ' -f 1 <"$topics") |
133 sort -u -b -k1,1 | join - "$topics" | sort -u -b -k2,2 |
134 while read rev name; do
135 case "$exclude" in *" $name "*) continue; esac
136 printf '%s\n' "$name"
137 done
140 show_heads_topgit()
142 if [ -n "$branches" ]; then
143 navigate_deps -s=-1 -1 -- "$branches" | sort
144 else
145 navigate_deps -s=-1
146 fi |
147 while read -r name; do
148 case "$exclude" in *" $name "*) continue; esac
149 printf '%s\n' "$name"
150 done
153 show_heads()
155 if [ -n "$headsindep" ]; then
156 show_heads_independent "$@"
157 else
158 show_heads_topgit "$@"
162 if [ -n "$heads" -a -z "$rdeps" ]; then
163 show_heads
164 exit 0
167 skip_ann=
168 show_dep() {
169 case "$exclude" in *" $_dep "*) return; esac
170 case " $seen_deps " in *" $_dep "*) return 0; esac
171 seen_deps="${seen_deps:+$seen_deps }$_dep"
172 [ -z "$tgish" -o -n "$_dep_is_tgish" ] || return 0
173 [ -z "$skip_ann" ] || [ -z "$_dep_annihilated" ] && printf '%s\n' "$_dep"
174 return 0
177 show_deps()
179 no_remotes=1
180 recurse_deps_exclude=
181 get_branch_list | while read _b; do
182 case "$exclude" in *" $_b "*) continue; esac
183 case " $recurse_deps_exclude " in *" $_b "*) continue; esac
184 seen_deps=
185 save_skip="$skip_ann"
186 _dep="$_b"; _dep_is_tgish=1; skip_ann=; show_dep; skip_ann="$save_skip"
187 recurse_deps show_dep "$_b"
188 recurse_deps_exclude="$recurse_deps_exclude $seen_deps"
189 done
192 if [ -n "$depsonly" ]; then
193 show_deps | sort -u -b -k1,1
194 exit 0
197 show_rdeps()
199 case "$exclude" in *" $_dep "*) return; esac
200 [ -z "$tgish" -o -n "$_dep_is_tgish" ] || return 0
201 printf '%s %s\n' "$_depchain" "$_dep"
204 if [ -n "$rdeps" ]; then
205 no_remotes=1
206 showbreak=
208 if [ -n "$heads" ]; then
209 show_heads
210 else
211 get_branch_list
213 } | while read b; do
214 case "$exclude" in *" $b "*) continue; esac
215 [ -z "$showbreak" ] || echo
216 showbreak=1
217 ref_exists "refs/heads/$b" || continue
219 echol "$b"
220 recurse_preorder=1
221 recurse_deps show_rdeps "$b"
222 } | sed -e 's/[^ ][^ ]*[ ]/ /g'
223 done
224 exit 0
227 if [ -n "$headsonly" ]; then
228 defwithdeps=
229 branches="$(show_heads)"
232 [ -n "$withdeps" ] || withdeps="$defwithdeps"
233 if [ -z "$doingall$terse$graphviz$sort$deps$withdeps$branches" ]; then
234 branches="$(tg info --heads 2>/dev/null | paste -d " " -s -)" || :
235 [ -z "$branches" ] || withdeps=1
237 [ "$withdeps" != "0" ] || withdeps=
238 if [ -n "$withdeps" ]; then
239 savetgish="$tgish"
240 tgish=1
241 origbranches="$branches"
242 branches="$(skip_ann=1; show_deps | sort -u -b -k1,1 | paste -d " " -s -)"
243 tgish="$savetgish"
246 curname="$(strip_ref "$(git symbolic-ref -q HEAD)")" || :
248 if [ -n "$graphviz" ]; then
249 cat <<EOT
250 # GraphViz output; pipe to:
251 # | dot -Tpng -o <output>
252 # or
253 # | dot -Txlib
255 digraph G {
257 graph [
258 rankdir = "TB"
259 label="TopGit Layout\n\n\n"
260 fontsize = 14
261 labelloc=top
262 pad = "0.5,0.5"
268 if [ -n "$sort" ]; then
269 tsort_input="$(get_temp tg-summary-sort)"
270 exec 4>$tsort_input
271 exec 5<$tsort_input
274 ## List branches
276 aheadlist=
277 processed=' '
278 needslist=' '
279 compute_ahead_list()
281 [ -z "$branches" ] || [ -n "$withdeps" ] || return 0
282 [ -n "$withdeps" ] || origbranches="$(tg summary --topgit-heads | paste -d ' ' -s -)"
283 aheadfile="$(get_temp aheadlist)"
284 savebr="$base_remote"
285 savenr="$no_remotes"
286 base_remote=
287 no_remotes=1
288 for onehead in $origbranches; do
289 case "$exclude" in *" $onehead "*) continue; esac
290 case "$processed" in *" $onehead "*) continue; esac
291 processed="${processed}$onehead "
292 needs_update "$onehead" || needslist="${needslist}$onehead "
293 done >"$aheadfile"
294 no_remotes="$savenr"
295 base_remote="$savebr"
296 aheadlist=" $(cut -d ' ' -f 1 <"$aheadfile" | sort -u | paste -d ' ' -s -) "
299 process_branch()
301 missing_deps=
303 current=' '
304 [ "$name" != "$curname" ] || current='>'
305 from=$head_from
306 [ "$name" = "$curname" ] ||
307 from=
308 nonempty=' '
309 ! branch_empty "$name" $from || nonempty='0'
310 remote=' '
311 [ -z "$base_remote" ] || remote='l'
312 ! has_remote "$name" || remote='r'
313 rem_update=' '
314 [ "$remote" != 'r' ] || ! ref_exists "refs/remotes/$base_remote/${topbases#heads/}/$name" || {
315 branch_contains "refs/$topbases/$name" "refs/remotes/$base_remote/${topbases#heads/}/$name" &&
316 branch_contains "refs/heads/$name" "refs/remotes/$base_remote/$name"
317 } || rem_update='R'
318 [ "$remote" != 'r' -o "$rem_update" = 'R' ] || {
319 branch_contains "refs/remotes/$base_remote/$name" "refs/heads/$name" 2>/dev/null
320 } || rem_update='L'
321 deps_update=' '
322 case "$processed" in
323 *" $name "*)
324 case "$needslist" in *" $name "*) deps_update='D'; esac;;
326 needs_update "$name" >/dev/null || deps_update='D';;
327 esac
328 deps_missing=' '
329 [ -z "$missing_deps" ] || deps_missing='!'
330 base_update=' '
331 branch_contains "refs/heads/$name" "refs/$topbases/$name" || base_update='B'
332 ahead=' '
333 case "$aheadlist" in *" $name "*) ahead='*'; esac
335 if [ "$(ref_exists_rev "refs/heads/$name")" != "$(ref_exists_rev "refs/$topbases/$name")" ]; then
336 subject="$(cat_file "refs/heads/$name:.topmsg" $from | sed -n 's/^Subject: //p')"
337 else
338 # No commits yet
339 subject="(No commits)"
342 printf '%-8s %-30s\t%s\n' "$current$nonempty$remote$rem_update$deps_update$deps_missing$base_update$ahead" \
343 "$name" "$subject"
346 if [ -n "$deps" ]; then
347 if [ -n "$branches" ]; then
348 get_branch_list |
349 while read b; do
350 case "$exclude" in *" $b "*) continue; esac
351 list_deps $head_from $b |
352 while read name dep; do
353 case "$exclude" in *" $dep "*) continue; esac
354 [ -z "$tgish" ] || ref_exists "refs/$topbases/$dep" || continue
355 echo "$name $dep"
356 done
357 done
358 else
359 list_deps $head_from |
360 while read name dep; do
361 case "$exclude" in *" $dep "*) continue; esac
362 [ -z "$tgish" ] || ref_exists "refs/$topbases/$dep" || continue
363 echo "$name $dep"
364 done
366 exit 0
369 if [ -n "$terse" ]; then
370 refslist=
371 [ -z "$tg_read_only" ] || [ -z "$tg_ref_cache" ] || ! [ -s "$tg_ref_cache" ] ||
372 refslist="-r=\"$tg_ref_cache\""
373 cmd="run_awk_topgit_msg --list"
374 [ "${verbose:-0}" != "0" ] || cmd="run_awk_topgit_branches -n"
375 eval "$cmd" "$refslist" '-i="$branches" -x="$exclude" "refs/$topbases"'
376 exit 0
379 [ -n "$graphviz$sort" ] || compute_ahead_list
380 get_branch_list |
381 while read name; do
382 case "$exclude" in *" $name "*) continue; esac
383 if [ -n "$graphviz$sort" ]; then
384 from=$head_from
385 [ "$name" = "$curname" ] ||
386 from=
387 cat_file "refs/heads/$name:.topdeps" $from | while read dep; do
388 dep_is_tgish=true
389 ref_exists "refs/$topbases/$dep" ||
390 dep_is_tgish=false
391 [ -z "$tgish" ] || [ "$dep_is_tgish" = "true" ] || continue
392 if ! "$dep_is_tgish" || ! branch_annihilated $dep; then
393 if [ -n "$graphviz" ]; then
394 echo "\"$name\" -> \"$dep\";"
395 if [ "$name" = "$curname" ] || [ "$dep" = "$curname" ]; then
396 echo "\"$curname\" [style=filled,fillcolor=yellow];"
398 else
399 echo "$name $dep" >&4
402 done
403 else
404 process_branch
406 done
408 if [ -n "$graphviz" ]; then
409 echo '}'
412 if [ -n "$sort" ]; then
413 tsort <&5