This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
add the --diff option to corelist
[perl5.git] / dist / Module-CoreList / corelist
1 #!/usr/bin/perl
2
3 =head1 NAME
4
5 corelist - a commandline frontend to Module::CoreList
6
7 =head1 DESCRIPTION
8
9 See L<Module::CoreList> for one.
10
11 =head1 SYNOPSIS
12
13     corelist -v
14     corelist [-a|-d] <ModuleName> | /<ModuleRegex>/ [<ModuleVersion>] ...
15     corelist [-v <PerlVersion>] [ <ModuleName> | /<ModuleRegex>/ ] ...
16     corelist [-r <PerlVersion>] ...
17     corelist --diff PerlVersion PerlVersion
18
19 =head1 OPTIONS
20
21 =over
22
23 =item -a
24
25 lists all versions of the given module (or the matching modules, in case you
26 used a module regexp) in the perls Module::CoreList knows about.
27
28     corelist -a Unicode
29
30     Unicode was first released with perl v5.6.2
31       v5.6.2     3.0.1
32       v5.8.0     3.2.0
33       v5.8.1     4.0.0
34       v5.8.2     4.0.0
35       v5.8.3     4.0.0
36       v5.8.4     4.0.1
37       v5.8.5     4.0.1
38       v5.8.6     4.0.1
39       v5.8.7     4.1.0
40       v5.8.8     4.1.0
41       v5.8.9     5.1.0
42       v5.9.0     4.0.0
43       v5.9.1     4.0.0
44       v5.9.2     4.0.1
45       v5.9.3     4.1.0
46       v5.9.4     4.1.0
47       v5.9.5     5.0.0
48       v5.10.0    5.0.0
49       v5.10.1    5.1.0
50       v5.11.0    5.1.0
51       v5.11.1    5.1.0
52       v5.11.2    5.1.0
53       v5.11.3    5.2.0
54       v5.11.4    5.2.0
55       v5.11.5    5.2.0
56       v5.12.0    5.2.0
57       v5.12.1    5.2.0
58       v5.12.2    5.2.0
59       v5.12.3    5.2.0
60       v5.12.4    5.2.0
61       v5.13.0    5.2.0
62       v5.13.1    5.2.0
63       v5.13.2    5.2.0
64       v5.13.3    5.2.0
65       v5.13.4    5.2.0
66       v5.13.5    5.2.0
67       v5.13.6    5.2.0
68       v5.13.7    6.0.0
69       v5.13.8    6.0.0
70       v5.13.9    6.0.0
71       v5.13.10   6.0.0
72       v5.13.11   6.0.0
73       v5.14.0    6.0.0
74       v5.14.1    6.0.0
75       v5.15.0    6.0.0
76
77 =item -d
78
79 finds the first perl version where a module has been released by
80 date, and not by version number (as is the default).
81
82 =item --diff
83
84 Given two versions of perl, this prints a human-readable table of all module
85 changes between the two.  The output format may change in the future, and is
86 meant for I<humans>, not programs.  For programs, use the L<Module::CoreList>
87 API.
88
89 =item -? or -help
90
91 help! help! help! to see more help, try --man.
92
93 =item -man
94
95 all of the help
96
97 =item -v
98
99 lists all of the perl release versions we got the CoreList for.
100
101 If you pass a version argument (value of C<$]>, like C<5.00503> or C<5.008008>),
102 you get a list of all the modules and their respective versions.
103 (If you have the C<version> module, you can also use new-style version numbers,
104 like C<5.8.8>.)
105
106 In module filtering context, it can be used as Perl version filter.
107
108 =item -r
109
110 lists all of the perl releases and when they were released
111
112 If you pass a perl version you get the release date for that version only.
113
114 =back
115
116 As a special case, if you specify the module name C<Unicode>, you'll get
117 the version number of the Unicode Character Database bundled with the
118 requested perl versions.
119
120 =cut
121
122 use Module::CoreList;
123 use Getopt::Long;
124 use Pod::Usage;
125 use strict;
126 use warnings;
127
128 my %Opts;
129
130 GetOptions(
131     \%Opts,
132     qw[ help|?! man! r|release:s v|version:s a! d diff|D ]
133 );
134
135 pod2usage(1) if $Opts{help};
136 pod2usage(-verbose=>2) if $Opts{man};
137
138 if(exists $Opts{r} ){
139     if ( !$Opts{r} ) {
140         print "\nModule::CoreList has release info for the following perl versions:\n";
141         my $versions = { };
142         my $max_ver_len = max_mod_len(\%Module::CoreList::released);
143         for my $ver ( sort keys %Module::CoreList::released ) {
144           printf "%-${max_ver_len}s    %s\n", format_perl_version($ver), $Module::CoreList::released{$ver};
145         }
146         print "\n";
147         exit 0;
148     }
149
150     my $num_r = numify_version( $Opts{r} );
151     my $version_hash = Module::CoreList->find_version($num_r);
152
153     if( !$version_hash ) {
154         print "\nModule::CoreList has no info on perl $Opts{r}\n\n";
155         exit 1;
156     }
157
158     printf "Perl %s was released on %s\n\n", format_perl_version($num_r), $Module::CoreList::released{$num_r};
159     exit 0;
160 }
161
162 if(exists $Opts{v} ){
163     if( !$Opts{v} ) {
164         print "\nModule::CoreList has info on the following perl versions:\n";
165         print format_perl_version($_)."\n" for sort keys %Module::CoreList::version;
166         print "\n";
167         exit 0;
168     }
169
170     my $num_v = numify_version( $Opts{v} );
171     my $version_hash = Module::CoreList->find_version($num_v);
172
173     if( !$version_hash ) {
174         print "\nModule::CoreList has no info on perl $Opts{v}\n\n";
175         exit 1;
176     }
177
178     if ( !@ARGV ) {
179         print "\nThe following modules were in perl $Opts{v} CORE\n";
180         my $max_mod_len = max_mod_len($version_hash);
181         for my $mod ( sort keys %$version_hash ) {
182             printf "%-${max_mod_len}s  %s\n", $mod, $version_hash->{$mod} || "";
183         }
184         print "\n";
185         exit 0;
186     }
187 }
188
189 if ($Opts{diff}) {
190     if(@ARGV != 2) {
191         die "\nprovide exactly two perl core versions to diff with --diff\n";
192     }
193
194     my ($old_ver, $new_ver) = @ARGV;
195
196     my $old = $Module::CoreList::version{ numify_version($old_ver) };
197     my $new = $Module::CoreList::version{ numify_version($new_ver) };
198
199     my %uniq = (%$old, %$new);
200     for my $lib (sort keys %uniq) {
201         my $old = exists $old->{ $lib }
202                 ? (defined $old->{ $lib } ? $old->{ $lib } : '(undef)')
203                 : '(absent)';
204         my $new = exists $new->{ $lib }
205                 ? (defined $new->{ $lib } ? $new->{ $lib } : '(undef)')
206                 : '(absent)';
207
208         next if $old eq $new;
209
210         printf "%-35s %10s %10s\n", $lib, $old, $new;
211     }
212     exit(0);
213 }
214
215 if ( !@ARGV ) {
216     pod2usage(0);
217 }
218
219 while (@ARGV) {
220         my ($mod, $ver);
221         if ($ARGV[0] =~ /=/) {
222             ($mod, $ver) = split /=/, shift @ARGV;
223         } else {
224             $mod = shift @ARGV;
225             $ver = (@ARGV && $ARGV[0] =~ /^\d/) ? shift @ARGV : "";
226         }
227
228         if ($mod !~ m|^/(.*)/([imosx]*)$|) { # not a regex
229             module_version($mod,$ver);
230         } else {
231             my $re;
232             eval { $re = $2 ? qr/(?$2)($1)/ : qr/$1/; }; # trap exceptions while building regex
233             if ($@) {
234                 # regex errors are usually like 'Quantifier follow nothing in regex; marked by ...'
235                 # then we drop text after ';' to shorten message
236                 my $errmsg = $@ =~ /(.*);/ ? $1 : $@;
237                 warn "\n$mod  is a bad regex: $errmsg\n";
238                 next;
239             }
240             my @mod = Module::CoreList->find_modules($re);
241             if (@mod) {
242                 module_version($_, $ver) for @mod;
243             } else {
244                 $ver |= '';
245                 print "\n$mod $ver has no match in CORE (or so I think)\n";
246             }
247
248         }
249 }
250
251 exit();
252
253 sub module_version {
254     my($mod,$ver) = @_;
255
256     if ( $Opts{v} ) {
257         my $numeric_v = numify_version($Opts{v});
258         my $version_hash = Module::CoreList->find_version($numeric_v);
259         if ($version_hash) {
260             print $mod, " ", $version_hash->{$mod} || 'undef', "\n";
261             return;
262         }
263         else { die "Shouldn't happen" }
264     }
265
266     my $ret = $Opts{d}
267         ? Module::CoreList->first_release_by_date(@_)
268         : Module::CoreList->first_release(@_);
269     my $msg = $mod;
270     $msg .= " $ver" if $ver;
271
272     my $rem = $Opts{d}
273         ? Module::CoreList->removed_from_by_date($mod)
274         : Module::CoreList->removed_from($mod);
275
276     if( defined $ret ) {
277         $msg .= " was ";
278         $msg .= "first " unless $ver;
279         $msg .= "released with perl " . format_perl_version($ret);
280         $msg .= " and removed from " . format_perl_version($rem) if $rem;
281     } else {
282         $msg .= " was not in CORE (or so I think)";
283     }
284
285     print "\n",$msg,"\n";
286
287     if(defined $ret and exists $Opts{a} and $Opts{a}){
288         display_a($mod);
289     }
290 }
291
292
293 sub max_mod_len {
294     my $versions = shift;
295     my $max = 0;
296     for my $mod (keys %$versions) {
297         $max = max($max, length $mod);
298     }
299
300     return $max;
301 }
302
303 sub max {
304     my($this, $that) = @_;
305     return $this if $this > $that;
306     return $that;
307 }
308
309 sub display_a {
310     my $mod = shift;
311
312     for my $v (grep !/000$/, sort keys %Module::CoreList::version ) {
313         next unless exists $Module::CoreList::version{$v}{$mod};
314
315         my $mod_v = $Module::CoreList::version{$v}{$mod} || 'undef';
316         printf "  %-10s %-10s\n", format_perl_version($v), $mod_v;
317     }
318     print "\n";
319 }
320
321
322 {
323     my $have_version_pm;
324     sub have_version_pm {
325         return $have_version_pm if defined $have_version_pm;
326         return $have_version_pm = eval { require version; 1 };
327     }
328 }
329
330
331 sub format_perl_version {
332     my $v = shift;
333     return $v if $v < 5.006 or !have_version_pm;
334     return version->new($v)->normal;
335 }
336
337
338 sub numify_version {
339     my $ver = shift;
340     if ($ver =~ /\..+\./) {
341         have_version_pm()
342             or die "You need to install version.pm to use dotted version numbers\n";
343         $ver = version->new($ver)->numify;
344     }
345     $ver += 0;
346     return $ver;
347 }
348
349 =head1 EXAMPLES
350
351     $ corelist File::Spec
352
353     File::Spec was first released with perl 5.005
354
355     $ corelist File::Spec 0.83
356
357     File::Spec 0.83 was released with perl 5.007003
358
359     $ corelist File::Spec 0.89
360
361     File::Spec 0.89 was not in CORE (or so I think)
362
363     $ corelist File::Spec::Aliens
364
365     File::Spec::Aliens  was not in CORE (or so I think)
366
367     $ corelist /IPC::Open/
368
369     IPC::Open2 was first released with perl 5
370
371     IPC::Open3 was first released with perl 5
372
373     $ corelist /MANIFEST/i
374
375     ExtUtils::Manifest was first released with perl 5.001
376
377     $ corelist /Template/
378
379     /Template/  has no match in CORE (or so I think)
380
381     $ corelist -v 5.8.8 B
382
383     B                        1.09_01
384
385     $ corelist -v 5.8.8 /^B::/
386
387     B::Asmdata               1.01
388     B::Assembler             0.07
389     B::Bblock                1.02_01
390     B::Bytecode              1.01_01
391     B::C                     1.04_01
392     B::CC                    1.00_01
393     B::Concise               0.66
394     B::Debug                 1.02_01
395     B::Deparse               0.71
396     B::Disassembler          1.05
397     B::Lint                  1.03
398     B::O                     1.00
399     B::Showlex               1.02
400     B::Stackobj              1.00
401     B::Stash                 1.00
402     B::Terse                 1.03_01
403     B::Xref                  1.01
404
405 =head1 COPYRIGHT
406
407 Copyright (c) 2002-2007 by D.H. aka PodMaster
408
409 Currently maintained by the perl 5 porters E<lt>perl5-porters@perl.orgE<gt>.
410
411 This program is distributed under the same terms as perl itself.
412 See http://perl.org/ or http://cpan.org/ for more info on that.
413
414 =cut