What's cooking
[git/spearce.git] / cook.sh
blob56904fa59fa4a646151b9487f203e169bf079c78
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 count=$(git rev-list "master..$1" | wc -l)
31 mcount=$(git rev-list "maint..$1" | wc -l)
32 if test $mcount = $count
33 then
34 label="$label."
37 echo "$label"
38 lasttimelabel=
39 lastfoundmerge=
40 while read commit
42 merged= merged_with=
43 while read merge at
45 if test -n "$lastfoundmerge"
46 then
47 if test "$lastfoundmerge" = "$merge"
48 then
49 lastfoundmerge=
50 else
51 continue
54 mb=$(git merge-base $merge $commit)
55 if test "$mb" = "$commit"
56 then
57 merged=$at merged_with=$merge
58 else
59 break
61 done <"$tmp.next"
63 lastfoundmerge=$merged_with
64 thistimelabel=
65 if test -n "$merged"
66 then
67 thistimelabel=$merged
68 commitlabel="+"
69 elif grep "$commit" "$tmp.commits.in.pu" >/dev/null
70 then
71 commitlabel="-"
72 else
73 commitlabel="."
75 if test "$lasttimelabel" != "$thistimelabel"
76 then
77 with=$(git rev-parse --short $merged_with)
78 echo " (merged to 'next' on $thistimelabel at $with)"
79 lasttimelabel=$thistimelabel
81 git show -s --format=" $commitlabel %s" $commit
82 done <"$tmp.list"
85 add_desc () {
86 kind=$1
87 shift
88 test -z "$description" || description="$description;"
89 others=
90 while :
92 other=$1
93 shift
94 case "$#,$others" in
95 0,)
96 others="$other"
97 break ;;
98 0,?*)
99 others="$others and $other"
100 break ;;
102 others="$other"
104 *,?*)
105 others="$others, $other"
107 esac
108 done
109 description="$description $kind $others"
112 show_topic () {
113 old=$1 new=$2
115 sed -n -e '/^ ..*/p' -e '/^\* /p' "$old" >"$tmp.old.nc"
116 sed -n -e '/^ ..*/p' -e '/^\* /p' "$new" >"$tmp.new.nc"
117 if cmp "$tmp.old.nc" "$tmp.new.nc" >/dev/null
118 then
119 cat "$old"
120 else
121 cat "$new"
122 echo "<<"
123 cat "$old"
124 echo ">>"
128 while read b
130 git rev-list --no-merges "master..$b"
131 done <"$tmp.branches" | sort | uniq -d >"$tmp.shared"
133 while read shared
135 b=$(git branch --contains "$shared" | sed -n -e 's/^..//' -e '/\//p')
136 echo "" $b ""
137 done <"$tmp.shared" | sort -u >"$tmp.related"
139 serial=1
140 while read b
142 related=$(grep " $b " "$tmp.related" | tr ' ' '\012' | sort -u | sed -e '/^$/d')
144 based_on=
145 used_by=
146 forks=
147 same_as=
148 if test -n "$related"
149 then
150 for r in $related
152 test "$b" = "$r" && continue
153 based=$(git rev-list --no-merges $b..$r | wc -l | tr -d ' ')
154 bases=$(git rev-list --no-merges $r..$b | wc -l | tr -d ' ')
155 case "$based,$bases" in
156 0,0)
157 same_as="$same_as$r "
159 0,*)
160 based_on="$based_on$r "
162 *,0)
163 used_by="$used_by$r "
165 *,*)
166 forks="$forks$r "
168 esac
169 done
173 format_branch "$b" "$based_on"
175 description=
176 test -z "$same_as" || add_desc 'is same as' $same_as
177 test -z "$based_on" || add_desc 'uses' $based_on
178 test -z "$used_by" || add_desc 'is used by' $used_by
179 test -z "$forks" || add_desc 'is related to' $forks
181 test -z "$description" ||
182 echo " (this branch$description.)"
183 } >"$tmp.output.$serial"
184 echo "$b $serial"
185 serial=$(( $serial + 1 ))
186 done <"$tmp.branches" >"$tmp.output.toc"
188 eval $(date +"monthname=%b month=%m year=%Y date=%d dow=%a")
189 lead="whats/cooking/$year/$month"
190 issue=$(
191 cd Meta &&
192 git ls-tree -r --name-only HEAD "$lead" | tail -n 1
194 if test -n "$issue"
195 then
196 issue=$( expr "$issue" : '.*/0*\([1-9][0-9]*\)\.txt$' )
197 issue=$(( $issue + 1 ))
198 else
199 issue=1
201 issue=$( printf "%02d" $issue )
202 mkdir -p "Meta/$lead"
204 last=$(
205 cd Meta &&
206 git ls-tree -r --name-only HEAD "whats/cooking" | tail -n 1
209 # We may have a half-written one already.
210 incremental=no
211 if test -f "Meta/$lead/$issue.txt"
212 then
213 last="$lead/$issue.txt"
214 incremental=yes
217 master_at=$(git rev-parse --verify refs/heads/master)
218 next_at=$(git rev-parse --verify refs/heads/next)
219 cat >"$tmp.output.blurb" <<EOF
220 To: git@vger.kernel.org
221 Subject: What's cooking in git.git ($monthname $year, #$issue; $dow, $date)
222 X-master-at: $master_at
223 X-next-at: $next_at
225 What's cooking in git.git ($monthname $year, #$issue; $dow, $date)
226 --------------------------------------------------
228 Here are the topics that have been cooking. Commits prefixed with '-' are
229 only in 'pu' while commits prefixed with '+' are in 'next'. The ones
230 marked with '.' do not appear in any of the branches, but I am still
231 holding onto them.
235 if test -z "$NO_TEMPLATE" && test -f "Meta/$last"
236 then
237 template="Meta/$last"
238 else
239 template=/dev/null
241 perl -w -e '
242 my $section = undef;
243 my $serial = 1;
244 my $blurb = "b..l..u..r..b";
245 my $branch = $blurb;
246 my $tmp = $ARGV[0];
247 my $incremental = $ARGV[1] eq "yes";
248 my $last_empty = undef;
249 my (@section, %section, @branch, %branch, %description, @leader);
250 my $in_unedited_olde = 0;
252 while (<STDIN>) {
253 if ($in_unedited_olde) {
254 if (/^>>$/) {
255 $in_unedited_olde = 0;
256 $_ = " | $_";
258 } elsif (/^<<$/) {
259 $in_unedited_olde = 1;
262 if ($in_unedited_olde) {
263 $_ = " | $_";
266 if (defined $section && /^-{20,}$/) {
267 $_ = "\n";
269 if (/^$/) {
270 $last_empty = 1;
271 next;
273 if (/^\[(.*)\]\s*$/) {
274 $section = $1;
275 $branch = undef;
276 if ($section eq "New Topics" && !$incremental) {
277 $section = "Old New Topics";
279 if (!exists $section{$section}) {
280 push @section, $section;
281 $section{$section} = [];
283 next;
285 if (defined $section && /^\* (\S+) /) {
286 $branch = $1;
287 $last_empty = 0;
288 if (!exists $branch{$branch}) {
289 push @branch, [$branch, $section];
290 $branch{$branch} = 1;
292 push @{$section{$section}}, $branch;
294 if (defined $branch) {
295 my $was_last_empty = $last_empty;
296 $last_empty = 0;
297 if (!exists $description{$branch}) {
298 $description{$branch} = [];
300 if ($was_last_empty) {
301 push @{$description{$branch}}, "\n";
303 push @{$description{$branch}}, $_;
307 if (open I, "<$tmp.output.toc") {
308 $section = "New Topics";
309 while (<I>) {
310 my ($branch, $oldserial) = /^(\S*) (\d+)$/;
311 next if (exists $branch{$branch});
312 if (!exists $section{$section}) {
313 # Have it at the beginning
314 unshift @section, $section;
315 $section{$section} = [];
317 push @{$section{$section}}, $branch;
318 push @branch, [$branch, $section];
319 $branch{$branch} = 1;
320 if (!exists $description{$branch}) {
321 $description{$branch} = [];
323 open II, "<$tmp.output.$oldserial";
324 while (<II>) {
325 push @{$description{$branch}}, $_;
327 close II;
329 close I;
332 while (0 <= @{$description{$blurb}}) {
333 my $last = pop @{$description{$blurb}};
334 if ($last =~ /^$/ || $last =~ /^-{20,}$/) {
335 next;
336 } else {
337 push @{$description{$blurb}}, $last;
338 last;
342 open O, ">$tmp.template.blurb";
343 for (@{$description{$blurb}}) {
344 print O $_;
346 close O;
348 open TOC, ">$tmp.template.toc";
349 $serial = 1;
350 for my $section (@section) {
351 for my $branch (@{$section{$section}}) {
352 print TOC "$branch $serial $section\n";
353 open O, ">$tmp.template.$serial";
354 for (@{$description{$branch}}) {
355 print O $_;
357 close O;
358 $serial++;
361 ' <"$template" "$tmp" "$incremental"
363 tmpserial=$(
364 tail -n 1 "$tmp.template.toc" | read branch serial section && echo $serial
367 # Assemble them all
369 if test -z "$TO_STDOUT"
370 then
371 exec >"Meta/$lead/$issue.txt"
374 if test -s "$tmp.template.blurb"
375 then
376 sed -e '/^---------------*$/q' <"$tmp.output.blurb"
377 sed -e '1,/^---------------*$/d' <"$tmp.template.blurb"
378 else
379 cat "$tmp.output.blurb"
382 current='
383 --------------------------------------------------
384 [Graduated to "master"]
386 while read branch oldserial section
388 test "$section" = 'Graduated to "master"' &&
389 test "$incremental" = no && continue
391 tip=$(git rev-parse --quiet --verify "refs/heads/$branch") || continue
392 mb=$(git merge-base master $tip)
393 test "$mb" = "$tip" || continue
394 if test -n "$current"
395 then
396 echo "$current"
397 current=
398 else
399 echo
401 cat "$tmp.template.$oldserial"
402 done <"$tmp.template.toc"
404 current=
405 while read branch oldserial section
407 found=$(grep "^$branch " "$tmp.output.toc") || continue
408 newserial=$(expr "$found" : '[^ ]* \(.*\)')
409 if test "$current" != "$section"
410 then
411 current=$section
412 echo "
413 --------------------------------------------------
414 [$section]
416 else
417 echo
420 show_topic "$tmp.template.$oldserial" "$tmp.output.$newserial"
421 done <"$tmp.template.toc"