]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Meta/cook: What's cooking script (third generation)
authorJunio C Hamano <gitster@pobox.com>
Mon, 12 Apr 2010 21:29:50 +0000 (14:29 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 12 Apr 2010 21:29:50 +0000 (14:29 -0700)
cook [new file with mode: 0755]
cook.sh [deleted file]

diff --git a/cook b/cook
new file mode 100755 (executable)
index 0000000..b3af892
--- /dev/null
+++ b/cook
@@ -0,0 +1,548 @@
+#!/usr/bin/perl -w
+# Maintain "what's cooking" messages
+
+use strict;
+
+sub phrase_these {
+       my (@u) = @_;
+       my @d = ();
+       for (my $i = 0; $i < @u; $i++) {
+               push @d, $u[$i];
+               if ($i == @u - 2) {
+                       push @d, " and ";
+               } elsif ($i < @u - 2) {
+                       push @d, ", ";
+               }
+       }
+       return join('', @d);
+}
+
+sub describe_relation {
+       my ($topic_info) = @_;
+       my @desc;
+
+       if (exists $topic_info->{'used'}) {
+               push @desc, ("is used by " .
+                            phrase_these(@{$topic_info->{'used'}}));
+       }
+
+       if (exists $topic_info->{'uses'}) {
+               push @desc, ("uses " .
+                            phrase_these(@{$topic_info->{'uses'}}));
+       }
+
+       if (exists $topic_info->{'shares'}) {
+               push @desc, ("shares commits with " .
+                            phrase_these(@{$topic_info->{'shares'}}));
+       }
+
+       if (!@desc) {
+               return "";
+       }
+
+       return "(this branch " . join("; ", @desc) . ".)";
+}
+
+sub forks_from {
+       my ($topic, $fork, $forkee, @overlap) = @_;
+       my %ovl = map { $_ => 1 } (@overlap, @{$topic->{$forkee}{'log'}});
+
+       push @{$topic->{$fork}{'uses'}}, $forkee;
+       push @{$topic->{$forkee}{'used'}}, $fork;
+       @{$topic->{$fork}{'log'}} = (grep { !exists $ovl{$_} }
+                                    @{$topic->{$fork}{'log'}});
+}
+
+sub topic_relation {
+       my ($topic, $one, $two) = @_;
+
+       my $fh;
+       open($fh, '-|',
+            qw(git log --abbrev=7), "--format=%m %h",
+            "$one...$two", "^master")
+           or die "$!: open log --left-right";
+       my (@left, @right);
+       while (<$fh>) {
+               my ($sign, $sha1) = /^(.) (.*)/;
+               if ($sign eq '<') {
+                       push @left, $sha1;
+               } elsif ($sign eq '>') {
+                       push @right, $sha1;
+               }
+       }
+       close($fh) or die "$!: close log --left-right";
+
+       if (!@left) {
+               if (@right) {
+                       forks_from($topic, $two, $one);
+               }
+       } elsif (!@right) {
+               forks_from($topic, $one, $two);
+       } else {
+               if (@left < @right) {
+                       forks_from($topic, $two, $one, @left);
+               } elsif (@right < @left) {
+                       forks_from($topic, $one, $two, @right);
+               } else {
+                       push @{$topic->{$one}{'shares'}}, $two;
+                       push @{$topic->{$two}{'shares'}}, $one;
+               }
+       }
+}
+
+sub get_commit {
+       my (@base) = qw(master next pu);
+       my $fh;
+       open($fh, '-|',
+            qw(git for-each-ref),
+            "--format=%(refname:short) %(authordate:iso8601)",
+            "refs/heads/??/*")
+           or die "$!: open for-each-ref";
+       my @topic;
+       my %topic;
+
+       while (<$fh>) {
+               chomp;
+               my ($branch, $date) = /^(\S+) (.*)$/;
+               push @topic, $branch;
+               $date =~ s/ .*//;
+               $topic{$branch} = +{
+                       log => [],
+                       tipdate => $date,
+               };
+       }
+       close($fh) or die "$!: close for-each-ref";
+
+       my %base = map { $_ => undef } @base;
+       my %commit;
+       my $show_branch_batch = 20;
+
+       while (@topic) {
+               my @t = (@base, splice(@topic, 0, $show_branch_batch));
+               my $header_delim = '-' x scalar(@t);
+               my $contain_pat = '.' x scalar(@t);
+               open($fh, '-|', qw(git show-branch --sparse --sha1-name),
+                    map { "refs/heads/$_" } @t)
+                   or die "$!: open show-branch";
+               while (<$fh>) {
+                       chomp;
+                       if ($header_delim) {
+                               if (/^$header_delim$/) {
+                                       $header_delim = undef;
+                               }
+                               next;
+                       }
+                       my ($contain, $sha1, $log) =
+                           ($_ =~ /^($contain_pat) \[([0-9a-f]+)\] (.*)$/);
+
+                       for (my $i = 0; $i < @t; $i++) {
+                               my $branch = $t[$i];
+                               my $sign = substr($contain, $i, 1);
+                               next if ($sign eq ' ');
+                               next if (substr($contain, 0, 1) ne ' ');
+
+                               if (!exists $commit{$sha1}) {
+                                       $commit{$sha1} = +{
+                                               branch => {},
+                                               log => $log,
+                                       };
+                               }
+                               my $co = $commit{$sha1};
+                               $co->{'branch'}{$branch} = 1;
+                               next if (exists $base{$branch});
+                               push @{$topic{$branch}{'log'}}, $sha1;
+                       }
+               }
+               close($fh) or die "$!: close show-branch";
+       }
+
+       my %shared;
+       for my $sha1 (keys %commit) {
+               my $sign;
+               my $co = $commit{$sha1};
+               if (exists $co->{'branch'}{'next'}) {
+                       $sign = '+';
+               } elsif (exists $co->{'branch'}{'pu'}) {
+                       $sign = '-';
+               } else {
+                       $sign = '.';
+               }
+               $co->{'log'} = $sign . ' ' . $co->{'log'};
+               my @t = (sort grep { !exists $base{$_} }
+                        keys %{$co->{'branch'}});
+               next if (@t < 2);
+               my $t = "@t";
+               $shared{$t} = 1;
+       }
+
+       for my $combo (keys %shared) {
+               my @combo = split(' ', $combo);
+               for (my $i = 0; $i < @combo - 1; $i++) {
+                       for (my $j = $i + 1; $j < @combo; $j++) {
+                               topic_relation(\%topic, $combo[$i], $combo[$j]);
+                       }
+               }
+       }
+
+       open($fh, '-|',
+            qw(git log --first-parent --abbrev=7),
+            "--format=%ci %h %p :%s", "master..next")
+           or die "$!: open log master..next";
+       while (<$fh>) {
+               my ($date, $commit, $parent, $tips);
+               unless (($date, $commit, $parent, $tips) =
+                       /^([-0-9]+) ..:..:.. .\d{4} (\S+) (\S+) ([^:]*):/) {
+                       die "Oops: $_";
+               }
+               for my $tip (split(' ', $tips)) {
+                       my $co = $commit{$tip};
+                       $co->{'merged'} = " (merged to 'next' on $date at $commit)";
+               }
+       }
+       close($fh) or die "$!: close log master..next";
+
+       for my $branch (keys %topic) {
+               my @log = ();
+               my $n = scalar(@{$topic{$branch}{'log'}});
+               if (!$n) {
+                       delete $topic{$branch};
+                       next;
+               } elsif ($n == 1) {
+                       $n = "1 commit";
+               } else {
+                       $n = "$n commits";
+               }
+               my $d = $topic{$branch}{'tipdate'};
+               my $head = "* $branch ($d) $n\n";
+               my @desc;
+               for (@{$topic{$branch}{'log'}}) {
+                       my $co = $commit{$_};
+                       if (exists $co->{'merged'}) {
+                               push @desc, $co->{'merged'};
+                       }
+                       push @desc, $commit{$_}->{'log'};
+               }
+               my $list = join("\n", map { " " . $_ } @desc);
+               my $relation = describe_relation($topic{$branch});
+               $topic{$branch}{'desc'} = $head . $list;
+               if ($relation) {
+                       $topic{$branch}{'desc'} .= "\n $relation";
+               }
+       }
+
+       return \%topic;
+}
+
+sub blurb_text {
+       my ($mon, $year, $issue, $dow, $date,
+           $master_at, $next_at, $text) = @_;
+
+       my $now_string = localtime;
+       my ($current_dow, $current_mon, $current_date, $current_year) =
+           ($now_string =~ /^(\w+) (\w+) (\d+) [\d:]+ (\d+)$/);
+
+       $mon ||= $current_mon;
+       $year ||= $current_year;
+       $issue ||= "01";
+       $dow ||= $current_dow;
+       $date ||= $current_date;
+       $master_at ||= '0' x 40;
+       $next_at ||= '0' x 40;
+       $text ||= <<'EOF';
+Here are the topics that have been cooking.  Commits prefixed with '-' are
+only in 'pu' while commits prefixed with '+' are in 'next'.  The ones
+marked with '.' do not appear in any of the integration branches, but I am
+still holding onto them.
+EOF
+
+       $text = <<EOF;
+To: git\@vger.kernel.org
+Subject: What's cooking in git.git ($mon $year, #$issue; $dow, $date)
+X-master-at: $master_at
+X-next-at: $next_at
+
+What's cooking in git.git ($mon $year, #$issue; $dow, $date)
+--------------------------------------------------
+
+$text
+EOF
+       $text =~ s/\n+\Z/\n/;
+       return $text;
+}
+
+my $blurb_match = <<'EOF';
+To: .*
+Subject: What's cooking in \S+ \((\w+) (\d+), #(\d+); (\w+), (\d+)\)
+X-master-at: ([0-9a-f]{40})
+X-next-at: ([0-9a-f]{40})
+
+What's cooking in \S+ \(\1 \2, #\3; \4, \5\)
+-{30,}
+\n*
+EOF
+
+my $blurb = "b..l..u..r..b";
+sub read_previous {
+       my ($fn) = @_;
+       my $fh;
+       my $section = undef;
+       my $serial = 1;
+       my $branch = $blurb;
+       my $last_empty = undef;
+       my (@section, %section, @branch, %branch, %description, @leader);
+       my $in_unedited_olde = 0;
+
+       if (!-r $fn) {
+               return +{
+                       'section_list' => [],
+                       'section_data' => {},
+                       'topic_description' => {
+                               $blurb => {
+                                       desc => undef,
+                                       text => blurb_text(),
+                               },
+                       },
+               };
+       }
+
+       open ($fh, '<', $fn) or die "$!: open $fn";
+       while (<$fh>) {
+               chomp;
+               if ($in_unedited_olde) {
+                       if (/^>>$/) {
+                               $in_unedited_olde = 0;
+                               $_ = " | $_";
+                       }
+               } elsif (/^<<$/) {
+                       $in_unedited_olde = 1;
+               }
+
+               if ($in_unedited_olde) {
+                       $_ = " | $_";
+               }
+
+               if (defined $section && /^-{20,}$/) {
+                       $_ = "";
+               }
+               if (/^$/) {
+                       $last_empty = 1;
+                       next;
+               }
+               if (/^\[(.*)\]\s*$/) {
+                       $section = $1;
+                       $branch = undef;
+                       if (!exists $section{$section}) {
+                               push @section, $section;
+                               $section{$section} = [];
+                       }
+                       next;
+               }
+               if (defined $section && /^\* (\S+) /) {
+                       $branch = $1;
+                       $last_empty = 0;
+                       if (!exists $branch{$branch}) {
+                               push @branch, [$branch, $section];
+                               $branch{$branch} = 1;
+                       }
+                       push @{$section{$section}}, $branch;
+               }
+               if (defined $branch) {
+                       my $was_last_empty = $last_empty;
+                       $last_empty = 0;
+                       if (!exists $description{$branch}) {
+                               $description{$branch} = [];
+                       }
+                       if ($was_last_empty) {
+                               push @{$description{$branch}}, "";
+                       }
+                       push @{$description{$branch}}, $_;
+               }
+       }
+       close($fh);
+
+       for my $branch (keys %description) {
+               my $ary = $description{$branch};
+               if ($branch eq $blurb) {
+                       while (@{$ary} && $ary->[-1] =~ /^-{30,}$/) {
+                               pop @{$ary};
+                       }
+                       $description{$branch} = +{
+                               desc => undef,
+                               text => join("\n", @{$ary}),
+                       };
+               } else {
+                       my @desc = ();
+                       while (@{$ary}) {
+                               my $elem = shift @{$ary};
+                               last if ($elem eq '');
+                               push @desc, $elem;
+                       }
+                       $description{$branch} = +{
+                               desc => join("\n", @desc),
+                               text => join("\n", @{$ary}),
+                       };
+               }
+       }
+
+       return +{
+               section_list => \@section,
+               section_data => \%section,
+               topic_description => \%description,
+       };
+}
+
+sub write_cooking {
+       my ($fn, $cooking) = @_;
+       my $fh;
+
+       open($fh, '>', $fn) or die "$!: open $fn";
+       print $fh $cooking->{'topic_description'}{$blurb}{'text'};
+
+       for my $section_name (@{$cooking->{'section_list'}}) {
+               my $topic_list = $cooking->{'section_data'}{$section_name};
+               next if (!@{$topic_list});
+
+               print $fh "\n";
+               print $fh '-' x 50, "\n";
+               print $fh "[$section_name]\n";
+               for my $topic (@{$topic_list}) {
+                       my $d = $cooking->{'topic_description'}{$topic};
+
+                       print $fh "\n", $d->{'desc'}, "\n";
+                       if ($d->{'text'}) {
+                               print $fh "\n", $d->{'text'}, "\n";
+                       }
+               }
+       }
+       close($fh);
+}
+
+my $graduated = 'Graduated to "master"';
+my $new_topics = 'New Topics';
+my $old_new_topics = 'Old New Topics';
+
+sub update_issue {
+       my ($cooking) = @_;
+       my ($fh, $master_at, $next_at, $incremental);
+
+       open($fh, '-|',
+            qw(git for-each-ref),
+            "--format=%(refname:short) %(objectname)",
+            "refs/heads/master",
+            "refs/heads/next") or die "$!: open for-each-ref";
+       while (<$fh>) {
+               my ($branch, $at) = /^(\S+) (\S+)$/;
+               if ($branch eq 'master') { $master_at = $at; }
+               if ($branch eq 'next') { $next_at = $at; }
+       }
+       close($fh) or die "$!: close for-each-ref";
+
+       $incremental = ((-r "Meta/whats-cooking.txt") &&
+                       system("cd Meta && " .
+                              "git diff --quiet --no-ext-diff HEAD -- " .
+                              "whats-cooking.txt"));
+
+       my $now_string = localtime;
+       my ($current_dow, $current_mon, $current_date, $current_year) =
+           ($now_string =~ /^(\w+) (\w+) (\d+) [\d:]+ (\d+)$/);
+
+       my $btext = $cooking->{'topic_description'}{$blurb}{'text'};
+       if ($btext !~ s/\A$blurb_match//) {
+               die "match pattern broken?";
+       }
+       my ($mon, $year, $issue, $dow, $date) = ($1, $2, $3, $4, $5);
+
+       if ($current_mon ne $mon || $current_year ne $year) {
+               $issue = "01";
+       } elsif (!$incremental) {
+               $issue =~ s/^0*//;
+               $issue = sprintf "%02d", ($issue + 1);
+       }
+       $mon = $current_mon;
+       $year = $current_year;
+       $dow = $current_dow;
+       $date = $current_date;
+
+       $cooking->{'topic_description'}{$blurb}{'text'} =
+           blurb_text($mon, $year, $issue, $dow, $date,
+                      $master_at, $next_at, $btext);
+
+       if (!$incremental) {
+               my $sd = $cooking->{'section_data'};
+               my $sl = $cooking->{'section_list'};
+               for (my $i = 0; $i < @{$sl}; $i++) {
+                       if ($sl->[$i] eq $new_topics) {
+                               $sl->[$i] = $old_new_topics;
+                               unshift @{$sl}, $new_topics;
+                               last;
+                       }
+               }
+               $sd->{$old_new_topics} = $sd->{$new_topics};
+               $sd->{$new_topics} = [];
+       }
+}
+
+sub merge_cooking {
+       my ($cooking, $current) = @_;
+       my $td = $cooking->{'topic_description'};
+       my $sd = $cooking->{'section_data'};
+       my $sl = $cooking->{'section_list'};
+       my (@new_topic, @gone_topic);
+
+       if (!exists $sd->{$new_topics}) {
+               $sd->{$new_topics} = [];
+               unshift @{$sl}, $new_topics;
+       }
+
+       if (!exists $sd->{$graduated}) {
+               $sd->{$graduated} = [];
+               unshift @{$sl}, $graduated;
+       }
+
+       update_issue($cooking);
+
+       for my $topic (sort keys %{$current}) {
+               if (!exists $td->{$topic}) {
+                       push @new_topic, $topic;
+                       next;
+               }
+               my $n = $current->{$topic}{'desc'};
+               my $o = $td->{$topic}{'desc'};
+               if ($n ne $o) {
+                       $td->{$topic}{'desc'} = $n . "\n<<\n" . $o ."\n>>";
+               }
+       }
+
+       for my $topic (sort keys %{$td}) {
+               next if ($topic eq $blurb);
+               if (!exists $current->{$topic}) {
+                       push @gone_topic, $topic;
+               }
+       }
+
+       for (@new_topic) {
+               push @{$sd->{$new_topics}}, $_;
+               $td->{$_}{'desc'} = $current->{$_}{'desc'};
+       }
+
+       if (@gone_topic) {
+               for my $topic (@gone_topic) {
+                       for my $section (@{$sl}) {
+                               @{$sd->{$section}} = (grep { $_ ne $topic }
+                                                     @{$sd->{$section}});
+                       }
+               }
+               for (@gone_topic) {
+                       push @{$sd->{$graduated}}, $_;
+               }
+       }
+
+}
+
+################################################################
+# Main
+
+my $topic = get_commit();
+my $cooking = read_previous('Meta/whats-cooking.txt');
+merge_cooking($cooking, $topic);
+write_cooking('Meta/whats-cooking.txt', $cooking);
diff --git a/cook.sh b/cook.sh
deleted file mode 100755 (executable)
index 3156c06..0000000
--- a/cook.sh
+++ /dev/null
@@ -1,449 +0,0 @@
-#!/bin/sh
-
-LANG=C LC_ALL=C GIT_PAGER=cat
-export LANG LC_ALL GIT_PAGER
-
-tmpdir=/var/tmp/cook.$$
-mkdir "$tmpdir" || exit
-tmp="$tmpdir/t"
-trap 'rm -fr "$tmpdir"' 0
-
-git branch --merged "master" | sed -n -e 's/^..//' -e '/\//p' >"$tmp.in.master"
-git branch --merged "pu" | sed -n -e 's/^..//' -e '/\//p' >"$tmp.in.pu"
-{
-       comm -13 "$tmp.in.master" "$tmp.in.pu" 
-       git branch --no-merged pu |
-       sed -n -e 's/^..//' -e '/\//p'
-} >"$tmp.branches"
-
-git log --first-parent --format="%H %ci" master..next |
-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"
-git rev-list master..pu >"$tmp.commits.in.pu"
-
-format_branch () {
-       # branch=$1 others=$2
-       git rev-list --no-merges --topo-order "master..$1" --not $2 >"$tmp.list"
-       count=$(wc -l <"$tmp.list" | tr -d ' ')
-       label="* $1 ($(git show -s --format="%ai" $1 | sed -e 's/ .*//')) $count commit"
-       test "$count" = 1 || label="${label}s"
-
-       echo "$label"
-       lasttimelabel=
-       lastfoundmerge=
-       while read commit
-       do
-               merged= merged_with=
-               while read merge at
-               do
-                       if test -n "$lastfoundmerge"
-                       then
-                               if test "$lastfoundmerge" = "$merge"
-                               then
-                                       lastfoundmerge=
-                               else
-                                       continue
-                               fi
-                       fi
-                       mb=$(git merge-base $merge $commit)
-                       if test "$mb" = "$commit"
-                       then
-                               merged=$at merged_with=$merge
-                       else
-                               break
-                       fi
-               done <"$tmp.next"
-
-               lastfoundmerge=$merged_with
-               thistimelabel=
-               if test -n "$merged"
-               then
-                       thistimelabel=$merged
-                       commitlabel="+"
-               elif grep "$commit" "$tmp.commits.in.pu" >/dev/null
-               then
-                       commitlabel="-"
-               else
-                       commitlabel="."
-               fi
-               if test "$lasttimelabel" != "$thistimelabel"
-               then
-                       with=$(git rev-parse --short $merged_with)
-                       echo "  (merged to 'next' on $thistimelabel at $with)"
-                       lasttimelabel=$thistimelabel
-               fi
-               git show -s --format=" $commitlabel %s" $commit
-       done <"$tmp.list"
-}
-
-add_desc () {
-       kind=$1
-       shift
-       test -z "$description" || description="$description;"
-       others=
-       while :
-       do
-               other=$1
-               case "$other" in
-               "#EPO-"*) other="early parts of ${other#"#EPO-"}"
-               esac
-               shift
-               case "$#,$others" in
-               0,)
-                       others="$other"
-                       break ;;
-               0,?*)
-                       others="$others and $other"
-                       break ;;
-               *,)
-                       others="$other"
-                       ;;
-               *,?*)
-                       others="$others, $other"
-                       ;;
-               esac
-       done
-       description="$description $kind $others"
-}
-
-show_topic () {
-       old=$1 new=$2
-
-       sed -n -e '/^ ..*/p' -e '/^\* /p' "$old" >"$tmp.old.nc"
-       sed -n -e '/^ ..*/p' -e '/^\* /p' "$new" >"$tmp.new.nc"
-       if cmp "$tmp.old.nc" "$tmp.new.nc" >/dev/null
-       then
-               cat "$old"
-       else
-               cat "$new"
-               echo "<<"
-               cat "$old"
-               echo ">>"
-       fi
-}
-
-compare_topic () {
-       b=$1 r=$2
-       based=$(git rev-list --no-merges $b..$r | wc -l | tr -d ' ')
-       bases=$(git rev-list --no-merges $r..$b | wc -l | tr -d ' ')
-       case "$based,$bases" in
-       0,0)    echo same; exit ;;
-       0,*)    echo left; exit ;;
-       *,0)    echo right; exit ;;
-       esac
-
-       if test $based -lt $bases
-       then
-               echo left-p
-       else
-               echo fork
-       fi
-}
-
-# List commits that are shared between more than one topic branches
-while read b
-do
-       git rev-list --no-merges "master..$b"
-done <"$tmp.branches" | sort | uniq -d >"$tmp.shared"
-
-# Set of branches related to each other due to sharing the same commit
-while read shared
-do
-       b=$(git branch --contains "$shared" | sed -n -e 's/^..//' -e '/\//p')
-       echo "" $b ""
-done <"$tmp.shared" | sort -u >"$tmp.related"
-
-serial=1
-while read b
-do
-       related=$(grep " $b " "$tmp.related" | tr ' ' '\012' | sort -u | sed -e '/^$/d')
-
-       based_on= based_on_msg=
-       used_by=
-       forks=
-       same_as=
-       if test -n "$related"
-       then
-               for r in $related
-               do
-                       test "$b" = "$r" && continue
-                       case "$(compare_topic "$b" "$r")" in
-                       same)
-                               same_as="$same_as$r "
-                               ;;
-                       left)
-                               based_on="$based_on$r "
-                               based_on_msg="$based_on_msg$r "
-                               ;;
-                       left-p)
-                               based_on="$based_on$r "
-                               based_on_msg="${based_on_msg}#EPO-$r "
-                               ;;
-                       right)
-                               used_by="$used_by$r "
-                               ;;
-                       fork)
-                               forks="$forks$r "
-                               ;;
-                       esac
-               done
-       fi
-
-       {
-               format_branch "$b" "$based_on"
-
-               description=
-               test -z "$same_as" || add_desc 'is same as' $same_as
-               test -z "$based_on" || add_desc 'uses' $based_on_msg
-               test -z "$used_by" || add_desc 'is used by' $used_by
-               test -z "$forks" || add_desc 'shares commits with' $forks
-
-               test -z "$description" ||
-               echo " (this branch$description.)"
-       } >"$tmp.output.$serial"
-       echo "$b $serial"
-       serial=$(( $serial + 1 ))
-done <"$tmp.branches" >"$tmp.output.toc"
-
-eval $(date +"monthname=%b month=%m year=%Y date=%d dow=%a")
-
-incremental=$(
-       cd Meta &&
-       if git diff --quiet --no-ext-diff HEAD -- whats-cooking.txt >/dev/null
-       then
-               echo no
-       else
-               echo yes
-       fi
-)
-
-# Find the current issue
-eval $(sed -ne '/^Subject: /{
-       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
-       q
-}' Meta/whats-cooking.txt)
-if test "$monthname $year" = "$lastmon $lastyear"
-then
-       while case "$lastissue" in 0?*) ;; *) break ;; esac
-       do
-               lastissue=${lastissue#0}
-       done
-       if test "$incremental" = no
-       then
-               issue=$(( $lastissue + 1 ))
-       else
-               issue=$(( $lastissue + 0 ))
-       fi
-else
-       issue=1
-fi
-
-issue=$( printf "%02d" $issue )
-last=whats-cooking.txt
-
-master_at=$(git rev-parse --verify refs/heads/master)
-next_at=$(git rev-parse --verify refs/heads/next)
-cat >"$tmp.output.blurb" <<EOF
-To: git@vger.kernel.org
-Subject: What's cooking in git.git ($monthname $year, #$issue; $dow, $date)
-X-master-at: $master_at
-X-next-at: $next_at
-
-What's cooking in git.git ($monthname $year, #$issue; $dow, $date)
---------------------------------------------------
-
-Here are the topics that have been cooking.  Commits prefixed with '-' are
-only in 'pu' while commits prefixed with '+' are in 'next'.  The ones
-marked with '.' do not appear in any of the branches, but I am still
-holding onto them.
-
-EOF
-
-if test -z "$NO_TEMPLATE" && test -f "Meta/$last"
-then
-       template="Meta/$last"
-else
-       template=/dev/null
-fi
-perl -w -e '
-       my $section = undef;
-       my $serial = 1;
-       my $blurb = "b..l..u..r..b";
-       my $branch = $blurb;
-       my $tmp = $ARGV[0];
-       my $incremental = $ARGV[1] eq "yes";
-       my $last_empty = undef;
-       my (@section, %section, @branch, %branch, %description, @leader);
-       my $in_unedited_olde = 0;
-
-       while (<STDIN>) {
-               if ($in_unedited_olde) {
-                       if (/^>>$/) {
-                               $in_unedited_olde = 0;
-                               $_ = " | $_";
-                       }
-               } elsif (/^<<$/) {
-                       $in_unedited_olde = 1;
-               }
-
-               if ($in_unedited_olde) {
-                       $_ = " | $_";
-               }
-
-               if (defined $section && /^-{20,}$/) {
-                       $_ = "\n";
-               }
-               if (/^$/) {
-                       $last_empty = 1;
-                       next;
-               }
-               if (/^\[(.*)\]\s*$/) {
-                       $section = $1;
-                       $branch = undef;
-                       if ($section eq "New Topics" && !$incremental) {
-                               $section = "Old New Topics";
-                       }
-                       if (!exists $section{$section}) {
-                               push @section, $section;
-                               $section{$section} = [];
-                       }
-                       next;
-               }
-               if (defined $section && /^\* (\S+) /) {
-                       $branch = $1;
-                       $last_empty = 0;
-                       if (!exists $branch{$branch}) {
-                               push @branch, [$branch, $section];
-                               $branch{$branch} = 1;
-                       }
-                       push @{$section{$section}}, $branch;
-               }
-               if (defined $branch) {
-                       my $was_last_empty = $last_empty;
-                       $last_empty = 0;
-                       if (!exists $description{$branch}) {
-                               $description{$branch} = [];
-                       }
-                       if ($was_last_empty) {
-                               push @{$description{$branch}}, "\n";
-                       }
-                       push @{$description{$branch}}, $_;
-               }
-       }
-
-       if (open I, "<$tmp.output.toc") {
-               $section = "New Topics";
-               while (<I>) {
-                       my ($branch, $oldserial) = /^(\S*) (\d+)$/;
-                       next if (exists $branch{$branch});
-                       if (!exists $section{$section}) {
-                               # Have it at the beginning
-                               unshift @section, $section;
-                               $section{$section} = [];
-                       }
-                       push @{$section{$section}}, $branch;
-                       push @branch, [$branch, $section];
-                       $branch{$branch} = 1;
-                       if (!exists $description{$branch}) {
-                               $description{$branch} = [];
-                       }
-                       open II, "<$tmp.output.$oldserial";
-                       while (<II>) {
-                               push @{$description{$branch}}, $_;
-                       }
-                       close II;
-               }
-               close I;
-       }
-
-       while (0 <= @{$description{$blurb}}) {
-               my $last = pop @{$description{$blurb}};
-               if ($last =~ /^$/ || $last =~ /^-{20,}$/) {
-                       next;
-               } else {
-                       push @{$description{$blurb}}, $last;
-                       last;
-               }
-       }
-
-       open O, ">$tmp.template.blurb";
-       for (@{$description{$blurb}}) {
-               print O $_;
-       }
-       close O;
-
-       open TOC, ">$tmp.template.toc";
-       $serial = 1;
-       for my $section (@section) {
-               for my $branch (@{$section{$section}}) {
-                       print TOC "$branch $serial $section\n";
-                       open O, ">$tmp.template.$serial";
-                       for (@{$description{$branch}}) {
-                               print O $_;
-                       }
-                       close O;
-                       $serial++;
-               }
-       }
-' <"$template" "$tmp" "$incremental"
-
-tmpserial=$(
-       tail -n 1 "$tmp.template.toc" |
-       read branch serial section &&
-       echo $serial
-)
-
-# Assemble them all
-
-if test -z "$TO_STDOUT"
-then
-       exec >"Meta/whats-cooking.txt"
-fi
-
-if test -s "$tmp.template.blurb"
-then
-       sed -e '/^---------------*$/q' <"$tmp.output.blurb"
-       sed -e '1,/^---------------*$/d' <"$tmp.template.blurb"
-else
-       cat "$tmp.output.blurb"
-fi
-
-current='
---------------------------------------------------
-[Graduated to "master"]
-'
-while read branch oldserial section
-do
-       test "$section" = 'Graduated to "master"' &&
-       test "$incremental" = no && continue
-
-       tip=$(git rev-parse --quiet --verify "refs/heads/$branch") || continue
-       mb=$(git merge-base master $tip)
-       test "$mb" = "$tip" || continue
-       if test -n "$current"
-       then
-               echo "$current"
-               current=
-       else
-               echo
-       fi
-       cat "$tmp.template.$oldserial"
-done <"$tmp.template.toc"
-
-current=
-while read branch oldserial section
-do
-       found=$(grep "^$branch " "$tmp.output.toc") || continue
-       newserial=$(expr "$found" : '[^ ]* \(.*\)')
-       if test "$current" != "$section"
-       then
-               current=$section
-               echo "
---------------------------------------------------
-[$section]
-"
-       else
-               echo
-       fi
-
-       show_topic "$tmp.template.$oldserial" "$tmp.output.$newserial"
-done <"$tmp.template.toc"