cook.sh: separate reading and output of template in separate phases
[git/dscho.git] / cook.sh
blob471a8da98e3492e4076352a9f63ed080ee8a8932
1 #!/bin/sh
3 LANG=C LC_ALL=C GIT_PAGER=cat
4 export LANG LC_ALL GIT_PAGER
6 tmp=/var/tmp/cook.$$
7 trap 'rm -f "$tmp".*' 0
9 git branch --merged "master" | sed -n -e 's/^..//' -e '/\//p' >"$tmp.in.master"
10 git branch --merged "pu" | sed -n -e 's/^..//' -e '/\//p' >"$tmp.in.pu"
12 comm -13 "$tmp.in.master" "$tmp.in.pu"
13 git branch --no-merged pu |
14 sed -n -e 's/^..//' -e '/\//p'
15 } >"$tmp.branches"
17 git log --first-parent --format="%H %ci" master..next |
18 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"
19 git rev-list master..pu >"$tmp.commits.in.pu"
21 format_branch () {
22 # branch=$1 others=$2
23 git rev-list --no-merges --topo-order "master..$1" --not $2 >"$tmp.list"
24 count=$(wc -l <"$tmp.list" | tr -d ' ')
25 label="* $1 ($(git show -s --format="%ai" $1 | sed -e 's/ .*//')) $count commit"
26 test "$count" = 1 || label="${label}s"
28 count=$(git rev-list "master..$1" | wc -l)
29 mcount=$(git rev-list "maint..$1" | wc -l)
30 if test $mcount = $count
31 then
32 label="$label."
35 echo "$label"
36 lasttimelabel=
37 lastfoundmerge=
38 while read commit
40 merged= merged_with=
41 while read merge at
43 if test -n "$lastfoundmerge"
44 then
45 if test "$lastfoundmerge" = "$merge"
46 then
47 lastfoundmerge=
48 else
49 continue
52 mb=$(git merge-base $merge $commit)
53 if test "$mb" = "$commit"
54 then
55 merged=$at merged_with=$merge
56 else
57 break
59 done <"$tmp.next"
61 lastfoundmerge=$merged_with
62 thistimelabel=
63 if test -n "$merged"
64 then
65 thistimelabel=$merged
66 commitlabel="+"
67 elif grep "$commit" "$tmp.commits.in.pu" >/dev/null
68 then
69 commitlabel="-"
70 else
71 commitlabel="."
73 if test "$lasttimelabel" != "$thistimelabel"
74 then
75 with=$(git rev-parse --short $merged_with)
76 echo " (merged to 'next' on $thistimelabel at $with)"
77 lasttimelabel=$thistimelabel
79 git show -s --format=" $commitlabel %s" $commit
80 done <"$tmp.list"
83 add_desc () {
84 kind=$1
85 shift
86 test -z "$description" || description="$description;"
87 others=
88 while :
90 other=$1
91 shift
92 case "$#,$others" in
93 0,)
94 others="$other"
95 break ;;
96 0,?*)
97 others="$others and $other"
98 break ;;
99 *,)
100 others="$other"
102 *,?*)
103 others="$others, $other"
105 esac
106 done
107 description="$description $kind $others"
110 show_topic () {
111 old=$1 new=$2
113 sed -n -e '/^ ..*/p' "$old" >"$tmp.old.nc"
114 sed -n -e '/^ ..*/p' "$new" >"$tmp.new.nc"
115 if cmp "$tmp.old.nc" "$tmp.new.nc" >/dev/null
116 then
117 cat "$old"
118 else
119 cat "$new"
120 echo "<<"
121 cat "$old"
122 echo ">>"
126 while read b
128 git rev-list --no-merges "master..$b"
129 done <"$tmp.branches" | sort | uniq -d >"$tmp.shared"
131 while read shared
133 b=$(git branch --contains "$shared" | sed -n -e 's/^..//' -e '/\//p')
134 echo "" $b ""
135 done <"$tmp.shared" | sort -u >"$tmp.related"
137 serial=1
138 while read b
140 related=$(grep " $b " "$tmp.related" | tr ' ' '\012' | sort -u | sed -e '/^$/d')
142 based_on=
143 used_by=
144 forks=
145 same_as=
146 if test -n "$related"
147 then
148 for r in $related
150 test "$b" = "$r" && continue
151 based=$(git rev-list --no-merges $b..$r | wc -l | tr -d ' ')
152 bases=$(git rev-list --no-merges $r..$b | wc -l | tr -d ' ')
153 case "$based,$bases" in
154 0,0)
155 same_as="$same_as$r "
157 0,*)
158 based_on="$based_on$r "
160 *,0)
161 used_by="$used_by$r "
163 *,*)
164 forks="$forks$r "
166 esac
167 done
171 format_branch "$b" "$based_on"
173 description=
174 test -z "$same_as" || add_desc 'is same as' $same_as
175 test -z "$based_on" || add_desc 'uses' $based_on
176 test -z "$used_by" || add_desc 'is used by' $used_by
177 test -z "$forks" || add_desc 'is related to' $forks
179 test -z "$description" ||
180 echo " (this branch$description.)"
181 } >"$tmp.output.$serial"
182 echo "$b $serial"
183 serial=$(( $serial + 1 ))
184 done <"$tmp.branches" >"$tmp.output.toc"
186 eval $(date +"monthname=%b month=%m year=%Y date=%d dow=%a")
187 lead="whats/cooking/$year/$month"
188 issue=$(
189 cd Meta &&
190 git ls-tree -r --name-only HEAD "$lead" | tail -n 1
192 if test -n "$issue"
193 then
194 issue=$( expr "$issue" : '.*/0*\([1-9][0-9]*\)\.txt$' )
195 issue=$(( $issue + 1 ))
196 else
197 issue=1
199 issue=$( printf "%02d" $issue )
200 mkdir -p "Meta/$lead"
202 last=$(
203 cd Meta &&
204 git ls-tree -r --name-only HEAD "whats/cooking" | tail -n 1
207 # We may have a half-written one already.
208 incremental=no
209 if test -f "Meta/$lead/$issue.txt"
210 then
211 last="$lead/$issue.txt"
212 incremental=yes
215 master_at=$(git rev-parse --verify refs/heads/master)
216 next_at=$(git rev-parse --verify refs/heads/next)
217 cat >"$tmp.output.blurb" <<EOF
218 To: git@vger.kernel.org
219 Subject: What's cooking in git.git ($monthname $year, #$issue; $dow, $date)
220 X-master-at: $master_at
221 X-next-at: $next_at
223 What's cooking in git.git ($monthname $year, #$issue; $dow, $date)
224 --------------------------------------------------
226 Here are the topics that have been cooking. Commits prefixed with '-' are
227 only in 'pu' while commits prefixed with '+' are in 'next'. The ones
228 marked with '.' do not appear in any of the branches, but I am still
229 holding onto them.
233 if test -z "$NO_TEMPLATE" && test -f "Meta/$last"
234 then
235 template="Meta/$last"
236 else
237 template=/dev/null
239 perl -w -e '
240 my $section = undef;
241 my $serial = 1;
242 my $blurb = "b..l..u..r..b";
243 my $branch = $blurb;
244 my $tmp = $ARGV[0];
245 my $incremental = $ARGV[1] eq "yes";
246 my $last_empty = undef;
247 my (@section, %section, @branch, %branch, %description, @leader);
249 while (<STDIN>) {
250 if (defined $section && /^-{20,}$/) {
251 $_ = "\n";
253 if (/^$/) {
254 $last_empty = 1;
255 next;
257 if (/^\[(.*)\]\s*$/) {
258 $section = $1;
259 $branch = undef;
260 if ($section eq "New Topics" && !$incremental) {
261 $section = "Old New Topics";
263 if (!exists $section{$section}) {
264 push @section, $section;
265 $section{$section} = [];
267 next;
269 if (defined $section && /^\* (\S+) /) {
270 $branch = $1;
271 $last_empty = 0;
272 if (!exists $branch{$branch}) {
273 push @branch, [$branch, $section];
274 $branch{$branch} = (scalar @branch) - 1;
276 push @{$section{$section}}, $branch;
278 if (defined $branch) {
279 if ($last_empty) {
280 $_ = "\n$_";
282 $last_empty = 0;
283 if (!exists $description{$branch}) {
284 $description{$branch} = [];
286 push @{$description{$branch}}, $_;
290 open O, ">$tmp.template.blurb";
291 for (@{$description{$blurb}}) {
292 print O $_;
294 close O;
296 open TOC, ">$tmp.template.toc";
297 for my $section (@section) {
298 for my $branch (@{$section{$section}}) {
299 my $serial = $branch{$branch};
300 print TOC "$branch $serial $section\n";
301 open O, ">$tmp.template.$serial";
302 for (@{$description{$branch}}) {
303 print O $_;
305 close O;
308 ' <"$template" "$tmp" "$incremental"
310 tmpserial=$(
311 tail -n 1 "$tmp.template.toc" | read branch serial section && echo $serial
314 # Assemble them all
316 if test -z "$TO_STDOUT"
317 then
318 exec >"Meta/$lead/$issue.txt"
321 if test -s "$tmp.template.blurb"
322 then
323 sed -e '/^---------------*/q' <"$tmp.output.blurb"
324 sed -e '1,/^---------------*/d' <"$tmp.template.blurb"
325 else
326 cat "$tmp.output.blurb"
327 fi | sed -e '$d'
329 while read branch serial
331 grep "^$branch " "$tmp.template.toc" >/dev/null && continue
333 tmpserial=$(( $tmpserial + 1 ))
334 echo "$branch $tmpserial New Topics" >>"$tmp.template.toc"
335 cp "$tmp.output.$serial" "$tmp.template.$tmpserial"
336 done <"$tmp.output.toc"
338 current='--------------------------------------------------
339 [Graduated to "master"]
341 while read branch oldserial section
343 test "$section" = 'Graduated to "master"' &&
344 test "$incremental" = no && continue
346 tip=$(git rev-parse --quiet --verify "refs/heads/$branch")
347 mb=$(git merge-base master $tip)
348 test "$mb" = "$tip" || continue
349 if test -n "$current"
350 then
351 echo "$current"
352 current=
353 else
354 echo
356 cat "$tmp.template.$oldserial"
357 done <"$tmp.template.toc"
359 current=
360 while read branch oldserial section
362 found=$(grep "^$branch " "$tmp.output.toc") || continue
363 newserial=$(expr "$found" : '[^ ]* \(.*\)')
364 if test "$current" != "$section"
365 then
366 current=$section
367 echo "--------------------------------------------------
368 [$section]
370 else
371 echo
374 show_topic "$tmp.template.$oldserial" "$tmp.output.$newserial"
375 done <"$tmp.template.toc"