10d124e7b4bfedbf780fbc5da298bf2e3cfa0a93
[p5sagit/p5-mst-13.2.git] / Porting / Maintainers
1 #!/usr/bin/perl -w
2
3 #
4 # Maintainers - show information about maintainers
5 #
6
7 use strict;
8
9 use FindBin qw($Bin);
10 require "$Bin/Maintainers.pl";
11 use vars qw(%Modules %Maintainers);
12
13 use Getopt::Long;
14 use File::Find;
15
16 sub usage {
17     print <<__EOF__;
18 $0: Usage: $0 [[--maintainer M --module M --files]|file ...]
19 $0 --maintainer M       list all maintainers matching M
20 $0 --module M           list all modules matching M
21 $0 --files              list all files of the module
22 Matching is case-ignoring regexp, author matching is both by
23 the short id and by the full name and email.  A "module" may
24 not be just a module, it may be a file or files or a subdirectory.
25 $0 file ...             list the modules and maintainers of the files
26 __EOF__
27     exit(0);
28 }
29
30 my $Maintainer;
31 my $Module;
32 my $Files;
33
34 usage()
35     unless
36     GetOptions(
37                'maintainer=s'   => \$Maintainer,
38                'module=s'       => \$Module,
39                'files'          => \$Files,
40                );
41
42 my @Files = @ARGV;
43
44 usage() if @Files && ($Maintainer || $Module || $Files);
45
46 for my $mean ($Maintainer, $Module) {
47     warn "$0: Did you mean '$0 $mean'?\n"
48         if $mean && -e $mean && $mean ne '.';
49 }
50
51 warn "$0: Did you mean '$0 -mo $Maintainer'?\n"
52     if defined $Maintainer && exists $Modules{$Maintainer};
53
54 warn "$0: Did you mean '$0 -ma $Module'?\n"
55     if defined $Module     && exists $Maintainers{$Module};
56
57 sub get_module_pat {
58     my $m = shift;
59     split ' ', $Modules{$m}{FILES};
60 }
61
62 sub get_module_files {
63     my $m = shift;
64     sort { lc $a cmp lc $b }
65     map {
66         -f $_ ? # Files as-is.
67             $_ :
68             -d _ ? # Recurse into directories.
69             do {
70                 my @files;
71                 find(
72                      sub {
73                          push @files, $File::Find::name
74                              if -f $_;
75                      }, $_);
76                 @files;
77             }
78         : glob($_) # The rest are globbable patterns.
79         } get_module_pat($m);
80 }
81
82 sub get_maintainer_modules {
83     my $m = shift;
84     sort { lc $a cmp lc $b }
85     grep { $Modules{$_}{MAINTAINER} eq $m }
86     keys %Modules;
87 }
88
89 if ($Maintainer) {
90     for my $m (sort keys %Maintainers) {
91         if ($m =~ /$Maintainer/io) {
92             my @modules = get_maintainer_modules($m);
93             if ($Module) {
94                 @modules = grep { /$Module/io } @modules;
95             }
96             if ($Files) {
97                 my @files;
98                 for my $module (@modules) {
99                     push @files, get_module_files($module);
100                 }
101                 printf "%-15s @files\n", $m;
102             } else {
103                 if ($Module) {
104                     printf "%-15s @modules\n", $m;
105                 } else {
106                     printf "%-15s $Maintainers{$m}\n", $m;
107                 }
108             }
109         }
110     }
111 } elsif ($Module) {
112     for my $m (sort { lc $a cmp lc $b } keys %Modules) {
113         if ($m =~ /$Module/io) {
114             if ($Files) {
115                 my @files = get_module_files($m);
116                 printf "%-15s @files\n", $m;
117             } else {
118                 printf "%-15s $Modules{$m}{MAINTAINER}\n", $m;
119             }
120         }
121     }
122 } elsif (@Files) {
123     my %ModuleByFile;
124
125     for (@Files) { s:^\./:: }
126
127     @ModuleByFile{@Files} = ();
128
129     # First try fast match.
130
131     my %ModuleByPat;
132     for my $module (keys %Modules) {
133         for my $pat (get_module_pat($module)) {
134             $ModuleByPat{$pat} = $module;
135         }
136     }
137     # Expand any globs.
138     my %ExpModuleByPat;
139     for my $pat (keys %ModuleByPat) {
140         if (-e $pat) {
141             $ExpModuleByPat{$pat} = $ModuleByPat{$pat};
142         } else {
143             for my $exp (glob($pat)) {
144                 $ExpModuleByPat{$exp} = $ModuleByPat{$pat};
145             }
146         }
147     }
148     %ModuleByPat = %ExpModuleByPat;
149     for my $file (@Files) {
150         $ModuleByFile{$file} = $ModuleByPat{$file}
151             if exists $ModuleByPat{$file};
152     }
153
154     # If still unresolved files..
155     if (my @ToDo = grep { !defined $ModuleByFile{$_} } keys %ModuleByFile) {
156
157         # Cannot match what isn't there.
158         @ToDo = grep { -e $_ } @ToDo;
159
160         if (@ToDo) {
161             # Try prefix matching.
162
163             # Remove trailing slashes.
164             for (@ToDo) { s|/$|| }
165
166             my %ToDo;
167             @ToDo{@ToDo} = ();
168
169             for my $pat (keys %ModuleByPat) {
170                 last unless keys %ToDo;
171                 if (-d $pat) {
172                     my @Done;
173                     for my $file (keys %ToDo) {
174                         if ($file =~ m|^$pat|i) {
175                             $ModuleByFile{$file} = $ModuleByPat{$pat};
176                             push @Done, $file;
177                         }
178                     }
179                     delete @ToDo{@Done};
180                 }
181             }
182         }
183     }
184
185     for my $file (@Files) {
186         if (defined $ModuleByFile{$file}) {
187             my $module     = $ModuleByFile{$file};
188             my $maintainer = $Modules{$ModuleByFile{$file}}{MAINTAINER};
189             printf "%-15s $module $maintainer $Maintainers{$maintainer}\n", $file;
190         } else {
191             printf "%-15s ?\n", $file;
192         }
193     }
194 }
195 else {
196     usage();
197 }
198