Skip to content

Commit 5a3846f

Browse files
committed
Add UWC script to help maintaining What's Cooking messages
1 parent 677f31c commit 5a3846f

File tree

2 files changed

+220
-1
lines changed

2 files changed

+220
-1
lines changed

UWC

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
#!/usr/bin/perl -w
2+
#
3+
# Update an older edition of What's Cooking with the latest data.
4+
#
5+
# Usage: UWC [ old [ new ] ]
6+
#
7+
# Giving no parameter is the same as giving a single "-" to the command.
8+
#
9+
# The command reads the old edition of (annotated) "What's Cooking"
10+
# message from "old", and "new". If "old" is "-", it is read from
11+
# the standard input. If "new" is not specified, WC script is run
12+
# and its output is used.
13+
#
14+
# An annotated "What's Cooking" message can have group header (a line
15+
# that has the group name enclosed in "[" and "]"), and annotatation
16+
# paragraphs after each topic's commit list, in addition to the bare
17+
# "WC" output.
18+
#
19+
# The group headers, topics in each group and their order in the group,
20+
# and annotation to topics are preserved from the "old" message. The
21+
# list of commits in each topic is replaced with the one taken from the
22+
# "new" message. Any topic in "new" that did not exist in "old" appear
23+
# in "New Topics" group. Also, topics that do not appear in the "new"
24+
# message are marked with <<deleted>>, topics whose commit list are
25+
# different from "old" are marked with <<updated from...>>>.
26+
#
27+
# Typically the maintainer would place the What's Cooking message
28+
# previously sent in a buffer in Emacs, and filter the buffer contents
29+
# with this script, to prepare an up-to-date message.
30+
31+
sub parse_whats_cooking {
32+
my ($fh) = @_;
33+
my $head = undef;
34+
my $group = undef;
35+
my %wc = ("group list" => [], "topic hash" => {});
36+
my $topic;
37+
my $skipping_comment = 0;
38+
39+
while (<$fh>) {
40+
if (/^-{40,}$/) {
41+
# Group separator
42+
next;
43+
}
44+
45+
if (!defined $head) {
46+
if (/^Here are the topics that have been cooking\./) {
47+
$head = $_;
48+
}
49+
next;
50+
}
51+
52+
if (/^<<.*>>$/) {
53+
next;
54+
}
55+
56+
if ($skipping_comment) {
57+
if (/^>>$/) {
58+
$skipping_comment = 0;
59+
}
60+
next;
61+
}
62+
63+
if (!$skipping_comment && /^<</) {
64+
$skipping_comment = 1;
65+
next;
66+
}
67+
68+
if (/^\[(.*)\]$/) {
69+
$group = $1;
70+
push @{$wc{"group list"}}, $group;
71+
$wc{" $group"} = [];
72+
$topic = undef;
73+
next;
74+
}
75+
76+
if (!defined $group) {
77+
if (/^\* (\S+) (\(.*\) \d+ commits?)$/) {
78+
# raw output
79+
$group = "Misc";
80+
push @{$wc{"group list"}}, $group;
81+
$wc{" $group"} = [];
82+
} else {
83+
$head .= $_;
84+
next;
85+
}
86+
}
87+
88+
if (/^\* (\S+) (\(.*\) \d+ commits?)$/) {
89+
$topic = +{
90+
topic => $1,
91+
head => $_,
92+
names => "",
93+
text => "",
94+
};
95+
$wc{"topic hash"}{$topic->{"topic"}} = $topic;
96+
push @{$wc{" $group"}}, $topic;
97+
next;
98+
}
99+
100+
if (/^ [-+.?] / || /^ \S/) {
101+
$topic->{"names"} .= $_;
102+
next;
103+
}
104+
$topic->{"text"} .= $_;
105+
}
106+
107+
for ($head) {
108+
s/\A\s+//s;
109+
s/\s+\Z//s;
110+
}
111+
$wc{"head text"} = $head;
112+
for $topic (values %{$wc{"topic hash"}}) {
113+
for ($topic->{"text"}) {
114+
s/\A\s+//s;
115+
s/\s+\Z//s;
116+
}
117+
}
118+
return \%wc;
119+
}
120+
121+
sub print_whats_cooking {
122+
my ($wc) = @_;
123+
124+
print $wc->{"head text"}, "\n";
125+
126+
for my $group (@{$wc->{"group list"}}) {
127+
print "\n", "-" x 64, "\n";
128+
print "[$group]\n";
129+
for my $topic (@{$wc->{" $group"}}) {
130+
print "\n", $topic->{"head"};
131+
print $topic->{"names"};
132+
if ($topic->{"text"} ne '') {
133+
print "\n", $topic->{"text"}, "\n";
134+
}
135+
}
136+
}
137+
}
138+
139+
sub delete_topic {
140+
my ($wc, $topic) = @_;
141+
$topic->{"status"} = "deleted";
142+
}
143+
144+
sub merge_whats_cooking {
145+
my ($old_wc, $new_wc) = @_;
146+
my $group;
147+
148+
for $group (@{$old_wc->{"group list"}}) {
149+
for my $topic (@{$old_wc->{" $group"}}) {
150+
my $name = $topic->{"topic"};
151+
my $newtopic = delete $new_wc->{"topic hash"}{$name};
152+
153+
if (!defined $newtopic) {
154+
$topic->{"names"} = "";
155+
$topic->{"text"} = "<<deleted>>";
156+
next;
157+
}
158+
if (($newtopic->{"names"} ne $topic->{"names"}) ||
159+
($newtopic->{"head"} ne $topic->{"head"})) {
160+
my $text = ("<<updated from\n" .
161+
$topic->{"head"} .
162+
$topic->{"names"} . ">>");
163+
164+
if ($topic->{"text"} ne '') {
165+
$text .= "\n\n" . $topic->{"text"};
166+
}
167+
for ($text) {
168+
s/\A\s+//s;
169+
s/\s+\Z//s;
170+
}
171+
$topic->{"text"} = $text;
172+
$topic->{"names"} = $newtopic->{"names"};
173+
$topic->{"head"} = $newtopic->{"head"};
174+
}
175+
}
176+
}
177+
178+
if (%{$new_wc->{"topic hash"}}) {
179+
$group = "New Topics";
180+
if (!exists $old_wc->{" $group"}) {
181+
unshift @{$old_wc->{"group list"}}, $group;
182+
$old_wc->{" $group"} = [];
183+
}
184+
for my $topic (values %{$new_wc->{"topic hash"}}) {
185+
my $name = $topic->{"topic"};
186+
$old_wc->{"topic hash"}{$name} = $topic;
187+
push @{$old_wc->{" $group"}}, $topic;
188+
$topic->{"text"} = $topic->{"text"};
189+
}
190+
}
191+
}
192+
193+
if (@ARGV == 0) {
194+
@ARGV = ('-');
195+
}
196+
if (@ARGV != 2 && @ARGV != 1) {
197+
die "Usage: $0 old [new]\n";
198+
}
199+
200+
my ($old_wc, $new_wc);
201+
202+
if ($ARGV[0] eq '-') {
203+
*FH = *STDIN;
204+
} else {
205+
open FH, "$ARGV[0]";
206+
}
207+
$old_wc = parse_whats_cooking(\*FH);
208+
close FH;
209+
210+
if (@ARGV > 1) {
211+
open FH, "$ARGV[1]";
212+
} else {
213+
open FH, "Meta/WC |";
214+
}
215+
$new_wc = parse_whats_cooking(\*FH);
216+
close FH;
217+
218+
merge_whats_cooking($old_wc, $new_wc);
219+
print_whats_cooking($old_wc);

WC

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ order.
1717
1818
EOF
1919

20-
Meta/git-topic.perl --base=master | sed -e 's/^\*./*/'
20+
Meta/git-topic.perl --base=master | sed -e 's/^\*./\n*/'

0 commit comments

Comments
 (0)