3 # topgit_msg - TopGit awk utility script used by tg--awksome
4 # Copyright (C) 2017 Kyle J. McKay <mackyle@gmail.com>
10 # variable arguments (-v):
12 # withan if true, include annihilated branches in output
13 # withmt empty branches: "" (like withan), true (include) false (exclude)
14 # nokind exclude the kind (2nd) field from any output lines
15 # noname exclude the name (1st) field from any output line
16 # only1 exit successfully after outputting first result
17 # colfmt do some simple column formatting if more than one output column
18 # kwregex case-insensitive keyword to match instead of "Subject"
19 # exclbr whitespace separated list of names to exclude
20 # inclbr whitespace separated list of names to include
22 # Note that if kwregex is non-empty and not "Subject" fancy missing
23 # descriptions will be omitted and an empty string will be used
25 # kwregex must match the entire keyword or it will not be considered a match
27 # if kwregex starts with a "+" the "+" will be stripped and each matching
28 # line will have the "pretty" keyword plus ": " prefixed to it (the "pretty"
29 # keyword is all lowercased except for the first and any chars following an
30 # internal "-" except that "ID" and "MIME" are always all uppercased)
32 # use of the "+"<regex> form will cause multiple matches for the same keyword
33 # to all be output in the order encountered (otherwise just the first match is
36 # if inclbr is non-empty a branch name must be listed to appear on stdout
38 # if a branch name appears in exclbr it is omitted from stdout trumping inclbr
40 # input must be result of the git --batch output as described for
41 # awk_topgit_msg_prepare
43 # Note that if only1 is true or kwregex starts with a "+" then nothing at
44 # all (normally there would at least be a blank line) will be output when
45 # there are no matches
47 # output is 0 or more branch lines with .topmsg "Subject:" descriptions
48 # in the same order they appear on the input in this format:
50 # <TopGit_branch_name> K description of the TopGit branch
52 # But if nokind is true the "K" field will be omitted; K has the same semantics
53 # as described for awk_topgit_msg_prepare output
55 # If noname is true the branch name field will be omitted (typically this is
56 # only ever useful when processing a single branch in which case a faked length
57 # may be used on the input as long as it includes at least the last character
58 # in the subject string -- it may even be much bigger than the actual data
59 # length with no problem if used together with only1 set to true)
61 # If withmt is empty then empty branches (K == 3) will be treated exactly the
62 # same as annihilated (K == 2) branches; otherwise if withmt is true empty
63 # branches will be included regardless of the withan value; otherwise if
64 # withmt is false (but not "") empty branches will be excluded regardless of
67 # If withan is true annihilated branches will be included (and empty branches
68 # if withmt is "") otherwise if withan is false annihilated branches will be
69 # excluded (and empty branches if withmt is "") from the output
71 # note that if branches were excluded during the prepare phase they will
72 # continue to be excluded here regardless of any withan/withmt values as this
73 # script lacks the ability to resurrect them in that case
75 # Some valid TopGit branches may not have a .topmsg file and annihilated
76 # branches certainly do not so setting withan/withmt true will only give good
77 # results if awk_topgit_msg_prepare was passed the empty blob's hash for its
80 # ALWAYS PASS THE EMPTY BLOB'S HASH AS awk_topgit_msg_prepare's missing VALUE!
82 # Read the previous paragraphs again; unless you are 100% certain that every
83 # branch you want to appear in the output has a .topmsg file even if only an
84 # empty one, do what it says to do when running the prepare step
87 BEGIN { exitcode =
"" }
88 function exitnow
(e
) { exitcode=e
; exit e
}
89 END { if (exitcode
!= "") exit exitcode
}
93 cnt =
split(inclbr
, scratch
, " ")
96 for (i =
1; i
<= cnt
; ++i
) incnames
[scratch
[i
]] =
1
98 cnt =
split(exclbr
, scratch
, " ")
99 for (i =
1; i
<= cnt
; ++i
) excnames
[scratch
[i
]] =
1
100 if (kwregex ==
"") kwregex =
"subject"
101 kwregex =
tolower(kwregex
)
102 subjrx = kwregex ==
"subject"
103 if (substr(kwregex
, 1, 1) ==
"+") {
105 kwregex =
substr(kwregex
, 2)
107 if (index(kwregex
, "|") &&
108 (substr(kwregex
, 1, 1) != "(" || substr(kwregex
, length(kwregex
)) != ")"))
109 kwregex =
"(" kwregex
")"
110 if (substr(kwregex
, 1, 1) != "^") kwregex =
"^" kwregex
111 if (substr(kwregex
, length(kwregex
)) != "$") kwregex = kwregex
"$"
112 if (OFS ==
"") OFS =
" "
113 doblank = !only1
&& !inclkw
116 function included
(abranch
) {
117 return (!inconly
|| incnames
[abranch
]) && !excnames
[abranch
]
120 function wanted
(abranch
, akind
) {
121 return !akind
|| akind ==
1 || akind ==
4 ||
122 (withmt
!= "" && akind ==
3 && withmt
) ||
123 ((akind
!= 3 || withmt ==
"") && withan
)
126 function strapp
(str1
, str2
) {
127 if (str1 ==
"") return str2
128 if (str2 ==
"") return str1
132 function trimsp
(str
) {
133 gsub(/[ \t\r\n]+/, " ", str
)
134 sub(/^
[ \t\r\n]+/, "", str
)
135 sub(/[ \t\r\n]+$
/, "", str
)
139 function prettykw
(k
, _kparts
, _i
, _c
, _ans
, _kpart
) {
141 _c =
split(tolower(k
), _kparts
, /-/)
142 for (_i=
1; _i
<=_c
; ++_i
) {
144 if (_kpart ==
"id") _kpart =
"ID"
145 else if (_kpart ==
"mime") _kpart =
"MIME"
146 else _kpart =
toupper(substr(_kpart
, 1, 1)) substr(_kpart
, 2)
147 _ans = _ans
"-" _kpart
149 return substr(_ans
, 2)
152 NF ==
4 && $
4 != "" && $
3 != "" && $
2 != "missing" && $
1 != "" &&
153 $
3 ~
/^
[01234]$
/ && $
2 ~
/^
[0-9]+$
/ {
160 inbody = $
1 != "blob"
163 while (curlen
< datalen
&& (err =
getline) > 0) {
164 curlen
+=
length($
0) + 1
166 if (/^
[ \t]*$
/) inbody =
1
168 if (/^
[ \t\r\n]/) subj = strapp
(subj
, trimsp
($
0))
169 else if (inclkw
) insubj =
0
173 if (inbody
|| insubj
) continue
174 if (match($
0, /^
[^
\t\r\n:]+:/) &&
175 match((kw=
tolower(substr($
0, RSTART, RLENGTH - 1))), kwregex
)) {
178 subj = trimsp
(substr($
0, RLENGTH + 2))
180 subj = strapp
(prettykw
(kw
) ":", subj
)
181 if (oldsubj
!= "") subj = oldsubj
"\n" subj
185 if (included
(bn
) && wanted
(bn
, kind
)) {
190 subj =
"branch " bn
" (empty \"Subject:\" in .topmsg)"
192 subj =
"branch " bn
" (missing \"Subject:\" in .topmsg)"
194 } else if (kind ==
1) {
195 subj =
"branch " bn
" (missing .topmsg)"
196 } else if (kind ==
4) {
197 subj =
"branch " bn
" (bare branch)"
198 } else if (kind ==
3) {
199 subj =
"branch " bn
" (no commits)"
201 subj =
"branch " bn
" (annihilated)"
205 if (!noname
|| !nokind
) {
208 if (!nokind
) outline = outline
" " kind
209 } else outline = kind
210 if (colfmt
) outline =
sprintf("%-39s\t", outline
)
211 else outline = outline
OFS
213 if (doblank
|| subj
!= "" || outline
!= "")
215 if (only1
) exitnow
(0)
217 if (err
< 0) exitnow
(2)