| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Test::Prereq::Meta; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 6 |  |  | 6 |  | 296636 | use 5.010;	# because Module::Extract::Use has this. | 
|  | 6 |  |  |  |  | 57 |  | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 6 |  |  | 6 |  | 35 | use strict; | 
|  | 6 |  |  |  |  | 10 |  | 
|  | 6 |  |  |  |  | 137 |  | 
| 6 | 6 |  |  | 6 |  | 31 | use warnings; | 
|  | 6 |  |  |  |  | 9 |  | 
|  | 6 |  |  |  |  | 154 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 6 |  |  | 6 |  | 29 | use Carp; | 
|  | 6 |  |  |  |  | 21 |  | 
|  | 6 |  |  |  |  | 385 |  | 
| 9 | 6 |  |  | 6 |  | 2704 | use CPAN::Meta; | 
|  | 6 |  |  |  |  | 154876 |  | 
|  | 6 |  |  |  |  | 205 |  | 
| 10 | 6 |  |  | 6 |  | 55 | use Exporter qw{ import }; | 
|  | 6 |  |  |  |  | 12 |  | 
|  | 6 |  |  |  |  | 236 |  | 
| 11 | 6 |  |  | 6 |  | 3393 | use ExtUtils::Manifest (); | 
|  | 6 |  |  |  |  | 62057 |  | 
|  | 6 |  |  |  |  | 177 |  | 
| 12 | 6 |  |  | 6 |  | 48 | use File::Find (); | 
|  | 6 |  |  |  |  | 13 |  | 
|  | 6 |  |  |  |  | 88 |  | 
| 13 | 6 |  |  | 6 |  | 32 | use File::Glob (); | 
|  | 6 |  |  |  |  | 11 |  | 
|  | 6 |  |  |  |  | 94 |  | 
| 14 | 6 |  |  | 6 |  | 26 | use File::Spec; | 
|  | 6 |  |  |  |  | 14 |  | 
|  | 6 |  |  |  |  | 102 |  | 
| 15 | 6 |  |  | 6 |  | 3032 | use Module::Extract::Use; | 
|  | 6 |  |  |  |  | 11361 |  | 
|  | 6 |  |  |  |  | 194 |  | 
| 16 | 6 |  |  | 6 |  | 17481 | use Module::CoreList; | 
|  | 6 |  |  |  |  | 607234 |  | 
|  | 6 |  |  |  |  | 90 |  | 
| 17 | 6 |  |  | 6 |  | 8851 | use Module::Metadata; | 
|  | 6 |  |  |  |  | 35756 |  | 
|  | 6 |  |  |  |  | 222 |  | 
| 18 | 6 |  |  | 6 |  | 46 | use Scalar::Util (); | 
|  | 6 |  |  |  |  | 16 |  | 
|  | 6 |  |  |  |  | 134 |  | 
| 19 | 6 |  |  | 6 |  | 33 | use Test::More 0.88; | 
|  | 6 |  |  |  |  | 145 |  | 
|  | 6 |  |  |  |  | 66 |  | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | our $VERSION = '0.002_01'; | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | our @EXPORT_OK = qw{ all_prereq_ok file_prereq_ok prereq_ok }; | 
| 24 |  |  |  |  |  |  | our %EXPORT_TAGS = ( | 
| 25 |  |  |  |  |  |  | all	=> \@EXPORT_OK, | 
| 26 |  |  |  |  |  |  | ); | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | # Hash lifted verbatim from File::Spec 3.78 published 2018-08-29 | 
| 29 |  |  |  |  |  |  | use constant DEFAULT_PATH_TYPE	=> { | 
| 30 |  |  |  |  |  |  | MSWin32 => 'Win32', | 
| 31 |  |  |  |  |  |  | os2     => 'OS2', | 
| 32 |  |  |  |  |  |  | VMS     => 'VMS', | 
| 33 |  |  |  |  |  |  | NetWare => 'Win32', # Yes, File::Spec::Win32 works on NetWare. | 
| 34 |  |  |  |  |  |  | symbian => 'Win32', # Yes, File::Spec::Win32 works on symbian. | 
| 35 |  |  |  |  |  |  | dos     => 'OS2',   # Yes, File::Spec::OS2 works on DJGPP. | 
| 36 |  |  |  |  |  |  | cygwin  => 'Cygwin', | 
| 37 |  |  |  |  |  |  | amigaos => 'AmigaOS', | 
| 38 | 6 |  | 50 | 6 |  | 2136 | }->{$^O} || 'Unix'; | 
|  | 6 |  |  |  |  | 30 |  | 
|  | 6 |  |  |  |  | 731 |  | 
| 39 |  |  |  |  |  |  |  | 
| 40 | 6 |  |  | 6 |  | 42 | use constant REF_ARRAY	=> ref []; | 
|  | 6 |  |  |  |  | 14 |  | 
|  | 6 |  |  |  |  | 11653 |  | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | sub new { | 
| 43 | 16 |  |  | 16 | 1 | 18825 | my ( $class, %arg ) = @_; | 
| 44 |  |  |  |  |  |  |  | 
| 45 | 16 |  | 50 |  |  | 129 | $arg{file_error} //= 'Failed to analyze %f: %e'; | 
| 46 | 16 |  | 100 |  |  | 80 | $arg{name} //= 'Prereq test: %f uses %m'; | 
| 47 |  |  |  |  |  |  | # NOTE that {path_type} is unsupported, and may change or be | 
| 48 |  |  |  |  |  |  | # retracted without warning. I thought I needed it to support | 
| 49 |  |  |  |  |  |  | # argument {prune}, which is itself experimental. | 
| 50 | 16 |  | 50 |  |  | 101 | $arg{path_type} //= DEFAULT_PATH_TYPE; | 
| 51 | 16 |  | 50 |  |  | 98 | $arg{per_file_note} //= '%f'; | 
| 52 | 16 |  | 100 |  |  | 98 | $arg{perl_version} //= 'none'; | 
| 53 | 16 |  | 50 |  |  | 103 | $arg{skip_name} //= 'Prereq test: %f does not use any modules'; | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | state $default = { | 
| 56 |  |  |  |  |  |  | accept	=> [], | 
| 57 |  |  |  |  |  |  | meta_file	=> [ qw{ | 
| 58 |  |  |  |  |  |  | MYMETA.json MYMETA.yml META.json META.yml } ], | 
| 59 |  |  |  |  |  |  | prune	=> [], | 
| 60 |  |  |  |  |  |  | uses	=> [], | 
| 61 |  |  |  |  |  |  | verbose	=> ( | 
| 62 | 16 | 50 |  |  |  | 52 | scalar grep { -d } qw{ .bzr .cdv .git .hg .svn CVS } ) ? 1 : 0, | 
|  | 30 |  |  |  |  | 323 |  | 
| 63 |  |  |  |  |  |  | }; | 
| 64 | 16 |  |  |  |  | 36 | foreach my $name ( keys %{ $default } ) { | 
|  | 16 |  |  |  |  | 86 |  | 
| 65 | 80 |  | 100 |  |  | 371 | $arg{$name} //= $default->{$name}; | 
| 66 |  |  |  |  |  |  | my $code = __PACKAGE__->can( "__validate_$name" ) || | 
| 67 |  |  |  |  |  |  | __PACKAGE__->can( '__validate_' . ref $default->{$name} ) || | 
| 68 | 80 |  | 100 | 16 |  | 844 | sub {}; | 
| 69 | 80 |  |  |  |  | 323 | $code->( $name, \%arg ); | 
| 70 |  |  |  |  |  |  | } | 
| 71 |  |  |  |  |  |  |  | 
| 72 | 16 |  |  |  |  | 44 | my $core_modules; | 
| 73 |  |  |  |  |  |  | { | 
| 74 |  |  |  |  |  |  | # %Module::CoreList::version is public, so I figured the easiest | 
| 75 |  |  |  |  |  |  | # implementation of the 'special' Perl versions was to just hack | 
| 76 |  |  |  |  |  |  | # them into it. | 
| 77 | 16 |  |  |  |  | 30 | local $Module::CoreList::version{none} = {}; | 
|  | 16 |  |  |  |  | 68 |  | 
| 78 |  |  |  |  |  |  | local $Module::CoreList::version{this} = | 
| 79 | 16 |  |  |  |  | 97 | $Module::CoreList::version{$]}; | 
| 80 |  |  |  |  |  |  | $core_modules = $Module::CoreList::version{$arg{perl_version}} | 
| 81 | 16 | 50 |  |  |  | 98 | or croak( "Unknown 'perl_version' $arg{perl_version}" ); | 
| 82 |  |  |  |  |  |  | } | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | # The below is pretty much verbatim from the CPAN::Meta synopsis | 
| 85 |  |  |  |  |  |  |  | 
| 86 | 16 |  |  |  |  | 46 | my $meta_data = $arg{_meta_file}; | 
| 87 |  |  |  |  |  |  |  | 
| 88 | 16 |  |  |  |  | 36 | my %requires; | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 16 |  |  |  |  | 85 | my $prereqs = $meta_data->effective_prereqs(); | 
| 91 | 16 |  |  |  |  | 15738 | foreach my $phase ( qw{ configure build test runtime } ) { | 
| 92 | 64 |  |  |  |  | 278 | my $reqs = $prereqs->requirements_for( $phase, 'requires' ); | 
| 93 | 64 |  |  |  |  | 2529 | foreach my $module ( $reqs->required_modules() ) { | 
| 94 | 169 |  |  |  |  | 558 | $requires{$module} = {}; | 
| 95 |  |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  | } | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | # The above is pretty much verbatim from the CPAN::Meta synopsis | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | # NOTE that if we actually need the Perl version, we need to nab it | 
| 101 |  |  |  |  |  |  | # before here. | 
| 102 | 16 |  |  |  |  | 44 | delete $requires{perl}; | 
| 103 |  |  |  |  |  |  |  | 
| 104 | 16 |  |  |  |  | 69 | my $provides = _provides(); | 
| 105 |  |  |  |  |  |  |  | 
| 106 | 2159 |  |  |  |  | 4009 | my %has = map { $_ => 1 } | 
| 107 | 16 |  |  |  |  | 57 | @{ $arg{accept} }, | 
| 108 | 16 |  |  |  |  | 551 | keys %{ $core_modules }, | 
| 109 | 16 |  |  |  |  | 82 | keys %{ $provides }, | 
|  | 16 |  |  |  |  | 107 |  | 
| 110 |  |  |  |  |  |  | keys %requires, | 
| 111 |  |  |  |  |  |  | ; | 
| 112 |  |  |  |  |  |  |  | 
| 113 | 16 |  |  |  |  | 199 | $arg{uses} = { map { $_ => 1 } @{ $arg{uses} } }; | 
|  | 2 |  |  |  |  | 10 |  | 
|  | 16 |  |  |  |  | 61 |  | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 16 | 100 |  |  |  | 88 | if ( $arg{verbose} ) { | 
| 116 | 2 |  |  |  |  | 5 | my @dup; | 
| 117 | 2 | 100 |  |  |  | 4 | @dup = grep { $requires{$_} } @{ $arg{accept} } | 
|  | 1 |  |  |  |  | 7 |  | 
|  | 2 |  |  |  |  | 8 |  | 
| 118 |  |  |  |  |  |  | and diag "The following @{[ | 
| 119 | 1 | 50 |  |  |  | 19 | @dup == 1 ? 'module appears' : 'modules appear' | 
| 120 |  |  |  |  |  |  | ]} in both the prerequisites and\nthe 'accept' argument: ", | 
| 121 |  |  |  |  |  |  | join ', ', sort @dup; | 
| 122 | 2 | 100 |  |  |  | 451 | @dup = grep { $arg{uses}{$_} } @{ $arg{accept} } | 
|  | 1 |  |  |  |  | 8 |  | 
|  | 2 |  |  |  |  | 9 |  | 
| 123 |  |  |  |  |  |  | and diag "The following @{[ | 
| 124 | 1 | 50 |  |  |  | 12 | @dup == 1 ? 'module appears' : 'modules appear' | 
| 125 |  |  |  |  |  |  | ]} in both the 'accept' argument and\nthe 'uses' argument: ", | 
| 126 |  |  |  |  |  |  | join ', ', sort @dup; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 16 |  |  |  |  | 301 | delete $arg{accept}; | 
| 130 | 16 |  |  |  |  | 81 | delete $arg{_meta_file}; | 
| 131 | 16 |  |  |  |  | 42 | delete $arg{path_type}; | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | my $self = bless { | 
| 134 |  |  |  |  |  |  | # accept		=> $arg{accept}, | 
| 135 |  |  |  |  |  |  | # core_modules	=> $core_modules, | 
| 136 |  |  |  |  |  |  | file_error	=> delete $arg{file_error}, | 
| 137 |  |  |  |  |  |  | has		=> \%has, | 
| 138 |  |  |  |  |  |  | meta_file	=> delete $arg{meta_file}, | 
| 139 |  |  |  |  |  |  | meta_data	=> $meta_data, | 
| 140 |  |  |  |  |  |  | name		=> delete $arg{name}, | 
| 141 |  |  |  |  |  |  | per_file_note	=> delete $arg{per_file_note}, | 
| 142 |  |  |  |  |  |  | perl_version	=> delete $arg{perl_version}, | 
| 143 |  |  |  |  |  |  | prune		=> delete $arg{prune}, | 
| 144 |  |  |  |  |  |  | # provides	=> $provides, | 
| 145 |  |  |  |  |  |  | skip_name	=> delete $arg{skip_name}, | 
| 146 |  |  |  |  |  |  | uses		=> delete $arg{uses}, | 
| 147 |  |  |  |  |  |  | verbose		=> delete $arg{verbose}, | 
| 148 |  |  |  |  |  |  | _both_tools	=> ( -e 'Makefile.PL' && -e 'Build.PL' ), | 
| 149 |  |  |  |  |  |  | _normalize_path	=> delete $arg{_normalize_path}, | 
| 150 | 16 |  | 33 |  |  | 890 | _requires	=> \%requires, | 
|  |  |  | 33 |  |  |  |  | 
| 151 |  |  |  |  |  |  | }, ref $class || $class; | 
| 152 |  |  |  |  |  |  |  | 
| 153 | 16 | 100 |  |  |  | 106 | if ( my $num = keys %arg ) { | 
| 154 | 1 | 50 |  |  |  | 11 | croak "Unknown argument@{[ $num > 1 ? 's' : '' ]} ", join ', ', | 
| 155 | 1 |  |  |  |  | 3 | map { "'$_'" } sort keys %arg; | 
|  | 1 |  |  |  |  | 207 |  | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  |  | 
| 158 | 15 |  |  |  |  | 401 | return $self; | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | sub all_prereq_ok { | 
| 162 | 10 |  |  | 10 | 1 | 60 | my ( $self, @file ) = _unpack_args( @_ ); | 
| 163 |  |  |  |  |  |  |  | 
| 164 | 10 | 100 |  |  |  | 36 | unless( @file ) { | 
| 165 |  |  |  |  |  |  | @file = ( | 
| 166 | 8 |  |  |  |  | 350 | ( grep { -d } qw{ blib/arch blib/lib blib/script t } ), | 
| 167 | 2 |  |  |  |  | 8 | ( map { File::Spec->abs2rel( $_ ) } | 
|  | 4 |  |  |  |  | 368 |  | 
| 168 |  |  |  |  |  |  | File::Glob::bsd_glob( '*.PL' ) ), | 
| 169 |  |  |  |  |  |  | ); | 
| 170 |  |  |  |  |  |  | } | 
| 171 |  |  |  |  |  |  |  | 
| 172 | 10 |  |  |  |  | 26 | my $need_skip = 1; | 
| 173 | 10 |  |  |  |  | 20 | my $ok = 1; | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | File::Find::find( | 
| 176 |  |  |  |  |  |  | { | 
| 177 |  |  |  |  |  |  | wanted	=> sub { | 
| 178 | 63 | 100 |  | 63 |  | 300 | if ( $self->{_normalize_path} ) { | 
| 179 | 1 |  |  |  |  | 5 | $self->{_normalize_path}->(); | 
| 180 | 1 | 50 |  |  |  | 5 | if ( $self->{prune}{$_} ) { | 
| 181 | 1 |  |  |  |  | 3 | $File::Find::prune = 1; | 
| 182 | 1 |  |  |  |  | 12 | return; | 
| 183 |  |  |  |  |  |  | } | 
| 184 |  |  |  |  |  |  | } | 
| 185 | 62 | 100 |  |  |  | 191 | _is_perl( $_ ) | 
| 186 |  |  |  |  |  |  | or return; | 
| 187 |  |  |  |  |  |  | # The following is because File::Find tends to give us | 
| 188 |  |  |  |  |  |  | # './fubar' if 'fubar' is in the current directory. | 
| 189 | 29 |  |  |  |  | 3373 | $_ = File::Spec->abs2rel( $_ ); | 
| 190 | 29 |  |  |  |  | 109 | $need_skip = 0; | 
| 191 | 29 | 100 |  |  |  | 126 | $self->file_prereq_ok( $_ ) | 
| 192 |  |  |  |  |  |  | or $ok = 0; | 
| 193 | 29 |  |  |  |  | 964 | return; | 
| 194 |  |  |  |  |  |  | }, | 
| 195 |  |  |  |  |  |  | no_chdir	=> 1, | 
| 196 | 23 |  |  | 23 |  | 939 | preprocess	=> sub { return( sort @_ ) }, | 
| 197 |  |  |  |  |  |  | }, | 
| 198 | 10 |  |  |  |  | 1175 | @file, | 
| 199 |  |  |  |  |  |  | ); | 
| 200 |  |  |  |  |  |  |  | 
| 201 | 10 | 100 |  |  |  | 122 | if ( $need_skip ) { | 
| 202 | 1 |  |  |  |  | 10 | state $TEST = Test::More->builder(); | 
| 203 | 1 |  |  |  |  | 17 | local $Test::Builder::Level = _nest_depth(); | 
| 204 |  |  |  |  |  |  | # $TEST->skip( "$file does not use any modules" ); | 
| 205 | 1 |  |  |  |  | 5 | $TEST->skip( 'No Perl files found' ); | 
| 206 |  |  |  |  |  |  | } | 
| 207 |  |  |  |  |  |  |  | 
| 208 | 10 |  |  |  |  | 673 | return $ok; | 
| 209 |  |  |  |  |  |  | } | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | sub all_prereqs_used { | 
| 212 | 3 |  |  | 3 | 1 | 438 | my ( $self ) = @_; | 
| 213 |  |  |  |  |  |  |  | 
| 214 | 3 |  |  |  |  | 23 | state $TEST = Test::More->builder(); | 
| 215 | 3 |  |  |  |  | 36 | local $Test::Builder::Level = _nest_depth(); | 
| 216 |  |  |  |  |  |  |  | 
| 217 | 3 |  |  |  |  | 15 | $TEST->note( '' ); | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | my @unused = sort | 
| 220 | 19 |  | 100 |  |  | 124 | grep { ! $self->{uses}{$_} && ! $self->{_requires}{$_}{file} } | 
| 221 | 3 |  |  |  |  | 890 | keys %{ $self->{_requires} }; | 
|  | 3 |  |  |  |  | 21 |  | 
| 222 | 3 | 100 |  |  |  | 18 | my $rslt = $TEST->ok( ! @unused, 'All required modules are used' ) | 
| 223 |  |  |  |  |  |  | or $TEST->diag( "The following @{[ | 
| 224 | 1 | 50 |  |  |  | 1193 | @unused == 1 ? 'prerequisite is' : 'prerequisites are' | 
| 225 |  |  |  |  |  |  | ]} unused: ", join ', ', @unused ); | 
| 226 |  |  |  |  |  |  |  | 
| 227 | 3 | 100 | 66 |  |  | 880 | if ( $self->{verbose} and | 
| 228 | 1 | 50 |  |  |  | 13 | my @dup = grep { $self->{_requires}{$_}{file} && $self->{uses}{$_} } | 
| 229 | 1 |  |  |  |  | 5 | keys %{ $self->{_requires} } | 
| 230 |  |  |  |  |  |  | ) { | 
| 231 | 1 |  |  |  |  | 3 | $TEST->diag( "The following @{[ | 
| 232 | 1 | 50 |  |  |  | 13 | @dup == 1 ? 'module appears' : 'modules appear' | 
| 233 |  |  |  |  |  |  | ]} in both 'use' statements and\nthe 'uses' argument: ", | 
| 234 |  |  |  |  |  |  | join ', ', sort @dup ); | 
| 235 |  |  |  |  |  |  | } | 
| 236 |  |  |  |  |  |  |  | 
| 237 | 3 |  |  |  |  | 281 | return $rslt; | 
| 238 |  |  |  |  |  |  | } | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | sub file_prereq_ok { | 
| 241 | 35 |  |  | 35 | 1 | 159 | my ( $self, $file, @arg ) = _unpack_args( @_ ); | 
| 242 |  |  |  |  |  |  | @arg | 
| 243 | 35 | 50 |  |  |  | 116 | and confess( | 
| 244 |  |  |  |  |  |  | 'Usage: $tpm->file_prereq_ok( $file ) or file_prereq_ok( $file )' ); | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | # Because this gets us a pre-built object I use $Test::Builder::Level | 
| 247 |  |  |  |  |  |  | # (localized) to get tests reported relative to the correct file and | 
| 248 |  |  |  |  |  |  | # line, rather than setting the 'level' attribute. | 
| 249 | 35 |  |  |  |  | 135 | state $TEST = Test::More->builder(); | 
| 250 | 35 |  |  |  |  | 185 | local $Test::Builder::Level = _nest_depth(); | 
| 251 |  |  |  |  |  |  |  | 
| 252 | 35 | 50 |  |  |  | 131 | if ( $self->{per_file_note} ne '' ) { | 
| 253 |  |  |  |  |  |  | # We are not interested in the actual test number, but we need | 
| 254 |  |  |  |  |  |  | # to know how many digits it is so that the note can be indented | 
| 255 |  |  |  |  |  |  | # properly. | 
| 256 | 35 |  |  |  |  | 204 | $TEST->note( '' ); | 
| 257 |  |  |  |  |  |  | $TEST->note( | 
| 258 |  |  |  |  |  |  | ' ' x ( 4 + length( $TEST->current_test() + 1 ) ), | 
| 259 |  |  |  |  |  |  | _format( | 
| 260 |  |  |  |  |  |  | $self->{per_file_note}, | 
| 261 |  |  |  |  |  |  | { | 
| 262 | 35 |  |  |  |  | 13366 | e	=> '', | 
| 263 |  |  |  |  |  |  | f	=> $file, | 
| 264 |  |  |  |  |  |  | m	=> '', | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  | ), | 
| 267 |  |  |  |  |  |  | ); | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  |  | 
| 270 | 35 |  |  |  |  | 9630 | my $need_skip = 1; | 
| 271 | 35 |  |  |  |  | 89 | my $ok = 1; | 
| 272 | 35 |  |  |  |  | 78 | my %module_found; | 
| 273 |  |  |  |  |  |  |  | 
| 274 | 35 |  |  |  |  | 95 | state $extor = Module::Extract::Use->new(); | 
| 275 |  |  |  |  |  |  |  | 
| 276 | 35 |  |  |  |  | 240 | my $modules = $extor->get_modules_with_details( $file ); | 
| 277 | 35 | 100 |  |  |  | 3475160 | if ( my $err = $extor->error() ) { | 
| 278 |  |  |  |  |  |  | $TEST->ok( 0, | 
| 279 |  |  |  |  |  |  | _format( | 
| 280 |  |  |  |  |  |  | $self->{file_error}, | 
| 281 |  |  |  |  |  |  | { | 
| 282 | 1 |  |  |  |  | 12 | e	=> $err, | 
| 283 |  |  |  |  |  |  | f	=> $file, | 
| 284 |  |  |  |  |  |  | m	=> '', | 
| 285 |  |  |  |  |  |  | }, | 
| 286 |  |  |  |  |  |  | ) | 
| 287 |  |  |  |  |  |  | ); | 
| 288 | 1 |  |  |  |  | 1583 | return 0; | 
| 289 |  |  |  |  |  |  | } | 
| 290 |  |  |  |  |  |  |  | 
| 291 | 34 |  |  |  |  | 265 | foreach my $usage ( | 
| 292 | 215 |  |  |  |  | 499 | sort { $a->{module} cmp $b->{module} } | 
| 293 | 34 |  |  |  |  | 233 | @{ $modules } | 
| 294 |  |  |  |  |  |  | ) { | 
| 295 | 137 |  |  |  |  | 32843 | my $module = $usage->{module}; | 
| 296 |  |  |  |  |  |  |  | 
| 297 |  |  |  |  |  |  | # The following is needed because Module::Extract::Use tries too | 
| 298 |  |  |  |  |  |  | # hard to find return() statements embedded in other statements. | 
| 299 | 137 | 100 |  |  |  | 904 | $module =~ m/ \A [\w:]+ \z /smx | 
| 300 |  |  |  |  |  |  | or next; | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  | # The following is needed because Module::Extract::Use returns | 
| 303 |  |  |  |  |  |  | # duplicate 'require' statements because it finds them both in | 
| 304 |  |  |  |  |  |  | # the scan for PPI::Statement::Include objects and in the scan | 
| 305 |  |  |  |  |  |  | # for PPI::Token::Word 'require' objects. | 
| 306 | 136 | 100 |  |  |  | 1071 | $module_found{$module}++ | 
| 307 |  |  |  |  |  |  | and next; | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | $self->{_requires}{$module} | 
| 310 | 134 | 100 | 100 |  |  | 479 | and push @{ $self->{_requires}{$module}{file} ||= [] }, $file; | 
|  | 107 |  |  |  |  | 622 |  | 
| 311 |  |  |  |  |  |  |  | 
| 312 | 134 |  |  |  |  | 277 | state $toolchain = { | 
| 313 |  |  |  |  |  |  | 'Makefile.PL'	=> { | 
| 314 |  |  |  |  |  |  | 'ExtUtils::MakeMaker'	=> 1, | 
| 315 |  |  |  |  |  |  | 'inc::Module::Install'	=> 1, | 
| 316 |  |  |  |  |  |  | }, | 
| 317 |  |  |  |  |  |  | 'Build.PL'		=> { | 
| 318 |  |  |  |  |  |  | 'Module::Build'		=> 1, | 
| 319 |  |  |  |  |  |  | 'Module::Build::Tiny'	=> 1, | 
| 320 |  |  |  |  |  |  | }, | 
| 321 |  |  |  |  |  |  | }; | 
| 322 |  |  |  |  |  |  |  | 
| 323 | 134 |  |  |  |  | 202 | $need_skip = 0; | 
| 324 |  |  |  |  |  |  | $TEST->ok( | 
| 325 |  |  |  |  |  |  | $self->{has}{$module} || | 
| 326 |  |  |  |  |  |  | $self->{_both_tools} && $toolchain->{$file}{$module} || | 
| 327 |  |  |  |  |  |  | 0, | 
| 328 |  |  |  |  |  |  | _format( | 
| 329 |  |  |  |  |  |  | $self->{name}, | 
| 330 |  |  |  |  |  |  | { | 
| 331 | 134 | 100 | 100 |  |  | 922 | e	=> '', | 
| 332 |  |  |  |  |  |  | f	=> $file, | 
| 333 |  |  |  |  |  |  | m	=> $module, | 
| 334 |  |  |  |  |  |  | }, | 
| 335 |  |  |  |  |  |  | ), | 
| 336 |  |  |  |  |  |  | ) or $ok = 0; | 
| 337 |  |  |  |  |  |  |  | 
| 338 |  |  |  |  |  |  | } | 
| 339 |  |  |  |  |  |  |  | 
| 340 | 34 | 100 |  |  |  | 10128 | if ( $need_skip ) { | 
| 341 | 4 |  |  |  |  | 24 | local $Test::Builder::Level = _nest_depth(); | 
| 342 |  |  |  |  |  |  | # $TEST->skip( "$file does not use any modules" ); | 
| 343 |  |  |  |  |  |  | $TEST->skip( _format( | 
| 344 |  |  |  |  |  |  | $self->{skip_name}, | 
| 345 |  |  |  |  |  |  | { | 
| 346 | 4 |  |  |  |  | 31 | e	=> '', | 
| 347 |  |  |  |  |  |  | f	=> $file, | 
| 348 |  |  |  |  |  |  | m	=> '', | 
| 349 |  |  |  |  |  |  | }, | 
| 350 |  |  |  |  |  |  | ), | 
| 351 |  |  |  |  |  |  | ); | 
| 352 |  |  |  |  |  |  | } | 
| 353 |  |  |  |  |  |  |  | 
| 354 | 34 |  |  |  |  | 2486 | return $ok; | 
| 355 |  |  |  |  |  |  | } | 
| 356 |  |  |  |  |  |  |  | 
| 357 |  |  |  |  |  |  | sub _format { | 
| 358 | 174 |  |  | 174 |  | 4937 | my ( $tplt, $sub ) = @_; | 
| 359 | 174 |  | 33 |  |  | 991 | $tplt =~ s| % ( . ) | $sub->{$1} // $1 |smxge; | 
|  | 307 |  |  |  |  | 1451 |  | 
| 360 | 174 |  |  |  |  | 805 | return $tplt; | 
| 361 |  |  |  |  |  |  | } | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  | sub prereq_ok { | 
| 364 | 1 |  |  | 1 | 1 | 86 | my ( $perl_version, $name, $accept ) = @_; | 
| 365 | 1 |  | 33 |  |  | 13 | my $self = __PACKAGE__->new( | 
| 366 |  |  |  |  |  |  | accept		=> $accept, | 
| 367 |  |  |  |  |  |  | name		=> $name, | 
| 368 |  |  |  |  |  |  | perl_version	=> $perl_version // $], | 
| 369 |  |  |  |  |  |  | ); | 
| 370 | 1 |  |  |  |  | 8 | return $self->all_prereq_ok(); | 
| 371 |  |  |  |  |  |  | } | 
| 372 |  |  |  |  |  |  |  | 
| 373 |  |  |  |  |  |  | sub _is_perl { | 
| 374 | 62 |  |  | 62 |  | 146 | my ( $file ) = @_; | 
| 375 | 62 | 100 |  |  |  | 6418 | -T $file | 
| 376 |  |  |  |  |  |  | or return 0; | 
| 377 | 39 | 100 |  |  |  | 462 | $file =~ m/ [.] (?: (?i: pl ) | pm | t ) \z /smx | 
| 378 |  |  |  |  |  |  | and return 1; | 
| 379 | 10 | 50 |  |  |  | 344 | open my $fh, '<', $file | 
| 380 |  |  |  |  |  |  | or return 0; | 
| 381 | 10 |  |  |  |  | 137 | local $_ = <$fh>; | 
| 382 | 10 |  |  |  |  | 124 | close $fh; | 
| 383 |  |  |  |  |  |  | defined | 
| 384 | 10 | 50 |  |  |  | 35 | or return 0; | 
| 385 | 10 |  |  |  |  | 286 | return m/ \A [#]! .* perl /smx; | 
| 386 |  |  |  |  |  |  | } | 
| 387 |  |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | { | 
| 389 |  |  |  |  |  |  | my %ignore; | 
| 390 |  |  |  |  |  |  | BEGIN { | 
| 391 | 6 |  |  | 6 |  | 35 | %ignore = map { $_ => 1 } __PACKAGE__, qw{ DB File::Find }; | 
|  | 18 |  |  |  |  | 5118 |  | 
| 392 |  |  |  |  |  |  | } | 
| 393 |  |  |  |  |  |  |  | 
| 394 |  |  |  |  |  |  | sub _nest_depth { | 
| 395 | 43 |  |  | 43 |  | 89 | my $nest = 0; | 
| 396 | 43 |  | 50 |  |  | 505 | $nest++ while $ignore{ caller( $nest ) || '' }; | 
| 397 | 43 |  |  |  |  | 119 | return $nest; | 
| 398 |  |  |  |  |  |  | } | 
| 399 |  |  |  |  |  |  | } | 
| 400 |  |  |  |  |  |  |  | 
| 401 |  |  |  |  |  |  | # All the __normalize_path_* subroutines operate on $_. They take no | 
| 402 |  |  |  |  |  |  | # arguments and return nothing relevant. The names are File::Spec:: | 
| 403 |  |  |  |  |  |  | # OS-specific class names, and the intent is that anything supported by | 
| 404 |  |  |  |  |  |  | # File::Spec should appear here. | 
| 405 |  |  |  |  |  |  |  | 
| 406 |  |  |  | 1 |  |  | sub __normalize_path_AmigaOS {}	# Assumed based on File::Spec::AmigaOS | 
| 407 |  |  |  |  |  |  |  | 
| 408 |  |  |  | 1 |  |  | sub __normalize_path_Cygwin {}	# I believe. | 
| 409 |  |  |  |  |  |  |  | 
| 410 | 1 |  |  | 1 |  | 514 | sub __normalize_path_OS2 { s| \\ |/|smxg; }	## no critic (RequireFinalReturn) | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  | 3 |  |  | sub __normalize_path_Unix {} | 
| 413 |  |  |  |  |  |  |  | 
| 414 |  |  |  |  |  |  | sub __normalize_path_VMS { | 
| 415 | 1 |  |  | 1 |  | 692 | croak( 'Can not normalize VMS paths' ); | 
| 416 |  |  |  |  |  |  | } | 
| 417 |  |  |  |  |  |  |  | 
| 418 | 1 |  |  | 1 |  | 585 | sub __normalize_path_Win32 { s| \\ |/|smxg; }	## no critic (RequireFinalReturn) | 
| 419 |  |  |  |  |  |  |  | 
| 420 |  |  |  |  |  |  | # We don't use Module::Metadata->provides(), because it filters out | 
| 421 |  |  |  |  |  |  | # private packages. While we're at it, we just process every .pm we find. | 
| 422 |  |  |  |  |  |  | sub _provides { | 
| 423 | 16 |  |  | 16 |  | 38 | my %provides; | 
| 424 | 16 |  |  |  |  | 85 | my $manifest = ExtUtils::Manifest::maniread(); | 
| 425 | 16 |  |  |  |  | 9919 | foreach my $file ( keys %{ $manifest } ) { | 
|  | 16 |  |  |  |  | 147 |  | 
| 426 | 608 | 100 |  |  |  | 1434 | $file =~ m/ [.] pm \z /smx | 
| 427 |  |  |  |  |  |  | or next; | 
| 428 | 64 | 50 |  |  |  | 421 | my $info = Module::Metadata->new_from_file( $file ) | 
| 429 |  |  |  |  |  |  | or next; | 
| 430 | 64 |  |  |  |  | 283920 | foreach my $module ( $info->packages_inside() ) { | 
| 431 | 64 |  |  |  |  | 438 | state $ignore = { map { $_ => 1 } qw{ main DB } }; | 
|  | 10 |  |  |  |  | 37 |  | 
| 432 | 64 | 100 |  |  |  | 253 | $ignore->{$module} | 
| 433 |  |  |  |  |  |  | and next; | 
| 434 | 48 |  |  |  |  | 392 | $provides{$module} = 1; | 
| 435 |  |  |  |  |  |  | } | 
| 436 |  |  |  |  |  |  | } | 
| 437 | 16 |  |  |  |  | 299 | return \%provides; | 
| 438 |  |  |  |  |  |  | } | 
| 439 |  |  |  |  |  |  |  | 
| 440 |  |  |  |  |  |  | sub _unpack_args { | 
| 441 | 45 |  |  | 45 |  | 133 | my @arg = @_; | 
| 442 | 45 | 100 | 66 |  |  | 507 | my $self = ( ref( $arg[0] ) && ref( $arg[0] )->isa( __PACKAGE__ ) ) ? | 
| 443 |  |  |  |  |  |  | shift @arg : | 
| 444 |  |  |  |  |  |  | __PACKAGE__->new(); | 
| 445 | 45 |  |  |  |  | 209 | return ( $self, @arg ); | 
| 446 |  |  |  |  |  |  | } | 
| 447 |  |  |  |  |  |  |  | 
| 448 |  |  |  |  |  |  | sub __validate_meta_file { | 
| 449 | 16 |  |  | 16 |  | 50 | my ( $name, $arg ) = @_; | 
| 450 | 16 | 100 | 66 |  |  | 109 | if ( Scalar::Util::blessed( $arg->{$name} ) && | 
| 451 |  |  |  |  |  |  | $arg->{$name}->isa( 'CPAN::Meta' ) | 
| 452 |  |  |  |  |  |  | ) { | 
| 453 | 1 |  |  |  |  | 5 | $arg->{"_$name"} = $arg->{$name}; | 
| 454 | 1 |  |  |  |  | 4 | return; | 
| 455 |  |  |  |  |  |  | } | 
| 456 | 15 |  |  |  |  | 48 | __validate_ARRAY( $name, $arg ); | 
| 457 | 15 | 50 |  |  |  | 28 | @{ $arg->{$name} } | 
|  | 15 |  |  |  |  | 50 |  | 
| 458 |  |  |  |  |  |  | or croak( "'$name' must specify at least one file" ); | 
| 459 | 15 |  |  |  |  | 29 | foreach my $fn ( @{ $arg->{$name} } ) { | 
|  | 15 |  |  |  |  | 43 |  | 
| 460 | 16 | 100 |  |  |  | 346 | -r $fn | 
| 461 |  |  |  |  |  |  | or next; | 
| 462 | 15 |  |  |  |  | 57 | $arg->{$name} = $fn; | 
| 463 | 15 |  |  |  |  | 145 | $arg->{"_$name"} = CPAN::Meta->load_file( $fn ); | 
| 464 | 15 |  |  |  |  | 383920 | return; | 
| 465 |  |  |  |  |  |  | } | 
| 466 | 0 | 0 |  |  |  | 0 | 1 == @{ $arg } | 
|  | 0 |  |  |  |  | 0 |  | 
| 467 |  |  |  |  |  |  | and croak( "$arg->{$name}[0] not readable" ); | 
| 468 | 0 |  |  |  |  | 0 | local $" = ', '; | 
| 469 | 0 |  |  |  |  | 0 | croak( "None of @{ $arg->{$name} } readable" ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 470 |  |  |  |  |  |  | } | 
| 471 |  |  |  |  |  |  |  | 
| 472 |  |  |  |  |  |  | sub __validate_prune { | 
| 473 | 16 |  |  | 16 |  | 57 | my ( $name, $arg ) = @_; | 
| 474 | 16 |  |  |  |  | 60 | __validate_ARRAY( $name, $arg ); | 
| 475 | 16 |  |  |  |  | 27 | my %rslt; | 
| 476 | 16 |  |  |  |  | 31 | foreach ( @{ $arg->{$name} } ) { | 
|  | 16 |  |  |  |  | 50 |  | 
| 477 | 1 |  | 33 |  |  | 13 | $arg->{_normalize_path} ||= __PACKAGE__->can( | 
|  |  |  | 33 |  |  |  |  | 
| 478 |  |  |  |  |  |  | "__normalize_path_$arg->{path_type}" ) | 
| 479 |  |  |  |  |  |  | || croak( "Invalid path type '$arg->{path_type}'" ); | 
| 480 | 1 |  |  |  |  | 5 | $arg->{_normalize_path}->(); | 
| 481 | 1 |  |  |  |  | 4 | $rslt{$_} = 1; | 
| 482 |  |  |  |  |  |  | } | 
| 483 | 16 |  | 100 |  |  | 89 | $arg->{_normalize_path} ||= undef; | 
| 484 | 16 |  |  |  |  | 42 | $arg->{$name} = \%rslt; | 
| 485 | 16 |  |  |  |  | 37 | return; | 
| 486 |  |  |  |  |  |  | } | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | sub __validate_ARRAY { | 
| 489 | 63 |  |  | 63 |  | 142 | my ( $name, $arg ) = @_; | 
| 490 |  |  |  |  |  |  | ref $arg->{$name} | 
| 491 | 63 | 100 |  |  |  | 184 | or $arg->{$name} = [ $arg->{$name} ]; | 
| 492 | 63 | 50 |  |  |  | 170 | REF_ARRAY eq ref $arg->{$name} | 
| 493 |  |  |  |  |  |  | or croak( "'$name' must be a SCALAR or an ARRAY reference" ); | 
| 494 | 63 |  |  |  |  | 133 | return; | 
| 495 |  |  |  |  |  |  | } | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  | 1; | 
| 498 |  |  |  |  |  |  |  | 
| 499 |  |  |  |  |  |  | __END__ |