This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[PATCH] corelist: Provide access to info on utilities via Module::CoreList::Utils
[perl5.git] / dist / Module-CoreList / corelist
CommitLineData
aee92da2 1#!/usr/bin/perl
8f2fd531
JB
2
3=head1 NAME
4
5corelist - a commandline frontend to Module::CoreList
6
7=head1 DESCRIPTION
8
9See L<Module::CoreList> for one.
10
11=head1 SYNOPSIS
12
555bd962
BG
13 corelist -v
14 corelist [-a|-d] <ModuleName> | /<ModuleRegex>/ [<ModuleVersion>] ...
15 corelist [-v <PerlVersion>] [ <ModuleName> | /<ModuleRegex>/ ] ...
16 corelist [-r <PerlVersion>] ...
117c08bf
TS
17 corelist --utils [-d] <UtilityName> [<UtilityName>] ...
18 corelist --utils -v <PerlVersion>
555bd962
BG
19 corelist --feature <FeatureName> [<FeatureName>] ...
20 corelist --diff PerlVersion PerlVersion
21 corelist --upstream <ModuleName>
8f2fd531
JB
22
23=head1 OPTIONS
24
567f8e5b
RGS
25=over
26
6127f3cd 27=item -a
8f2fd531 28
87fbace9
RGS
29lists all versions of the given module (or the matching modules, in case you
30used a module regexp) in the perls Module::CoreList knows about.
31
4f38928e
MB
32 corelist -a Unicode
33
34 Unicode was first released with perl v5.6.2
35 v5.6.2 3.0.1
36 v5.8.0 3.2.0
37 v5.8.1 4.0.0
38 v5.8.2 4.0.0
39 v5.8.3 4.0.0
40 v5.8.4 4.0.1
41 v5.8.5 4.0.1
42 v5.8.6 4.0.1
43 v5.8.7 4.1.0
44 v5.8.8 4.1.0
45 v5.8.9 5.1.0
46 v5.9.0 4.0.0
47 v5.9.1 4.0.0
48 v5.9.2 4.0.1
49 v5.9.3 4.1.0
50 v5.9.4 4.1.0
51 v5.9.5 5.0.0
52 v5.10.0 5.0.0
53 v5.10.1 5.1.0
54 v5.11.0 5.1.0
55 v5.11.1 5.1.0
56 v5.11.2 5.1.0
57 v5.11.3 5.2.0
58 v5.11.4 5.2.0
59 v5.11.5 5.2.0
60 v5.12.0 5.2.0
61 v5.12.1 5.2.0
62 v5.12.2 5.2.0
63 v5.12.3 5.2.0
64 v5.12.4 5.2.0
65 v5.13.0 5.2.0
66 v5.13.1 5.2.0
67 v5.13.2 5.2.0
68 v5.13.3 5.2.0
69 v5.13.4 5.2.0
70 v5.13.5 5.2.0
71 v5.13.6 5.2.0
72 v5.13.7 6.0.0
73 v5.13.8 6.0.0
74 v5.13.9 6.0.0
75 v5.13.10 6.0.0
76 v5.13.11 6.0.0
77 v5.14.0 6.0.0
78 v5.14.1 6.0.0
79 v5.15.0 6.0.0
8f2fd531 80
6127f3cd
RGS
81=item -d
82
83finds the first perl version where a module has been released by
84date, and not by version number (as is the default).
85
835bc841
RS
86=item --diff
87
88Given two versions of perl, this prints a human-readable table of all module
89changes between the two. The output format may change in the future, and is
90meant for I<humans>, not programs. For programs, use the L<Module::CoreList>
91API.
92
aee92da2 93=item -? or -help
8f2fd531
JB
94
95help! help! help! to see more help, try --man.
96
567f8e5b 97=item -man
8f2fd531
JB
98
99all of the help
100
567f8e5b 101=item -v
8f2fd531
JB
102
103lists all of the perl release versions we got the CoreList for.
104
87fbace9 105If you pass a version argument (value of C<$]>, like C<5.00503> or C<5.008008>),
8f2fd531 106you get a list of all the modules and their respective versions.
87fbace9
RGS
107(If you have the C<version> module, you can also use new-style version numbers,
108like C<5.8.8>.)
8f2fd531 109
0cecb811
RGS
110In module filtering context, it can be used as Perl version filter.
111
dd413713
CBW
112=item -r
113
114lists all of the perl releases and when they were released
115
116If you pass a perl version you get the release date for that version only.
117
117c08bf
TS
118=item --utils
119
120lists the first version of perl each named utility program was released with
121
122May be used with -d to modify the first release criteria.
123
124If used with -v <version> then all utilities released with that version of perl
125are listed, and any utility programs named on the command line are ignored.
126
5f352ba2
TS
127=item --feature, -f
128
129lists the first version bundle of each named feature given
130
d8a821fe
AC
131=item --upstream, -u
132
133Shows if the given module is primarily maintained in perl core or on CPAN
134and bug tracker URL.
135
567f8e5b 136=back
8f2fd531 137
6f00ef79
RGS
138As a special case, if you specify the module name C<Unicode>, you'll get
139the version number of the Unicode Character Database bundled with the
140requested perl versions.
141
8f2fd531
JB
142=cut
143
cee96d52 144BEGIN { pop @INC if $INC[-1] eq '.' }
8f2fd531 145use Module::CoreList;
81115207 146use Getopt::Long qw(:config no_ignore_case);
8f2fd531
JB
147use Pod::Usage;
148use strict;
aee92da2 149use warnings;
10526356 150use List::Util qw/maxstr/;
8f2fd531
JB
151
152my %Opts;
153
835bc841
RS
154GetOptions(
155 \%Opts,
117c08bf 156 qw[ help|?! man! r|release:s v|version:s a! d diff|D utils feature|f u|upstream ]
835bc841 157);
8f2fd531
JB
158
159pod2usage(1) if $Opts{help};
160pod2usage(-verbose=>2) if $Opts{man};
161
dd413713
CBW
162if(exists $Opts{r} ){
163 if ( !$Opts{r} ) {
164 print "\nModule::CoreList has release info for the following perl versions:\n";
165 my $versions = { };
166 my $max_ver_len = max_mod_len(\%Module::CoreList::released);
8e036272 167 for my $ver ( grep !/0[01]0$/, sort keys %Module::CoreList::released ) {
dd413713
CBW
168 printf "%-${max_ver_len}s %s\n", format_perl_version($ver), $Module::CoreList::released{$ver};
169 }
170 print "\n";
171 exit 0;
172 }
173
174 my $num_r = numify_version( $Opts{r} );
175 my $version_hash = Module::CoreList->find_version($num_r);
176
177 if( !$version_hash ) {
178 print "\nModule::CoreList has no info on perl $Opts{r}\n\n";
179 exit 1;
180 }
181
182 printf "Perl %s was released on %s\n\n", format_perl_version($num_r), $Module::CoreList::released{$num_r};
183 exit 0;
184}
185
8f2fd531 186if(exists $Opts{v} ){
0cecb811 187 if( !$Opts{v} ) {
b69ffb0c 188 print "\nModule::CoreList has info on the following perl versions:\n";
ff0f0afd 189 print format_perl_version($_)."\n" for grep !/0[01]0$/, sort keys %Module::CoreList::version;
8f2fd531 190 print "\n";
0cecb811
RGS
191 exit 0;
192 }
193
157ebcf5 194 my $num_v = numify_version( $Opts{v} );
117c08bf
TS
195
196 if ($Opts{utils}) {
197 utilities_in_version($num_v);
198 exit 0;
199 }
200
157ebcf5
MS
201 my $version_hash = Module::CoreList->find_version($num_v);
202
6127f3cd 203 if( !$version_hash ) {
157ebcf5 204 print "\nModule::CoreList has no info on perl $Opts{v}\n\n";
0cecb811 205 exit 1;
8f2fd531 206 }
0cecb811
RGS
207
208 if ( !@ARGV ) {
157ebcf5
MS
209 print "\nThe following modules were in perl $Opts{v} CORE\n";
210 my $max_mod_len = max_mod_len($version_hash);
211 for my $mod ( sort keys %$version_hash ) {
212 printf "%-${max_mod_len}s %s\n", $mod, $version_hash->{$mod} || "";
213 }
0cecb811
RGS
214 print "\n";
215 exit 0;
216 }
217}
218
835bc841
RS
219if ($Opts{diff}) {
220 if(@ARGV != 2) {
221 die "\nprovide exactly two perl core versions to diff with --diff\n";
222 }
223
224 my ($old_ver, $new_ver) = @ARGV;
225
797ced94
RS
226 my $old = numify_version($old_ver);
227 my $new = numify_version($new_ver);
835bc841 228
797ced94 229 my %diff = Module::CoreList::changes_between($old, $new);
835bc841 230
797ced94
RS
231 for my $lib (sort keys %diff) {
232 my $diff = $diff{$lib};
835bc841 233
797ced94
RS
234 my $was = ! exists $diff->{left} ? '(absent)'
235 : ! defined $diff->{left} ? '(undef)'
236 : $diff->{left};
237
238 my $now = ! exists $diff->{right} ? '(absent)'
239 : ! defined $diff->{right} ? '(undef)'
240 : $diff->{right};
241
242 printf "%-35s %10s %10s\n", $lib, $was, $now;
835bc841
RS
243 }
244 exit(0);
245}
246
117c08bf
TS
247if ($Opts{utils}) {
248 die "\n--utils only available with perl v5.19.1 or greater\n"
249 if $] < 5.019001;
250
251 die "\nprovide at least one utility name to --utils\n"
252 unless @ARGV;
253
254 warn "\n-a has no effect when --utils is used\n" if $Opts{a};
255 warn "\n--diff has no effect when --utils is used\n" if $Opts{diff};
256 warn "\n--upstream, or -u, has no effect when --utils is used\n" if $Opts{u};
257
258 my $when = maxstr(values %Module::CoreList::released);
259 print "\n","Data for $when\n";
260
261 utility_version($_) for @ARGV;
262
263 exit(0);
264}
265
5f352ba2 266if ($Opts{feature}) {
352d600d
CBW
267 die "\n--feature is only available with perl v5.16.0 or greater\n"
268 if $] < 5.016;
81648096 269
5f352ba2
TS
270 die "\nprovide at least one feature name to --feature\n"
271 unless @ARGV;
272
273 no warnings 'once';
274 require feature;
275
276 my %feature2version;
277 my @bundles = map { $_->[0] }
278 sort { $b->[1] <=> $a->[1] }
279 map { [$_, numify_version($_)] }
280 grep { not /[^0-9.]/ }
281 keys %feature::feature_bundle;
282
283 for my $version (@bundles) {
284 $feature2version{$_} = $version =~ /^\d\.\d+$/ ? "$version.0" : $version
285 for @{ $feature::feature_bundle{$version} };
286 }
287
288 # allow internal feature names, just in case someone gives us __SUB__
289 # instead of current_sub.
290 while (my ($name, $internal) = each %feature::feature) {
291 $internal =~ s/^feature_//;
292 $feature2version{$internal} = $feature2version{$name}
293 if $feature2version{$name};
294 }
295
296 my $when = maxstr(values %Module::CoreList::released);
297 print "\n","Data for $when\n";
298
299 for my $feature (@ARGV) {
300 print "feature \"$feature\" ",
301 exists $feature2version{$feature}
302 ? "was first released with the perl "
303 . format_perl_version(numify_version($feature2version{$feature}))
304 . " feature bundle\n"
305 : "doesn't exist (or so I think)\n";
306 }
307 exit(0);
308}
309
0cecb811
RGS
310if ( !@ARGV ) {
311 pod2usage(0);
312}
313
314while (@ARGV) {
567f8e5b
RGS
315 my ($mod, $ver);
316 if ($ARGV[0] =~ /=/) {
317 ($mod, $ver) = split /=/, shift @ARGV;
318 } else {
319 $mod = shift @ARGV;
320 $ver = (@ARGV && $ARGV[0] =~ /^\d/) ? shift @ARGV : "";
321 }
18b19aec
RGS
322
323 if ($mod !~ m|^/(.*)/([imosx]*)$|) { # not a regex
324 module_version($mod,$ver);
325 } else {
326 my $re;
327 eval { $re = $2 ? qr/(?$2)($1)/ : qr/$1/; }; # trap exceptions while building regex
328 if ($@) {
329 # regex errors are usually like 'Quantifier follow nothing in regex; marked by ...'
330 # then we drop text after ';' to shorten message
331 my $errmsg = $@ =~ /(.*);/ ? $1 : $@;
332 warn "\n$mod is a bad regex: $errmsg\n";
333 next;
334 }
335 my @mod = Module::CoreList->find_modules($re);
336 if (@mod) {
337 module_version($_, $ver) for @mod;
338 } else {
339 $ver |= '';
340 print "\n$mod $ver has no match in CORE (or so I think)\n";
341 }
342
343 }
8f2fd531
JB
344}
345
346exit();
347
348sub module_version {
349 my($mod,$ver) = @_;
350
0cecb811 351 if ( $Opts{v} ) {
157ebcf5
MS
352 my $numeric_v = numify_version($Opts{v});
353 my $version_hash = Module::CoreList->find_version($numeric_v);
6127f3cd
RGS
354 if ($version_hash) {
355 print $mod, " ", $version_hash->{$mod} || 'undef', "\n";
356 return;
357 }
358 else { die "Shouldn't happen" }
0cecb811
RGS
359 }
360
6127f3cd
RGS
361 my $ret = $Opts{d}
362 ? Module::CoreList->first_release_by_date(@_)
363 : Module::CoreList->first_release(@_);
f9cff7e6
RGS
364 my $msg = $mod;
365 $msg .= " $ver" if $ver;
8f2fd531 366
044d64a8
CBW
367 my $rem = $Opts{d}
368 ? Module::CoreList->removed_from_by_date($mod)
369 : Module::CoreList->removed_from($mod);
370
10526356
AC
371 my $when = maxstr(values %Module::CoreList::released);
372 print "\n","Data for $when\n";
373
8f2fd531 374 if( defined $ret ) {
10526356 375 my $deprecated = Module::CoreList->deprecated_in($mod);
8f2fd531
JB
376 $msg .= " was ";
377 $msg .= "first " unless $ver;
044d64a8 378 $msg .= "released with perl " . format_perl_version($ret);
d8a821fe 379 $msg .= ( $rem ? ',' : ' and' ) . " deprecated (will be CPAN-only) in " . format_perl_version($deprecated) if $deprecated;
044d64a8 380 $msg .= " and removed from " . format_perl_version($rem) if $rem;
8f2fd531
JB
381 } else {
382 $msg .= " was not in CORE (or so I think)";
383 }
384
10526356 385 print $msg,"\n";
567f8e5b 386
d8a821fe 387 if( defined $ret and exists $Opts{u} ) {
88223661
TS
388 my $upstream = $Module::CoreList::upstream{$mod};
389 $upstream = 'undef' unless $upstream;
390 print "upstream: $upstream\n";
391 if ( $upstream ne 'blead' ) {
d8a821fe
AC
392 my $bugtracker = $Module::CoreList::bug_tracker{$mod};
393 $bugtracker = 'unknown' unless $bugtracker;
394 print "bug tracker: $bugtracker\n";
395 }
396 }
397
8f2fd531 398 if(defined $ret and exists $Opts{a} and $Opts{a}){
157ebcf5
MS
399 display_a($mod);
400 }
401}
402
117c08bf
TS
403sub utility_version {
404 my ($utility) = @_;
405
406 require Module::CoreList::Utils;
407
408 my $released = $Opts{d}
409 ? Module::CoreList::Utils->first_release_by_date($utility)
410 : Module::CoreList::Utils->first_release($utility);
411
412 my $removed = $Opts{d}
413 ? Module::CoreList::Utils->removed_from_by_date($utility)
414 : Module::CoreList::Utils->removed_from($utility);
415
416 if ($released) {
417 print "$utility was first released with perl ", format_perl_version($released);
418 print " and later removed in ", format_perl_version($removed)
419 if $removed;
420 print "\n";
421 } else {
422 print "$utility was not in CORE (or so I think)\n";
423 }
424}
425
426sub utilities_in_version {
427 my ($version) = @_;
428
429 require Module::CoreList::Utils;
430
431 my @utilities = Module::CoreList::Utils->utilities($version);
432
433 if (not @utilities) {
434 print "\nModule::CoreList::Utils has no info on perl $version\n\n";
435 exit 1;
436 }
437
438 print "\nThe following utilities were in perl ",
439 format_perl_version($version), " CORE\n";
440 print "$_\n" for sort { lc($a) cmp lc($b) } @utilities;
441 print "\n";
442}
443
157ebcf5
MS
444
445sub max_mod_len {
446 my $versions = shift;
447 my $max = 0;
448 for my $mod (keys %$versions) {
449 $max = max($max, length $mod);
8f2fd531 450 }
157ebcf5
MS
451
452 return $max;
453}
454
455sub max {
456 my($this, $that) = @_;
457 return $this if $this > $that;
458 return $that;
8f2fd531
JB
459}
460
157ebcf5
MS
461sub display_a {
462 my $mod = shift;
463
ff0f0afd 464 for my $v (grep !/0[01]0$/, sort keys %Module::CoreList::version ) {
157ebcf5
MS
465 next unless exists $Module::CoreList::version{$v}{$mod};
466
467 my $mod_v = $Module::CoreList::version{$v}{$mod} || 'undef';
468 printf " %-10s %-10s\n", format_perl_version($v), $mod_v;
469 }
470 print "\n";
471}
472
473
474{
475 my $have_version_pm;
476 sub have_version_pm {
477 return $have_version_pm if defined $have_version_pm;
478 return $have_version_pm = eval { require version; 1 };
479 }
480}
481
482
483sub format_perl_version {
484 my $v = shift;
485 return $v if $v < 5.006 or !have_version_pm;
486 return version->new($v)->normal;
487}
488
489
0cecb811
RGS
490sub numify_version {
491 my $ver = shift;
6127f3cd 492 if ($ver =~ /\..+\./) {
157ebcf5 493 have_version_pm()
6127f3cd 494 or die "You need to install version.pm to use dotted version numbers\n";
0cecb811
RGS
495 $ver = version->new($ver)->numify;
496 }
6127f3cd 497 $ver += 0;
0cecb811
RGS
498 return $ver;
499}
8f2fd531
JB
500
501=head1 EXAMPLES
502
503 $ corelist File::Spec
504
f9cff7e6 505 File::Spec was first released with perl 5.005
8f2fd531
JB
506
507 $ corelist File::Spec 0.83
508
509 File::Spec 0.83 was released with perl 5.007003
510
511 $ corelist File::Spec 0.89
512
513 File::Spec 0.89 was not in CORE (or so I think)
514
515 $ corelist File::Spec::Aliens
516
517 File::Spec::Aliens was not in CORE (or so I think)
518
18b19aec
RGS
519 $ corelist /IPC::Open/
520
f9cff7e6 521 IPC::Open2 was first released with perl 5
18b19aec 522
f9cff7e6 523 IPC::Open3 was first released with perl 5
18b19aec
RGS
524
525 $ corelist /MANIFEST/i
526
f9cff7e6 527 ExtUtils::Manifest was first released with perl 5.001
18b19aec
RGS
528
529 $ corelist /Template/
530
531 /Template/ has no match in CORE (or so I think)
532
0cecb811
RGS
533 $ corelist -v 5.8.8 B
534
535 B 1.09_01
536
537 $ corelist -v 5.8.8 /^B::/
538
539 B::Asmdata 1.01
540 B::Assembler 0.07
541 B::Bblock 1.02_01
542 B::Bytecode 1.01_01
543 B::C 1.04_01
544 B::CC 1.00_01
545 B::Concise 0.66
546 B::Debug 1.02_01
547 B::Deparse 0.71
548 B::Disassembler 1.05
549 B::Lint 1.03
550 B::O 1.00
551 B::Showlex 1.02
552 B::Stackobj 1.00
553 B::Stash 1.00
554 B::Terse 1.03_01
555 B::Xref 1.01
18b19aec 556
8f2fd531
JB
557=head1 COPYRIGHT
558
6f00ef79 559Copyright (c) 2002-2007 by D.H. aka PodMaster
567f8e5b 560
6f00ef79 561Currently maintained by the perl 5 porters E<lt>perl5-porters@perl.orgE<gt>.
8f2fd531
JB
562
563This program is distributed under the same terms as perl itself.
f372d768 564See http://perl.org/ or http://cpan.org/ for more info on that.
8f2fd531
JB
565
566=cut