1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
#!/usr/bin/perl -w
use strict;
use File::Basename;
use File::Spec;
-d '.git' or die "$0: Not a Git repository";
my $root = dirname($0);
my $application = "$root/application";
my $last = `(cd $root; git ls-files "whats" | tail -1)`;
@ARGV = ("$root/$last");
my $date;
my $output_file;
{
my($sec,$min,$h,$mday,$month,$year) = localtime(time);
$year += 1900;
$month++;
$date = sprintf("%04d-%02d-%02d", $year, $month, $mday);
my $dir = sprintf("$root/whats/cooking/%04d/%02d", $year, $month);
system "mkdir -p $dir";
$output_file = sprintf("$dir/%02d.txt", $mday);
$output_file = File::Spec->rel2abs($output_file);
open STDOUT, ">", $output_file or
die "$0: Failed to open $output_file for writing: $!\n";
}
my $title = "What's cooking in erlang/otp ($date)";
print "To: erlang patches <erlang-patches\@erlang.org>\n";
print "Subject: $title\n";
print "X-dev-at: ", `git rev-parse dev`;
my %cooking;
my $current;
my $prev_dev = 'master';
if (@ARGV) {
my $state = 'header';
while (<>) {
$prev_dev = $1 if /^X-dev-at: ([\da-f]{40})/;
next if /^-------/;
$state = 'intro' if $state eq 'header' && /^\s*$/;
if (m/^\[([^\]]*)\]/) {
my $group = $1;
if ($group =~ /^Graduated/) {
$state = 'skip';
} else {
$state = 'cooking';
}
next;
}
print if $state eq 'intro';
if ($state eq 'cooking') {
if (/^[*] (\S+)/) {
$current = $1;
$cooking{$current} = "";
next;
}
next if /^ [+-]/;
next unless $current;
$cooking{$current} .= $_
unless /^\s*$/ && $cooking{$current} eq '';
}
}
}
my @old_in_dev = `git branch --merged $prev_dev`;
chomp @old_in_dev;
map { s/^\s*// } @old_in_dev;
@old_in_dev = grep { m@^[^/]{2,4}/[^/]*@ } @old_in_dev;
my %old_in_dev = map { $_ => 1 } @old_in_dev;
my @in_dev = `git branch --merged dev`;
chomp @in_dev;
map { s/^\s*// } @in_dev;
@in_dev = grep { m@^[^/]{2,4}/[^/]*@ && !exists $old_in_dev{$_} } @in_dev;
my %in_dev = map { $_ => 1 } @in_dev;
my @in_pu = `git branch --merged pu`;
chomp @in_pu;
map { s/^\s*// } @in_pu;
@in_pu = grep { m@^[^/]{2,4}/[^/]*@ } @in_pu;
@in_pu = grep { !exists $in_dev{$_} && !exists $old_in_dev{$_} } @in_pu;
my %child;
foreach (`git rev-list --no-merges --children master..dev`) {
chomp;
my($ref,$child) = split ' ';
$child{$ref} = $child;
}
if (@in_dev) {
header("[Graduated]");
foreach (@in_dev) {
describe_graduated($_);
}
}
header("[New topics]");
foreach (@in_pu) {
describe($_, '') unless defined $cooking{$_};
}
header("[Cooking]");
foreach (@in_pu) {
my $text = $cooking{$_};
describe($_, $text) if defined $text;
}
close STDOUT;
system qq(cd $root; git add $output_file >/dev/null; git commit -m "Add $title" >/dev/null);
sub header {
print '-' x 60, "\n";
print $_[0], "\n\n";
}
sub describe {
my($topic,$text) = @_;
print_commits($topic, "dev..$topic");
print "\n$text" if $text ne '';
print "\n";
}
sub describe_graduated {
my($topic) = @_;
my $id = `git rev-parse $topic`;
chomp $id;
print_commits($topic, "$child{$id}^1..$id");
print "\n";
}
sub print_commits {
my($topic,$range) = @_;
my(@revs) = `git rev-list $range`;
my $commits = @revs == 1 ? "1 commit" : scalar(@revs) . " commits";
my $max = 12;
my $diff_range = $range;
$diff_range =~ s/[.][.]/.../;
my $apps = `$application $diff_range`;
chomp $apps;
system qq[git show -s --date=short --format="* $topic ($apps) (%ad) $commits" $topic];
system qq[git --no-pager log -n $max --format=" - %s (%h)" $range];
print ".\n.\n\.\n" if @revs > $max;
}
|