What's cooking (2023/11) #03
[alt-git.git] / Reintegrate
blobddff2664bcda4c149f91ef96d6684431021a5446
1 #!/bin/sh
3 accept_rerere="--rerere-autoupdate"
4 generate=no
5 exec=:
6 update= diff= edit= stop_at_cut= skip_cocci= force_cocci= no_cocci=
7 while case "$#,$1" in 0,*) break;; *,-*) ;; esac
8 do
9 case "$1" in
10 -n) accept_rerere= ;;
11 -e) edit=t ;;
12 -c) stop_at_cut=1 ;;
13 -c?*) stop_at_cut=${1#-c} ;;
14 -d) update=${2?"diff with what?"}
15 diff=yes
16 generate=yes
17 shift ;;
18 -u) update=${2?"update what?"}
19 generate=yes
20 shift ;;
21 -x) exec=${2?exec}; shift ;;
22 -x?*) exec=${1#-x} ;;
23 -ss) skip_cocci=t ;;
24 -fs) force_cocci=t ;;
25 -ns) no_cocci=t ;;
26 *) generate=yes
27 break ;;
28 esac
29 shift
30 done
32 annotate_merge () {
33 test -f Meta/whats-cooking.txt || return 0
35 # NEEDSWORK: unify with cook::wildo_match
36 perl -e '
37 sub wildo_match {
38 s/^\s*//;
39 if (/^Will (?:\S+ ){0,2}(fast-track|hold|keep|merge|drop|discard|cook|kick|defer|eject|be re-?rolled|wait)[,. ]/ ||
40 /^Not urgent/ || /^Not ready/ || /^Waiting for / ||
41 /^Can wait in / || /^Still / || /^Stuck / || /^On hold/ || /^Breaks / ||
42 /^Needs? / || /^Expecting / || /^May want to / || /^Under review/) {
43 return 1;
45 return 0;
48 sub read_message {
49 my ($fh, $branch) = @_;
50 my ($in_section, $in_desc);
51 my @msg = ();
52 while (<$fh>) {
53 chomp;
54 if (/^\* \Q$branch\E /) {
55 $in_section = 1;
56 next;
58 last if (/^[-*\[]/ && $in_section);
59 next unless $in_section;
60 s/^\s+//;
61 if (/^$/) {
62 $in_desc = 1;
64 next unless ($in_section && $in_desc);
65 next if (/Originally merged to '\''next'\'' on ([-0-9]+)/);
66 next if (/^source: /);
67 last if (wildo_match($_));
68 push @msg, "$_\n";
70 return ($in_section, @msg);
73 my ($branch) = $ARGV[0];
74 my ($fh, $in_section, @msg);
75 if (open $fh, "<", "Meta/whats-cooking.txt") {
76 ($in_section, @msg) = read_message($fh, $branch);
78 if (!@msg) {
79 open my $revs, "-|",
80 qw(git -C Meta rev-list -32 HEAD -- whats-cooking.txt);
81 while (my $rev = <$revs>) {
82 chomp($rev);
83 open $fh, "-|",
84 qw(git -C Meta cat-file blob), "$rev:whats-cooking.txt";
85 ($in_section, @msg) = read_message($fh, $branch);
86 last if (@msg);
89 if (@msg) {
90 open(my $fh, "-|", qw(git cat-file commit HEAD));
91 my @original = (<$fh>);
92 close $fh;
93 my @final;
94 $in_section = 0;
95 for (@original) {
96 if (!$in_section) {
97 $in_section = 1 if (/^$/);
98 next;
100 if (/^Conflicts:$/ && $in_section == 2) {
101 $in_section = 3;
104 if ($in_section == 3) {
105 $_ = "# $_";
107 push @final, $_;
108 if (/^$/ && $in_section == 1) {
109 push @final, @msg;
110 push @final, "\n";
111 $in_section = 2;
114 open($fh, "|-", qw(git commit --amend -F -));
115 print $fh @final;
116 close $fh;
118 ' "$1"
121 cocci_mark="treewide: apply cocci patch"
123 case "$generate" in
125 accept_rerere () {
126 if ! git write-tree 2>/dev/null >/dev/null
127 then
128 git rerere remaining
129 return 1
130 else
131 GIT_EDITOR=: git commit --no-verify
132 echo "Accepted previous resolution"
133 return 0
137 mark_cut () {
138 test -n "$stop_at_cut" && return
140 count_since_last_cut=$(( $count_since_last_cut + 1 ))
141 test -z "$prev_cut" && return
142 git commit --allow-empty -m "$prev_cut"
143 prev_cut=
146 cut_seen=0 prev_cut= count_since_last_cut=0 cocci_count=0
147 while read branch eh
149 case "$branch" in '###') cut_seen=$(( $cut_seen + 1 )) ;; esac
150 if test -n "$stop_at_cut" && test $stop_at_cut -le $cut_seen
151 then
152 continue ;# slurp the remainder and skip
155 case "$branch" in
156 '###')
157 if test "$count_since_last_cut" = 0
158 then
159 prev_cut=
160 else
161 echo >&2 "$branch $eh"
162 prev_cut="$branch $eh"
163 count_since_last_cut=0
165 continue ;;
166 '#cocci')
167 if test -n "$no_cocci"
168 then
169 continue
170 elif test 0 = "$cocci_count" && test -z "$force_cocci"
171 then
172 continue
175 if test -n "$skip_cocci" && test -n "$eh"
176 then
177 git cherry-pick --no-commit "$eh"
178 else
179 rm -f contrib/coccinelle/*.patch
180 Meta/Make -j8 coccicheck
181 if grep coccicheck-pending Makefile >/dev/null
182 then
183 Meta/Make -j8 coccicheck-pending
185 cat contrib/coccinelle/*.patch >cocci.patch
186 if ! test -s cocci.patch
187 then
188 exit 0
190 git apply --index -3 cocci.patch || exit
191 rm cocci.patch
192 git diff --quiet HEAD && continue
194 git commit -m "$cocci_mark" || exit
196 mark_cut
197 continue
199 '#'* | '')
200 continue ;;
201 esac
203 case "$eh" in
204 "" | "#"* | [0-9][0-9]-[0-9][0-9]*)
205 echo >&2 "* $branch"
207 save=$(git rev-parse --verify HEAD) &&
208 tip=$(git rev-parse --verify "$branch^0") &&
209 mb=$(git merge-base "$tip" "$save") ||
210 exit
212 test "$mb" = "$tip" && continue
214 mark_cut
215 cocci_count=$(( $cocci_count + 1 ))
217 rebuild=$(git config "branch.$branch.rebuild" || :)
219 GIT_EDITOR=: git merge --no-ff $rebuild $accept_rerere --edit "$branch" ||
220 accept_rerere ||
221 exit
223 annotate_merge "$branch" || exit
224 test -z "$edit" ||
225 git commit --amend || exit
227 this=$(git rev-parse --verify HEAD)
228 if test "$this" = "$save"
229 then
231 elif git show-ref -q --verify "refs/merge-fix/$branch"
232 then
233 echo >&2 "Fixing up the merge"
234 git cherry-pick --no-commit "refs/merge-fix/$branch" &&
235 git diff --stat HEAD &&
236 GIT_EDITOR=: git commit --amend -a || exit
239 pick" "*)
240 echo >&2 "* $eh"
242 mark_cut
244 git cherry-pick "$branch" || exit ;;
245 *) echo >&2 "Eh? $branch $eh"; exit ;;
246 esac
248 eval "$exec" || exit
249 done
250 exit
251 esac
253 if test -n "$update" && test $# = 0
254 then
255 set x $(sed -n -e '2s/^# //p' <"$update") &&
256 shift
259 # Generation (or updating)
261 x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
262 x40="$x40$x40$x40$x40$x40$x40$x40$x40"
263 LF='
266 show_merge () {
267 case "$msg" in
268 "Merge branch '"*"'"*)
269 branch=$(expr "$msg" : "Merge branch '\(.*\)'")
270 merge_hier=heads/
272 "Merge remote branch '"*"'"*)
273 branch=$(expr "$msg" : "Merge remote branch '\(.*\)'")
274 merge_hier=
277 echo 2>&1 "Huh?: $msg"
278 return
280 esac &&
281 tip=$(git rev-parse --verify "refs/$merge_hier$branch" 2>/dev/null) &&
282 merged=$(git name-rev --refs="refs/$merge_hier$branch" "$other" 2>/dev/null) &&
283 merged=$(expr "$merged" : "$x40 \(.*\)") &&
284 test "$merged" != undefined || {
285 other=$(git log -1 --pretty='format:%s' $other) &&
286 merged="$branch :rebased? $other"
290 show_pick () {
291 case "$msg" in
292 "### "* | "###")
293 merged="$msg$LF"
296 merged="$(git rev-parse --verify "$commit") pick $msg"
298 esac
302 generate () {
303 PROGRAM=$1
304 shift
305 echo '#!/bin/sh'
306 echo "# $1"
307 echo 'case "$#,$1" in'
308 echo '1,-u|1,-d)'
309 echo " exec $PROGRAM" '"$1" "$0"'
310 echo 'esac'
311 echo "$PROGRAM" '"$@" <<\EOF'
312 git log --no-decorate --pretty=oneline --first-parent "$1" |
314 series=
315 while read commit msg
317 if other=$(git rev-parse -q --verify "$commit^2")
318 then
319 show_merge
320 elif test "$msg" = "$cocci_mark"
321 then
322 merged="#cocci "$(git rev-parse "$commit^0")
323 else
324 show_pick
327 if test -z "$series"
328 then
329 series="$merged"
330 else
331 series="$merged$LF$series"
333 done
334 echo "$series"
336 echo EOF
339 if test -z "$update"
340 then
341 generate "$0" "$@"
342 elif test -z "$diff"
343 then
344 generate "$0" "$@" | diff -w -u "$update" -
345 if test $? = 0
346 then
347 echo >&2 "No changes."
348 else
349 echo >&2 -n "Update [y/N]? "
350 read yesno
351 case "$yesno" in
352 [Yy]*)
353 generate "$0" "$@" |
354 sed -e 's/ :rebased?.*//' >"$update" ;;
356 echo >&2 "No update then." ;;
357 esac
359 else
360 generate "$0" "$@" | diff -w -u "$update" -