Meta/worklog: new script

Junio C Hamano committed Apr 28, 2011 at 16:48 UTC d1d05d1d722a1317d1d5cabad30e98b56f92927a
1 file changed +219
worklog new
+219
@@ -0,0 +1,219 @@
1 +#!/usr/bin/perl
2 +
3 +use strict;
4 +use warnings;
5 +use Getopt::Long;
6 +use Time::Local;
7 +
8 +sub seconds_in_a_week () {
9 + return 7 * 24 * 3600;
10 +}
11 +
12 +my $verbose = 0;
13 +my $week;
14 +my $cycles;
15 +my $bow = 0;
16 +
17 +sub bow {
18 + my ($week) = @_;
19 + my (@time, $time);
20 +
21 + if (!defined $week) {
22 + $time = time;
23 + } elsif ($week =~ /^\d+$/) {
24 + $time = time - seconds_in_a_week * $week;
25 + } else {
26 + my ($year, $mon, $mday) = ($week =~ /^(\d{4})-(\d{2})-(\d{2})$/);
27 + unless (defined $year && defined $mon && defined $mday &&
28 + 1 <= $mon && $mon <= 12 &&
29 + 1 <= $mday && $mday <= 31) {
30 + die "Bad week specification: $week";
31 + }
32 + $time = timelocal(0, 0, 0, $mday, $mon - 1, $year - 1900);
33 + }
34 +
35 + @time = localtime($time);
36 + if ($time[6] <= $bow) {
37 + $time -= seconds_in_a_week;
38 + @time = localtime($time);
39 + }
40 + $time -= $time[0] + 60 * ($time[1] + 60 * ($time[2] + 24 * ($time[6] - $bow)));
41 + return $time;
42 +}
43 +
44 +if (!GetOptions(
45 + "verbose!" => \$verbose,
46 + "week=s" => \$week,
47 + "cycles=i" => \$cycles,
48 + "bow=i" => \$bow,
49 + )) {
50 + print STDERR "$0 [-v]\n";
51 + exit 1;
52 +}
53 +
54 +if (defined $cycles && !defined $week) {
55 + $week = bow($week);
56 + $week -= ($cycles - 1) * seconds_in_a_week;
57 +} else {
58 + $week = bow($week);
59 +}
60 +if (!defined $cycles) {
61 + my $ends = time();
62 + my $clock = $week;
63 + for ($cycles = 0; $clock < $ends; $cycles++) {
64 + $clock += seconds_in_a_week;
65 + }
66 +}
67 +
68 +my $cull_old = "--since=" . $week;
69 +
70 +sub plural {
71 + my ($number, $singular, $plural) = @_;
72 + return ($number == 1) ? "$number $singular": "$number $plural";
73 +}
74 +
75 +sub fmt_join {
76 + my ($leader, $limit, $joiner, @ary) = @_;
77 + my @result = ();
78 + my $width = 0;
79 + my $wj = length($joiner);
80 + my $wl = length($leader);
81 +
82 + for my $item (@ary) {
83 + my $need_joiner;
84 + if ($width == 0) {
85 + $width += $wl;
86 + push @result, $leader;
87 + $need_joiner = 0;
88 + } else {
89 + $need_joiner = 1;
90 + }
91 + my $len = length($item);
92 + if (($need_joiner ? $wj : 0) + $len + $width < $limit) {
93 + if ($need_joiner) {
94 + $width += $wj;
95 + push @result, $joiner;
96 + }
97 + $width += $len;
98 + push @result, $item;
99 + } else {
100 + if ($width) {
101 + push @result, "\n";
102 + $width = 0;
103 + }
104 + $width += $wl;
105 + push @result, $leader;
106 + $width += $len;
107 + push @result, $item;
108 + }
109 + }
110 + push @result, "\n" unless ($result[-1] eq "\n");
111 + return join("", @result);
112 +}
113 +
114 +my %patch;
115 +my %dates;
116 +my %patch_by_date;
117 +my %merge_by_branch_date;
118 +my @integrate = (['master', ', to include in the next release'],
119 + ['next', ' for public testing'],
120 + ['maint', ', to include in the maintenance release'],
121 +);
122 +
123 +open I, "-|", ("git", "log", "--pretty=%ci %H %an <%ae>\001%s",
124 + $cull_old, "--glob=refs/heads",
125 + "--no-merges") or die;
126 +while (<I>) {
127 + my ($date, $sha1, $rest) = /^([-0-9]+) [:0-9]+ [-+][0-9]{4} ([0-9a-f]+) (.*)$/;
128 + $patch_by_date{$date} ||= [];
129 + push @{$patch_by_date{$date}}, $sha1;
130 + my ($name, $subject) = split(/\001/, $rest, 2);
131 + $patch{$sha1} = [$sha1, $name, $subject];
132 + $dates{$date}++;
133 +}
134 +close (I) or die;
135 +
136 +for my $branch (map { $_->[0] } @integrate) {
137 + open I, "-|", ("git", "log", "--pretty=%ci %H %s",
138 + $cull_old,
139 + "--first-parent",
140 + "--merges",
141 + $branch) or die;
142 + while (<I>) {
143 + my ($date, $sha1, $rest) = /^([-0-9]+) [:0-9]+ [-+][0-9]{4} ([0-9a-f]+) (.*)$/;
144 + my $msg = $rest;
145 + $msg =~ s/^Merge branch //;
146 + $msg =~ s/ into \Q$branch\E$//;
147 + $msg =~ s/^'(.*)'$/$1/;
148 +
149 + next if (grep { $_ eq $msg } map { $_->[0] } @integrate);
150 +
151 + $merge_by_branch_date{$branch} ||= {};
152 + $merge_by_branch_date{$branch}{$date} ||= [];
153 + push @{$merge_by_branch_date{$branch}{$date}}, $sha1;
154 + $patch{$sha1} = [$sha1, undef, $msg];
155 + $dates{$date}++;
156 + }
157 + close (I) or die;
158 +}
159 +
160 +my $sep = "";
161 +my %total_names = ();
162 +my %total_merges = ();
163 +my $total_patch = 0;
164 +my @dates = sort keys %dates;
165 +
166 +for my $date (@dates) {
167 + print "$sep$date\n";
168 + if (exists $patch_by_date{$date}) {
169 + my $count = scalar @{$patch_by_date{$date}};
170 + my %names = ();
171 + for my $patch (map { $patch{$_} } (@{$patch_by_date{$date}})) {
172 + my $name = $patch->[1];
173 + $names{$name}++;
174 + $total_names{$name}++;
175 + }
176 + my $people = scalar @{[keys %names]};
177 + $total_patch += $count;
178 +
179 + $count = plural($count, "patch", "patches");
180 + $people = plural($people, "person", "people");
181 + print "Queued $count from $people.\n";
182 + if ($verbose) {
183 + for my $patch (map { $patch{$_} } @{$patch_by_date{$date}}) {
184 + print " $patch->[2]\n";
185 + }
186 + }
187 + }
188 + for my $branch_data (@integrate) {
189 + my ($branch, $purpose) = @{$branch_data};
190 + next unless (exists $merge_by_branch_date{$branch}{$date});
191 + my $merges = $merge_by_branch_date{$branch}{$date};
192 + my $count = scalar @$merges;
193 + next unless $count;
194 +
195 + $total_merges{$branch} ||= 0;
196 + $total_merges{$branch} += $count;
197 + $count = plural($count, "topic", "topics");
198 + print "Merged $count to '$branch' branch$purpose.\n";
199 + if ($verbose) {
200 + print fmt_join(" ", 72, " ", (map { $patch{$_}->[2] } @$merges));
201 + }
202 + }
203 + $sep = "\n";
204 +}
205 +
206 +if (1 < @dates) {
207 + print "${sep}Between $dates[0]..$dates[-1]\n";
208 +
209 + my $people = plural(scalar @{[keys %total_names]}, "person", "people");
210 + my $count = plural($total_patch, "patch", "patches");
211 + print "Queued $count from $people.\n";
212 +
213 + for my $branch_data (@integrate) {
214 + my ($branch, $purpose) = @{$branch_data};
215 + next unless $total_merges{$branch};
216 + my $count = plural($total_merges{$branch}, "merge", "merges");
217 + print "Made $count to '$branch' branch$purpose.\n";
218 + }
219 +}