| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Perl5::Dist::Backcompat; | 
| 2 | 1 |  |  | 1 |  | 106512 | use 5.14.0; | 
|  | 1 |  |  |  |  | 5 |  | 
| 3 | 1 |  |  | 1 |  | 7 | use warnings; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 60 |  | 
| 4 |  |  |  |  |  |  | our $VERSION = '0.04'; | 
| 5 | 1 |  |  | 1 |  | 2921 | use Archive::Tar; | 
|  | 1 |  |  |  |  | 133332 |  | 
|  | 1 |  |  |  |  | 108 |  | 
| 6 | 1 |  |  | 1 |  | 13 | use Carp qw( carp croak ); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 59 |  | 
| 7 | 1 |  |  | 1 |  | 6 | use Cwd qw( cwd ); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 46 |  | 
| 8 | 1 |  |  | 1 |  | 695 | use File::Copy qw( copy move ); | 
|  | 1 |  |  |  |  | 6220 |  | 
|  | 1 |  |  |  |  | 113 |  | 
| 9 | 1 |  |  | 1 |  | 10 | use File::Find qw( find ); | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 77 |  | 
| 10 | 1 |  |  | 1 |  | 8 | use File::Spec; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 24 |  | 
| 11 | 1 |  |  | 1 |  | 1824 | use File::Temp qw( tempdir ); | 
|  | 1 |  |  |  |  | 13144 |  | 
|  | 1 |  |  |  |  | 75 |  | 
| 12 |  |  |  |  |  |  | # From CPAN | 
| 13 | 1 |  |  | 1 |  | 1343 | use CPAN::DistnameInfo; | 
|  | 1 |  |  |  |  | 1077 |  | 
|  | 1 |  |  |  |  | 48 |  | 
| 14 | 1 |  |  | 1 |  | 550 | use Data::Dump qw( dd pp ); | 
|  | 1 |  |  |  |  | 5915 |  | 
|  | 1 |  |  |  |  | 125 |  | 
| 15 | 1 |  |  | 1 |  | 751 | use File::Copy::Recursive::Reduced qw( dircopy ); | 
|  | 1 |  |  |  |  | 2110 |  | 
|  | 1 |  |  |  |  | 5079 |  | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | =head1 NAME | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | Perl5::Dist::Backcompat - Analyze F distributions for CPAN release viability | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | my $params = { | 
| 24 |  |  |  |  |  |  | perl_workdir => '/path/to/git/checkout/of/perl', | 
| 25 |  |  |  |  |  |  | verbose => 1, | 
| 26 |  |  |  |  |  |  | }; | 
| 27 |  |  |  |  |  |  | my $self = Perl5::Dist::Backcompat->new( $params ); | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | This module serves as the backend for the program F which | 
| 32 |  |  |  |  |  |  | is also part of the F distribution.  This document's | 
| 33 |  |  |  |  |  |  | focus is on documenting the methods used publicly in that program as well as | 
| 34 |  |  |  |  |  |  | internal methods and subroutines called by those public methods.  For | 
| 35 |  |  |  |  |  |  | discussion on the problem which this distribution tries to solve, and how well | 
| 36 |  |  |  |  |  |  | it currently does that or not, please (i) read the plain-text F in the | 
| 37 |  |  |  |  |  |  | CPAN distribution or the F in the L | 
| 38 |  |  |  |  |  |  | repository|https://github.com/jkeenan/p5-dist-backcompat>; and (ii) read the | 
| 39 |  |  |  |  |  |  | front-end program's documentation via F. | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | =head1 PREREQUISITES | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | F 5.14.0 or newer, with the following modules installed from CPAN: | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | =over 4 | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | =item * F | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | =item * F | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | =item * F | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | =back | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | =head1 PUBLIC METHODS | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | =head2 C | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | =over 4 | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | =item * Purpose | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | Perl5::Dist::Backcompat constructor. | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | =item * Arguments | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | my $self = Perl5::Dist::Backcompat->new( $params ); | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | Single hash reference. | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | =item * Return Value | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | Perl5::Dist::Backcompat object. | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | =back | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | =cut | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | sub new { | 
| 80 | 0 |  |  | 0 | 1 |  | my ($class, $params) = @_; | 
| 81 | 0 | 0 | 0 |  |  |  | if (defined $params and ref($params) ne 'HASH') { | 
| 82 | 0 |  |  |  |  |  | croak "Argument supplied to constructor must be hashref"; | 
| 83 |  |  |  |  |  |  | } | 
| 84 | 0 |  |  |  |  |  | my %valid_params = map {$_ => 1} qw( | 
|  | 0 |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | verbose | 
| 86 |  |  |  |  |  |  | host | 
| 87 |  |  |  |  |  |  | path_to_perls | 
| 88 |  |  |  |  |  |  | perl_workdir | 
| 89 |  |  |  |  |  |  | tarball_dir | 
| 90 |  |  |  |  |  |  | ); | 
| 91 | 0 |  |  |  |  |  | my @invalid_params = (); | 
| 92 | 0 |  |  |  |  |  | for my $p (keys %$params) { | 
| 93 | 0 | 0 |  |  |  |  | push @invalid_params, $p unless $valid_params{$p}; | 
| 94 |  |  |  |  |  |  | } | 
| 95 | 0 | 0 |  |  |  |  | if (@invalid_params) { | 
| 96 | 0 |  |  |  |  |  | my $msg = "Constructor parameter(s) @invalid_params not valid"; | 
| 97 | 0 |  |  |  |  |  | croak $msg; | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  | croak "Must supply value for 'perl_workdir'" | 
| 100 | 0 | 0 |  |  |  |  | unless $params->{perl_workdir}; | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 0 |  |  |  |  |  | my $data = {}; | 
| 103 | 0 |  |  |  |  |  | for my $p (keys %valid_params) { | 
| 104 | 0 | 0 |  |  |  |  | $data->{$p} = (defined $params->{$p}) ? $params->{$p} : ''; | 
| 105 |  |  |  |  |  |  | } | 
| 106 | 0 |  | 0 |  |  |  | $data->{host} ||= 'dromedary.p5h.org'; | 
| 107 | 0 |  | 0 |  |  |  | $data->{path_to_perls} ||= '/media/Tux/perls-t/bin'; | 
| 108 | 0 |  | 0 |  |  |  | $data->{tarball_dir} ||= "$ENV{P5P_DIR}/dist-backcompat/tarballs"; | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | croak "Could not locate directory $data->{path_to_perls} for perl executables" | 
| 111 | 0 | 0 |  |  |  |  | unless -d $data->{path_to_perls}; | 
| 112 |  |  |  |  |  |  | croak "Could not locate directory $data->{tarball_dir} for downloaded tarballs" | 
| 113 | 0 | 0 |  |  |  |  | unless -d $data->{tarball_dir}; | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 0 |  |  |  |  |  | return bless $data, $class; | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | =head2 C | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | =over 4 | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | =item * Purpose | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | Guarantee that we can find the F executables we'll be using; the F | 
| 125 |  |  |  |  |  |  | checkout of the core distribution; metadata files and loading of data | 
| 126 |  |  |  |  |  |  | therefrom. | 
| 127 |  |  |  |  |  |  |  | 
| 128 |  |  |  |  |  |  | =item * Arguments | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | $self->init(); | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | None; all data needed is found within the object. | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | =item * Return Value | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | Returns the object itself. | 
| 137 |  |  |  |  |  |  |  | 
| 138 |  |  |  |  |  |  | =back | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | =cut | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | sub init { | 
| 143 |  |  |  |  |  |  | # From here on, we assume we're starting from the home directory of | 
| 144 |  |  |  |  |  |  | # someone with an account on Dromedary. | 
| 145 |  |  |  |  |  |  |  | 
| 146 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 147 |  |  |  |  |  |  |  | 
| 148 | 0 |  |  |  |  |  | my $currdir = cwd(); | 
| 149 |  |  |  |  |  |  | chdir $self->{perl_workdir} | 
| 150 | 0 | 0 |  |  |  |  | or croak "Unable to change to $self->{perl_workdir}"; | 
| 151 |  |  |  |  |  |  |  | 
| 152 | 0 |  |  |  |  |  | my $describe = `git describe`; | 
| 153 | 0 |  |  |  |  |  | chomp($describe); | 
| 154 | 0 | 0 |  |  |  |  | croak "Unable to get value for 'git describe'" | 
| 155 |  |  |  |  |  |  | unless $describe; | 
| 156 | 0 |  |  |  |  |  | $self->{describe} = $describe; | 
| 157 | 0 | 0 |  |  |  |  | chdir $currdir or croak "Unable to change back to starting directory"; | 
| 158 |  |  |  |  |  |  |  | 
| 159 | 0 |  |  |  |  |  | my $manifest = File::Spec->catfile($self->{perl_workdir}, 'MANIFEST'); | 
| 160 | 0 | 0 |  |  |  |  | croak "Could not locate $manifest" unless -f $manifest; | 
| 161 | 0 |  |  |  |  |  | $self->{manifest} = $manifest; | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 0 |  |  |  |  |  | my $maint_file = File::Spec->catfile($self->{perl_workdir}, 'Porting', 'Maintainers.pl'); | 
| 164 | 0 |  |  |  |  |  | require $maint_file;   # to get %Modules in package Maintainers | 
| 165 | 0 |  |  |  |  |  | $self->{maint_file} = $maint_file; | 
| 166 |  |  |  |  |  |  |  | 
| 167 | 0 |  |  |  |  |  | my $manilib_file = File::Spec->catfile($self->{perl_workdir}, 'Porting', 'manifest_lib.pl'); | 
| 168 | 0 |  |  |  |  |  | require $manilib_file; # to get function sort_manifest() | 
| 169 | 0 |  |  |  |  |  | $self->{manilib_file} = $manilib_file; | 
| 170 |  |  |  |  |  |  |  | 
| 171 | 0 |  |  |  |  |  | my %distmodules = (); | 
| 172 | 0 |  |  |  |  |  | for my $m (keys %Maintainers::Modules) { | 
| 173 | 0 | 0 |  |  |  |  | if ($Maintainers::Modules{$m}{FILES} =~ m{dist/}) { | 
| 174 | 0 |  |  |  |  |  | $distmodules{$m} = $Maintainers::Modules{$m}; | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  | } | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | # Sanity checks; all modules under dist/ should be blead-upstream and have P5P | 
| 179 |  |  |  |  |  |  | # as maintainer. | 
| 180 | 0 |  |  |  |  |  | _sanity_check(\%distmodules, $self->{describe}, $self->{verbose}); | 
| 181 | 0 |  |  |  |  |  | $self->{distmodules} = \%distmodules; | 
| 182 |  |  |  |  |  |  |  | 
| 183 | 0 |  |  |  |  |  | my $metadata_file = File::Spec->catfile( | 
| 184 |  |  |  |  |  |  | '.', 'etc', 'dist-backcompat-distro-metadata.txt'); | 
| 185 | 0 | 0 |  |  |  |  | croak "Could not locate $metadata_file" unless -f $metadata_file; | 
| 186 | 0 |  |  |  |  |  | $self->{metadata_file} = $metadata_file; | 
| 187 |  |  |  |  |  |  |  | 
| 188 | 0 |  |  |  |  |  | my %distro_metadata = (); | 
| 189 |  |  |  |  |  |  |  | 
| 190 | 0 | 0 |  |  |  |  | open my $IN, '<', $metadata_file or croak "Unable to open $metadata_file for reading"; | 
| 191 | 0 |  |  |  |  |  | while (my $l = <$IN>) { | 
| 192 | 0 |  |  |  |  |  | chomp $l; | 
| 193 | 0 | 0 |  |  |  |  | next if $l =~ m{^(\#|\s*$)}; | 
| 194 | 0 |  |  |  |  |  | my @rowdata = split /\|/, $l; | 
| 195 |  |  |  |  |  |  | # Refine this later | 
| 196 | 0 |  | 0 |  |  |  | $distro_metadata{$rowdata[0]} = { | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 197 |  |  |  |  |  |  | minimum_perl_version => $rowdata[1] // '', | 
| 198 |  |  |  |  |  |  | needs_threaded_perl  => $rowdata[2] // '', | 
| 199 |  |  |  |  |  |  | needs_ppport_h       => $rowdata[3] // '', | 
| 200 |  |  |  |  |  |  | needs_threads_h      => $rowdata[4] // '', | 
| 201 |  |  |  |  |  |  | needs_shared_h       => $rowdata[5] // '', | 
| 202 |  |  |  |  |  |  |  | 
| 203 |  |  |  |  |  |  | }; | 
| 204 |  |  |  |  |  |  | } | 
| 205 | 0 | 0 |  |  |  |  | close $IN or die "Unable to close $metadata_file after reading: $!"; | 
| 206 |  |  |  |  |  |  |  | 
| 207 | 0 |  |  |  |  |  | my $this = $self->identify_cpan_tarballs_with_makefile_pl(); | 
| 208 | 0 |  |  |  |  |  | for my $d (keys %{$this}) { | 
|  | 0 |  |  |  |  |  |  | 
| 209 | 0 |  |  |  |  |  | $distro_metadata{$d}{tarball}   = $this->{$d}->{tarball}; | 
| 210 | 0 |  |  |  |  |  | $distro_metadata{$d}{distvname} = $this->{$d}->{distvname}; | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  |  | 
| 213 | 0 |  |  |  |  |  | $self->{distro_metadata} = \%distro_metadata; | 
| 214 |  |  |  |  |  |  |  | 
| 215 | 0 |  |  |  |  |  | my $older_perls_file = File::Spec->catfile( | 
| 216 |  |  |  |  |  |  | '.', 'etc', 'dist-backcompat-older-perls.txt'); | 
| 217 | 0 | 0 |  |  |  |  | croak "Could not locate $older_perls_file" unless -f $older_perls_file; | 
| 218 | 0 |  |  |  |  |  | $self->{older_perls_file} = $older_perls_file; | 
| 219 |  |  |  |  |  |  |  | 
| 220 | 0 |  |  |  |  |  | return $self; | 
| 221 |  |  |  |  |  |  | } | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | =head2 C | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | =over 4 | 
| 226 |  |  |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | =item * Purpose | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | Categorize each F distro in one of 4 categories based on the status and | 
| 230 |  |  |  |  |  |  | appropriateness of its F (if any). | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | =item * Arguments | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | $self->categorize_distros(); | 
| 235 |  |  |  |  |  |  |  | 
| 236 |  |  |  |  |  |  | None; all data needed is already within the object. | 
| 237 |  |  |  |  |  |  |  | 
| 238 |  |  |  |  |  |  | =item * Return Value | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | Returns the object. | 
| 241 |  |  |  |  |  |  |  | 
| 242 |  |  |  |  |  |  | =item * Comment | 
| 243 |  |  |  |  |  |  |  | 
| 244 |  |  |  |  |  |  | Since our objective is to determine the CPAN release viability of code found | 
| 245 |  |  |  |  |  |  | within F distros in core, we need various ways to categorize those | 
| 246 |  |  |  |  |  |  | distros.  This method will make a categorization based on the status of the | 
| 247 |  |  |  |  |  |  | distros's F.  The categories will be mutually exclusive. By order | 
| 248 |  |  |  |  |  |  | of processing the categories will be: | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | =item * | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | B As based on an examination of C<%Maintainers::Modules> in | 
| 253 |  |  |  |  |  |  | F, at least one distro has no current CPAN release. | 
| 254 |  |  |  |  |  |  | Such modules will be categorized as C. | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | =item * | 
| 257 |  |  |  |  |  |  |  | 
| 258 |  |  |  |  |  |  | B Certain F distros have a CPAN release which contains a F. | 
| 259 |  |  |  |  |  |  | Such distros I also have a F in core; that F | 
| 260 |  |  |  |  |  |  | may or may not be functionally identical to that on CPAN.  In either case, we | 
| 261 |  |  |  |  |  |  | shall make an assumption that the F found in the most recent CPAN | 
| 262 |  |  |  |  |  |  | release is the version to be preferred for the purpose of this program.  Such | 
| 263 |  |  |  |  |  |  | distros will be categorized as C. | 
| 264 |  |  |  |  |  |  |  | 
| 265 |  |  |  |  |  |  | B The following 3 categories should be considered I because, | 
| 266 |  |  |  |  |  |  | as the code in this methods is currently structured, all current F | 
| 267 |  |  |  |  |  |  | distros are categorized as either C or C.  These categories | 
| 268 |  |  |  |  |  |  | may be removed in a future release. | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | =over 4 | 
| 271 |  |  |  |  |  |  |  | 
| 272 |  |  |  |  |  |  | =item * | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | B Certain F distros have a F in core.  Assuming that such a | 
| 275 |  |  |  |  |  |  | distro has not already been categorized as C, we will use that version | 
| 276 |  |  |  |  |  |  | in this program.  Such distros will be categorized as C. | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | =item * | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | B If a F distro has no F either on CPAN or in core but, at | 
| 281 |  |  |  |  |  |  | the end of F in the Perl 5 build process does have a F | 
| 282 |  |  |  |  |  |  | generated by that process, we will categorize such a distro as C. | 
| 283 |  |  |  |  |  |  |  | 
| 284 |  |  |  |  |  |  | =item * | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | B The remaining F distros have a F neither on CPAN nor in | 
| 287 |  |  |  |  |  |  | core.  For purpose of compilation in core they I have a F | 
| 288 |  |  |  |  |  |  | generated by core's F process, but this file, if created, does | 
| 289 |  |  |  |  |  |  | not appear to be retained on disk at the end of F.  Such a distro might | 
| 290 |  |  |  |  |  |  | lack a F in its CPAN release because the CPAN releasor uses | 
| 291 |  |  |  |  |  |  | technology such as F to produce such a release and such | 
| 292 |  |  |  |  |  |  | technology does not require a F to be included in the CPAN | 
| 293 |  |  |  |  |  |  | tarball.  At the present time we will categorize such distros as C and | 
| 294 |  |  |  |  |  |  | these will be skipped by subsequent methods. | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | =back | 
| 297 |  |  |  |  |  |  |  | 
| 298 |  |  |  |  |  |  | =back | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | =cut | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  | sub categorize_distros { | 
| 303 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 304 | 0 |  |  |  |  |  | my %makefile_pl_status = (); | 
| 305 |  |  |  |  |  |  |  | 
| 306 |  |  |  |  |  |  | # First, identify those dist/ distros which, on the basis of data in | 
| 307 |  |  |  |  |  |  | # Porting/Maintainers.PL, do not currently have CPAN releases. | 
| 308 |  |  |  |  |  |  |  | 
| 309 | 0 |  |  |  |  |  | for my $m (keys %{$self->{distmodules}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 310 | 0 | 0 |  |  |  |  | if (! exists $self->{distmodules}->{$m}{DISTRIBUTION}) { | 
| 311 | 0 |  |  |  |  |  | my ($distname) = $self->{distmodules}->{$m}{FILES} =~ m{^dist/(.*)/?$}; | 
| 312 | 0 |  |  |  |  |  | $makefile_pl_status{$distname} = 'unreleased'; | 
| 313 |  |  |  |  |  |  | } | 
| 314 |  |  |  |  |  |  | } | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | # Second, identify those dist/ distros which have their own hard-coded | 
| 317 |  |  |  |  |  |  | # Makefile.PLs in their CPAN releases.  We'll call these 'cpan'.  (We've | 
| 318 |  |  |  |  |  |  | # already done some of the work for this in | 
| 319 |  |  |  |  |  |  | # $self->identify_cpan_tarballs_with_makefile_pl() called from within | 
| 320 |  |  |  |  |  |  | # init().  The location of a distro's tarball is given by: | 
| 321 |  |  |  |  |  |  | # $self->{distro_metadata}->{$d}->{tarball}.) | 
| 322 |  |  |  |  |  |  |  | 
| 323 | 0 |  |  |  |  |  | for my $d (keys %{$self->{distro_metadata}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 324 | 0 | 0 |  |  |  |  | if (! $makefile_pl_status{$d}) { | 
| 325 | 0 |  |  |  |  |  | my $tb = $self->{distro_metadata}->{$d}->{tarball}; | 
| 326 | 0 |  |  |  |  |  | my ($tar, $hasmpl); | 
| 327 | 0 |  |  |  |  |  | $tar = Archive::Tar->new($tb); | 
| 328 | 0 | 0 |  |  |  |  | croak "Unable to create Archive::Tar object for $d" unless defined $tar; | 
| 329 | 0 |  |  |  |  |  | $self->{distro_metadata}->{$d}->{tar} = $tar; | 
| 330 |  |  |  |  |  |  | $hasmpl = $self->{distro_metadata}->{$d}->{tar}->contains_file( | 
| 331 | 0 |  |  |  |  |  | File::Spec->catfile($self->{distro_metadata}->{$d}->{distvname},'Makefile.PL') | 
| 332 |  |  |  |  |  |  | ); | 
| 333 | 0 | 0 |  |  |  |  | if ($hasmpl) { | 
| 334 | 0 |  |  |  |  |  | $makefile_pl_status{$d} = 'cpan'; | 
| 335 |  |  |  |  |  |  | } | 
| 336 |  |  |  |  |  |  | else { | 
| 337 | 0 | 0 |  |  |  |  | carp "$d Makefile.PL doubtful" unless $hasmpl; | 
| 338 |  |  |  |  |  |  | } | 
| 339 |  |  |  |  |  |  | } | 
| 340 |  |  |  |  |  |  | } | 
| 341 |  |  |  |  |  |  |  | 
| 342 |  |  |  |  |  |  | # Third, identify those dist/ distros which have their own hard-coded | 
| 343 |  |  |  |  |  |  | # Makefile.PLs in the core distribution.  We'll call these 'native'. | 
| 344 |  |  |  |  |  |  |  | 
| 345 | 0 |  |  |  |  |  | my @sorted = read_manifest($self->{manifest}); | 
| 346 |  |  |  |  |  |  |  | 
| 347 | 0 |  |  |  |  |  | for my $f (@sorted) { | 
| 348 | 0 | 0 |  |  |  |  | next unless $f =~ m{^dist/}; | 
| 349 | 0 |  |  |  |  |  | my $path = (split /\t+/, $f)[0]; | 
| 350 | 0 | 0 |  |  |  |  | if ($path =~ m{/(.*?)/Makefile\.PL$}) { | 
| 351 | 0 |  |  |  |  |  | my $distro = $1; | 
| 352 |  |  |  |  |  |  | $makefile_pl_status{$distro} = 'native' | 
| 353 | 0 | 0 |  |  |  |  | unless $makefile_pl_status{$distro}; | 
| 354 |  |  |  |  |  |  | } | 
| 355 |  |  |  |  |  |  | } | 
| 356 |  |  |  |  |  |  |  | 
| 357 |  |  |  |  |  |  | # Fourth, identify those dist/ distros whose Makefile.PL is generated during | 
| 358 |  |  |  |  |  |  | # Perl's own 'make' process. | 
| 359 |  |  |  |  |  |  |  | 
| 360 |  |  |  |  |  |  | my $get_generated_makefiles = sub { | 
| 361 | 0 |  |  | 0 |  |  | my $pattern = qr{dist/(.*?)/Makefile\.PL$}; | 
| 362 | 0 | 0 |  |  |  |  | if ( $File::Find::name =~ m{$pattern} ) { | 
| 363 | 0 |  |  |  |  |  | my $distro = $1; | 
| 364 | 0 | 0 |  |  |  |  | if (! $makefile_pl_status{$distro}) { | 
| 365 | 0 |  |  |  |  |  | $makefile_pl_status{$distro} = 'generated'; | 
| 366 |  |  |  |  |  |  | } | 
| 367 |  |  |  |  |  |  | } | 
| 368 | 0 |  |  |  |  |  | }; | 
| 369 |  |  |  |  |  |  | find( | 
| 370 | 0 |  |  |  |  |  | \&{$get_generated_makefiles}, | 
| 371 | 0 |  |  |  |  |  | File::Spec->catdir($self->{perl_workdir}, 'dist' ) | 
| 372 |  |  |  |  |  |  | ); | 
| 373 |  |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  | # Fifth, identify those dist/ distros whose Makefile.PLs are not yet | 
| 375 |  |  |  |  |  |  | # accounted for. | 
| 376 |  |  |  |  |  |  |  | 
| 377 | 0 |  |  |  |  |  | for my $d (sort keys %{$self->{distmodules}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 378 | 0 | 0 |  |  |  |  | next unless exists $self->{distmodules}->{$d}{FILES}; | 
| 379 | 0 |  |  |  |  |  | my ($distname) = $self->{distmodules}->{$d}{FILES} =~ m{^dist/([^/]+)/?$}; | 
| 380 | 0 | 0 |  |  |  |  | if (! exists $makefile_pl_status{$distname}) { | 
| 381 | 0 |  |  |  |  |  | $makefile_pl_status{$distname} = 'tbd'; | 
| 382 |  |  |  |  |  |  | } | 
| 383 |  |  |  |  |  |  | } | 
| 384 |  |  |  |  |  |  |  | 
| 385 | 0 |  |  |  |  |  | $self->{makefile_pl_status} = \%makefile_pl_status; | 
| 386 | 0 |  |  |  |  |  | return $self; | 
| 387 |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  |  | 
| 389 |  |  |  |  |  |  | =head2 C | 
| 390 |  |  |  |  |  |  |  | 
| 391 |  |  |  |  |  |  | =over 4 | 
| 392 |  |  |  |  |  |  |  | 
| 393 |  |  |  |  |  |  | =item * Purpose | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | Display a chart listing F distros in one column and the status of their | 
| 396 |  |  |  |  |  |  | respective Fs in the second column. | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | =item * Arguments | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | $self->show_makefile_pl_status(); | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | None; this method simply displays data already present in the object. | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | =item * Return Value | 
| 405 |  |  |  |  |  |  |  | 
| 406 |  |  |  |  |  |  | Returns a true value when complete. | 
| 407 |  |  |  |  |  |  |  | 
| 408 |  |  |  |  |  |  | =item * Comment | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | Does nothing unless a true value for C was passed to C. | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  |  |  |  | =back | 
| 413 |  |  |  |  |  |  |  | 
| 414 |  |  |  |  |  |  | =cut | 
| 415 |  |  |  |  |  |  |  | 
| 416 |  |  |  |  |  |  | sub show_makefile_pl_status { | 
| 417 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 418 | 0 |  |  |  |  |  | my %counts; | 
| 419 | 0 |  |  |  |  |  | for my $module (sort keys %{$self->{makefile_pl_status}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 420 | 0 |  |  |  |  |  | $counts{$self->{makefile_pl_status}->{$module}}++; | 
| 421 |  |  |  |  |  |  | } | 
| 422 | 0 | 0 |  |  |  |  | if ($self->{verbose}) { | 
| 423 | 0 |  |  |  |  |  | for my $k (sort keys %counts) { | 
| 424 | 0 |  |  |  |  |  | printf "  %-18s%4s\n" => ($k, $counts{$k}); | 
| 425 |  |  |  |  |  |  | } | 
| 426 | 0 |  |  |  |  |  | say ''; | 
| 427 | 0 |  |  |  |  |  | printf "%-24s%-12s\n" => ('Distribution', 'Status'); | 
| 428 | 0 |  |  |  |  |  | printf "%-24s%-12s\n" => ('------------', '------'); | 
| 429 | 0 |  |  |  |  |  | for my $module (sort keys %{$self->{makefile_pl_status}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 430 | 0 |  |  |  |  |  | printf "%-24s%-12s\n" => ($module, $self->{makefile_pl_status}->{$module}); | 
| 431 |  |  |  |  |  |  | } | 
| 432 |  |  |  |  |  |  | } | 
| 433 | 0 |  |  |  |  |  | return 1; | 
| 434 |  |  |  |  |  |  | } | 
| 435 |  |  |  |  |  |  |  | 
| 436 |  |  |  |  |  |  | =head2 C | 
| 437 |  |  |  |  |  |  |  | 
| 438 |  |  |  |  |  |  | =over 4 | 
| 439 |  |  |  |  |  |  |  | 
| 440 |  |  |  |  |  |  | =item * Purpose | 
| 441 |  |  |  |  |  |  |  | 
| 442 |  |  |  |  |  |  | Assemble the list of F distros which the program will actually test | 
| 443 |  |  |  |  |  |  | against older Fs. | 
| 444 |  |  |  |  |  |  |  | 
| 445 |  |  |  |  |  |  | =item * Arguments | 
| 446 |  |  |  |  |  |  |  | 
| 447 |  |  |  |  |  |  | my @distros_for_testing = $self->get_distros_for_testing( [ @distros_requested ] ); | 
| 448 |  |  |  |  |  |  |  | 
| 449 |  |  |  |  |  |  | Single arrayref, optional (though recommended).  If no arrayref is provided, | 
| 450 |  |  |  |  |  |  | then the program will test I F distros I those whose | 
| 451 |  |  |  |  |  |  | "Makefile.PL status" is C. | 
| 452 |  |  |  |  |  |  |  | 
| 453 |  |  |  |  |  |  | =item * Return Value | 
| 454 |  |  |  |  |  |  |  | 
| 455 |  |  |  |  |  |  | List holding distros to be tested.  (This is provided for readability of the | 
| 456 |  |  |  |  |  |  | code, but the list will be stored within the object and subsequently | 
| 457 |  |  |  |  |  |  | referenced therefrom. | 
| 458 |  |  |  |  |  |  |  | 
| 459 |  |  |  |  |  |  | =item * Comment | 
| 460 |  |  |  |  |  |  |  | 
| 461 |  |  |  |  |  |  | In a production program, the list of distros selected for testing may be | 
| 462 |  |  |  |  |  |  | provided on the command-line and processed by C | 
| 463 |  |  |  |  |  |  | within that program.  But it's only at this point that we need to add such a | 
| 464 |  |  |  |  |  |  | list to the object. | 
| 465 |  |  |  |  |  |  |  | 
| 466 |  |  |  |  |  |  | =back | 
| 467 |  |  |  |  |  |  |  | 
| 468 |  |  |  |  |  |  | =cut | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | sub get_distros_for_testing { | 
| 471 | 0 |  |  | 0 | 1 |  | my ($self, $distros) = @_; | 
| 472 | 0 | 0 |  |  |  |  | if (defined $distros) { | 
| 473 | 0 | 0 |  |  |  |  | croak "Argument passed to get_distros_for_testing() must be arrayref" | 
| 474 |  |  |  |  |  |  | unless ref($distros) eq 'ARRAY'; | 
| 475 |  |  |  |  |  |  | } | 
| 476 |  |  |  |  |  |  | else { | 
| 477 | 0 |  |  |  |  |  | $distros = []; | 
| 478 |  |  |  |  |  |  | } | 
| 479 | 0 |  |  |  |  |  | my @distros_for_testing = (scalar @{$distros}) | 
| 480 | 0 |  |  |  |  |  | ? @{$distros} | 
| 481 | 0 |  |  |  |  |  | : sort grep { $self->{makefile_pl_status}->{$_} ne 'unreleased' } | 
| 482 | 0 | 0 |  |  |  |  | keys %{$self->{makefile_pl_status}}; | 
|  | 0 |  |  |  |  |  |  | 
| 483 | 0 | 0 |  |  |  |  | if ($self->{verbose}) { | 
| 484 | 0 |  |  |  |  |  | say "\nWill test ", scalar @distros_for_testing, | 
| 485 |  |  |  |  |  |  | " distros which have been presumably released to CPAN:"; | 
| 486 | 0 |  |  |  |  |  | say "  $_" for @distros_for_testing; | 
| 487 |  |  |  |  |  |  | } | 
| 488 | 0 |  |  |  |  |  | $self->{distros_for_testing} = [ @distros_for_testing ]; | 
| 489 | 0 |  |  |  |  |  | return @distros_for_testing; | 
| 490 |  |  |  |  |  |  | } | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | =head2 C | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | =over 4 | 
| 495 |  |  |  |  |  |  |  | 
| 496 |  |  |  |  |  |  | =item * Purpose | 
| 497 |  |  |  |  |  |  |  | 
| 498 |  |  |  |  |  |  | Validate the paths and executability of the older perl versions against which | 
| 499 |  |  |  |  |  |  | we're going to test F distros. | 
| 500 |  |  |  |  |  |  |  | 
| 501 |  |  |  |  |  |  | =item * Arguments | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | my @perls = $self->validate_older_perls(); | 
| 504 |  |  |  |  |  |  |  | 
| 505 |  |  |  |  |  |  | None; all necessary information is found within the object. | 
| 506 |  |  |  |  |  |  |  | 
| 507 |  |  |  |  |  |  | =item * Return Value | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | List holding older F executables against which distros will be tested. | 
| 510 |  |  |  |  |  |  | (This is provided for readability of the code, but the list will be stored | 
| 511 |  |  |  |  |  |  | within the object and subsequently referenced therefrom. | 
| 512 |  |  |  |  |  |  |  | 
| 513 |  |  |  |  |  |  | =back | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | =cut | 
| 516 |  |  |  |  |  |  |  | 
| 517 |  |  |  |  |  |  | sub validate_older_perls { | 
| 518 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 519 | 0 |  |  |  |  |  | my @perllist = (); | 
| 520 |  |  |  |  |  |  | open my $IN1, '<', $self->{older_perls_file} | 
| 521 | 0 | 0 |  |  |  |  | or croak "Unable to open $self->{older_perls_file} for reading"; | 
| 522 | 0 |  |  |  |  |  | while (my $l = <$IN1>) { | 
| 523 | 0 |  |  |  |  |  | chomp $l; | 
| 524 | 0 | 0 |  |  |  |  | next if $l =~ m{^(\#|\s*$)}; | 
| 525 | 0 |  |  |  |  |  | push @perllist, $l; | 
| 526 |  |  |  |  |  |  | } | 
| 527 | 0 | 0 |  |  |  |  | close $IN1 | 
| 528 |  |  |  |  |  |  | or croak "Unable to close $self->{older_perls_file} after reading"; | 
| 529 |  |  |  |  |  |  |  | 
| 530 | 0 |  |  |  |  |  | my @perls = (); | 
| 531 |  |  |  |  |  |  |  | 
| 532 | 0 |  |  |  |  |  | for my $p (@perllist) { | 
| 533 | 0 | 0 |  |  |  |  | say "Locating $p executable ..." if $self->{verbose}; | 
| 534 | 0 |  |  |  |  |  | my $rv; | 
| 535 | 0 |  |  |  |  |  | my $path_to_perl = File::Spec->catfile($self->{path_to_perls}, $p); | 
| 536 | 0 | 0 |  |  |  |  | warn "Could not locate $path_to_perl" unless -e $path_to_perl; | 
| 537 | 0 |  |  |  |  |  | $rv = system(qq| $path_to_perl -v 1>/dev/null 2>&1 |); | 
| 538 | 0 | 0 |  |  |  |  | warn "Could not execute perl -v with $path_to_perl" if $rv; | 
| 539 |  |  |  |  |  |  |  | 
| 540 | 0 |  |  |  |  |  | my ($major, $minor, $patch) = $p =~ m{^perl(5)\.(\d+)\.(\d+)$}; | 
| 541 | 0 |  |  |  |  |  | my $canon = sprintf "%s.%03d%03d" => ($major, $minor, $patch); | 
| 542 |  |  |  |  |  |  |  | 
| 543 | 0 |  |  |  |  |  | push @perls, { | 
| 544 |  |  |  |  |  |  | version => $p, | 
| 545 |  |  |  |  |  |  | path => $path_to_perl, | 
| 546 |  |  |  |  |  |  | canon => $canon, | 
| 547 |  |  |  |  |  |  | }; | 
| 548 |  |  |  |  |  |  | } | 
| 549 | 0 |  |  |  |  |  | $self->{perls} = [ @perls ]; | 
| 550 | 0 |  |  |  |  |  | return @perls; | 
| 551 |  |  |  |  |  |  | } | 
| 552 |  |  |  |  |  |  |  | 
| 553 |  |  |  |  |  |  | =head2 C | 
| 554 |  |  |  |  |  |  |  | 
| 555 |  |  |  |  |  |  | =over 4 | 
| 556 |  |  |  |  |  |  |  | 
| 557 |  |  |  |  |  |  | =item * Purpose | 
| 558 |  |  |  |  |  |  |  | 
| 559 |  |  |  |  |  |  | Test a given F distro against each of the older Fs against which | 
| 560 |  |  |  |  |  |  | it is eligible to be tested. | 
| 561 |  |  |  |  |  |  |  | 
| 562 |  |  |  |  |  |  | =item * Arguments | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  | $self->test_distros_against_older_perls('/path/to/debugging/directory'); | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | String holding absolute path to an already created directory to which files | 
| 567 |  |  |  |  |  |  | can be written for later study and debugging.  That directory I be | 
| 568 |  |  |  |  |  |  | created by C, but it should I be created with C<( | 
| 569 |  |  |  |  |  |  | CLEANUP => 1)>; the user should manually remove this directory after analysis | 
| 570 |  |  |  |  |  |  | is complete. | 
| 571 |  |  |  |  |  |  |  | 
| 572 |  |  |  |  |  |  | =item * Return Value | 
| 573 |  |  |  |  |  |  |  | 
| 574 |  |  |  |  |  |  | Returns the object itself. | 
| 575 |  |  |  |  |  |  |  | 
| 576 |  |  |  |  |  |  | =item * Comment | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | The method will loop over the selected distros, calling | 
| 579 |  |  |  |  |  |  | C against each. | 
| 580 |  |  |  |  |  |  |  | 
| 581 |  |  |  |  |  |  | =back | 
| 582 |  |  |  |  |  |  |  | 
| 583 |  |  |  |  |  |  | =cut | 
| 584 |  |  |  |  |  |  |  | 
| 585 |  |  |  |  |  |  | sub test_distros_against_older_perls { | 
| 586 | 0 |  |  | 0 | 1 |  | my ($self, $results_dir) = @_; | 
| 587 |  |  |  |  |  |  | # $results_dir will be explicitly user-created to hold the results of | 
| 588 |  |  |  |  |  |  | # testing. | 
| 589 |  |  |  |  |  |  |  | 
| 590 |  |  |  |  |  |  | # A program using Perl5::Dist::Backcompat won't need it until now. So even | 
| 591 |  |  |  |  |  |  | # if we feed that directory to the program via GetOptions, it doesn't need | 
| 592 |  |  |  |  |  |  | # to go into the constructor.  It may be a tempdir but should almost | 
| 593 |  |  |  |  |  |  | # certainly NOT be set to get automatically cleaned up at program | 
| 594 |  |  |  |  |  |  | # conclusion (otherwise, where would you look for the results?). | 
| 595 |  |  |  |  |  |  |  | 
| 596 | 0 | 0 |  |  |  |  | croak "Unable to locate $results_dir" unless -d $results_dir; | 
| 597 | 0 |  |  |  |  |  | $self->{results_dir} = $results_dir; | 
| 598 |  |  |  |  |  |  |  | 
| 599 |  |  |  |  |  |  | # Calculations WILL, however, be done in a true tempdir.  We'll create | 
| 600 |  |  |  |  |  |  | # subdirs and files underneath that tempdir.  We'll cd to that tempdir but | 
| 601 |  |  |  |  |  |  | # come back to where we started before this method exits. | 
| 602 |  |  |  |  |  |  | # $self->{temp_top_dir} will be the conceptual equivalent of the top-level | 
| 603 |  |  |  |  |  |  | # directory in the Perl 5 distribution.  Hence, underneath it we'll create | 
| 604 |  |  |  |  |  |  | # the equivalents of the F, F, etc., and | 
| 605 |  |  |  |  |  |  | # F directories. | 
| 606 | 0 |  |  |  |  |  | $self->{currdir} = cwd(); | 
| 607 | 0 |  |  |  |  |  | $self->{temp_top_dir} = tempdir( CLEANUP => 1 ); | 
| 608 | 0 |  |  |  |  |  | my %results = (); | 
| 609 |  |  |  |  |  |  |  | 
| 610 | 0 | 0 |  |  |  |  | chdir $self->{temp_top_dir} or croak "Unable to change to tempdir $self->{temp_top_dir}"; | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  | # Create a 't/' directory underneath the temp_top_dir | 
| 613 | 0 |  |  |  |  |  | my $temp_t_dir = File::Spec->catdir($self->{temp_top_dir}, 't'); | 
| 614 | 0 | 0 |  |  |  |  | mkdir $temp_t_dir or croak "Unable to mkdir $temp_t_dir"; | 
| 615 | 0 |  |  |  |  |  | $self->{temp_t_dir} = $temp_t_dir; | 
| 616 |  |  |  |  |  |  |  | 
| 617 |  |  |  |  |  |  | # Several of the F distros need F for their tests; copy | 
| 618 |  |  |  |  |  |  | # it into position once only. | 
| 619 | 0 |  |  |  |  |  | my $testpl = File::Spec->catfile($self->{perl_workdir}, 't', 'test.pl'); | 
| 620 | 0 | 0 |  |  |  |  | croak "Could not locate $testpl" unless -f $testpl; | 
| 621 | 0 | 0 |  |  |  |  | copy $testpl => $self->{temp_t_dir} or croak "Unable to copy $testpl"; | 
| 622 |  |  |  |  |  |  |  | 
| 623 |  |  |  |  |  |  | # Create a 'dist/' directory underneath the temp_top_dir | 
| 624 | 0 |  |  |  |  |  | my $temp_dist_dir = File::Spec->catdir($self->{temp_top_dir}, 'dist'); | 
| 625 | 0 | 0 |  |  |  |  | mkdir $temp_dist_dir or croak "Unable to mkdir $temp_dist_dir"; | 
| 626 | 0 |  |  |  |  |  | $self->{temp_dist_dir} = $temp_dist_dir; | 
| 627 |  |  |  |  |  |  |  | 
| 628 | 0 |  |  |  |  |  | for my $d (@{$self->{distros_for_testing}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 629 | 0 |  |  |  |  |  | my $this_result = $self->test_one_distro_against_older_perls($d); | 
| 630 | 0 |  |  |  |  |  | $results{$d} = $this_result; | 
| 631 |  |  |  |  |  |  | } | 
| 632 |  |  |  |  |  |  |  | 
| 633 |  |  |  |  |  |  | chdir $self->{currdir} | 
| 634 | 0 | 0 |  |  |  |  | or croak "Unable to change back to starting directory $self->{currdir}"; | 
| 635 |  |  |  |  |  |  |  | 
| 636 | 0 |  |  |  |  |  | $self->{results} = { %results }; | 
| 637 | 0 |  |  |  |  |  | return $self; | 
| 638 |  |  |  |  |  |  |  | 
| 639 |  |  |  |  |  |  | # temp_top_dir should go out of scope here (though its path and those of | 
| 640 |  |  |  |  |  |  | # temp_t_dir and temp_dist_dir will still be in the object) | 
| 641 |  |  |  |  |  |  | } | 
| 642 |  |  |  |  |  |  |  | 
| 643 |  |  |  |  |  |  | =head2 C | 
| 644 |  |  |  |  |  |  |  | 
| 645 |  |  |  |  |  |  | =over 4 | 
| 646 |  |  |  |  |  |  |  | 
| 647 |  |  |  |  |  |  | =item * Purpose | 
| 648 |  |  |  |  |  |  |  | 
| 649 |  |  |  |  |  |  | Print on F: | 
| 650 |  |  |  |  |  |  |  | 
| 651 |  |  |  |  |  |  | =over 4 | 
| 652 |  |  |  |  |  |  |  | 
| 653 |  |  |  |  |  |  | =item 1 | 
| 654 |  |  |  |  |  |  |  | 
| 655 |  |  |  |  |  |  | A list of the F files created for each | 
| 656 |  |  |  |  |  |  | tested distro (each file containing a summary of the results for that distro | 
| 657 |  |  |  |  |  |  | against each designated F executable. Example: | 
| 658 |  |  |  |  |  |  |  | 
| 659 |  |  |  |  |  |  | Summaries | 
| 660 |  |  |  |  |  |  | --------- | 
| 661 |  |  |  |  |  |  | Attribute-Handlers      /tmp/29LsgNfjVb/Attribute-Handlers.summary.txt | 
| 662 |  |  |  |  |  |  | Carp                    /tmp/29LsgNfjVb/Carp.summary.txt | 
| 663 |  |  |  |  |  |  | Data-Dumper             /tmp/29LsgNfjVb/Data-Dumper.summary.txt | 
| 664 |  |  |  |  |  |  | ... | 
| 665 |  |  |  |  |  |  | threads                 /tmp/29LsgNfjVb/threads.summary.txt | 
| 666 |  |  |  |  |  |  | threads-shared          /tmp/29LsgNfjVb/threads-shared.summary.txt | 
| 667 |  |  |  |  |  |  |  | 
| 668 |  |  |  |  |  |  | =item 2 | 
| 669 |  |  |  |  |  |  |  | 
| 670 |  |  |  |  |  |  | A concatenation of all those files. | 
| 671 |  |  |  |  |  |  |  | 
| 672 |  |  |  |  |  |  | =back | 
| 673 |  |  |  |  |  |  |  | 
| 674 |  |  |  |  |  |  | =item * Arguments | 
| 675 |  |  |  |  |  |  |  | 
| 676 |  |  |  |  |  |  | To simply list the summary files: | 
| 677 |  |  |  |  |  |  |  | 
| 678 |  |  |  |  |  |  | $self->print_distro_summaries(); | 
| 679 |  |  |  |  |  |  |  | 
| 680 |  |  |  |  |  |  | To list the summary files and concatenate their content: | 
| 681 |  |  |  |  |  |  |  | 
| 682 |  |  |  |  |  |  | $self->print_distro_summaries( {cat_summaries => 1} ); | 
| 683 |  |  |  |  |  |  |  | 
| 684 |  |  |  |  |  |  | =item * Return Value | 
| 685 |  |  |  |  |  |  |  | 
| 686 |  |  |  |  |  |  | Returns true value upon success. | 
| 687 |  |  |  |  |  |  |  | 
| 688 |  |  |  |  |  |  | =item * Comment | 
| 689 |  |  |  |  |  |  |  | 
| 690 |  |  |  |  |  |  | You'll probably want to redirect or F F to a file for further | 
| 691 |  |  |  |  |  |  | study. | 
| 692 |  |  |  |  |  |  |  | 
| 693 |  |  |  |  |  |  | =back | 
| 694 |  |  |  |  |  |  |  | 
| 695 |  |  |  |  |  |  | =cut | 
| 696 |  |  |  |  |  |  |  | 
| 697 |  |  |  |  |  |  | sub print_distro_summaries { | 
| 698 | 0 |  |  | 0 | 1 |  | my ($self, $args) = @_; | 
| 699 | 0 | 0 |  |  |  |  | if (! defined $args) { $args = {}; } | 
|  | 0 |  |  |  |  |  |  | 
| 700 |  |  |  |  |  |  | else { | 
| 701 | 0 | 0 |  |  |  |  | croak "Argument to print_distro_summaries must be hashref" | 
| 702 |  |  |  |  |  |  | unless ref($args) eq 'HASH'; | 
| 703 |  |  |  |  |  |  | } | 
| 704 |  |  |  |  |  |  |  | 
| 705 | 0 |  |  |  |  |  | say "\nSummaries"; | 
| 706 | 0 |  |  |  |  |  | say '-' x 9; | 
| 707 | 0 |  |  |  |  |  | for my $d (sort keys %{$self->{results}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 708 | 0 |  |  |  |  |  | $self->print_distro_summary($d); | 
| 709 |  |  |  |  |  |  | } | 
| 710 |  |  |  |  |  |  |  | 
| 711 | 0 | 0 |  |  |  |  | if ($args->{cat_summaries}) { | 
| 712 | 0 |  |  |  |  |  | say "\nOverall (at $self->{describe}):"; | 
| 713 | 0 |  |  |  |  |  | for my $d (sort keys %{$self->{results}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 714 | 0 |  |  |  |  |  | say "\n$d"; | 
| 715 | 0 |  |  |  |  |  | dd $self->{results}->{$d}; | 
| 716 |  |  |  |  |  |  | } | 
| 717 |  |  |  |  |  |  | } | 
| 718 | 0 |  |  |  |  |  | return 1; | 
| 719 |  |  |  |  |  |  | } | 
| 720 |  |  |  |  |  |  |  | 
| 721 |  |  |  |  |  |  | =head2 C | 
| 722 |  |  |  |  |  |  |  | 
| 723 |  |  |  |  |  |  | =over 4 | 
| 724 |  |  |  |  |  |  |  | 
| 725 |  |  |  |  |  |  | =item * Purpose | 
| 726 |  |  |  |  |  |  |  | 
| 727 |  |  |  |  |  |  | Provide an overall summary of PASSes and FAILs in the distro/perl-version matrix. | 
| 728 |  |  |  |  |  |  |  | 
| 729 |  |  |  |  |  |  | =item * Arguments | 
| 730 |  |  |  |  |  |  |  | 
| 731 |  |  |  |  |  |  | None, all data needed is stored within object. | 
| 732 |  |  |  |  |  |  |  | 
| 733 |  |  |  |  |  |  | =item * Return Value | 
| 734 |  |  |  |  |  |  |  | 
| 735 |  |  |  |  |  |  | Array ref with 4 elements: overall attempts, overall passes, overall failures, | 
| 736 |  |  |  |  |  |  | overall skipped. | 
| 737 |  |  |  |  |  |  |  | 
| 738 |  |  |  |  |  |  | =item * Comment | 
| 739 |  |  |  |  |  |  |  | 
| 740 |  |  |  |  |  |  | An entry in the distro/perl-version matrix is skipped if there is a failure | 
| 741 |  |  |  |  |  |  | running F, which causes the C, C and C | 
| 742 |  |  |  |  |  |  | values to be all undefined. | 
| 743 |  |  |  |  |  |  |  | 
| 744 |  |  |  |  |  |  | =back | 
| 745 |  |  |  |  |  |  |  | 
| 746 |  |  |  |  |  |  | =cut | 
| 747 |  |  |  |  |  |  |  | 
| 748 |  |  |  |  |  |  | sub tally_results { | 
| 749 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 750 | 0 |  |  |  |  |  | my $overall_attempts = 0; | 
| 751 | 0 |  |  |  |  |  | my $overall_successes = 0; | 
| 752 | 0 |  |  |  |  |  | my $overall_skipped = 0; | 
| 753 | 0 |  |  |  |  |  | for my $d (keys %{$self->{results}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 754 | 0 |  |  |  |  |  | for my $p (keys %{$self->{results}->{$d}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 755 | 0 |  |  |  |  |  | $overall_attempts++; | 
| 756 | 0 |  |  |  |  |  | my %thisrun = %{$self->{results}->{$d}->{$p}}; | 
|  | 0 |  |  |  |  |  |  | 
| 757 | 0 | 0 | 0 |  |  |  | if ( | 
|  |  | 0 | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 758 |  |  |  |  |  |  | ! defined $thisrun{configure} and | 
| 759 |  |  |  |  |  |  | ! defined $thisrun{make} and | 
| 760 |  |  |  |  |  |  | ! defined $thisrun{test} | 
| 761 |  |  |  |  |  |  | ) { | 
| 762 | 0 |  |  |  |  |  | $overall_skipped++; | 
| 763 |  |  |  |  |  |  | } | 
| 764 |  |  |  |  |  |  | elsif ( | 
| 765 |  |  |  |  |  |  | $thisrun{configure} and | 
| 766 |  |  |  |  |  |  | $thisrun{make} and | 
| 767 |  |  |  |  |  |  | $thisrun{test} | 
| 768 |  |  |  |  |  |  | ) { | 
| 769 | 0 |  |  |  |  |  | $overall_successes++; | 
| 770 |  |  |  |  |  |  | } | 
| 771 |  |  |  |  |  |  | } | 
| 772 |  |  |  |  |  |  | } | 
| 773 | 0 |  |  |  |  |  | my $overall_failures = $overall_attempts - ($overall_successes + $overall_skipped); | 
| 774 | 0 |  |  |  |  |  | return [$overall_attempts, $overall_successes, $overall_failures, $overall_skipped]; | 
| 775 |  |  |  |  |  |  | } | 
| 776 |  |  |  |  |  |  |  | 
| 777 |  |  |  |  |  |  | =head1 INTERNAL METHODS | 
| 778 |  |  |  |  |  |  |  | 
| 779 |  |  |  |  |  |  | The following methods use the Perl5::Dist::Backcompat object but are called | 
| 780 |  |  |  |  |  |  | from within the public methods.  Other than this library's author, you | 
| 781 |  |  |  |  |  |  | shouldn't need to explicitly call these methods (or the internal subroutines | 
| 782 |  |  |  |  |  |  | documented below) in a production program.  The documentation here is mainly | 
| 783 |  |  |  |  |  |  | for people working on this distribution itself. | 
| 784 |  |  |  |  |  |  |  | 
| 785 |  |  |  |  |  |  | =cut | 
| 786 |  |  |  |  |  |  |  | 
| 787 |  |  |  |  |  |  | =head2 C | 
| 788 |  |  |  |  |  |  |  | 
| 789 |  |  |  |  |  |  | =over 4 | 
| 790 |  |  |  |  |  |  |  | 
| 791 |  |  |  |  |  |  | =item * Purpose | 
| 792 |  |  |  |  |  |  |  | 
| 793 |  |  |  |  |  |  | Test one selected F distribution against the list of older Fs. | 
| 794 |  |  |  |  |  |  |  | 
| 795 |  |  |  |  |  |  | =item * Arguments | 
| 796 |  |  |  |  |  |  |  | 
| 797 |  |  |  |  |  |  | Single string holding the name of the distro in C format. | 
| 798 |  |  |  |  |  |  |  | 
| 799 |  |  |  |  |  |  | =item * Return Value | 
| 800 |  |  |  |  |  |  |  | 
| 801 |  |  |  |  |  |  | Hash reference with one element for each F executable selected: | 
| 802 |  |  |  |  |  |  |  | 
| 803 |  |  |  |  |  |  | { | 
| 804 |  |  |  |  |  |  | "5.006002" => { a => "perl5.6.2",  configure => 1, make => 0, test => undef }, | 
| 805 |  |  |  |  |  |  | "5.008009" => { a => "perl5.8.9",  configure => 1, make => 0, test => undef }, | 
| 806 |  |  |  |  |  |  | "5.010001" => { a => "perl5.10.1", configure => 1, make => 0, test => undef }, | 
| 807 |  |  |  |  |  |  | ... | 
| 808 |  |  |  |  |  |  | "5.034000" => { a => "perl5.34.0", configure => 1, make => 1, test => 1 }, | 
| 809 |  |  |  |  |  |  | } | 
| 810 |  |  |  |  |  |  |  | 
| 811 |  |  |  |  |  |  | The value of each element is a hashref with elements keyed as follows: | 
| 812 |  |  |  |  |  |  |  | 
| 813 |  |  |  |  |  |  | =over 4 | 
| 814 |  |  |  |  |  |  |  | 
| 815 |  |  |  |  |  |  | =item * C | 
| 816 |  |  |  |  |  |  |  | 
| 817 |  |  |  |  |  |  | Perl version in the spelling used in the default value for C. | 
| 818 |  |  |  |  |  |  |  | 
| 819 |  |  |  |  |  |  | =item * C | 
| 820 |  |  |  |  |  |  |  | 
| 821 |  |  |  |  |  |  | The result of calling F: C<1> for success; C<0> for failure; | 
| 822 |  |  |  |  |  |  | C for not attempted. | 
| 823 |  |  |  |  |  |  |  | 
| 824 |  |  |  |  |  |  | =item * C | 
| 825 |  |  |  |  |  |  |  | 
| 826 |  |  |  |  |  |  | The result of calling F: same meaning as above. | 
| 827 |  |  |  |  |  |  |  | 
| 828 |  |  |  |  |  |  | =item * C | 
| 829 |  |  |  |  |  |  |  | 
| 830 |  |  |  |  |  |  | The result of calling F: same meaning as above. | 
| 831 |  |  |  |  |  |  |  | 
| 832 |  |  |  |  |  |  | =back | 
| 833 |  |  |  |  |  |  |  | 
| 834 |  |  |  |  |  |  | =back | 
| 835 |  |  |  |  |  |  |  | 
| 836 |  |  |  |  |  |  | =cut | 
| 837 |  |  |  |  |  |  |  | 
| 838 |  |  |  |  |  |  | sub test_one_distro_against_older_perls { | 
| 839 | 0 |  |  | 0 | 1 |  | my ($self, $d) = @_; | 
| 840 | 0 | 0 |  |  |  |  | say "Testing $d ..." if $self->{verbose}; | 
| 841 | 0 |  |  |  |  |  | my $this_result = {}; | 
| 842 |  |  |  |  |  |  |  | 
| 843 | 0 |  |  |  |  |  | my $source_dir = File::Spec->catdir($self->{perl_workdir}, 'dist', $d); | 
| 844 | 0 |  |  |  |  |  | my $this_tempdir  = File::Spec->catdir($self->{temp_dist_dir}, $d); | 
| 845 | 0 | 0 |  |  |  |  | mkdir $this_tempdir or croak "Unable to mkdir $this_tempdir"; | 
| 846 | 0 | 0 |  |  |  |  | dircopy($source_dir, $this_tempdir) | 
| 847 |  |  |  |  |  |  | or croak "Unable to copy $source_dir to $this_tempdir"; | 
| 848 |  |  |  |  |  |  |  | 
| 849 | 0 | 0 |  |  |  |  | chdir $this_tempdir or croak "Unable to chdir to tempdir for dist/$d"; | 
| 850 | 0 | 0 |  |  |  |  | say "  Now in $this_tempdir ..." if $self->{verbose}; | 
| 851 |  |  |  |  |  |  |  | 
| 852 | 0 |  |  |  |  |  | THIS_PERL: for my $p (@{$self->{perls}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 853 | 0 |  |  |  |  |  | $this_result->{$p->{canon}}{a} = $p->{version}; | 
| 854 |  |  |  |  |  |  | # Skip this perl version if (a) distro has a specified | 
| 855 |  |  |  |  |  |  | # 'minimum_perl_version' and (b) that minimum version is greater than | 
| 856 |  |  |  |  |  |  | # the current perl we're running. | 
| 857 | 0 | 0 | 0 |  |  |  | if ( | 
| 858 |  |  |  |  |  |  | ( | 
| 859 |  |  |  |  |  |  | $self->{distro_metadata}->{$d}{minimum_perl_version} | 
| 860 |  |  |  |  |  |  | and | 
| 861 |  |  |  |  |  |  | $self->{distro_metadata}->{$d}{minimum_perl_version} >= $p->{canon} | 
| 862 |  |  |  |  |  |  | ) | 
| 863 |  |  |  |  |  |  | #                Since we're currently using threaded perls for this | 
| 864 |  |  |  |  |  |  | #                process, the following condition is not pertinent.  But we'll | 
| 865 |  |  |  |  |  |  | #                retain it here commented out for possible future use. | 
| 866 |  |  |  |  |  |  | # | 
| 867 |  |  |  |  |  |  | #                or | 
| 868 |  |  |  |  |  |  | #            ( | 
| 869 |  |  |  |  |  |  | #                $self->{distro_metadata}->{$d}{needs_threaded_perl} | 
| 870 |  |  |  |  |  |  | #            ) | 
| 871 |  |  |  |  |  |  | ) { | 
| 872 | 0 |  |  |  |  |  | $this_result->{$p->{canon}}{configure} = undef; | 
| 873 | 0 |  |  |  |  |  | $this_result->{$p->{canon}}{make} = undef; | 
| 874 | 0 |  |  |  |  |  | $this_result->{$p->{canon}}{test} = undef; | 
| 875 | 0 |  |  |  |  |  | next THIS_PERL; | 
| 876 |  |  |  |  |  |  | } | 
| 877 | 0 |  |  |  |  |  | my $f = join '.' => ($d, $p->{version}, 'txt'); | 
| 878 | 0 |  |  |  |  |  | my $debugfile = File::Spec->catfile($self->{results_dir}, $f); | 
| 879 | 0 | 0 |  |  |  |  | if ($self->{verbose}) { | 
| 880 | 0 |  |  |  |  |  | say "Testing $d with $p->{canon} ($p->{version}); see $debugfile"; | 
| 881 |  |  |  |  |  |  | } | 
| 882 |  |  |  |  |  |  |  | 
| 883 |  |  |  |  |  |  | # Here, assuming the distro ($d) is classified as 'cpan', we should | 
| 884 |  |  |  |  |  |  | # extract the Makefile.PL from the tar and swap that into the | 
| 885 |  |  |  |  |  |  | # following 'perl Makefile.PL' command. | 
| 886 |  |  |  |  |  |  |  | 
| 887 | 0 |  |  |  |  |  | my ($rv, $cmd); | 
| 888 | 0 |  |  |  |  |  | my $this_makefile_pl = 'Makefile.PL'; | 
| 889 | 0 | 0 |  |  |  |  | if ($self->{makefile_pl_status}->{$d} eq 'cpan') { | 
| 890 |  |  |  |  |  |  | # We currently expect this branch to prevail 40 times | 
| 891 | 0 | 0 |  |  |  |  | if (-f $this_makefile_pl) { | 
| 892 | 0 |  |  |  |  |  | move $this_makefile_pl => "$this_makefile_pl.noncpan"; | 
| 893 |  |  |  |  |  |  | } | 
| 894 | 0 |  |  |  |  |  | my $source = File::Spec->catfile($self->{distro_metadata}->{$d}->{distvname},'Makefile.PL'); | 
| 895 | 0 |  |  |  |  |  | my $destination = File::Spec->catfile('.', $this_makefile_pl); | 
| 896 |  |  |  |  |  |  | my $extract = $self->{distro_metadata}->{$d}->{tar}->extract_file( | 
| 897 | 0 |  |  |  |  |  | $source, | 
| 898 |  |  |  |  |  |  | $destination, | 
| 899 |  |  |  |  |  |  | ); | 
| 900 | 0 | 0 |  |  |  |  | croak "Unable to extract Makefile.PL from tarball" unless $extract; | 
| 901 | 0 | 0 |  |  |  |  | croak "Unable to locate extracted Makefile.PL" unless -f $destination; | 
| 902 |  |  |  |  |  |  | } | 
| 903 | 0 | 0 |  |  |  |  | croak "Could not locate $this_makefile_pl for configuring" unless -f $this_makefile_pl; | 
| 904 |  |  |  |  |  |  |  | 
| 905 | 0 | 0 |  |  |  |  | if ($self->{distro_metadata}->{$d}->{needs_ppport_h}) { | 
| 906 | 0 |  |  |  |  |  | my $source = File::Spec->catfile($self->{distro_metadata}->{$d}->{distvname},'ppport.h'); | 
| 907 | 0 |  |  |  |  |  | my $destination = File::Spec->catfile('.', 'ppport.h'); | 
| 908 |  |  |  |  |  |  | my $extract = $self->{distro_metadata}->{$d}->{tar}->extract_file( | 
| 909 | 0 |  |  |  |  |  | $source, | 
| 910 |  |  |  |  |  |  | $destination, | 
| 911 |  |  |  |  |  |  | ); | 
| 912 | 0 | 0 |  |  |  |  | croak "Unable to extract ppport.h from tarball" unless $extract; | 
| 913 | 0 | 0 |  |  |  |  | croak "Unable to locate extracted ppport.h" unless -f $destination; | 
| 914 |  |  |  |  |  |  | } | 
| 915 |  |  |  |  |  |  |  | 
| 916 | 0 | 0 |  |  |  |  | if ($self->{distro_metadata}->{$d}->{needs_threads_h}) { | 
| 917 | 0 |  |  |  |  |  | my $source = File::Spec->catfile($self->{distro_metadata}->{$d}->{distvname},'threads.h'); | 
| 918 | 0 |  |  |  |  |  | my $destination = File::Spec->catfile('.', 'threads.h'); | 
| 919 |  |  |  |  |  |  | my $extract = $self->{distro_metadata}->{$d}->{tar}->extract_file( | 
| 920 | 0 |  |  |  |  |  | $source, | 
| 921 |  |  |  |  |  |  | $destination, | 
| 922 |  |  |  |  |  |  | ); | 
| 923 | 0 | 0 |  |  |  |  | croak "Unable to extract threads.h from tarball" unless $extract; | 
| 924 | 0 | 0 |  |  |  |  | croak "Unable to locate extracted threads.h" unless -f $destination; | 
| 925 |  |  |  |  |  |  | } | 
| 926 |  |  |  |  |  |  |  | 
| 927 | 0 | 0 |  |  |  |  | if ($self->{distro_metadata}->{$d}->{needs_shared_h}) { | 
| 928 | 0 |  |  |  |  |  | my $source = File::Spec->catfile($self->{distro_metadata}->{$d}->{distvname},'shared.h'); | 
| 929 | 0 |  |  |  |  |  | my $destination = File::Spec->catfile('.', 'shared.h'); | 
| 930 |  |  |  |  |  |  | my $extract = $self->{distro_metadata}->{$d}->{tar}->extract_file( | 
| 931 | 0 |  |  |  |  |  | $source, | 
| 932 |  |  |  |  |  |  | $destination, | 
| 933 |  |  |  |  |  |  | ); | 
| 934 | 0 | 0 |  |  |  |  | croak "Unable to extract shared.h from tarball" unless $extract; | 
| 935 | 0 | 0 |  |  |  |  | croak "Unable to locate extracted shared.h" unless -f $destination; | 
| 936 |  |  |  |  |  |  | } | 
| 937 |  |  |  |  |  |  |  | 
| 938 | 0 |  |  |  |  |  | $cmd = qq| $p->{path} $this_makefile_pl > $debugfile 2>&1 |; | 
| 939 | 0 | 0 |  |  |  |  | $rv = system($cmd) and say STDERR "  FAIL: $d: $p->{canon}: Makefile.PL"; | 
| 940 | 0 | 0 |  |  |  |  | $this_result->{$p->{canon}}{configure} = $rv ? 0 : 1; undef $rv; | 
|  | 0 |  |  |  |  |  |  | 
| 941 | 0 | 0 |  |  |  |  | unless ($this_result->{$p->{canon}}{configure}) { | 
| 942 | 0 |  |  |  |  |  | undef $this_result->{$p->{canon}}{make}; | 
| 943 | 0 |  |  |  |  |  | undef $this_result->{$p->{canon}}{test}; | 
| 944 | 0 |  |  |  |  |  | next THIS_PERL; | 
| 945 |  |  |  |  |  |  | } | 
| 946 |  |  |  |  |  |  |  | 
| 947 | 0 | 0 |  |  |  |  | $rv = system(qq| make >> $debugfile 2>&1 |) | 
| 948 |  |  |  |  |  |  | and say STDERR "  FAIL: $d: $p->{canon}: make"; | 
| 949 | 0 | 0 |  |  |  |  | $this_result->{$p->{canon}}{make} = $rv ? 0 : 1; undef $rv; | 
|  | 0 |  |  |  |  |  |  | 
| 950 | 0 | 0 |  |  |  |  | unless ($this_result->{$p->{canon}}{make}) { | 
| 951 | 0 |  |  |  |  |  | undef $this_result->{$p->{canon}}{test}; | 
| 952 | 0 |  |  |  |  |  | next THIS_PERL; | 
| 953 |  |  |  |  |  |  | } | 
| 954 |  |  |  |  |  |  |  | 
| 955 | 0 | 0 |  |  |  |  | $rv = system(qq| make test >> $debugfile 2>&1 |) | 
| 956 |  |  |  |  |  |  | and say STDERR "  FAIL: $d: $p->{canon}: make test"; | 
| 957 | 0 | 0 |  |  |  |  | $this_result->{$p->{canon}}{test} = $rv ? 0 : 1; undef $rv; | 
|  | 0 |  |  |  |  |  |  | 
| 958 |  |  |  |  |  |  |  | 
| 959 | 0 | 0 |  |  |  |  | system(qq| make clean 2>&1 1>/dev/null |) | 
| 960 |  |  |  |  |  |  | and carp "Unable to 'make clean' for $d"; | 
| 961 |  |  |  |  |  |  | } | 
| 962 |  |  |  |  |  |  | chdir $self->{temp_top_dir} | 
| 963 | 0 | 0 |  |  |  |  | or croak "Unable to change to tempdir $self->{temp_top_dir}"; | 
| 964 | 0 |  |  |  |  |  | return $this_result; | 
| 965 |  |  |  |  |  |  | } | 
| 966 |  |  |  |  |  |  |  | 
| 967 |  |  |  |  |  |  | =head2 C | 
| 968 |  |  |  |  |  |  |  | 
| 969 |  |  |  |  |  |  | =over 4 | 
| 970 |  |  |  |  |  |  |  | 
| 971 |  |  |  |  |  |  | =item * Purpose | 
| 972 |  |  |  |  |  |  |  | 
| 973 |  |  |  |  |  |  | Create a file holding a summary of the results for running one distro against | 
| 974 |  |  |  |  |  |  | each of the selected Fs. | 
| 975 |  |  |  |  |  |  |  | 
| 976 |  |  |  |  |  |  | =item * Arguments | 
| 977 |  |  |  |  |  |  |  | 
| 978 |  |  |  |  |  |  | $self->print_distro_summary('Some-Distro'); | 
| 979 |  |  |  |  |  |  |  | 
| 980 |  |  |  |  |  |  | String holding name of distro. | 
| 981 |  |  |  |  |  |  |  | 
| 982 |  |  |  |  |  |  | =item * Return Value | 
| 983 |  |  |  |  |  |  |  | 
| 984 |  |  |  |  |  |  | Returns true value on success. | 
| 985 |  |  |  |  |  |  |  | 
| 986 |  |  |  |  |  |  | =item * Comment | 
| 987 |  |  |  |  |  |  |  | 
| 988 |  |  |  |  |  |  | File created will be named like F. | 
| 989 |  |  |  |  |  |  |  | 
| 990 |  |  |  |  |  |  | File's content will look like this: | 
| 991 |  |  |  |  |  |  |  | 
| 992 |  |  |  |  |  |  | Attribute-Handlers                                   v5.35.7-48-g34e3587 | 
| 993 |  |  |  |  |  |  | { | 
| 994 |  |  |  |  |  |  | "5.006002" => { a => "perl5.6.2",  configure => 1, make => 0, test => undef }, | 
| 995 |  |  |  |  |  |  | "5.008009" => { a => "perl5.8.9",  configure => 1, make => 0, test => undef }, | 
| 996 |  |  |  |  |  |  | "5.010001" => { a => "perl5.10.1", configure => 1, make => 0, test => undef }, | 
| 997 |  |  |  |  |  |  | ... | 
| 998 |  |  |  |  |  |  | "5.034000" => { a => "perl5.34.0", configure => 1, make => 1, test => 1 }, | 
| 999 |  |  |  |  |  |  | } | 
| 1000 |  |  |  |  |  |  |  | 
| 1001 |  |  |  |  |  |  | =back | 
| 1002 |  |  |  |  |  |  |  | 
| 1003 |  |  |  |  |  |  | =cut | 
| 1004 |  |  |  |  |  |  |  | 
| 1005 |  |  |  |  |  |  | sub print_distro_summary { | 
| 1006 | 0 |  |  | 0 | 1 |  | my ($self, $d) = @_; | 
| 1007 | 0 |  |  |  |  |  | my $output = File::Spec->catfile($self->{results_dir}, "$d.summary.txt"); | 
| 1008 | 0 | 0 |  |  |  |  | open my $OUT, '>', $output or die "Unable to open $output for writing: $!"; | 
| 1009 | 0 |  |  |  |  |  | say $OUT sprintf "%-52s%20s" => ($d, $self->{describe}); | 
| 1010 | 0 |  |  |  |  |  | my $oldfh = select($OUT); | 
| 1011 | 0 |  |  |  |  |  | dd $self->{results}->{$d}; | 
| 1012 | 0 | 0 |  |  |  |  | close $OUT or die "Unable to close $output after writing: $!"; | 
| 1013 | 0 |  |  |  |  |  | select $oldfh; | 
| 1014 |  |  |  |  |  |  | say sprintf "%-24s%-48s" => ($d, $output) | 
| 1015 | 0 | 0 |  |  |  |  | if $self->{verbose}; | 
| 1016 |  |  |  |  |  |  | } | 
| 1017 |  |  |  |  |  |  |  | 
| 1018 |  |  |  |  |  |  | # Check tarballs we have on disk to see whether they contain a | 
| 1019 |  |  |  |  |  |  | # Makefile.PL. | 
| 1020 |  |  |  |  |  |  | # $ pwd | 
| 1021 |  |  |  |  |  |  | # /home/jkeenan/learn/perl/p5p/dist-backcompat/tarballs/authors/id | 
| 1022 |  |  |  |  |  |  | # $ ls . | head -n 5 | 
| 1023 |  |  |  |  |  |  | # Attribute-Handlers-0.99.tar.gz | 
| 1024 |  |  |  |  |  |  | # autouse-1.11.tar.gz | 
| 1025 |  |  |  |  |  |  | # base-2.23.tar.gz | 
| 1026 |  |  |  |  |  |  | # Carp-1.50.tar.gz | 
| 1027 |  |  |  |  |  |  | # constant-1.33.tar.gz | 
| 1028 |  |  |  |  |  |  |  | 
| 1029 |  |  |  |  |  |  | sub identify_cpan_tarballs_with_makefile_pl { | 
| 1030 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 1031 | 0 |  |  |  |  |  | my $id_dir = File::Spec->catdir($self->{tarball_dir}, 'authors', 'id'); | 
| 1032 | 0 | 0 |  |  |  |  | opendir my $DIR, $id_dir | 
| 1033 |  |  |  |  |  |  | or croak "Unable to open directory $id_dir for reading"; | 
| 1034 | 0 |  |  |  |  |  | my @available = map { File::Spec->catfile('authors', 'id', $_) } | 
| 1035 | 0 |  |  |  |  |  | grep { m/\.tar\.gz$/ } readdir $DIR; | 
|  | 0 |  |  |  |  |  |  | 
| 1036 | 0 | 0 |  |  |  |  | closedir $DIR or croak "Unable to close directory $id_dir after reading"; | 
| 1037 | 0 |  |  |  |  |  | my %this = (); | 
| 1038 | 0 |  |  |  |  |  | for my $tb (@available) { | 
| 1039 | 0 |  |  |  |  |  | my $d = CPAN::DistnameInfo->new($tb); | 
| 1040 | 0 |  |  |  |  |  | my $dist = $d->dist; | 
| 1041 | 0 |  |  |  |  |  | my $distvname = $d->distvname; | 
| 1042 | 0 |  |  |  |  |  | $this{$dist}{tarball} = File::Spec->catfile($self->{tarball_dir}, $tb); | 
| 1043 | 0 |  |  |  |  |  | $this{$dist}{distvname} = $distvname; | 
| 1044 |  |  |  |  |  |  | } | 
| 1045 | 0 |  |  |  |  |  | return \%this; | 
| 1046 |  |  |  |  |  |  | } | 
| 1047 |  |  |  |  |  |  |  | 
| 1048 |  |  |  |  |  |  | =head1 INTERNAL SUBROUTINES | 
| 1049 |  |  |  |  |  |  |  | 
| 1050 |  |  |  |  |  |  | =head2 C | 
| 1051 |  |  |  |  |  |  |  | 
| 1052 |  |  |  |  |  |  | =over 4 | 
| 1053 |  |  |  |  |  |  |  | 
| 1054 |  |  |  |  |  |  | =item * Purpose | 
| 1055 |  |  |  |  |  |  |  | 
| 1056 |  |  |  |  |  |  | Assure us that our environment is adequate to the task. | 
| 1057 |  |  |  |  |  |  |  | 
| 1058 |  |  |  |  |  |  | =item * Arguments | 
| 1059 |  |  |  |  |  |  |  | 
| 1060 |  |  |  |  |  |  | sanity_check(\%distmodules, $verbose); | 
| 1061 |  |  |  |  |  |  |  | 
| 1062 |  |  |  |  |  |  | List of two scalars: (i) reference to the hash which is storing list of | 
| 1063 |  |  |  |  |  |  | F distros; (ii) verbosity selection. | 
| 1064 |  |  |  |  |  |  |  | 
| 1065 |  |  |  |  |  |  | =item * Return Value | 
| 1066 |  |  |  |  |  |  |  | 
| 1067 |  |  |  |  |  |  | Implicitly returns true on success, but does not otherwise return any | 
| 1068 |  |  |  |  |  |  | meaningful value. | 
| 1069 |  |  |  |  |  |  |  | 
| 1070 |  |  |  |  |  |  | =item * Comment | 
| 1071 |  |  |  |  |  |  |  | 
| 1072 |  |  |  |  |  |  | If verbosity is selected, displays the current git commit and other useful | 
| 1073 |  |  |  |  |  |  | information on F. | 
| 1074 |  |  |  |  |  |  |  | 
| 1075 |  |  |  |  |  |  | =back | 
| 1076 |  |  |  |  |  |  |  | 
| 1077 |  |  |  |  |  |  | =cut | 
| 1078 |  |  |  |  |  |  |  | 
| 1079 |  |  |  |  |  |  | sub _sanity_check { | 
| 1080 | 0 |  |  | 0 |  |  | my ($distmodules, $describe, $verbose) = @_; | 
| 1081 | 0 |  |  |  |  |  | for my $m (keys %{$distmodules}) { | 
|  | 0 |  |  |  |  |  |  | 
| 1082 | 0 | 0 |  |  |  |  | if ($distmodules->{$m}{UPSTREAM} ne 'blead') { | 
| 1083 | 0 |  |  |  |  |  | warn "Distro $m has UPSTREAM other than 'blead'"; | 
| 1084 |  |  |  |  |  |  | } | 
| 1085 | 0 | 0 |  |  |  |  | if ($distmodules->{$m}{MAINTAINER} ne 'P5P') { | 
| 1086 | 0 |  |  |  |  |  | warn "Distro $m has MAINTAINER other than 'P5P'"; | 
| 1087 |  |  |  |  |  |  | } | 
| 1088 |  |  |  |  |  |  | } | 
| 1089 |  |  |  |  |  |  |  | 
| 1090 | 0 | 0 |  |  |  |  | if ($verbose) { | 
| 1091 | 0 |  |  |  |  |  | say "p5-dist-backcompat"; | 
| 1092 | 0 |  |  |  |  |  | my $ldescribe = length $describe; | 
| 1093 |  |  |  |  |  |  | my $message = q|Found | . | 
| 1094 | 0 |  |  |  |  |  | (scalar keys %{$distmodules}) . | 
|  | 0 |  |  |  |  |  |  | 
| 1095 |  |  |  |  |  |  | q| 'dist/' entries in %Maintainers::Modules|; | 
| 1096 | 0 |  |  |  |  |  | my $lmessage = length $message; | 
| 1097 | 0 |  |  |  |  |  | my $ldiff = $lmessage - $ldescribe; | 
| 1098 | 0 |  |  |  |  |  | say sprintf "%-${ldiff}s%s" => ('Results at commit:', $describe); | 
| 1099 | 0 |  |  |  |  |  | say "\n$message"; | 
| 1100 |  |  |  |  |  |  | } | 
| 1101 | 0 |  |  |  |  |  | return 1; | 
| 1102 |  |  |  |  |  |  | } | 
| 1103 |  |  |  |  |  |  |  | 
| 1104 |  |  |  |  |  |  | =head2 C | 
| 1105 |  |  |  |  |  |  |  | 
| 1106 |  |  |  |  |  |  | =over 4 | 
| 1107 |  |  |  |  |  |  |  | 
| 1108 |  |  |  |  |  |  | =item * Purpose | 
| 1109 |  |  |  |  |  |  |  | 
| 1110 |  |  |  |  |  |  | Get a sorted list of all files in F (without their descriptions). | 
| 1111 |  |  |  |  |  |  |  | 
| 1112 |  |  |  |  |  |  | =item * Arguments | 
| 1113 |  |  |  |  |  |  |  | 
| 1114 |  |  |  |  |  |  | read_manifest('/path/to/MANIFEST'); | 
| 1115 |  |  |  |  |  |  |  | 
| 1116 |  |  |  |  |  |  | One scalar: the path to F in a git checkout of the Perl 5 core distribution. | 
| 1117 |  |  |  |  |  |  |  | 
| 1118 |  |  |  |  |  |  | =item * Return Value | 
| 1119 |  |  |  |  |  |  |  | 
| 1120 |  |  |  |  |  |  | List (sorted) of all files in F. | 
| 1121 |  |  |  |  |  |  |  | 
| 1122 |  |  |  |  |  |  | =item * Comment | 
| 1123 |  |  |  |  |  |  |  | 
| 1124 |  |  |  |  |  |  | Depends on C from F. | 
| 1125 |  |  |  |  |  |  |  | 
| 1126 |  |  |  |  |  |  | (This is so elementary and useful that it should probably be in F!) | 
| 1127 |  |  |  |  |  |  |  | 
| 1128 |  |  |  |  |  |  | =back | 
| 1129 |  |  |  |  |  |  |  | 
| 1130 |  |  |  |  |  |  | =cut | 
| 1131 |  |  |  |  |  |  |  | 
| 1132 |  |  |  |  |  |  | sub read_manifest { | 
| 1133 | 0 |  |  | 0 | 1 |  | my $manifest = shift; | 
| 1134 | 0 | 0 |  |  |  |  | open(my $IN, '<', $manifest) or die("Can't read '$manifest': $!"); | 
| 1135 | 0 |  |  |  |  |  | my @manifest = <$IN>; | 
| 1136 | 0 | 0 |  |  |  |  | close($IN) or die($!); | 
| 1137 | 0 |  |  |  |  |  | chomp(@manifest); | 
| 1138 |  |  |  |  |  |  |  | 
| 1139 | 0 |  |  |  |  |  | my %seen= ( '' => 1 ); # filter out blank lines | 
| 1140 | 0 |  |  |  |  |  | return grep { !$seen{$_}++ } sort_manifest(@manifest); | 
|  | 0 |  |  |  |  |  |  | 
| 1141 |  |  |  |  |  |  | } | 
| 1142 |  |  |  |  |  |  |  | 
| 1143 |  |  |  |  |  |  | 1; | 
| 1144 |  |  |  |  |  |  |  |