-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathref_prefixes.awk
117 lines (110 loc) · 3.73 KB
/
ref_prefixes.awk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/awk -f
# ref_prefixes - TopGit awk utility script used by tg--awksome
# Copyright (C) 2017,2019,2021 Kyle J. McKay <mackyle@gmail.com>
# All rights reserved.
# License GPLv2
# ref_prefixes
#
# pckdrefs input refs are in packed-refs format (instead of just full ref name)
# prefix1 first ref prefix to look for and the default
# prefix2 second ref prefix to look for
# prefixh ignore prefix1/prefix2 matches without corresponding prefixh
# noerr instead of error 65 (EX_DATAERR) output default (prefix1) when both
# nodef instead of defaulting to prefix1, exit with error 66 (EX_NOINPUT)
#
# input is a list of full ref names one per line; if pckdrefs is true then the
# second field of the line will be used otherwise the first
#
# prefix1 may not be a prefix of prefix2 or vice versa
# if prefix1, prefix2 and/or prefixh are invalid exit status will be 2
#
# if prefixh is non-empty then matches for prefix1 or prefix2 must also match
# another line from the input after replacing the prefix1/prefix2 part with
# prefixh or they are discarded and do not participate in choosing the output
#
# note that the input need not be sorted in any particular order or be
# duplicate free even when prefixh is non-empty
#
# a prefix will only match at a "/" boundary
#
# ontput according to this table:
#
# any refs match any refs match noerr nodef exit output
# prefix1 prefix prefix2 prefix value value status value
# -------------- -------------- ----- ------ ------ -------
# no no any false 0 prefix1
# no no any true 66
# yes no any any 0 prefix1
# no yes any any 0 prefix2
# yes yes false any 65
# yes yes true any 0 prefix1
#
# there is no output when exit status is not 0
# the output value, if any, will have any trailing slash(es) removed from it
#
BEGIN { exitcode = "" }
function exitnow(e) { exitcode=e; exit e }
END { if (exitcode != "") exit exitcode }
BEGIN {
sub(/\/+$/, "", prefix1)
sub(/\/+$/, "", prefix2)
sub(/\/+$/, "", prefixh)
if (prefix1 == "" || prefix2 == "" ||
prefix1 == prefix2 ||
prefix1 == prefixh || prefix2 == prefixh)
exitnow(2)
if (substr(prefix1, 1, 5) != "refs/" ||
substr(prefix2, 1, 5) != "refs/" ||
(prefixh != "" && substr(prefixh, 1, 5) != "refs/"))
exitnow(2)
plen1 = length(prefix1)
plen2 = length(prefix2)
plenh = length(prefixh)
if (plen1 < 6 || plen2 < 6) exitnow(2)
prefix1 = prefix1 "/"
prefix2 = prefix2 "/"
++plen1
++plen2
if (prefixh != "") {
prefixh = prefixh "/"
++plenh
}
if (plen1 < plen2 && plen1 == substr(plen2, 1, plen1)) exitnow(2)
if (plen1 > plen2 && substr(plen1, 1, plen2) == plen2) exitnow(2)
sawp1 = 0
sawp2 = 0
cnt = 0
}
function check(r) {
if (length(r) > plen1 && prefix1 == substr(r, 1, plen1)) {
if (prefixh && !(substr(r, plen1) in heads)) return 0
sawp1 = 1
} else if (length(r) > plen2 && prefix2 == substr(r, 1, plen2)) {
if (prefixh && !(substr(r, plen2) in heads)) return 0
sawp2 = 1
}
if (sawp1 && sawp2) return 1
return 0
}
{
if (pckdrefs) ref = $2
else ref = $1
sub(/\/+$/, "", ref)
if (length(ref) < 6 || substr(ref, 1, 5) != "refs/") next
if (prefixh) {
refs[++cnt] = ref
if (length(ref) > plenh && prefixh == substr(ref, 1, plenh))
heads[substr(ref, plenh)] = 1
} else {
if (check(ref)) exit
}
}
END {
for (i = 1; i <= cnt && !check(refs[i]); ++i) ;
if (!noerr && sawp1 && sawp2) exit 65
if (!sawp1 && !sawp2 && nodef) exit 66
if (sawp1 || !sawp2)
print substr(prefix1, 1, plen1 - 1)
else
print substr(prefix2, 1, plen2 - 1)
}