tg-info.sh: support --deps and --dependents options
[topgit/pro.git] / awk / topgit_deps.awk
blobb47ca71b1f5bf2d3adaa6772c88ba4f52971eb1a
1 #!/usr/bin/awk -f
3 # topgit_deps - TopGit awk utility script used by tg--awksome
4 # Copyright (C) 2017 Kyle J. McKay <mackyle@gmail.com>
5 # All rights reserved.
6 # License GPLv2
8 # topgit_deps
10 # variable arguments (-v):
12 # brfile if non-empty, read TopGit branch names from here
13 # rmbr if true run system rm on brfile (after reading) if non-empty brfile
14 # anfile if non-empty, annihilated branch names are read from here
15 # rman if true run system rm on anfile (after reading) if non-empty anfile
16 # withan if true, mostly pretend anfile was empty (this is a convenience knob)
17 # withbr if true, output an "edge to self" for each input branch
18 # tgonly if true only emit deps listed in brfile
19 # rev if true, reverse each dep and the order from each .topdeps file
20 # exclbr whitespace separated list of names to exclude
21 # inclbr whitespace separated list of names to include
23 # if inclbr is non-empty a branch name must be listed to appear on stdout
25 # if a branch name appears in exclbr it is omitted from stdout trumping inclbr
27 # input must be result of the git --batch output as described for
28 # awk_topgit_deps_prepare
30 # output is 0 or more dependency "edges" from the .topdeps blob files output
31 # in the same order they appear on the input except that if rev is true
32 # the lines from each individual .topdeps blob are processed in reverse order
33 # and the edges themselves are output in opposite order
35 # each output line has this format:
37 # <TopGit_branch_name> <TopGit_branch_name>
39 # both branch names are guaranteed to be non-empty and non-matching unless
40 # withbr is true (but even then same-named branches from within the .topdeps
41 # content itself will still be suppressed) but other kinds of loops are not
42 # detected (until awk_topgit_recurse runs on the output)
44 # if withbr is true then a line will be output with the branch name as both
45 # the first and second fields (i.e. the edge points to itself) and this line
46 # will be output after all of the .topdeps content for the branch unless rev
47 # is true in which case it's output before any of the branch's .topdeps content
49 # Some valid TopGit branches may not have a .topdeps file and annihilated
50 # branches certainly do not so setting withbr true will only give good results
51 # if awk_topgit_deps_prepare was passed the empty blob's hash for its "missing"
52 # variable
54 # note that there can be duplicate output lines, especially when multiple
55 # patch series are present in the same repository and they share some of the
56 # patches
58 # note that anfile, if non-empty, is not read until after the first line of
59 # input is read, so the same file name passed to awk_topgit_deps_prepare can
60 # just be passed here as well without problem and, as a convenience, if rman
61 # is true the system "rm -f" command will be run on it after it's been read
62 # or if it's non-empty and withan is true
64 # using the withan knob, the same filename can always be passed as the anfile
65 # argument but it will be ignored when withan ("with annihilated in output")
66 # is set to true; this is done as a convenience as the same effect is always
67 # achieved by not passing any anfile value (or passing an empty string)
70 BEGIN { exitcode = "" }
71 function exitnow(e) { exitcode=e; exit e }
72 END { if (exitcode != "") exit exitcode }
74 BEGIN {
75 inconly = 0
76 cnt = split(inclbr, scratch, " ")
77 if (cnt) {
78 inconly = 1
79 for (i = 1; i <= cnt; ++i) incnames[scratch[i]] = 1
81 cnt = split(exclbr, scratch, " ")
82 for (i = 1; i <= cnt; ++i) excnames[scratch[i]] = 1
85 function quotevar(v) {
86 gsub(/\047/, "\047\\\047\047", v)
87 return "\047" v "\047"
90 function init(abranch, _e) {
91 rmlist = ""
92 if (brfile != "") {
93 if (tgonly) {
94 while ((_e = (getline abranch <brfile)) > 0) {
95 if (abranch != "") tgish[abranch] = 1
97 close(brfile)
98 if (_e < 0) exitnow(2)
100 if (rmbr) rmlist = rmlist " " quotevar(brfile)
102 if (!withan && anfile != "") {
103 while ((_e = (getline abranch <anfile)) > 0) {
104 if (abranch != "") ann[abranch] = 1
106 close(anfile)
107 if (_e < 0) exitnow(2)
108 if (rman) rmlist = rmlist " " quotevar(anfile)
110 if (rmlist != "") system("rm -f" rmlist)
113 function included(abranch) {
114 return (!inconly || incnames[abranch]) && !excnames[abranch]
117 function wanted(abranch) {
118 return !tgonly || tgish[abranch]
121 NR == 1 {init()}
123 NF == 3 && $3 != "" && $2 != "missing" && $1 != "" && $2 ~ /^[0-9]+$/ {
124 bn = $3
125 isann = ann[bn] || $1 != "blob"
126 incl = included(bn)
127 want = wanted(bn)
128 datalen = $2 + 1
129 curlen = 0
130 if (withbr && rev && incl && want) print bn " " bn
131 cnt = 0
132 err = 0
133 while (curlen < datalen && (err = getline) > 0) {
134 curlen += length($0) + 1
135 if (NF != 1 || $1 == "") continue
136 if (!isann && !ann[$1] && included($1) && wanted($1)) {
137 if (rev)
138 items[++cnt] = $1 " " bn
139 else
140 print bn " " $1
143 if (err < 0) exitnow(2)
144 for (i=cnt; i>0; --i) print items[i]
145 if (withbr && !rev && incl && want) print bn " " bn