Upgrade to podlators 2.1.2
[p5sagit/p5-mst-13.2.git] / Porting / Maintainers.pm
CommitLineData
0cf51544 1#
2# Maintainers.pm - show information about maintainers
3#
4
5package Maintainers;
6
7use strict;
8
9use lib "Porting";
357244ac 10# Please don't use post 5.008 features as this module is used by
11# Porting/makemeta, and that in turn has to be run by the perl just built.
12use 5.008;
0cf51544 13
14require "Maintainers.pl";
15use vars qw(%Modules %Maintainers);
16
d8528f07 17use vars qw(@ISA @EXPORT_OK $VERSION);
0cf51544 18@ISA = qw(Exporter);
19@EXPORT_OK = qw(%Modules %Maintainers
20 get_module_files get_module_pat
21 show_results process_options);
d8528f07 22$VERSION = 0.02;
0cf51544 23require Exporter;
24
25use File::Find;
26use Getopt::Long;
27
28my %MANIFEST;
29if (open(MANIFEST, "MANIFEST")) {
30 while (<MANIFEST>) {
31 if (/^(\S+)\t+(.+)$/) {
32 $MANIFEST{$1}++;
33 }
34 }
35 close MANIFEST;
36} else {
37 die "$0: Failed to open MANIFEST for reading: $!\n";
38}
39
40sub get_module_pat {
41 my $m = shift;
42 split ' ', $Modules{$m}{FILES};
43}
44
45sub get_module_files {
46 my $m = shift;
47 sort { lc $a cmp lc $b }
48 map {
49 -f $_ ? # Files as-is.
50 $_ :
51 -d _ ? # Recurse into directories.
52 do {
53 my @files;
54 find(
55 sub {
56 push @files, $File::Find::name
57 if -f $_ && exists $MANIFEST{$File::Find::name};
58 }, $_);
59 @files;
60 }
61 : glob($_) # The rest are globbable patterns.
62 } get_module_pat($m);
63}
64
65sub get_maintainer_modules {
66 my $m = shift;
67 sort { lc $a cmp lc $b }
68 grep { $Modules{$_}{MAINTAINER} eq $m }
69 keys %Modules;
70}
71
72sub usage {
73 print <<__EOF__;
3428fdd5 74$0: Usage: $0 [[--maintainer M --module M --files]|[--check] file ...]
0cf51544 75--maintainer M list all maintainers matching M
76--module M list all modules matching M
77--files list all files
678b26d7 78--check check consistency of Maintainers.pl
3428fdd5 79 with a file checks if it has a maintainer
80 with a dir checks all files have a maintainer
81 otherwise checks for multiple maintainers
d933dc9e 82--opened list all modules of files opened by perforce
0cf51544 83Matching is case-ignoring regexp, author matching is both by
84the short id and by the full name and email. A "module" may
85not be just a module, it may be a file or files or a subdirectory.
86The options may be abbreviated to their unique prefixes
87__EOF__
88 exit(0);
89}
90
91my $Maintainer;
92my $Module;
93my $Files;
678b26d7 94my $Check;
d933dc9e 95my $Opened;
0cf51544 96
97sub process_options {
98 usage()
99 unless
100 GetOptions(
101 'maintainer=s' => \$Maintainer,
102 'module=s' => \$Module,
103 'files' => \$Files,
678b26d7 104 'check' => \$Check,
d933dc9e 105 'opened' => \$Opened,
0cf51544 106 );
107
d933dc9e 108 my @Files;
109
110 if ($Opened) {
33768f13 111 @Files = `p4 opened`;
d933dc9e 112 die if $?;
33768f13 113 foreach (@Files) {
114 s!#.*!!s;
115 s!^//depot/(?:perl|.*?/perl)/!!;
116 }
d933dc9e 117 } else {
118 @Files = @ARGV;
119 }
0cf51544 120
121 usage() if @Files && ($Maintainer || $Module || $Files);
122
123 for my $mean ($Maintainer, $Module) {
124 warn "$0: Did you mean '$0 $mean'?\n"
125 if $mean && -e $mean && $mean ne '.' && !$Files;
126 }
127
128 warn "$0: Did you mean '$0 -mo $Maintainer'?\n"
129 if defined $Maintainer && exists $Modules{$Maintainer};
130
131 warn "$0: Did you mean '$0 -ma $Module'?\n"
132 if defined $Module && exists $Maintainers{$Module};
133
134 return ($Maintainer, $Module, $Files, @Files);
135}
136
137sub show_results {
138 my ($Maintainer, $Module, $Files, @Files) = @_;
139
140 if ($Maintainer) {
141 for my $m (sort keys %Maintainers) {
142 if ($m =~ /$Maintainer/io || $Maintainers{$m} =~ /$Maintainer/io) {
143 my @modules = get_maintainer_modules($m);
144 if ($Module) {
145 @modules = grep { /$Module/io } @modules;
146 }
147 if ($Files) {
148 my @files;
149 for my $module (@modules) {
150 push @files, get_module_files($module);
151 }
152 printf "%-15s @files\n", $m;
153 } else {
154 if ($Module) {
155 printf "%-15s @modules\n", $m;
156 } else {
157 printf "%-15s $Maintainers{$m}\n", $m;
158 }
159 }
160 }
161 }
162 } elsif ($Module) {
163 for my $m (sort { lc $a cmp lc $b } keys %Modules) {
164 if ($m =~ /$Module/io) {
165 if ($Files) {
166 my @files = get_module_files($m);
167 printf "%-15s @files\n", $m;
168 } else {
169 printf "%-15s $Modules{$m}{MAINTAINER}\n", $m;
170 }
171 }
172 }
3428fdd5 173 } elsif ($Check) {
174 if( @Files ) {
175 missing_maintainers( qr{\.(?:[chty]|p[lm]|xs)\z}msx, @Files)
176 }
177 else {
178 duplicated_maintainers();
179 }
0cf51544 180 } elsif (@Files) {
181 my %ModuleByFile;
182
183 for (@Files) { s:^\./:: }
184
185 @ModuleByFile{@Files} = ();
186
187 # First try fast match.
188
189 my %ModuleByPat;
190 for my $module (keys %Modules) {
191 for my $pat (get_module_pat($module)) {
192 $ModuleByPat{$pat} = $module;
193 }
194 }
195 # Expand any globs.
196 my %ExpModuleByPat;
197 for my $pat (keys %ModuleByPat) {
198 if (-e $pat) {
199 $ExpModuleByPat{$pat} = $ModuleByPat{$pat};
200 } else {
201 for my $exp (glob($pat)) {
202 $ExpModuleByPat{$exp} = $ModuleByPat{$pat};
203 }
204 }
205 }
206 %ModuleByPat = %ExpModuleByPat;
207 for my $file (@Files) {
208 $ModuleByFile{$file} = $ModuleByPat{$file}
209 if exists $ModuleByPat{$file};
210 }
211
212 # If still unresolved files...
213 if (my @ToDo = grep { !defined $ModuleByFile{$_} } keys %ModuleByFile) {
214
215 # Cannot match what isn't there.
216 @ToDo = grep { -e $_ } @ToDo;
217
218 if (@ToDo) {
219 # Try prefix matching.
220
221 # Remove trailing slashes.
222 for (@ToDo) { s|/$|| }
223
224 my %ToDo;
225 @ToDo{@ToDo} = ();
226
227 for my $pat (keys %ModuleByPat) {
228 last unless keys %ToDo;
229 if (-d $pat) {
230 my @Done;
231 for my $file (keys %ToDo) {
232 if ($file =~ m|^$pat|i) {
233 $ModuleByFile{$file} = $ModuleByPat{$pat};
234 push @Done, $file;
235 }
236 }
237 delete @ToDo{@Done};
238 }
239 }
240 }
241 }
242
243 for my $file (@Files) {
244 if (defined $ModuleByFile{$file}) {
245 my $module = $ModuleByFile{$file};
246 my $maintainer = $Modules{$ModuleByFile{$file}}{MAINTAINER};
247 printf "%-15s $module $maintainer $Maintainers{$maintainer}\n", $file;
248 } else {
249 printf "%-15s ?\n", $file;
250 }
251 }
252 }
253 else {
254 usage();
255 }
256}
257
3428fdd5 258my %files;
259
260sub maintainers_files {
261 %files = ();
678b26d7 262 for my $k (keys %Modules) {
263 for my $f (get_module_files($k)) {
264 ++$files{$f};
265 }
266 }
3428fdd5 267}
268
269sub duplicated_maintainers {
270 maintainers_files();
678b26d7 271 for my $f (keys %files) {
272 if ($files{$f} > 1) {
273 warn "File $f appears $files{$f} times in Maintainers.pl\n";
274 }
275 }
276}
277
357244ac 278sub warn_maintainer {
279 my $name = shift;
280 warn "File $name has no maintainer\n" if not $files{$name};
281}
282
3428fdd5 283sub missing_maintainers {
284 my($check, @path) = @_;
285 maintainers_files();
286 my @dir;
357244ac 287 for my $d (@path) {
288 if( -d $d ) { push @dir, $d } else { warn_maintainer($d) }
289 }
3428fdd5 290 find sub { warn_maintainer($File::Find::name) if /$check/; }, @dir
291 if @dir;
292}
293
0cf51544 2941;
295