File Coverage

blib/lib/CPAN/FindDependencies/MakeMaker.pm
Criterion Covered Total %
statement 61 69 88.4
branch 10 18 55.5
condition n/a
subroutine 11 11 100.0
pod 1 1 100.0
total 83 99 83.8


line stmt bran cond sub pod time code
1             #!perl -w
2             # TODO Figure out how to recover from fatal errors inside the 'eval $MakefilePL' call.
3              
4             package CPAN::FindDependencies::MakeMaker;
5              
6 8     8   46 use strict;
  8         14  
  8         221  
7 8     8   36 use vars qw($VERSION @ISA @EXPORT_OK);
  8         16  
  8         362  
8              
9 8     8   4862 use File::Temp qw(tempdir);
  8         111719  
  8         453  
10 8     8   60 use Cwd qw(getcwd abs_path);
  8         26  
  8         356  
11 8     8   3359 use Capture::Tiny qw(capture);
  8         39870  
  8         415  
12 8     8   51 use Config;
  8         19  
  8         3251  
13              
14             require Exporter;
15             @ISA = qw(Exporter);
16             @EXPORT_OK = qw( getreqs_from_mm );
17              
18             $VERSION = '1.0';
19              
20             =head1 NAME
21              
22             CPAN::FindDependencies::MakeMaker - retrieve dependencies specified in Makefile.PL's
23              
24             =head1 SYNOPSIS
25              
26             Dependencies are also specified in Makefile.PL files used with the ExtUtils::MakeMaker module.
27              
28             =head1 FUNCTIONS
29              
30             =over
31              
32             =item getreqs_from_mm
33              
34             Expects the contents of a Makefile.PL as a string.
35              
36             Returns a hash reference of the form:
37              
38             {
39             Module::Name => 0.1,
40             ...
41             Last::Module => 9.0,
42             }
43              
44             =back
45              
46             =cut
47              
48             sub getreqs_from_mm {
49 5     5 1 18 my $MakefilePL = shift;
50 5         146 local $/ = undef;
51              
52 5         52 my $cwd = getcwd();
53 5         80 my $tempdir = tempdir(CLEANUP => 1);
54 5         2800 chdir($tempdir);
55              
56             # write Makefile.PL ...
57 5 50       286 open(my $MKFH, '>Makefile.PL') || die("Can't write Makefile.PL in $tempdir\n");
58 5         35 print $MKFH $MakefilePL;
59 5         171 close($MKFH);
60              
61 5 50       34 if ($^O eq 'MSWin32') {
62             # NB *not* for Cygwin, hence not Devel::CheckOS MicrosoftWindows
63 0         0 require Win32::Job;
64 0         0 my $job = Win32::Job->new;
65 0         0 $job->spawn($Config{perlpath}, "perl Makefile.PL", {stdin => 'NUL', 'stdout'=>'stdout.log','stderr'=>'stderr.log'});
66 0 0       0 unless ($job->run(10)) {
67 0         0 chdir($cwd);
68 0         0 return "Makefile.PL didn't finish in a reasonable time\n";
69             }
70             } else {
71             # execute, suppressing noise ...
72 5         12 eval { capture {
73 5 100   5   29755 if(my $pid = fork()) { # parent
74             local $SIG{ALRM} = sub {
75 1         188 kill 9, $pid; # quit RIGHT FUCKING NOW
76 1         58 die("Makefile.PL didn't finish in a reasonable time\n");
77 3         440 };
78 3         45 alarm(10);
79 3         11469732 waitpid($pid, 0);
80 2         150 alarm(0);
81             } else {
82 2         0 exec($Config{perlpath}, 'Makefile.PL');
83             }
84 5         346 } };
85 3 100       3673 if($@) {
86 1         18 chdir($cwd);
87 1         43 return $@;
88             }
89             }
90              
91             # read Makefile
92 2 50       96 open($MKFH, 'Makefile') || warn "Can't read Makefile\n";
93 2         168 my $makefile_str = <$MKFH>;
94 2         32 close($MKFH);
95 2         42 chdir($cwd);
96              
97 2         46 return _parse_makefile( $makefile_str );
98             }
99              
100             sub _parse_makefile {
101 2     2   20 my $makefile_str = shift;
102 2 50       16 return "Unable to get Makefile" unless defined $makefile_str;
103 2         4 my %required_version_for;
104 2         544 my @prereq_lines = grep { /^\s*#.*PREREQ/ } split /\n/, $makefile_str;
  1766         2956  
105 2         76 for my $line ( @prereq_lines ) {
106 2 50       46 if ( $line =~ /PREREQ_PM \s+ => \s+ \{ \s* (.*) \s* \} $/x ) {
  0         0  
107 8     8   58 no strict 'subs';
  8         15  
  8         531  
108 2         414 %required_version_for = eval "( $1 )";
109 2 50       26 return "Failed to eval $1: $@" if $@;
110 8     8   48 use strict 'subs';
  8         16  
  8         683  
111             } else {
112 0         0 return "Unrecognized PREREQ line in Makefile.PL:\n$line";
113             }
114             }
115 2         76 return \%required_version_for;
116             }
117              
118             =head1 SECURITY
119              
120             This module assumes that its input is trustworthy and can be safely
121             executed. The only protection in place is that a vague attempt is made
122             to catch a Makefile.PL that just sits there doing nothing - either if it's
123             in a loop, or sitting at a prompt. But even that can be defeated by
124             an especially naughty person.
125              
126             =head1 BUGS/LIMITATIONS
127              
128             Makefile.PLs that have external dependencies/calls that can fatally die will
129             not be able to be successfully parsed and then scanned for dependencies, e.g.
130             libwww-perl.5808.
131              
132             =head1 SOURCE CODE REPOSITORY
133              
134             L<git://github.com/DrHyde/perl-modules-CPAN-FindDependencies.git>
135              
136             =head1 SEE ALSO
137              
138             L<CPAN::FindDepdendencies>
139              
140             L<CPAN>
141              
142             L<http://deps.cpantesters.org>
143              
144             =head1 AUTHOR, LICENCE and COPYRIGHT
145              
146             Copyright 2009 David Cantrell E<lt>F<david@cantrell.org.uk>E<gt> based largely
147             on code by Ian Tegebo (see L<http://rt.cpan.org/Public/Bug/Display.html?id=34814>)
148              
149             This software is free-as-in-speech software, and may be used,
150             distributed, and modified under the terms of either the GNU
151             General Public Licence version 2 or the Artistic Licence. It's
152             up to you which one you use. The full text of the licences can
153             be found in the files GPL2.txt and ARTISTIC.txt, respectively.
154              
155             =head1 CONSPIRACY
156              
157             This module is also free-as-in-mason software.
158              
159             =cut
160              
161             1;