xref: /openbsd-src/gnu/usr.bin/perl/Porting/corecpan.pl (revision 5759b3d249badf144a6240f7eec4dcf9df003e6b)
143890927Smillert#!perl
243890927Smillert# Reports, in a perl source tree, which dual-lived core modules have not the
343890927Smillert# same version than the corresponding module on CPAN.
443003dfeSmillert# with -t option, can compare multiple source trees in tabular form.
543890927Smillert
643890927Smillertuse 5.9.0;
743890927Smillertuse strict;
843890927Smillertuse Getopt::Std;
943890927Smillertuse ExtUtils::MM_Unix;
1043890927Smillertuse lib 'Porting';
1143003dfeSmillertuse Maintainers qw(get_module_files reload_manifest %Modules);
1243003dfeSmillertuse Cwd;
1343003dfeSmillert
1443003dfeSmillertuse List::Util qw(max);
1543890927Smillert
1643890927Smillertour $packagefile = '02packages.details.txt';
1743890927Smillert
1843890927Smillertsub usage () {
1943890927Smillert    die <<USAGE;
2043003dfeSmillert$0
2143003dfeSmillert$0 -t home1[:label] home2[:label] ...
2243003dfeSmillert
2343003dfeSmillertReport which core modules are outdated.
2443890927SmillertTo be run at the root of a perl source tree.
2543003dfeSmillert
2643890927SmillertOptions :
2743890927Smillert-h : help
2843890927Smillert-v : verbose (print all versions of all files, not only those which differ)
2943890927Smillert-f : force download of $packagefile from CPAN
3043890927Smillert     (it's expected to be found in the current directory)
3143003dfeSmillert-t : display in tabular form CPAN vs one or more perl source trees
3243890927SmillertUSAGE
3343890927Smillert}
3443890927Smillert
3543890927Smillertsub get_package_details () {
3643890927Smillert    my $url = 'http://www.cpan.org/modules/02packages.details.txt.gz';
3743890927Smillert    unlink $packagefile;
3843890927Smillert    system("wget $url && gunzip $packagefile.gz") == 0
3943890927Smillert	or die "Failed to get package details\n";
4043890927Smillert}
4143890927Smillert
4243003dfeSmillertgetopts('fhvt');
4343890927Smillertour $opt_h and usage;
4443003dfeSmillertour $opt_t;
4543003dfeSmillert
4643003dfeSmillertmy @sources = @ARGV ? @ARGV : '.';
47898184e3Ssthendie "Too many directories specified without -t option\n"
4843003dfeSmillert    if @sources != 1 and ! $opt_t;
4943003dfeSmillert
5043003dfeSmillert@sources = map {
5143003dfeSmillert		# handle /home/user/perl:bleed style labels
5243003dfeSmillert		my ($dir,$label) = split /:/;
5343003dfeSmillert		$label = $dir unless defined $label;
5443003dfeSmillert		[ $dir, $label ];
5543003dfeSmillert	    } @sources;
5643003dfeSmillert
57850e2753Smillertour $opt_f || !-f $packagefile and get_package_details;
5843890927Smillert
5943890927Smillert# Load the package details. All of them.
6043890927Smillertmy %cpanversions;
61*5759b3d2Safresh1open my $fh, '<', $packagefile or die $!;
6243890927Smillertwhile (<$fh>) {
6343890927Smillert    my ($p, $v) = split ' ';
6443003dfeSmillert    next if 1../^\s*$/; # skip header
6543890927Smillert    $cpanversions{$p} = $v;
6643890927Smillert}
6743890927Smillertclose $fh;
6843890927Smillert
6943003dfeSmillertmy %results;
7043003dfeSmillert
7143003dfeSmillert# scan source tree(s) and CPAN module list, and put results in %results
7243003dfeSmillert
7343003dfeSmillertforeach my $source (@sources) {
7443003dfeSmillert    my ($srcdir, $label) = @$source;
7543003dfeSmillert    my $olddir = getcwd();
7643003dfeSmillert    chdir $srcdir or die "chdir $srcdir: $!\n";
7743003dfeSmillert
7843003dfeSmillert    # load the MANIFEST file in the new directory
7943003dfeSmillert    reload_manifest;
8043003dfeSmillert
8143890927Smillert    for my $dist (sort keys %Modules) {
8243890927Smillert	next unless $Modules{$dist}{CPAN};
8343890927Smillert	for my $file (get_module_files($dist)) {
8443003dfeSmillert	    next if $file !~ /(\.pm|_pm.PL)\z/
8543003dfeSmillert			or $file =~ m{^t/} or $file =~ m{/t/};
8643003dfeSmillert	    my $vcore = '!EXIST';
8743003dfeSmillert	    $vcore = MM->parse_version($file) // 'undef' if -f $file;
8843003dfeSmillert
8943003dfeSmillert	    # get module name from filename to lookup CPAN version
9043890927Smillert	    my $module = $file;
9143003dfeSmillert	    $module =~ s/\_pm.PL\z//;
9243890927Smillert	    $module =~ s/\.pm\z//;
9343890927Smillert	    # some heuristics to figure out the module name from the file name
94b39c5158Smillert	    $module =~ s{^(lib|ext|dist|cpan)/}{}
95b39c5158Smillert		and $1 =~ /(?:ext|dist|cpan)/
9643003dfeSmillert		and (
9743003dfeSmillert		      # ext/Foo-Bar/Bar.pm
9843003dfeSmillert		      $module =~ s{^(\w+)-(\w+)/\2$}{$1/lib/$1/$2},
9943003dfeSmillert		      # ext/Encode/Foo/Foo.pm
10043003dfeSmillert		      $module =~ s{^(Encode)/(\w+)/\2$}{$1/lib/$1/$2},
10143003dfeSmillert		      $module =~ s{^[^/]+/}{},
10243003dfeSmillert		      $module =~ s{^lib/}{},
10343890927Smillert		    );
10443890927Smillert	    $module =~ s{/}{::}g;
10543003dfeSmillert	    my $vcpan = $cpanversions{$module} // 'undef';
10643003dfeSmillert	    $results{$dist}{$file}{$label} = $vcore;
10743003dfeSmillert	    $results{$dist}{$file}{CPAN} = $vcpan;
10843003dfeSmillert	}
10943003dfeSmillert    }
11043003dfeSmillert
11143003dfeSmillert    chdir $olddir or die "chdir $olddir: $!\n";
11243003dfeSmillert}
11343003dfeSmillert
11443003dfeSmillert# output %results in the requested format
11543003dfeSmillert
11643003dfeSmillertmy @labels = ((map $_->[1], @sources), 'CPAN' );
11743003dfeSmillert
11843003dfeSmillertif ($opt_t) {
11943003dfeSmillert    my %changed;
12043003dfeSmillert    my @fields;
12143003dfeSmillert    for my $dist (sort { lc $a cmp lc $b } keys %results) {
12243003dfeSmillert	for my $file (sort keys %{$results{$dist}}) {
12343003dfeSmillert	    my @versions = @{$results{$dist}{$file}}{@labels};
12443003dfeSmillert	    for (0..$#versions) {
12543003dfeSmillert		$fields[$_] = max($fields[$_],
12643003dfeSmillert				  length $versions[$_],
12743003dfeSmillert				  length $labels[$_],
12843003dfeSmillert				  length '!EXIST'
12943003dfeSmillert				);
13043003dfeSmillert	    }
13143003dfeSmillert	    if (our $opt_v or grep $_ ne $versions[0], @versions) {
13243003dfeSmillert		$changed{$dist} = 1;
13343003dfeSmillert	    }
13443003dfeSmillert	}
13543003dfeSmillert    }
13643003dfeSmillert    printf "%*s ", $fields[$_], $labels[$_] for 0..$#labels;
13743003dfeSmillert    print "\n";
13843003dfeSmillert    printf "%*s ", $fields[$_], '-' x length $labels[$_] for 0..$#labels;
13943003dfeSmillert    print "\n";
14043003dfeSmillert
14143003dfeSmillert    my $field_total;
14243003dfeSmillert    $field_total += $_ + 1 for @fields;
14343003dfeSmillert
14443003dfeSmillert    for my $dist (sort { lc $a cmp lc $b } keys %results) {
14543003dfeSmillert	next unless $changed{$dist};
14643003dfeSmillert	print " " x $field_total, " $dist\n";
14743003dfeSmillert	for my $file (sort keys %{$results{$dist}}) {
14843003dfeSmillert	    my @versions = @{$results{$dist}{$file}}{@labels};
14943003dfeSmillert	    for (0..$#versions) {
15043003dfeSmillert		printf "%*s ", $fields[$_], $versions[$_]//'!EXIST'
15143003dfeSmillert	    }
15243003dfeSmillert	    print "    $file\n";
15343003dfeSmillert	}
15443003dfeSmillert    }
15543003dfeSmillert}
15643003dfeSmillertelse {
15743003dfeSmillert    for my $dist (sort { lc $a cmp lc $b } keys %results) {
158b39c5158Smillert	my $distname_printed = 0;
15943003dfeSmillert	for my $file (sort keys %{$results{$dist}}) {
16043003dfeSmillert	    my ($vcore, $vcpan) = @{$results{$dist}{$file}}{@labels};
16143890927Smillert	    if (our $opt_v or $vcore ne $vcpan) {
162898184e3Ssthen		print "\n$dist ($Modules{$dist}{MAINTAINER}):\n" unless ($distname_printed++);
163b39c5158Smillert		print "\t$file: core=$vcore, cpan=$vcpan\n";
16443890927Smillert	    }
16543890927Smillert	}
16643890927Smillert    }
16743003dfeSmillert}
168