test-lib.sh: fully construct UNSET_VARS before test-lib-main.sh
[topgit/pro.git] / tg-patch.sh
bloba2daf0ce28e892481cbfb9f07b4469341224aa05
1 #!/bin/sh
2 # TopGit - A different patch queue manager
3 # Copyright (C) Petr Baudis <pasky@suse.cz> 2008
4 # All rights reserved.
5 # GPLv2
7 name=
8 head_from=
9 binary=
10 quiet=
11 fixfrom=
12 fromaddr=
14 gec=0
15 bool="$(git config --get --bool topgit.from 2>/dev/null)" || gec=$?
16 if [ $gec -eq 128 ]; then
17 fromaddr="$(git config --get topgit.from 2>/dev/null)" || :
18 if [ "$fromaddr" = "quiet" ]; then
19 quiet=1
20 else
21 [ -z "$fromaddr" ] || fixfrom=1
23 elif [ $gec -eq 0 ]; then
24 [ "$bool" = "false" ] || fixfrom=1
27 ## Parse options
29 while [ -n "$1" ]; do
30 arg="$1"
31 case "$arg" in
32 --)
33 case "$2" in
34 -*)
35 shift; break;;
37 break;;
38 esac;;
39 -|-h|--help)
40 echo "Usage: ${tgname:-tg} [...] patch [-q] [-i | -w] [--binary] [<name>] [--] [<git-diff-tree-option>...]" >&2
41 exit 1;;
42 -i|-w)
43 [ -z "$head_from" ] || die "-i and -w are mutually exclusive"
44 head_from="$arg";;
45 --binary)
46 binary=1;;
47 -q|--quiet)
48 quiet=1;;
49 --no-from)
50 fixfrom= fromaddr=;;
51 --from)
52 fixfrom=1;;
53 --from=*)
54 fixfrom=1 fromaddr="${1#--from=}";;
55 -?*)
56 if v_verify_topgit_branch test "$arg" -f; then
57 [ -z "$name" ] || die "name already specified ($name)"
58 name="$arg"
59 else
60 break
61 fi;;
63 [ -z "$name" ] || die "name already specified ($name)"
64 name="$arg";;
65 esac
66 shift
67 done
69 head="$(git symbolic-ref -q HEAD)" || :
70 head="${head#refs/heads/}"
72 [ -n "$name" ] ||
73 name="${head:-HEAD}"
74 v_verify_topgit_branch name "$name"
75 base_rev="$(git rev-parse --short --verify "refs/$topbases/$name^0" -- 2>/dev/null)" ||
76 die "not a TopGit-controlled branch"
78 if [ -n "$head_from" ] && [ "$name" != "$head" ]; then
79 die "$head_from makes only sense for the current branch"
81 [ -z "$head_from" ] || ensure_work_tree
83 usesob=
84 [ -z "$fixfrom" ] || [ -n "$fromaddr" ] || {
85 fromaddr="$(git var GIT_AUTHOR_IDENT)" || exit
86 usesob=1
89 # We now collect the rest of the code in this file into a function
90 # so we can redirect the output to the pager.
91 output()
94 # put out the commit message
95 # and put an empty line out, if the last one in the message was not an empty line
96 # and put out "---" if the commit message does not have one yet
97 result=0
98 cat_file "refs/heads/$name:.topmsg" $head_from |
99 awk -v "fixfrom=$fixfrom" -v "fromaddr=$fromaddr" -v "usesob=$usesob" '
100 function trimfb(s) {
101 sub(/^[ \t]+/, "", s)
102 sub(/[ \t]+$/, "", s)
103 return s
105 function fixident(val, fixmt, _name, _email) {
106 val = trimfb(val)
107 if (!fixmt && val == "") return ""
108 _name=""
109 _email=""
110 if ((leftangle = index(val, "<")) > 0) {
111 _name=trimfb(substr(val, 1, leftangle - 1))
112 _email=substr(val, leftangle+1)
113 sub(/>[^>]*$/, "", _email)
114 _email=trimfb(_email)
115 } else {
116 if ((atsign = index(val, "@")) > 0) {
117 _name=trimfb(substr(val, 1, atsign - 1))
118 _email=trimfb(val)
119 } else {
120 _name=trimfb(val)
121 if (_name != "") _email="-"
124 if (!fixmt && _name == "" && _email == "") return ""
125 if (_name == "") _name = "-"
126 if (_email == "") _email = "-"
127 return _name " <" _email ">"
129 BEGIN {
130 hdrline = 0
131 sawfrom = 0
132 sobname = ""
133 if (fixfrom) {
134 fromaddr = fixident(fromaddr)
135 if (fromaddr == "" && !usesob) fixfrom = 0
137 inhdr = 1
138 bodyline = 0
140 inhdr && /^[Ff][Rr][Oo][Mm][ \t]*:/ {
141 val = $0
142 sub(/^[^:]*:/, "", val)
143 val = fixident(val)
144 if (val != "") sawfrom = 1
145 if (val != "" || !fixfrom) hdrs[++hdrline] = $0
146 next
148 inhdr && /^[ \t]*$/ {
149 inhdr = 0
150 next
152 inhdr { hdrs[++hdrline] = $0; next; }
153 function writehdrs() {
154 if (!sawfrom && fixfrom && fromaddr != "") {
155 print "From: " fromaddr
156 sawfrom = 1
158 for (i=1; i <= hdrline; ++i) print hdrs[i]
159 print ""
161 /^---/ { has_3dash=1 }
162 usesob && /^[Ss][Ii][Gg][Nn][Ee][Dd]-[Oo][Ff][Ff]-[Bb][Yy][ \t]*:[ \t]*[^ \t]/ {
163 val = $0
164 sub(/^[^:]*:/, "", val)
165 val = fixident(val)
166 if (val != "") fromaddr=val
169 need_empty = 1
170 if ($0 == "") need_empty = 0
171 body[++bodyline] = $0
173 END {
174 writehdrs()
175 for (i = 1; i <= bodyline; ++i) print body[i]
176 if (need_empty) print ""
177 if (!has_3dash) print "---"
178 exit sawfrom ? 0 : 67 # EX_NOUSER
180 ' || result=$?
181 if [ "$result" = "67" ]; then
182 [ -n "$quiet" ] ||
183 echo "### tg: missing From: in .topmsg, 'git am' will barf (use --from to add)" >&2
184 result=0
186 [ "${result:-0}" = "0" ] || exit "$result"
188 v_pretty_tree b_tree -t "$name" -b
189 v_pretty_tree t_tree -t "$name" $head_from
191 if [ $b_tree = $t_tree ]; then
192 echo "No changes."
193 else
194 hasdd=
195 for a; do
196 [ "$a" != "--" ] || { hasdd=1; break; }
197 done
198 if [ -z "$hasdd" ]; then
199 git diff-tree -p --stat --summary ${binary:+--binary} "$@" $b_tree $t_tree
200 else
201 cmd="git diff-tree -p --stat --summary ${binary:+--binary}"
202 while [ $# -gt 0 ] && [ "$1" != "--" ]; do
203 cmd="$cmd $(quotearg "$1")"
204 shift
205 done
206 cmd="$cmd $(quotearg "$b_tree") $(quotearg "$t_tree")"
207 while [ $# -gt 0 ]; do
208 cmd="$cmd $(quotearg "$1")"
209 shift
210 done
211 eval "$cmd"
215 echo ''
216 echo '-- '
217 depon="$(cat_file "refs/heads/$name:.topdeps" $head_from 2>/dev/null | paste -s -d ' ' -)"
218 echo "$tgname: ($base_rev..) $name${depon:+ (depends on: $depon)}"
219 branch_contains "refs/heads/$name" "refs/$topbases/$name" ||
220 echo "$tgname: The patch is out-of-date wrt. the base! Run \`$tgdisplay update\`."
223 USE_PAGER_TYPE=diff
224 page output "$@"
225 # ... and then we run it through the pager with the page function