File Coverage

blib/lib/App/MechaCPAN/Perl.pm
Criterion Covered Total %
statement 110 135 81.4
branch 28 46 60.8
condition 7 18 38.8
subroutine 11 11 100.0
pod 1 1 100.0
total 157 211 74.4


line stmt bran cond sub pod time code
1             package App::MechaCPAN::Perl;
2              
3 25     25   284 use v5.14;
  25         77  
4 25     25   143 use autodie;
  25         44  
  25         170  
5 25     25   116795 use Config;
  25         46  
  25         1033  
6 25     25   14133 use File::Fetch qw//;
  25         1031002  
  25         700  
7 25     25   177 use App::MechaCPAN qw/:go/;
  25         46  
  25         27479  
8              
9             our @args = (
10             'threads!',
11             'skip-tests!',
12             'skip-local!',
13             'skip-lib!',
14             'smart-tests!',
15             'devel!',
16             );
17              
18             my $perl5_ver_re = qr/v? 5 [.] (\d{1,2}) (?: [.] (\d{1,2}) )?/xms;
19             my $perl5_re = qr/^ $perl5_ver_re $/xms;
20              
21             sub go
22             {
23 11     11 1 81 my $class = shift;
24 11         40 my $opts = shift;
25 11         54 my $src = shift;
26 11         57 my @argv = shift;
27              
28 11 50       111 if ( $^O eq 'MSWin32' )
29             {
30 0         0 info 'Cannot build perl on Win32';
31 0         0 return 0;
32             }
33              
34 11         59 my $orig_dir = &dest_dir;
35 11         71 my @orig_dir = File::Spec->splitdir("$orig_dir");
36 11         52 my $orig_len = $#orig_dir;
37 11         51 my $dest_dir = "$orig_dir/perl";
38 11         60 my $pv_ver; # Version in .perl-version file
39              
40             # Attempt to find the perl version if none was given
41 11 100       134 if ( -f '.perl-version' )
42             {
43 2         45 open my $pvFH, '<', '.perl-version';
44 2         2880 $pv_ver = do { local $/; <$pvFH> };
  2         14  
  2         56  
45 2         15 $pv_ver =~ s/\s+//xmsg;
46 2 50       63 if ( $pv_ver !~ $perl5_re )
47             {
48 0         0 info "$pv_ver in .perl-version doesn't look like a perl5 version";
49 0         0 undef $pv_ver;
50             }
51             }
52              
53 11   33     144 my ( $src_tz, $version ) = _get_targz( $src // $pv_ver );
54              
55             # If _get_targz couldn't find a version, guess based on the file
56 11 50 33     484 if ( !$version && $src_tz =~ m($perl5_ver_re [^/]* $)xms )
57             {
58 11         67 my $major = $1;
59 11         34 my $minor = $2;
60              
61 11         60 $version = "5.$major.$minor";
62 11         177 info("Looks like $src_tz is perl $version, assuming that's true");
63             }
64              
65 11 50       145 if ( -e -x "$dest_dir/bin/perl" )
66             {
67 0 0       0 unless ( $opts->{is_restarted_process} )
68             {
69             # If it exists, we're probably running it by now.
70 0 0 0     0 if ( $version && $^V ne "v$version" )
71             {
72 0         0 info(
73             $version,
74             "perl has already been installed ($^V, not $version)"
75             );
76             }
77             else
78             {
79 0         0 success( $version, "perl has already been installed" );
80             }
81             }
82 0         0 return 0;
83             }
84              
85 11         59 my $verstr = "perl $version";
86 11         75 info $verstr, "Fetching $verstr";
87              
88 11         72 my $src_dir = inflate_archive($src_tz);
89              
90 11         140 chdir $src_dir;
91              
92 11 50       788 if ( !-e 'Configure' )
93             {
94 11         979 my @files = glob('*');
95 11 50       67 if ( @files > 1 )
96             {
97 0         0 die 'Could not find perl to configure';
98             }
99 11         74 chdir $files[0];
100             }
101              
102 11         764 my $local_dir = File::Spec->catdir( @orig_dir, qw/lib perl5/ );
103 11         149 my $lib_dir
104             = File::Spec->catdir( @orig_dir[ 0 .. $orig_len - 1 ], qw/lib/ );
105              
106             my @otherlib = (
107             !$opts->{'skip-local'} ? $local_dir : (),
108 11 100 100     312 !$opts->{'skip-lib'} && -d $lib_dir ? $lib_dir : (),
    100          
109             );
110              
111 11         288 my @config = (
112             q[-des],
113             qq[-Dprefix=$dest_dir],
114             q[-Accflags=-DAPPLLIB_EXP=\"] . join( ":", @otherlib ) . q[\"],
115             qq[-A'eval:scriptdir=$dest_dir/bin'],
116             );
117              
118 11 100       58 if ( $opts->{threads} )
119             {
120 1         12 push @config, '-Dusethreads';
121             }
122              
123 11 100       59 if ( $opts->{devel} )
124             {
125 1         23 push @config, '-Dusedevel';
126             }
127              
128 11         206 delete @ENV{qw(PERL5LIB PERL5OPT)};
129              
130             # Make sure no tomfoolery is happening with perl, like plenv shims
131 11         418 $ENV{PATH} = $Config{binexp} . ":$ENV{PATH}";
132              
133 11         52 eval {
134 11         1790 require Devel::PatchPerl;
135 0         0 info $verstr, "Patching $verstr";
136 0         0 Devel::PatchPerl->patch_source();
137             };
138              
139 11         193 info $verstr, "Configuring $verstr";
140 11         133 _run_configure(@config);
141              
142 11         199 info $verstr, "Building $verstr";
143 11         77 _run_make();
144              
145 11         81 my $skip_tests = $opts->{'skip-tests'};
146              
147 11 100 66     196 if ( !$skip_tests && $opts->{'smart-tests'} )
148             {
149 3         35 $skip_tests = $pv_ver eq $version;
150             }
151              
152 11 100       67 if ( !$skip_tests )
153             {
154 10         193 info $verstr, "Testing $verstr";
155 10         42 _run_make('test_harness');
156             }
157              
158 11         260 info $verstr, "Installing $verstr";
159 11         79 _run_make('install');
160              
161 11         262 success "Installed $verstr";
162              
163 11         146 chdir $orig_dir;
164              
165 11         221 &restart_script();
166              
167 11         1545 return 0;
168             }
169              
170             # These are split out mostly so we can control testing
171             sub _run_configure
172             {
173 11     11   359 my @config = @_;
174 11         102 run qw[sh Configure], @config;
175             }
176              
177             sub _run_make
178             {
179 32     32   332 my @cmd = @_;
180 32         218 state $make = $Config{make};
181 32         203 run $make, @cmd;
182             }
183              
184             sub _dnld_url
185             {
186 5     5   15 my $version = shift;
187 5         7 my $minor = shift;
188 5         21 my $mirror = 'http://www.cpan.org/src/5.0';
189              
190 5         79 return "$mirror/perl-5.$version.$minor.tar.bz2";
191             }
192              
193             sub _get_targz
194             {
195 12     12   255 my $src = shift;
196              
197 12         59 local $File::Fetch::WARN;
198              
199             # If there's no src, find the newest version.
200 12 50       75 if ( !defined $src )
201             {
202             # Do a terrible job of guessing what the current version is
203 25     25   10534 use Time::localtime;
  25         97493  
  25         10223  
204 0         0 my $year = localtime->year() + 1900;
205              
206             # 5.12 was released in 2010, and approximatly every May, a new even
207             # version was released
208 0 0       0 my $major = ( $year - 2010 ) * 2 + ( localtime->mon < 4 ? 10 : 12 );
209              
210             # Verify our guess
211             {
212 0         0 my $dnld = _dnld_url( $major, 0 ) . ".md5.txt";
  0         0  
213 0         0 my $ff = File::Fetch->new( uri => $dnld );
214 0         0 my $contents = '';
215 0         0 my $where = $ff->fetch( to => \$contents );
216              
217 0 0 0     0 if ( !defined $where && $major > 12 )
218             {
219 0         0 $major -= 2;
220 0         0 redo;
221             }
222             }
223 0         0 $src = "5.$major";
224             }
225              
226             # file
227              
228 12 100       254 if ( -e $src )
229             {
230 11         136 return ( $src, '' );
231             }
232              
233 1         2 my $url;
234              
235             # URL
236 1 50       10 if ( $src =~ url_re )
237             {
238 0         0 return ( $src, '' );
239             }
240              
241             # CPAN
242 1 50       10 if ( $src =~ $perl5_re )
243             {
244 1         10 my $version = $1;
245 1         2 my $minor = $2;
246              
247             # They probably want the latest if minor wasn't given
248 1 50       5 if ( !defined $minor )
249             {
250             # 11 is the highest minor version seen as of this writing
251 1         4 my @possible = ( 0 .. 15 );
252              
253 1         3 while ( @possible > 1 )
254             {
255 4         21 my $i = int( @possible / 2 );
256 4         20 $minor = $possible[$i];
257 4         40 my $dnld = _dnld_url( $version, $minor ) . ".md5.txt";
258 4         35 my $ff = File::Fetch->new( uri => $dnld );
259 4         21520 my $contents = '';
260 4         51 my $where = $ff->fetch( to => \$contents );
261              
262 4 100       415856 if ( defined $where )
263             {
264             # The version exists, which means it's higher still
265 2         84 @possible = @possible[ $i .. $#possible ];
266             }
267             else
268             {
269             # The version doesn't exit. That means higher versions don't either
270 2         129 @possible = @possible[ 0 .. $i - 1 ];
271             }
272             }
273 1         13 $minor = $possible[0];
274             }
275              
276 1         17 return ( _dnld_url( $version, $minor ), "5.$version.$minor" );
277             }
278              
279 0           die "Cannot find $src\n";
280             }
281              
282             1;
283             __END__