t4000: add bare branch sanity checks
[topgit/pro.git] / awk / ref_prepare.awk
blob13537071da0ce3998a1d459a052435f67f3002d6
1 #!/usr/bin/awk -f
3 # ref_prepare - 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 # ref_prepare
10 # variable arguments (-v):
12 # topbases the full target topbases prefix (e.g. "refs/top-bases")
13 # headbase the full heads prefix (default is based on topbases value)
14 # chkblob if set spit out a verification line for this blob first
15 # depsblob if true include 6th line ".topdeps" blob otherwise not
16 # msgblob if true include 6th or 7th line ".topmsg" blob otherwise not
17 # refsfile ref definitions are read from here and used to output hashes
18 # pckdrefs ref table is in packed-refs format (ignored without refsfile)
19 # rmrf if true run system rm on refsfile (after reading)
20 # topdeps if in form <branch>:<hash> substitute <hash> for branch:.topdeps
21 # topmsg if in form <branch>:<hash> substitute <hash> for branch:.topmsg
22 # teeout if non-empty output lines are written here too
24 # if refsfile is non-empty, each line of the file it names must 2+ fields:
26 # <full-ref-name> <full-hash-for-ref> <anything-else-on-line-ignored>
28 # Unless pckdrefs is true and then packed-refs format is expected instead
30 # if refsfile is non-empty, instead of outputting refnames, the name will be
31 # looked up in the refsfile table and the corresponding hash (or a value
32 # guaranteed to generate a "missing" result) used
34 # if topdeps is provided (and matches <branch>:<hash> e.g. "t/foo:1234") then
35 # when depsblob is requested and the current branch is <branch> then instead
36 # of the normal output, <hash>^{blob} will be output instead which can be
37 # used to substitute an index or working tree version of a .topdeps file
39 # input must be a list of full ref names one per line
41 # output is 5, 6 or 7 lines per input line matching /^$topbases/
42 # to feed to:
44 # git cat-file --batch-check='%(objectname) %(objecttype) %(rest)'
46 # if both depsblob and msgblob are true depsblob is output before msgblob and
47 # both always come after the fixed first 5 lines
49 # if chkblob is not empty an additional line will precede all other output
50 # that verifies the existence of the chkblob object (and resolves it to a hash)
52 # note that if teeout is non-empty it will always be truncated before starting
53 # to write the output even if no output is produced; also note that unlike the
54 # other scripts this one writes to teeout simultaneously with stdout
57 BEGIN { exitcode = "" }
58 function exitnow(e) { exitcode=e; exit e }
59 END { if (exitcode != "") exit exitcode }
61 BEGIN {
62 sub(/\/+$/, "", topbases)
63 if (topbases == "") exitnow(2)
64 topbases = topbases "/"
65 tblen = length(topbases)
66 tbdrop = tblen + 1
67 if (headbase == "") {
68 if (topbases !~ /^refs\//) exitnow(2)
69 if (topbases ~ /^refs\/remotes\//) {
70 if (topbases !~ /^refs\/remotes\/[^\/]+\/[^\/]+\//) exitnow(2)
71 headbase = topbases
72 sub(/\/[^\/]+\/$/, "/", headbase)
73 } else {
74 headbase = "refs/heads/"
76 } else {
77 sub(/\/+$/, "", headbase)
78 if (headbase == "") exitnow(2)
79 headbase = headbase "/"
81 if (topdeps ~ /^[^ \t\r\n:]+:[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]+$/) {
82 colonat = index(topdeps, ":")
83 topdepsbr = substr(topdeps, 1, colonat - 1)
84 topdepsha = tolower(substr(topdeps, colonat + 1))
86 if (topmsg ~ /^[^ \t\r\n:]+:[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]+$/) {
87 colonat = index(topmsg, ":")
88 topmsgbr = substr(topmsg, 1, colonat - 1)
89 topmsgha = tolower(substr(topmsg, colonat + 1))
91 if (teeout != "") printf "" >teeout
94 function doprint(line) {
95 if (teeout != "") print line >teeout
96 print line
99 function quotevar(v) {
100 gsub(/\047/, "\047\\\047\047", v)
101 return "\047" v "\047"
104 function rmrefs() {
105 if (refsfile != "" && rmrf) {
106 system("rm -f " quotevar(refsfile))
107 rmrf = 0
108 refsfile = ""
111 END { rmrefs() }
113 function init(_e) {
114 if (refsfile != "") {
115 while ((_e = (getline info <refsfile)) > 0) {
116 cnt = split(info, scratch, " ")
117 if (cnt < 2 || scratch[1] == "" || scratch[2] == "") continue
118 if (pckdrefs) {
119 swapfield = scratch[1]
120 scratch[1] = scratch[2]
121 scratch[2] = swapfield
123 if (scratch[1] ~ /^refs\/./ &&
124 scratch[2] ~ /^[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]+$/)
125 refs[scratch[1]] = scratch[2]
127 close(refsfile)
128 if (_e < 0) exitnow(2)
130 rmrefs()
133 BEGIN {
134 if (chkblob != "") doprint(chkblob "^{blob}" " check ?")
137 NR == 1 {init()}
139 function getref(r) { return refsfile == "" ? r : (refs[r] ? refs[r] : "?") }
141 NF == 1 && substr($1, 1, tblen) == topbases {
142 bn = substr($1, tbdrop)
143 if (bn == "") next
144 baseref = getref(topbases bn)
145 headref = getref(headbase bn)
146 doprint(baseref " " bn " :")
147 doprint(baseref "^0")
148 doprint(headref "^0")
149 doprint(baseref "^{tree}")
150 doprint(headref "^{tree}")
151 if (depsblob) {
152 if (bn == topdepsbr)
153 doprint(topdepsha "^{blob}")
154 else
155 doprint(headref "^{tree}:.topdeps")
157 if (msgblob) {
158 if (bn == topmsgbr)
159 doprint(topmsgha "^{blob}")
160 else
161 doprint(headref "^{tree}:.topmsg")