File Coverage

blib/lib/CPAN/Testers/Common/Client/PrereqCheck.pm
Criterion Covered Total %
statement 15 102 14.7
branch 0 58 0.0
condition 0 15 0.0
subroutine 5 7 71.4
pod n/a
total 20 182 10.9


line stmt bran cond sub pod time code
1 4     4   24 use strict;
  4         8  
  4         148  
2             package CPAN::Testers::Common::Client::PrereqCheck;
3              
4             # forked from CPAN::Reporter::PrereqCheck 1.2018
5              
6 4     4   2924 use ExtUtils::MakeMaker 6.36;
  4         346320  
  4         420  
7 4     4   31 use File::Spec;
  4         9  
  4         67  
8 4     4   1545 use CPAN::Version;
  4         3755  
  4         1125  
9              
10             _run() if ! caller();
11              
12             sub _run {
13 0     0     my %saw_mod;
14             # read module and prereq string from STDIN
15             # do this as early as possible: https://github.com/cpan-testers/CPAN-Reporter/issues/20
16             my @modules;
17 0           while ( <> ) {
18 0           push @modules, $_;
19             }
20 0           local *DEVNULL;
21 0           open DEVNULL, '>' . File::Spec->devnull; ## no critic
22             # ensure actually installed, not ./inc/... or ./t/..., etc.
23 0           local @INC = grep { $_ ne '.' } @INC;
  0            
24 0           for (@modules) {
25 0           m/^(\S+)\s+([^\n]*)/;
26 0           my ($mod, $need) = ($1, $2);
27 0 0         die "Couldn't read module for '$_'" unless $mod;
28 0 0         $need = 0 if not defined $need;
29              
30             # only evaluate a module once
31 0 0         next if $saw_mod{$mod}++;
32              
33             # get installed version from file with EU::MM
34 0           my($have, $inst_file, $dir, @packpath);
35 0 0         if ( $mod eq "perl" ) {
36 0           $have = $];
37             }
38             else {
39 0           @packpath = split( /::/, $mod );
40 0           $packpath[-1] .= '.pm';
41 0 0 0       if (@packpath == 1 && $packpath[0] eq 'readline.pm') {
42 0           unshift @packpath, 'Term', 'ReadLine'; # historical reasons
43             }
44             INCDIR:
45 0           foreach my $dir (@INC) {
46 0           my $pmfile = File::Spec->catfile($dir,@packpath);
47 0 0         if (-f $pmfile){
48 0           $inst_file = $pmfile;
49 0           last INCDIR;
50             }
51             }
52              
53             # get version from file or else report missing
54 0 0         if ( defined $inst_file ) {
55 0           $have = my $preliminary_version = MM->parse_version($inst_file);
56 0 0 0       $preliminary_version = '0' if ! defined $preliminary_version || $preliminary_version eq 'undef';
57             # report broken if it can't be loaded
58             # "select" to try to suppress spurious newlines
59 0           select DEVNULL; ## no critic
60 0 0         if ( ! _try_load( $mod, $preliminary_version ) ) {
61 0           select STDOUT; ## no critic
62 0           print "$mod 0 broken\n";
63 0           next;
64             }
65             # Now the module is loaded: if MM->parse_version previously failed to
66             # get the version, then we can now look at the value of the $VERSION
67             # variable.
68 0 0 0       if (! defined $have || $have eq 'undef') {
69 4     4   29 no strict 'refs';
  4         8  
  4         3047  
70 0           my $mod_version = ${$mod.'::VERSION'};
  0            
71 0 0         if (defined $mod_version) {
72 0           $have = $mod_version;
73             } else {
74 0           $have = 0; # fallback
75             }
76             }
77 0           select STDOUT; ## no critic
78             }
79             else {
80 0           print "$mod 0 n/a\n";
81 0           next;
82             }
83             }
84              
85             # complex requirements are comma separated
86 0           my ( @requirements ) = split /\s*,\s*/, $need;
87              
88 0           my $passes = 0;
89             RQ:
90 0           for my $rq (@requirements) {
91 0 0         if ($rq =~ s|>=\s*||) {
    0          
    0          
    0          
    0          
92             # no-op -- just trimmed string
93             } elsif ($rq =~ s|>\s*||) {
94 0 0         if (CPAN::Version->vgt($have,$rq)){
95 0           $passes++;
96             }
97 0           next RQ;
98             } elsif ($rq =~ s|!=\s*||) {
99 0 0         if (CPAN::Version->vcmp($have,$rq)) {
100 0           $passes++; # didn't match
101             }
102 0           next RQ;
103             } elsif ($rq =~ s|<=\s*||) {
104 0 0         if (! CPAN::Version->vgt($have,$rq)){
105 0           $passes++;
106             }
107 0           next RQ;
108             } elsif ($rq =~ s|<\s*||) {
109 0 0         if (CPAN::Version->vlt($have,$rq)){
110 0           $passes++;
111             }
112 0           next RQ;
113             }
114             # if made it here, then it's a normal >= comparison
115 0 0         if (! CPAN::Version->vlt($have, $rq)){
116 0           $passes++;
117             }
118             }
119 0 0         my $ok = $passes == @requirements ? 1 : 0;
120 0           print "$mod $ok $have\n"
121             }
122 0           return;
123             }
124              
125             sub _try_load {
126 0     0     my ($module, $have) = @_;
127              
128 0           my @do_not_load = (
129             # should not be loaded directly
130             qw/Term::ReadLine::Perl Term::ReadLine::Gnu MooseX::HasDefaults Readonly::XS
131             POE::Loop::Event SOAP::Constants
132             Moose::Meta::TypeConstraint::Parameterizable Moose::Meta::TypeConstraint::Parameterized/,
133             'Devel::Trepan', #"require Enbugger; require Devel::Trepan;" starts debugging session
134              
135             #removed modules
136             qw/Pegex::Mo YAML::LibYAML/,
137              
138             #have additional prereqs
139             qw/Log::Dispatch::Email::MailSender RDF::NS::Trine Plack::Handler::FCGI Web::Scraper::LibXML/,
140              
141             #modify @INC. 'lib' appearing in @INC will prevent correct
142             #checking of modules with XS part, for ex. List::Util
143             qw/ExtUtils::ParseXS ExtUtils::ParseXS::Utilities/,
144              
145             #require special conditions to run
146             qw/mylib/,
147              
148             #do not return true value
149             qw/perlsecret Alt::Crypt::RSA::BigInt/,
150             );
151              
152 0           my %loading_conflicts = (
153             'signatures' => ['Catalyst'],
154             'Dancer::Plugin::FlashMessage' => ['Dancer::Plugin::FlashNote'],
155             'Dancer::Plugin::FlashNote' => ['Dancer::Plugin::FlashMessage'],
156             'Dancer::Plugin::Mongoose' => ['Dancer::Plugin::DBIC'],
157             'Dancer::Plugin::DBIC' => ['Dancer::Plugin::Mongoose'],
158             'Test::BDD::Cucumber::Loader' => ['Test::Exception', 'Test::MockObject'], #works in different order
159             'Test::Mock::LWP::UserAgent' => ['HTTP::Response'],
160             'Test::SharedFork' => ['threads'], #dies if $INC{'threads.pm'}
161             'Test::TCP' => ['threads'], #loads Test::SharedFork
162             'Test::Fake::HTTPD' => ['threads'], #loads Test::SharedFork
163             #Note: Test::Perl::Critic and other modules load threads, so reordering will not help
164             ); #modules that conflict with each other
165              
166 0           my %load_before = (
167             'Tk::Font' => 'Tk',
168             'Tk::Widget' => 'Tk',
169             'Tk::Label' => 'Tk',
170             'Tk::Menubutton' => 'Tk',
171             'Tk::Entry' => 'Tk',
172             'Class::MOP::Class' => 'Class::MOP',
173             'Moose::Meta::TypeConstraint::Role' => 'Moose',
174             'Moose::Meta::TypeConstraint::Union' => 'Moose',
175             'Moose::Meta::Attribute::Native' => 'Class::MOP',
176             'Moose::Meta::Role::Attribute' => 'Class::MOP',
177             'Test::More::Hooks' => 'Test::More',
178             'Net::HTTP::Spore::Middleware::DefaultParams' => 'Net::HTTP::Spore::Meta::Method',
179             'Log::Log4perl::Filter' => 'Log::Log4perl',
180             'RDF::DOAP::Project' => 'RDF::Trine', #or other modules that use RDF::Trine will fail
181             );
182              
183             # M::I < 0.95 dies in require, so we can't check if it loads
184             # Instead we just pretend that it works
185 0 0 0       if ( $module eq 'Module::Install' && $have < 0.95 ) {
    0 0        
    0          
    0          
186 0           return 1;
187             }
188             # circular dependency with Catalyst::Runtime, so this module
189             # does not depends on it, but still does not work without it.
190             elsif ( $module eq 'Catalyst::DispatchType::Regex' && $have <= 5.90032 ) {
191 0           return 1;
192             }
193 0           elsif ( grep { $_ eq $module } @do_not_load ) {
194 0           return 1;
195             }
196             # loading Acme modules like Acme::Bleach can do bad things,
197             # so never try to load them; just pretend that they work
198             elsif( $module =~ /^Acme::/ ) {
199 0           return 1;
200             }
201              
202 0 0         if ( exists $loading_conflicts{$module} ) {
203 0           foreach my $mod1 ( @{ $loading_conflicts{$module} } ) {
  0            
204 0           my $file = "$mod1.pm";
205 0           $file =~ s{::}{/}g;
206 0 0         if (exists $INC{$file}) {
207 0           return 1;
208             }
209             }
210             }
211              
212 0 0         if (exists $load_before{$module}) {
213 0           eval "require $load_before{$module};1;";
214             }
215 0           my $file = "$module.pm";
216 0           $file =~ s{::}{/}g;
217              
218 0           return eval {require $file; 1}; ## no critic
  0            
  0            
219             }
220              
221             1;
222             __END__