add a perl script to convert MaintNotes to wiki format
[git/dscho.git] / cook.sh
blobdabee4b38c60eddfc44ed9424455bc774acb449e
1 #!/bin/sh
3 LANG=C LC_ALL=C GIT_PAGER=cat
4 export LANG LC_ALL GIT_PAGER
6 tmpdir=/var/tmp/cook.$$
7 mkdir "$tmpdir" || exit
8 tmp="$tmpdir/t"
9 trap 'rm -fr "$tmpdir"' 0
11 git branch --merged "master" | sed -n -e 's/^..//' -e '/\//p' >"$tmp.in.master"
12 git branch --merged "pu" | sed -n -e 's/^..//' -e '/\//p' >"$tmp.in.pu"
14 comm -13 "$tmp.in.master" "$tmp.in.pu"
15 git branch --no-merged pu |
16 sed -n -e 's/^..//' -e '/\//p'
17 } >"$tmp.branches"
19 git log --first-parent --format="%H %ci" master..next |
20 sed -e 's/ [0-2][0-9]:[0-6][0-9]:[0-6][0-9] [-+][0-2][0-9][0-6][0-9]$//' >"$tmp.next"
21 git rev-list master..pu >"$tmp.commits.in.pu"
23 format_branch () {
24 # branch=$1 others=$2
25 git rev-list --no-merges --topo-order "master..$1" --not $2 >"$tmp.list"
26 count=$(wc -l <"$tmp.list" | tr -d ' ')
27 label="* $1 ($(git show -s --format="%ai" $1 | sed -e 's/ .*//')) $count commit"
28 test "$count" = 1 || label="${label}s"
30 echo "$label"
31 lasttimelabel=
32 lastfoundmerge=
33 while read commit
35 merged= merged_with=
36 while read merge at
38 if test -n "$lastfoundmerge"
39 then
40 if test "$lastfoundmerge" = "$merge"
41 then
42 lastfoundmerge=
43 else
44 continue
47 mb=$(git merge-base $merge $commit)
48 if test "$mb" = "$commit"
49 then
50 merged=$at merged_with=$merge
51 else
52 break
54 done <"$tmp.next"
56 lastfoundmerge=$merged_with
57 thistimelabel=
58 if test -n "$merged"
59 then
60 thistimelabel=$merged
61 commitlabel="+"
62 elif grep "$commit" "$tmp.commits.in.pu" >/dev/null
63 then
64 commitlabel="-"
65 else
66 commitlabel="."
68 if test "$lasttimelabel" != "$thistimelabel"
69 then
70 with=$(git rev-parse --short $merged_with)
71 echo " (merged to 'next' on $thistimelabel at $with)"
72 lasttimelabel=$thistimelabel
74 git show -s --format=" $commitlabel %s" $commit
75 done <"$tmp.list"
78 add_desc () {
79 kind=$1
80 shift
81 test -z "$description" || description="$description;"
82 others=
83 while :
85 other=$1
86 case "$other" in
87 "#EPO-"*) other="early parts of ${other#"#EPO-"}"
88 esac
89 shift
90 case "$#,$others" in
91 0,)
92 others="$other"
93 break ;;
94 0,?*)
95 others="$others and $other"
96 break ;;
97 *,)
98 others="$other"
100 *,?*)
101 others="$others, $other"
103 esac
104 done
105 description="$description $kind $others"
108 show_topic () {
109 old=$1 new=$2
111 sed -n -e '/^ ..*/p' -e '/^\* /p' "$old" >"$tmp.old.nc"
112 sed -n -e '/^ ..*/p' -e '/^\* /p' "$new" >"$tmp.new.nc"
113 if cmp "$tmp.old.nc" "$tmp.new.nc" >/dev/null
114 then
115 cat "$old"
116 else
117 cat "$new"
118 echo "<<"
119 cat "$old"
120 echo ">>"
124 compare_topic () {
125 b=$1 r=$2
126 based=$(git rev-list --no-merges $b..$r | wc -l | tr -d ' ')
127 bases=$(git rev-list --no-merges $r..$b | wc -l | tr -d ' ')
128 case "$based,$bases" in
129 0,0) echo same; exit ;;
130 0,*) echo left; exit ;;
131 *,0) echo right; exit ;;
132 esac
134 if test $based -lt $bases
135 then
136 echo left-p
137 else
138 echo fork
142 # List commits that are shared between more than one topic branches
143 while read b
145 git rev-list --no-merges "master..$b"
146 done <"$tmp.branches" | sort | uniq -d >"$tmp.shared"
148 # Set of branches related to each other due to sharing the same commit
149 while read shared
151 b=$(git branch --contains "$shared" | sed -n -e 's/^..//' -e '/\//p')
152 echo "" $b ""
153 done <"$tmp.shared" | sort -u >"$tmp.related"
155 serial=1
156 while read b
158 related=$(grep " $b " "$tmp.related" | tr ' ' '\012' | sort -u | sed -e '/^$/d')
160 based_on= based_on_msg=
161 used_by=
162 forks=
163 same_as=
164 if test -n "$related"
165 then
166 for r in $related
168 test "$b" = "$r" && continue
169 case "$(compare_topic "$b" "$r")" in
170 same)
171 same_as="$same_as$r "
173 left)
174 based_on="$based_on$r "
175 based_on_msg="$based_on_msg$r "
177 left-p)
178 based_on="$based_on$r "
179 based_on_msg="${based_on_msg}#EPO-$r "
181 right)
182 used_by="$used_by$r "
184 fork)
185 forks="$forks$r "
187 esac
188 done
192 format_branch "$b" "$based_on"
194 description=
195 test -z "$same_as" || add_desc 'is same as' $same_as
196 test -z "$based_on" || add_desc 'uses' $based_on_msg
197 test -z "$used_by" || add_desc 'is used by' $used_by
198 test -z "$forks" || add_desc 'shares commits with' $forks
200 test -z "$description" ||
201 echo " (this branch$description.)"
202 } >"$tmp.output.$serial"
203 echo "$b $serial"
204 serial=$(( $serial + 1 ))
205 done <"$tmp.branches" >"$tmp.output.toc"
207 eval $(date +"monthname=%b month=%m year=%Y date=%d dow=%a")
209 incremental=$(
210 cd Meta &&
211 if git diff --quiet --no-ext-diff HEAD -- whats-cooking.txt >/dev/null
212 then
213 echo no
214 else
215 echo yes
219 # Find the current issue
220 eval $(sed -ne '/^Subject: /{
221 s/^Subject: What.s cooking in git.git (\([A-Z][a-z][a-z]\) \([0-9][0-9][0-9][0-9]\), #\([0-9][0-9]*\); [A-Z][a-z][a-z], [0-9][0-9])$/lastmon=\1 lastyear=\2 lastissue=\3/p
223 }' Meta/whats-cooking.txt)
224 if test "$monthname $year" = "$lastmon $lastyear"
225 then
226 if test "$incremental" = no
227 then
228 issue=$(( $lastissue + 1 ))
229 else
230 issue=$(( lastissue + 0 ))
232 else
233 issue=1
236 issue=$( printf "%02d" $issue )
237 last=whats-cooking.txt
239 master_at=$(git rev-parse --verify refs/heads/master)
240 next_at=$(git rev-parse --verify refs/heads/next)
241 cat >"$tmp.output.blurb" <<EOF
242 To: git@vger.kernel.org
243 Subject: What's cooking in git.git ($monthname $year, #$issue; $dow, $date)
244 X-master-at: $master_at
245 X-next-at: $next_at
247 What's cooking in git.git ($monthname $year, #$issue; $dow, $date)
248 --------------------------------------------------
250 Here are the topics that have been cooking. Commits prefixed with '-' are
251 only in 'pu' while commits prefixed with '+' are in 'next'. The ones
252 marked with '.' do not appear in any of the branches, but I am still
253 holding onto them.
257 if test -z "$NO_TEMPLATE" && test -f "Meta/$last"
258 then
259 template="Meta/$last"
260 else
261 template=/dev/null
263 perl -w -e '
264 my $section = undef;
265 my $serial = 1;
266 my $blurb = "b..l..u..r..b";
267 my $branch = $blurb;
268 my $tmp = $ARGV[0];
269 my $incremental = $ARGV[1] eq "yes";
270 my $last_empty = undef;
271 my (@section, %section, @branch, %branch, %description, @leader);
272 my $in_unedited_olde = 0;
274 while (<STDIN>) {
275 if ($in_unedited_olde) {
276 if (/^>>$/) {
277 $in_unedited_olde = 0;
278 $_ = " | $_";
280 } elsif (/^<<$/) {
281 $in_unedited_olde = 1;
284 if ($in_unedited_olde) {
285 $_ = " | $_";
288 if (defined $section && /^-{20,}$/) {
289 $_ = "\n";
291 if (/^$/) {
292 $last_empty = 1;
293 next;
295 if (/^\[(.*)\]\s*$/) {
296 $section = $1;
297 $branch = undef;
298 if ($section eq "New Topics" && !$incremental) {
299 $section = "Old New Topics";
301 if (!exists $section{$section}) {
302 push @section, $section;
303 $section{$section} = [];
305 next;
307 if (defined $section && /^\* (\S+) /) {
308 $branch = $1;
309 $last_empty = 0;
310 if (!exists $branch{$branch}) {
311 push @branch, [$branch, $section];
312 $branch{$branch} = 1;
314 push @{$section{$section}}, $branch;
316 if (defined $branch) {
317 my $was_last_empty = $last_empty;
318 $last_empty = 0;
319 if (!exists $description{$branch}) {
320 $description{$branch} = [];
322 if ($was_last_empty) {
323 push @{$description{$branch}}, "\n";
325 push @{$description{$branch}}, $_;
329 if (open I, "<$tmp.output.toc") {
330 $section = "New Topics";
331 while (<I>) {
332 my ($branch, $oldserial) = /^(\S*) (\d+)$/;
333 next if (exists $branch{$branch});
334 if (!exists $section{$section}) {
335 # Have it at the beginning
336 unshift @section, $section;
337 $section{$section} = [];
339 push @{$section{$section}}, $branch;
340 push @branch, [$branch, $section];
341 $branch{$branch} = 1;
342 if (!exists $description{$branch}) {
343 $description{$branch} = [];
345 open II, "<$tmp.output.$oldserial";
346 while (<II>) {
347 push @{$description{$branch}}, $_;
349 close II;
351 close I;
354 while (0 <= @{$description{$blurb}}) {
355 my $last = pop @{$description{$blurb}};
356 if ($last =~ /^$/ || $last =~ /^-{20,}$/) {
357 next;
358 } else {
359 push @{$description{$blurb}}, $last;
360 last;
364 open O, ">$tmp.template.blurb";
365 for (@{$description{$blurb}}) {
366 print O $_;
368 close O;
370 open TOC, ">$tmp.template.toc";
371 $serial = 1;
372 for my $section (@section) {
373 for my $branch (@{$section{$section}}) {
374 print TOC "$branch $serial $section\n";
375 open O, ">$tmp.template.$serial";
376 for (@{$description{$branch}}) {
377 print O $_;
379 close O;
380 $serial++;
383 ' <"$template" "$tmp" "$incremental"
385 tmpserial=$(
386 tail -n 1 "$tmp.template.toc" |
387 read branch serial section &&
388 echo $serial
391 # Assemble them all
393 if test -z "$TO_STDOUT"
394 then
395 exec >"Meta/whats-cooking.txt"
398 if test -s "$tmp.template.blurb"
399 then
400 sed -e '/^---------------*$/q' <"$tmp.output.blurb"
401 sed -e '1,/^---------------*$/d' <"$tmp.template.blurb"
402 else
403 cat "$tmp.output.blurb"
406 current='
407 --------------------------------------------------
408 [Graduated to "master"]
410 while read branch oldserial section
412 test "$section" = 'Graduated to "master"' &&
413 test "$incremental" = no && continue
415 tip=$(git rev-parse --quiet --verify "refs/heads/$branch") || continue
416 mb=$(git merge-base master $tip)
417 test "$mb" = "$tip" || continue
418 if test -n "$current"
419 then
420 echo "$current"
421 current=
422 else
423 echo
425 cat "$tmp.template.$oldserial"
426 done <"$tmp.template.toc"
428 current=
429 while read branch oldserial section
431 found=$(grep "^$branch " "$tmp.output.toc") || continue
432 newserial=$(expr "$found" : '[^ ]* \(.*\)')
433 if test "$current" != "$section"
434 then
435 current=$section
436 echo "
437 --------------------------------------------------
438 [$section]
440 else
441 echo
444 show_topic "$tmp.template.$oldserial" "$tmp.output.$newserial"
445 done <"$tmp.template.toc"