cf4e14e5ebeceb97ecb4ae77e387803de6408616
[p5sagit/p5-mst-13.2.git] / Porting / Modules
1 #!/usr/bin/perl -w
2
3 #
4 # Modules - show information about modules and their maintainers
5 #
6
7 use strict;
8
9 use vars qw($Maintainers $Modules);
10
11 $Maintainers =
12         {
13         'ams'           => 'Abhijit Menon-Sen <ams@wiw.org>',
14         'andreas'       => 'Andreas J. Koenig <andreas.koenig@anima.de>',
15         'arthur'        => 'Arthur Bergman <sky@nanisky.com>',
16         'bbb'           => 'Rob Brown <bbb@cpan.org>',
17         'damian'        => 'Damian Conway <damian@conway.org>',
18         'dankogai'      => 'Dan Kogai <dankogai@dan.co.jp>',
19         'gbarr'         => 'Graham Barr <gbarr@pobox.com>',
20         'gisle'         => 'Gisle Aas <gisle@activestate.com>',
21         'ilyaz'         => 'Ilya Zakharevich <ilyaz@cpan.org>',
22         'jhi'           => 'Jarkko Hietaniemi <jhi@iki.fi>',
23         'jns'           => 'Jonathan Stowe <jns@gellyfish.com>',
24         'jvromans'      => 'Johan Vromans <jvromans@squirrel.nl>',
25         'lstein'        => 'Lincoln D. Stein <lstein@cshl.org>',
26         'mjd'           => 'Mark-Jason Dominus <mjd@plover.com>',
27         'muir'          => 'David Muir Sharnoff <muir@idiom.com>',
28         'neilb'         => 'Neil Bowers <neil@bowers.com>',
29         'rra'           => 'Russ Allbery <rra@stanford.edu>',
30         'pmarquess'     => 'Paul Marquess <Paul.Marquess@btinternet.com>',
31         'sadahiro'      => 'SADAHIRO Tomoyuki <SADAHIRO@cpan.org>',
32         'sburke'        => 'Sean Burke <sburke@cpan.org>',
33         'smcc'          => 'Stephen McCamant <smcc@CSUA.Berkeley.EDU>',
34         'schwern'       => 'Michael Schwern <schwern@pobox.com>',
35         'tels'          => 'Tels a-t bloodgate.com',
36         'tjenness'      => 'Tim Jenness <t.jenness@jach.hawaii.edu>'
37         };
38
39 $Modules = {
40
41         'Attribute::Handlers' =>
42                 {
43                 'MAINTAINER'    => 'arthur',
44                 'FILES'         =>
45                         q[lib/Attribute/Handlers.pm lib/Attribute/Handlers],
46                 },
47
48         'B::Concise' =>
49                 {
50                 'MAINTAINER'    => 'smcc',
51                 'FILES'         => q[ext/B/B/Concise.pm ext/B/t/concise.t],
52                 },
53
54         'bignum' =>
55                 {
56                 'MAINTAINER'    => 'tels',
57                 'FILES'         => q[lib/big{int,num,rat}.pm lib/bignum],
58                 },
59
60         'CGI' =>
61                 {
62                 'MAINTAINER'    => 'lstein',
63                 'FILES'         => q[lib/CGI.pm lib/CGI],
64                 },
65
66         'Class::ISA' =>
67                 {
68                 'MAINTAINER'    => 'sburke',
69                 'FILES'         => q[lib/Class/ISA.pm lib/Class/ISA],
70                 },
71
72         'CPAN' =>
73                 {
74                 'MAINTAINER'    => 'andreas',
75                 'FILES'         => q[lib/CPAN.pm lib/CPAN],
76                 },
77
78 # Data::Dumper is not here, Sarathy has given up the maintenance
79 # and Data::Dumper should be considered a part of the Perl core.
80
81         'DB::File' =>
82                 {
83                 'MAINTAINER'    => 'pmarquess',
84                 'FILES'         => q[ext/DB_File],
85                 },
86
87         'Devel::PPPort' =>
88                 {
89                 'MAINTAINER'    => 'pmarquess',
90                 'FILES'         => q[ext/Devel/PPPort],
91                 },
92
93         'Digest' =>
94                 {
95                 'MAINTAINER'    => 'gisle',
96                 'FILES'         => q[lib/Digest.{pm,t}],
97                 },
98
99         'Digest::MD5' =>
100                 {
101                 'MAINTAINER'    => 'gisle',
102                 'FILES'         => q[ext/Digest/MD5],
103                 },
104
105         'Encode' =>
106                 {
107                 'MAINTAINER'    => 'dankogai',
108                 'FILES'         => q[ext/Encode],
109                 },
110
111 # Errno is not here, Graham has given up the maintenance
112 # and Errno should be considered a part of the Perl core.
113
114         'ExtUtils::MakeMaker' =>
115                 {
116                 'MAINTAINER'    => 'schwern',
117                 'FILES'         => q[lib/ExtUtils/MakeMaker],
118                 },
119
120         'File::Temp' =>
121                 {
122                 'MAINTAINER'    => 'tjenness',
123                 'FILES'         => q[lib/File/Temp.pm lib/File/Temp],
124                 },
125
126         'Filter::Simple' =>
127                 {
128                 'MAINTAINER'    => 'damian',
129                 'FILES'         => q[lib/Filter/Simple.pm lib/Filter/Simple],
130                 },
131
132         'Filter::Util::Call' =>
133                 {
134                 'MAINTAINER'    => 'pmarquess',
135                 'FILES'         => q[ext/Filter/Util/Call],
136                 },
137
138         'Getopt::Long' =>
139                 {
140                 'MAINTAINER'    => 'jvromans',
141                 'FILES'         => q[lib/Getopt/Long.pm lib/Getopt/Long],
142                 },
143
144         'I18N::LangTags' =>
145                 {
146                 'MAINTAINER'    => 'sburke',
147                 'FILES'         => q[lib/I18N/LangTags.pm lib/I18N/LangTags],
148                 },
149
150         'if' =>
151                 {
152                 'MAINTAINER'    => 'ilyaz',
153                 'FILES'         => q[lib/if.{pm,t}],
154                 },
155
156 # IO is not here, Graham has given up the maintenance
157 # and IO should be considered a part of the Perl core.
158
159         'libnet' =>
160                 {
161                 'MAINTAINER'    => 'gbarr',
162                 'FILES'         =>
163                         q[lib/Net/{Cmd,Domain,FTP,Netrc,NNTP,POP3,SMTP,Time}.pm lib/Net/ChangeLog.libnet lib/Net/FTP lib/Net/*.eg lib/Net/libnetFAQ.pod lib/Net/README.libnet lib/Net/t],
164                 },
165
166         'Scalar-List-Util' =>
167                 {
168                 'MAINTAINER'    => 'gbarr',
169                 'FILES'         => q[ext/List/Util],
170                 },
171
172         'Locale::Codes' =>
173                 {
174                 'MAINTAINER'    => 'neilb',
175                 'FILES'         => q[lib/Locale/{Codes,Constants,Country,Currency,Language,Script}*],
176                 },
177
178         'Locale::Maketext' =>
179                 {
180                 'MAINTAINER'    => 'sburke',
181                 'FILES'         => q[lib/Locale/Maketext.pm lib/Locale/Maketext],
182                 },
183
184         'Math::BigFloat' =>
185                 {
186                 'MAINTAINER'    => 'tels',
187                 'FILES'         => q[lib/Math/BigFloat.pm lib/Math/BigFloat],
188                 },
189
190         'Math::BigInt' =>
191                 {
192                 'MAINTAINER'    => 'tels',
193                 'FILES'         => q[lib/Math/BigInt.pm lib/Math/BigInt],
194                 },
195
196         'Math::BigRat' =>
197                 {
198                 'MAINTAINER'    => 'tels',
199                 'FILES'         => q[lib/Math/BigRat.pm lib/Math/BigRat],
200                 },
201
202         'Memoize' =>
203                 {
204                 'MAINTAINER'    => 'mjd',
205                 'FILES'         => q[lib/Memoize.pm lib/Memoize],
206                 },
207
208         'MIME::Base64' =>
209                 {
210                 'MAINTAINER'    => 'gisle',
211                 'FILES'         => q[ext/MIME/Base64],
212                 },
213
214         'Net::Ping' =>
215                 {
216                 'MAINTAINER'    => 'bbb',
217                 'FILES'         => q[lib/Net/Ping.pm lib/Net/Ping],
218                 },
219
220         'NEXT' =>
221                 {
222                 'MAINTAINER'    => 'damian',
223                 'FILES'         => q[lib/NEXT.pm lib/NEXT],
224                 },
225
226 # The PerlIO::* are part of Perl core.
227
228         'podlators' =>
229                 {
230                 'MAINTAINER'    => 'rra',
231                 'FILES'         => q[lib/Pod/{Html,Man,ParseLink,Text,Text/{Color,Overstrike,Termcap}}.pm pod/pod2man.PL pod/pod2text.PL lib/Pod/t/{basic.*,{basic,man,parselink,text*}.t}],
232                 },
233
234         'Storable' =>
235                 {
236                 'MAINTAINER'    => 'ams',
237                 'FILES'         => q[ext/Storable],
238                 },
239
240         'Switch' =>
241                 {
242                 'MAINTAINER'    => 'damian',
243                 'FILES'         => q[lib/Switch.pm lib/Switch],
244                 },
245
246         'TabsWrap' =>
247                 {
248                 'MAINTAINER'    => 'muir',
249                 'FILES'         =>
250                         q[lib/Text/{Tabs,Wrap}.pm lib/Text/TabsWrap],
251                 },
252
253         'Text::Balanced' =>
254                 {
255                 'MAINTAINER'    => 'damian',
256                 'FILES'         => q[lib/Text/Balanced.pm lib/Text/Balanced],
257                 },
258
259         'Term::ANSIColor' =>
260                 {
261                 'MAINTAINER'    => 'rra',
262                 'FILES'         => q[lib/Term/ANSIColor.pm lib/Term/ANSIColor],
263                 },
264
265         'Test::Builder' =>
266                 {
267                 'MAINTAINER'    => 'schwern',
268                 'FILES'         => q[lib/Test/Builder.pm],
269                 },
270
271         'Test::Harness' =>
272                 {
273                 'MAINTAINER'    => 'schwern',
274                 'FILES'         => q[lib/Test/Harness.pm lib/Test/Harness],
275                 },
276
277         'Test::More' =>
278                 {
279                 'MAINTAINER'    => 'schwern',
280                 'FILES'         => q[lib/Test/More.pm],
281                 },
282
283         'Test::Simple' =>
284                 {
285                 'MAINTAINER'    => 'schwern',
286                 'FILES'         => q[lib/Test/Simple.pm lib/Test/Simple],
287                 },
288
289         'Term::Cap' =>
290                 {
291                 'MAINTAINER'    => 'jns',
292                 'FILES'         => q[lib/Term/Cap.{pm,t}],
293                 },
294
295
296         'threads' =>
297                 {
298                 'MAINTAINER' => 'arthur',
299                 'FILES'  => q[ext/threads],
300                 },
301
302         'Tie::File' =>
303                 {
304                 'MAINTAINER'    => 'mjd',
305                 'FILES'         => q[lib/Tie/File.pm lib/Tie/File],
306                 },
307
308         'Time::HiRes' =>
309                 {
310                 'MAINTAINER'    => 'jhi',
311                 'FILES'         => q[ext/Time/HiRes],
312                 },
313
314         'Unicode::Collate' =>
315                 {
316                 'MAINTAINER'    => 'sadahiro',
317                 'FILES'         =>
318                         q[lib/Unicode/Collate.pm lib/Unicode/Collate],
319                 },
320
321         'Unicode::Normalize' =>
322                 {
323                 'MAINTAINER'    => 'sadahiro',
324                 'FILES'         => q[ext/Unicode/Normalize],
325                 },
326
327         'warnings' =>
328                 {
329                 'MAINTAINER'    => 'pmarquess',
330                 'FILES'         =>
331                     q[warnings.pl lib/warnings.{pm,t}
332                       lib/warnings t/lib/warnings],
333                 },
334
335         };
336
337 use Getopt::Long;
338 use File::Find;
339
340 sub usage {
341     print <<__EOF__;
342 $0: Usage: $0 [[--maintainer M --module M --files]|file ...]
343 $0 --maintainer M       list all maintainers matching M
344 $0 --module M           list all modules matching M
345 $0 --files              list all files of the module
346 Matching is case-ignoring regexp, author matching is both by
347 the short id and by the full name and email.
348 $0 file ...             list the module and maintainer
349 __EOF__
350     exit(0);
351 }
352
353 my $Maintainer;
354 my $Module;
355 my $Files;
356
357 usage()
358     unless
359     GetOptions(
360                'maintainer=s'   => \$Maintainer,
361                'module=s'       => \$Module,
362                'files'          => \$Files,
363                );
364
365 my @Files = @ARGV;
366
367 usage() if @Files && ($Maintainer || $Module || $Files);
368
369 for my $mean ($Maintainer, $Module) {
370     warn "$0: Did you mean '$0 $mean'?\n"
371         if $mean && -e $mean && $mean ne '.';
372 }
373
374 warn "$0: Did you mean '$0 -mo $Maintainer'?\n"
375     if defined $Maintainer && exists $Modules->{$Maintainer};
376
377 warn "$0: Did you mean '$0 -ma $Module'?\n"
378     if defined $Module     && exists $Maintainers->{$Module};
379
380 sub get_module_pat {
381     my $m = shift;
382     split ' ', $Modules->{$m}->{FILES};
383 }
384
385 sub get_module_files {
386     my $m = shift;
387     sort { lc $a cmp lc $b }
388     map {
389         -f $_ ? # Files as-is.
390             $_ :
391             -d _ ? # Recurse into directories.
392             do {
393                 my @files;
394                 find(
395                      sub {
396                          push @files, $File::Find::name
397                              if -f $_;
398                      }, $_);
399                 @files;
400             }
401         : glob($_) # The rest are globbable patterns.
402         } get_module_pat($m);
403 }
404
405 sub get_maintainer_modules {
406     my $m = shift;
407     sort { lc $a cmp lc $b }
408     grep { $Modules->{$_}->{MAINTAINER} eq $m }
409     keys %$Modules;
410 }
411
412 if ($Maintainer) {
413     for my $m (sort keys %$Maintainers) {
414         if ($m =~ /$Maintainer/io) {
415             my @modules = get_maintainer_modules($m);
416             if ($Module) {
417                 @modules = grep { /$Module/io } @modules;
418             }
419             if ($Files) {
420                 my @files;
421                 for my $module (@modules) {
422                     push @files, get_module_files($module);
423                 }
424                 printf "%-15s @files\n", $m;
425             } else {
426                 if ($Module) {
427                     printf "%-15s @modules\n", $m;
428                 } else {
429                     printf "%-15s $Maintainers->{$m}\n", $m;
430                 }
431             }
432         }
433     }
434 } elsif ($Module) {
435     for my $m (sort { lc $a cmp lc $b } keys %$Modules) {
436         if ($m =~ /$Module/io) {
437             if ($Files) {
438                 my @files = get_module_files($m);
439                 printf "%-15s @files\n", $m;
440             } else {
441                 printf "%-15s $Modules->{$m}->{MAINTAINER}\n", $m;
442             }
443         }
444     }
445 } elsif (@Files) {
446     my %ModuleByFile;
447
448     @ModuleByFile{@Files} = ();
449
450     # First try fast match.
451
452     my %ModuleByPat;
453     for my $module (keys %$Modules) {
454         for my $pat (get_module_pat($module)) {
455             $ModuleByPat{$pat} = $module;
456         }
457     }
458     # Expand any globs.
459     my %ExpModuleByPat;
460     for my $pat (keys %ModuleByPat) {
461         if (-e $pat) {
462             $ExpModuleByPat{$pat} = $ModuleByPat{$pat};
463         } else {
464             for my $exp (glob($pat)) {
465                 $ExpModuleByPat{$exp} = $ModuleByPat{$pat};
466             }
467         }
468     }
469     %ModuleByPat = %ExpModuleByPat;
470     for my $file (@Files) {
471         $ModuleByFile{$file} = $ModuleByPat{$file}
472             if exists $ModuleByPat{$file};
473     }
474
475     # If still unresolved files..
476     if (my @ToDo = grep { !defined $ModuleByFile{$_} } keys %ModuleByFile) {
477
478         # Cannot match what isn't there.
479         @ToDo = grep { -e $_ } @ToDo;
480
481         if (@ToDo) {
482             # Try prefix matching.
483
484             # Remove trailing slashes.
485             for (@ToDo) { s|/$|| }
486
487             my %ToDo;
488             @ToDo{@ToDo} = ();
489
490             for my $pat (keys %ModuleByPat) {
491                 last unless keys %ToDo;
492                 if (-d $pat) {
493                     my @Done;
494                     for my $file (keys %ToDo) {
495                         if ($file =~ m|^$pat|i) {
496                             $ModuleByFile{$file} = $ModuleByPat{$pat};
497                             push @Done, $file;
498                         }
499                     }
500                     delete @ToDo{@Done};
501                 }
502             }
503         }
504     }
505
506     for my $file (@Files) {
507         if (defined $ModuleByFile{$file}) {
508             my $module     = $ModuleByFile{$file};
509             my $maintainer = $Modules->{$ModuleByFile{$file}}->{MAINTAINER};
510             printf "%-15s $module $maintainer $Maintainers->{$maintainer}\n", $file;
511         } else {
512             printf "%-15s ?\n", $file;
513         }
514     }
515 }
516
517 exit(0);