File Coverage

blib/lib/App/MechaCPAN/Install.pm
Criterion Covered Total %
statement 471 489 96.3
branch 139 168 82.7
condition 39 53 73.5
subroutine 47 47 100.0
pod 1 1 100.0
total 697 758 91.9


line stmt bran cond sub pod time code
1             package App::MechaCPAN::Install;
2              
3 25     25   276 use v5.14;
  25         78  
4              
5 25     25   116 use Carp;
  25         44  
  25         1190  
6 25     25   132 use Config;
  25         47  
  25         845  
7 25     25   110 use Cwd qw/cwd/;
  25         43  
  25         809  
8 25     25   14290 use JSON::PP qw//;
  25         281229  
  25         659  
9 25     25   164 use File::Spec qw//;
  25         44  
  25         325  
10 25     25   101 use File::Path qw//;
  25         46  
  25         381  
11 25     25   105 use File::Temp qw/tempdir tempfile/;
  25         42  
  25         1181  
12 25     25   11102 use CPAN::Meta qw//;
  25         589019  
  25         593  
13 25     25   200 use CPAN::Meta::Prereqs qw//;
  25         52  
  25         377  
14 25     25   112 use File::Fetch qw//;
  25         51  
  25         338  
15 25     25   60289 use Module::CoreList;
  25         2117255  
  25         1286  
16 25     25   31164 use ExtUtils::MakeMaker qw//;
  25         2154729  
  25         896  
17 25     25   188 use App::MechaCPAN qw/:go/;
  25         49  
  25         61665  
18              
19             our @args = (
20             'skip-tests!',
21             'skip-tests-for:s@',
22             'smart-tests!',
23             'install-man!',
24             'source=s%',
25             'only-sources!',
26             'update!',
27             'stop-on-error!',
28             );
29              
30             our $dest_lib;
31              
32             # Constants
33             my $COMPLETE = 'COMPLETE';
34             my $FAILED = 'FAILED';
35              
36             sub go
37             {
38 34     34 1 33166 my $class = shift;
39 34         231 my $opts = shift;
40 34   50     404 my $src = shift // '.';
41 34         186 my @srcs = @_;
42              
43 34         118824 my $orig_dir = cwd;
44 34         1215 my $dest_dir = &dest_dir;
45              
46 34         839 local $dest_lib = "$dest_dir/lib/perl5";
47              
48 34         470 my @targets = ( $src, @srcs );
49 34         433 my %src_names;
50             my @deps;
51              
52 34 100 66     937 if ( ref $opts->{source} ne 'HASH' && ref $opts->{source} ne 'CODE' )
53             {
54 30         555 $opts->{source} = {};
55             }
56              
57 34 100       409 if ( ref $opts->{'skip-tests-for'} ne 'ARRAY' )
58             {
59 33         421 $opts->{'skip-tests-for'} = [];
60             }
61             $opts->{'skip-tests-for'}
62 34         162 = { map { $_ => 1 } @{ $opts->{'skip-tests-for'} } };
  1         38  
  34         358  
63              
64             my $unsafe_inc
65 34 100       413 = exists $ENV{PERL_USE_UNSAFE_INC} ? $ENV{PERL_USE_UNSAFE_INC} : 1;
66              
67             # trick AutoInstall
68 34         868 local $ENV{PERL5_CPAN_IS_RUNNING} = $$;
69 34         801 local $ENV{PERL5_CPANPLUS_IS_RUNNING} = $$;
70              
71 34         856 local $ENV{PERL_MM_USE_DEFAULT} = 1;
72 34         913 local $ENV{PERL_USE_UNSAFE_INC} = $unsafe_inc;
73              
74 34         479 local $ENV{PERL_MM_OPT} = "INSTALL_BASE=$dest_dir";
75 34         419 local $ENV{PERL_MB_OPT} = "--install_base $dest_dir";
76              
77 34         772 local $ENV{PERL5LIB} = "$dest_lib";
78              
79             # skip man page generation
80 34 50       335 if ( !$opts->{'install-man'} )
81             {
82             $ENV{PERL_MM_OPT}
83 34         328 .= " " . join( " ", "INSTALLMAN1DIR=none", "INSTALLMAN3DIR=none" );
84 34         389 $ENV{PERL_MB_OPT} .= " " . join(
85             " ", "--config installman1dir=",
86             "--config installsiteman1dir=", "--config installman3dir=",
87             "--config installsiteman3dir="
88             );
89             }
90              
91             #if ( $self->{pure_perl} )
92             #{
93             # $ENV{PERL_MM_OPT} .= " PUREPERL_ONLY=1";
94             # $ENV{PERL_MB_OPT} .= " --pureperl-only";
95             #}
96              
97 34         461 my $cache = { opts => $opts };
98              
99             # Prepopulate all of the sources as targets
100 34         190 foreach my $source_key ( keys %{ $opts->{source} } )
  34         416  
101             {
102 19         69 my $source = $opts->{source}->{$source_key};
103              
104             # If there is no source to translate to, continue
105 19 100       65 if ( !defined $source )
106             {
107 14         65 _create_target( $source_key, $cache );
108 14         21 next;
109             }
110              
111             # If we can find a target, reuse it, otherwise create a new one
112 5         78 my $target = _find_target( $source, $cache );
113 5 50       45 if ( defined $target )
114             {
115 0         0 _alias_target( $target, $source_key, $cache );
116             }
117             else
118             {
119 5         43 $target = _create_target( $source_key, $cache );
120 5         38 _alias_target( $target, $source, $cache );
121             }
122             }
123              
124 34         1473 my @full_states = (
125             'Resolving' => \&_resolve,
126             'Configuring' => \&_meta,
127             'Configuring' => \&_config_prereq,
128             'Configuring' => \&_configure,
129             'Configuring' => \&_mymeta,
130             'Prerequisites' => \&_prereq,
131             'Prerequisites' => \&_test_prereq,
132             'Prerequisites' => \&_prereq_verify,
133             'Building' => \&_build,
134             'Testing' => \&_test,
135             'Installing' => \&_install,
136             'Installed' => \&_write_meta,
137             );
138              
139 34         293 my @states = grep { ref $_ eq 'CODE' } @full_states;
  816         2242  
140 34         195 my @state_desc = grep { ref $_ ne 'CODE' } @full_states;
  816         2044  
141              
142 34         289 foreach my $target (@targets)
143             {
144 40         520 $target = _create_target( $target, $cache );
145 40   100     583 $target->{update} = $opts->{update} // 1;
146             }
147              
148             TARGET:
149 34         374 while ( my $target = shift @targets )
150             {
151 474         4085 $target = _create_target( $target, $cache );
152              
153 474 100 66     4792 if ( $target->{state} eq $COMPLETE || $target->{state} eq $FAILED )
154             {
155 1         9 next;
156             }
157              
158 473         5518 chdir $orig_dir;
159             chdir $target->{dir}
160 473 100       4772 if exists $target->{dir};
161              
162 473         3676 my $line = _target_line( $target, $state_desc[ $target->{state} ] );
163 473         4534 info( $target->{key}, $line );
164 473         1492 my $method = $states[ $target->{state} ];
165              
166             {
167 473         903 local $@;
  473         819  
168 473         1151 my $succ = eval { unshift @targets, $method->( $target, $cache ); 1; };
  473         2525  
  463         3120  
169 473         5757 my $err = $@;
170              
171 473 100       2335 if ( !$succ )
172             {
173 10         143 my $line = sprintf(
174             '%-13s %s', 'Error',
175             "Could not install " . _name_target($target)
176             );
177              
178 10         119 error( $target->{key}, $line );
179              
180 10         75 _failed($target);
181              
182 10 50       56 if ( $opts->{'stop-on-error'} )
183             {
184 0         0 croak $err;
185             }
186              
187 10         93 next TARGET;
188             }
189             }
190              
191             $target->{state}++
192 463 100       3162 if $target->{state} ne $COMPLETE;
193              
194 463 100       5715 if ( $target->{state} eq scalar @states )
195             {
196 33         308 _complete($target);
197 33         114 $target->{was_installed} = 1;
198 33         301 success( $target->{key}, $line );
199             }
200             }
201              
202 34         479 chdir $orig_dir;
203              
204 34         140 my %attempted = map { $_->{name} => $_ } values %{ $cache->{targets} };
  104         612  
  34         344  
205 34         198 my @failed = grep { $_->{state} eq $FAILED } values %attempted;
  49         273  
206 34         165 my @installed = grep { $_->{was_installed} } values %attempted;
  49         226  
207              
208 34         532 success "\tsuccess", "Installed " . scalar @installed . " modules";
209              
210 34 100       217 if ( @failed > 0 )
211             {
212 9         80 logmsg "Failed modules: " . join( ", ", @failed );
213 9         2364 die "Failed to install " . scalar @failed . " modules\n";
214             }
215              
216 25         12549 return 0;
217             }
218              
219             sub _resolve
220             {
221 50     50   149 my $target = shift;
222 50         157 my $cache = shift;
223              
224             # Verify we need to install it
225             return
226 50 100       532 if !_should_install($target);
227              
228 44         141 my $src_name = $target->{src_name};
229              
230 44         561 $target->{src_name} = _source_translate( $src_name, $cache->{opts} );
231              
232             # fetch
233 44         428 my $src_tgz = _get_targz($target);
234              
235             return
236 44 100       405 if !_should_install($target);
237              
238 43         405 my $src_dir = inflate_archive($src_tgz);
239              
240 43         4627 my @files = glob( $src_dir . '/*' );
241 43 50       349 if ( @files == 1 )
242             {
243 43         183 $src_dir = $files[0];
244             }
245              
246 43         202 @{$target}{qw/src_tgz dir was_installed/} = ( $src_tgz, $src_dir, 0 );
  43         746  
247 43         675 return $target;
248             }
249              
250             sub _meta
251             {
252 43     43   143 my $target = shift;
253 43         112 my $cache = shift;
254              
255 43         396 $target->{meta} = _load_meta( $target, $cache, 0 );
256 43         206 return $target;
257             }
258              
259             sub _config_prereq
260             {
261 43     43   143 my $target = shift;
262 43         136 my $cache = shift;
263              
264 43         163 my $meta = $target->{meta};
265              
266 43 100       172 return $target
267             if !defined $meta;
268              
269 42         357 my @config_deps = _phase_prereq( $target, $cache, 'configure' );
270              
271 42         269 $target->{configure_prereq} = [@config_deps];
272              
273 42         168 return @config_deps, $target;
274             }
275              
276             sub _configure
277             {
278 38     38   103 my $target = shift;
279 38         85 my $cache = shift;
280 38         137 my $meta = $target->{meta};
281              
282 38         89 state $mb_deps = { map { $_ => 1 }
  48         248  
283             qw/version ExtUtils-ParseXS ExtUtils-Install ExtUtilsManifest/ };
284              
285             # meta may not be defined, so wrap it in an eval
286 38         97 my $is_mb_dep = eval { exists $mb_deps->{ $meta->name } };
  38         365  
287 38         317 my $maker;
288              
289 38 100 66     725 if ( -e 'Build.PL' && !$is_mb_dep )
290             {
291 2         29 run( $^X, 'Build.PL' );
292 2         50 my $configured = -e -f 'Build';
293             croak 'Unable to configure Buid.PL for ' . $target->{src_name}
294 2 50       20 unless $configured;
295 2         15 $maker = 'mb';
296             }
297              
298 38 100 66     774 if ( !defined $maker && -e 'Makefile.PL' )
299             {
300 36         490 run( $^X, 'Makefile.PL' );
301 36         834 my $configured = -e 'Makefile';
302             croak 'Unable to configure Makefile.PL for ' . $target->{src_name}
303 36 50       372 unless $configured;
304 36         266 $maker = 'mm';
305             }
306              
307             croak 'Unable to configure ' . $target->{src_name}
308 38 50       246 if !defined $maker;
309              
310 38         478 $target->{maker} = $maker;
311 38         827 return $target;
312             }
313              
314             sub _mymeta
315             {
316 38     38   167 my $target = shift;
317 38         144 my $cache = shift;
318              
319 38         486 my $new_meta = _load_meta( $target, $cache, 1 );
320 38 50       3505 $target->{meta} = $new_meta
321             if defined $new_meta;
322              
323 38         510 $target->{name} = $target->{meta}->name;
324 38         621 $target->{name} =~ s[-][::]xmsg;
325              
326 38         169 return $target;
327             }
328              
329             sub _prereq
330             {
331 38     38   135 my $target = shift;
332 38         90 my $cache = shift;
333              
334 38         103 my $meta = $target->{meta};
335              
336 38         168 my @deps = map { _phase_prereq( $target, $cache, $_ ) } qw/runtime build/;
  76         349  
337              
338 38         311 $target->{prereq} = [@deps];
339              
340 38         219 return @deps, $target;
341             }
342              
343             sub _test_prereq
344             {
345 38     38   133 my $target = shift;
346 38         131 my $cache = shift;
347              
348 38         106 my $meta = $target->{meta};
349 38         176 my $opts = $cache->{opts};
350              
351 38         123 my $skip_tests = $opts->{'skip-tests'};
352 38 100       186 if ( !$skip_tests )
353             {
354 37         158 my $skips = $opts->{'skip-tests-for'};
355 37         197 $skip_tests = exists $skips->{ $target->{src_name} };
356              
357 37 100 100     515 if ( !$skip_tests && defined $target->{modules} )
358             {
359 20         56 foreach my $module ( %{ $target->{modules} } )
  20         172  
360             {
361 40 50       154 if ( $skips->{$module} )
362             {
363 0         0 $skip_tests = 1;
364 0         0 last;
365             }
366             }
367             }
368              
369 37 100 100     502 if ( !$skip_tests && $opts->{'smart-tests'} )
370             {
371 6         72 $skip_tests = _target_prereqs_were_installed( $target, $cache );
372             }
373             }
374              
375 38         278 $target->{skip_tests} = $skip_tests;
376              
377 38         111 my @deps;
378              
379 38 100       132 if ( !$skip_tests )
380             {
381 31         81 @deps = map { _phase_prereq( $target, $cache, $_ ) } qw/test/;
  31         172  
382 31         95 push @{ $target->{prereq} }, @deps;
  31         161  
383             }
384              
385 38         122 return @deps, $target;
386             }
387              
388             sub _prereq_verify
389             {
390 38     38   98 my $target = shift;
391 38         126 my $cache = shift;
392              
393 38         353 my @deps = _target_prereqs( $target, $cache );
394 38         134 my @incomplete_deps = grep { $_->{state} ne $COMPLETE } @deps;
  11         59  
395              
396 38 50       207 if ( @incomplete_deps > 0 )
397             {
398 0         0 my $line = 'Unmet dependencies for: ' . $target->{src_name};
399 0         0 error $target->{key}, $line;
400             logmsg "Missing requirements: "
401 0         0 . join( ", ", map { $_->{src_name} } @incomplete_deps );
  0         0  
402 0         0 croak 'Error with prerequisites';
403             }
404              
405 38         147 return $target;
406             }
407              
408             sub _build
409             {
410 38     38   131 my $target = shift;
411 38         131 my $cache = shift;
412              
413 38         602 local $ENV{PERL_MM_USE_DEFAULT} = 0;
414 38         387 local $ENV{NONINTERACTIVE_TESTING} = 0;
415 38         530 state $make = $Config{make};
416              
417 38         126 my $opts = $cache->{opts};
418              
419 38 100       211 if ( $target->{maker} eq 'mb' )
420             {
421 2         30 run( $^X, './Build' );
422 2         152 return $target;
423             }
424              
425 36 50       194 if ( $target->{maker} eq 'mm' )
426             {
427 36         245 run($make);
428 36         2399 return $target;
429             }
430              
431 0         0 croak 'Unable to determine how to install ' . $target->{meta}->name;
432             }
433              
434             sub _test
435             {
436 38     38   213 my $target = shift;
437 38         171 my $cache = shift;
438              
439 38         402 local $ENV{PERL_MM_USE_DEFAULT} = 0;
440 38         247 local $ENV{NONINTERACTIVE_TESTING} = 0;
441 38         645 state $make = $Config{make};
442              
443 38         237 my $opts = $cache->{opts};
444              
445 38 100       321 if ( $target->{skip_tests} )
446             {
447 7         81 return $target;
448             }
449              
450 31 100       258 if ( $target->{maker} eq 'mb' )
451             {
452 2         26 run( $^X, './Build', 'test' );
453 2         125 return $target;
454             }
455              
456 29 50       219 if ( $target->{maker} eq 'mm' )
457             {
458 29         276 run( $make, 'test' );
459 24         1516 return $target;
460             }
461              
462 0         0 croak 'Unable to determine how to install ' . $target->{meta}->name;
463             }
464              
465             sub _install
466             {
467 33     33   177 my $target = shift;
468 33         158 my $cache = shift;
469              
470 33         301 local $ENV{PERL_MM_USE_DEFAULT} = 0;
471 33         210 local $ENV{NONINTERACTIVE_TESTING} = 0;
472 33         554 state $make = $Config{make};
473              
474 33         140 my $opts = $cache->{opts};
475              
476 33 100       247 if ( $target->{maker} eq 'mb' )
477             {
478 2         23 run( $^X, './Build', 'install' );
479 2         124 return $target;
480             }
481              
482 31 50       231 if ( $target->{maker} eq 'mm' )
483             {
484 31         306 run( $make, 'install' );
485 31         2008 return $target;
486             }
487              
488 0         0 croak 'Unable to determine how to install ' . $target->{meta}->name;
489             }
490              
491             sub _write_meta
492             {
493 33     33   203 my $target = shift;
494 33         190 my $cache = shift;
495              
496 33         668 state $arch_dir = "$Config{archname}/.meta/";
497              
498 33 100       373 if ( $target->{is_cpan} )
499             {
500 15         207 my $dir = "$dest_lib/$arch_dir/" . $target->{distvname};
501 15         5237 File::Path::mkpath( $dir, 0, 0777 );
502 15         438 $target->{meta}->save("$dir/MYMETA.json");
503              
504             my $install = {
505             name => $target->{name},
506             target => $target->{src_name},
507             version => $target->{meta}->version,
508             dist => $target->{distvname},
509             pathname => $target->{pathname},
510             provides => $target->{meta}->provides,
511 15         551472 };
512              
513 15         2079 open my $fh, ">", "$dir/install.json";
514 15         198 print $fh JSON::PP::encode_json($install);
515             }
516 33         8123 return;
517             }
518              
519             my $full_pause_re = qr[
520             (?: authors/id/ )
521             ( \w / \w\w )
522             /
523             ( \w{2,} )
524             /
525             ( [^/]+ )
526             ]xms;
527             my $pause_re = qr[
528             ^
529              
530             (?: authors/id/ )?
531             (?: \w / \w\w /)?
532              
533             ( \w{2,} )
534             /
535             ( .+ )
536              
537             $
538             ]xms;
539              
540             sub _escape
541             {
542 19     19   53 my $str = shift;
543 19         175 $str =~ s/ ([^A-Za-z0-9\-\._~]) / sprintf("%%%02X", ord($1)) /xmsge;
  31         214  
544 19         109 return $str;
545             }
546              
547 25     25   234 my $ident_re = qr/^ \p{ID_Start} (?: :: | \p{ID_Continue} )* $/xms;
  25         68  
  25         870  
548              
549             sub _src_normalize
550             {
551 1154     1154   1939 my $target = shift;
552              
553 1154 100       4444 if ( ref $target eq '' )
554             {
555 133 100       721 if ( $target =~ m{^ ([^/]+) @ (.*) $}xms )
556             {
557 2         22 $target = [ $1, "==$2" ];
558             }
559             else
560             {
561 131         765 $target = [ split /[~]/xms, $target, 2 ];
562             }
563             }
564              
565 1154 100       3691 if ( ref $target eq 'ARRAY' )
566             {
567 186         1045 $target = {
568             src_name => $target->[0],
569             constraint => $target->[1],
570             };
571             }
572              
573             return {
574             src_name => $target->{src_name},
575             constraint => $target->{constraint},
576 1154         6753 };
577             }
578              
579             sub _find_target
580             {
581 607     607   1258 my $target = shift;
582 607         1131 my $cache = shift;
583              
584 607         1351 my $src = _src_normalize($target);
585 607         1458 my $src_name = $src->{src_name};
586              
587 607         2366 return $cache->{targets}->{$src_name};
588             }
589              
590             sub _alias_target
591             {
592 42     42   201 my $target = shift;
593 42         192 my $alias = shift;
594 42         127 my $cache = shift;
595              
596 42         295 my $target = _find_target( $target, $cache );
597              
598 42 100       870 if ( $alias =~ $ident_re )
599             {
600 21         266 $target->{modules}->{$alias} = {
601             inital_version => _get_mod_ver($alias),
602             };
603             }
604              
605 42         270 $cache->{targets}->{$alias} = $target;
606 42         220 return;
607             }
608              
609             sub _create_target
610             {
611 547     547   20181 my $target = shift;
612 547         1286 my $cache = shift;
613              
614 547         2916 my $src = _src_normalize($target);
615 547         2572 my $cached_target = _find_target( $target, $cache );
616              
617 547 100       1862 if ( !defined $cached_target )
618             {
619 76         296 my $src_name = $src->{src_name};
620              
621 76         614 $cached_target = { %$src, state => 0 };
622 76         516 $cache->{targets}->{$src_name} = $cached_target;
623 76         473 $cached_target->{key} = $src_name;
624             }
625              
626 547 100 100     2223 if ( $cached_target->{state} eq $COMPLETE
627             && $src->{constraint} ne $cached_target->{constraint} )
628             {
629 2         16 $cached_target->{constraint} = $src->{constraint};
630 2         15 $cached_target->{state} = 0;
631 2         20 delete $cached_target->{version};
632             }
633              
634 547         2679 for my $altkey (qw/distvname name module/)
635             {
636 1641         4185 my $altname = $cached_target->{$altkey};
637 1641 100       4207 if ( defined $altname )
638             {
639 652 100       2706 if ( !exists $cache->{targets}->{$altname} )
640             {
641 37         432 _alias_target( $cached_target, $altname, $cache );
642             }
643             }
644             }
645              
646 547 100       8724 if ( $src->{src_name} =~ $ident_re )
647             {
648 214         967 $cached_target->{module} = $src->{src_name};
649             }
650              
651 547         1833 return $cached_target;
652             }
653              
654             sub _target_prereqs
655             {
656 46     46   144 my $target = shift;
657 46         108 my $cache = shift;
658              
659             return
660 13         80 map { _find_target $_, $cache }
661 46         126 ( @{ $target->{prereq} }, @{ $target->{configure_prereq} } );
  46         159  
  46         208  
662             }
663              
664             sub _target_prereqs_were_installed
665             {
666 8     8   33 my $target = shift;
667 8         30 my $cache = shift;
668              
669 8         65 foreach my $prereq ( _target_prereqs( $target, $cache ) )
670             {
671 2         25 _target_prereqs_were_installed( $prereq, $cache );
672              
673 2 100 66     23 if ( !$prereq->{prereqs_was_installed} || !$prereq->{was_installed} )
674             {
675 1         10 return $target->{prereqs_was_installed} = 0;
676             }
677             }
678              
679 7         56 return $target->{prereqs_was_installed} = 1;
680             }
681              
682             sub _search_metacpan
683             {
684 21     21   88 my $src = shift;
685 21         46 my $constraint = shift;
686              
687 21         41 state %seen;
688              
689             return $seen{$src}->{$constraint}
690 21 100       150 if exists $seen{$src}->{$constraint};
691              
692             # TODO mirrors
693 14         117 my $dnld = 'https://fastapi.metacpan.org/download_url/' . _escape($src);
694 14 100       130 if ( defined $constraint )
695             {
696 5         26 $dnld .= '?version=' . _escape($constraint);
697             }
698              
699 14         75 local $File::Fetch::WARN;
700 14         275 my $ff = File::Fetch->new( uri => $dnld );
701 14 50       62245 $ff->scheme('http')
702             if $ff->scheme eq 'https';
703 14         401 my $json_info = '';
704 14         201 my $where = $ff->fetch( to => \$json_info );
705              
706 14 50       5494366 croak "Could not find module $src on metacpan"
707             if !defined $where;
708              
709 14         223 my $result = JSON::PP::decode_json($json_info);
710 14         19051 $seen{$src}->{$constraint} = $result;
711              
712 14         568 return $result;
713             }
714              
715             sub _get_targz
716             {
717 58     58   278 my $target = shift;
718              
719 58         252 my $src = $target->{src_name};
720              
721 58 100       1166 if ( -e -f $src )
722             {
723 26         147 return $src;
724             }
725              
726 32         130 my $url;
727              
728             # git
729 32 100       403 if ( $src =~ git_re )
730             {
731 2         38 my $min_git_ver = min_git_ver;
732 2 50       20 croak "System has git version < $min_git_ver, cannot retrieve git URL"
733             unless has_updated_git;
734              
735 2 50       12 croak "System does not have git, cannot retrieve git URL"
736             unless has_git;
737              
738 2         19 my ( $git_url, $commit ) = $src =~ git_extract_re;
739              
740 2         48 my $dir
741             = tempdir( TEMPLATE => File::Spec->tmpdir . '/mechacpan_XXXXXXXX' );
742 2         467 my ( $fh, $file ) = tempfile(
743             TEMPLATE => File::Spec->tmpdir . '/mechacpan_tar.gz_XXXXXXXX',
744             CLEANUP => 1
745             );
746              
747 2         607 run( 'git', 'clone', '--bare', $git_url, $dir );
748 2   100     69 run(
749             $fh, 'git', 'archive', '--format=tar.gz', "--remote=$dir",
750             $commit || 'master'
751             );
752 2         61 close $fh;
753 2         102 return $file;
754             }
755              
756             # URL
757 30 100       233 if ( $src =~ url_re )
758             {
759 1         14 $url = $src;
760             }
761              
762             # PAUSE
763 30 100       338 if ( $src =~ $pause_re )
764             {
765 6         97 my $author = $1;
766 6         45 my $package = $2;
767 6         44 $url = join(
768             '/',
769             'https://cpan.metacpan.org/authors/id',
770             substr( $author, 0, 1 ),
771             substr( $author, 0, 2 ),
772             $author,
773             $package,
774             );
775              
776 6         40 $target->{is_cpan} = 1;
777             }
778              
779             # Module Name
780 30 100       144 if ( !defined $url )
781             {
782 23         185 my $json_data = _search_metacpan( $src, $target->{constraint} );
783              
784 23         159 $url = $json_data->{download_url};
785              
786 23         159 $target->{is_cpan} = 1;
787 23         450 $target->{version} = version->parse( $json_data->{version} );
788             }
789              
790 30 50       339 if ( defined $url )
791             {
792             # if it's pause like, parse out the distibution's version name
793 30 100       678 if ( $url =~ $full_pause_re )
794             {
795 27         168 my $package = $3;
796 27         259 $target->{pathname} = "$1/$2/$3";
797 27         486 $package =~ s/ (.*) [.] ( tar[.](gz|z|bz2) | zip | tgz) $/$1/xmsi;
798 27         134 $target->{distvname} = $package;
799             }
800              
801 30         129 local $File::Fetch::WARN;
802 30         527 my $ff = File::Fetch->new( uri => $url );
803 30         159621 my $dest_dir = dest_dir() . "/pkgs";
804              
805 30 100       297 $ff->scheme('http')
806             if $ff->scheme eq 'https';
807 30         1464 my $where = $ff->fetch( to => $dest_dir );
808 30 50 0     2880916 croak $ff->error || "Could not download $url"
809             if !defined $where;
810              
811 30         1712 return $where;
812             }
813              
814 0         0 croak "Cannot find $src\n";
815             }
816              
817             sub _get_mod_ver
818             {
819 71     71   214 my $module = shift;
820 71 50       330 return $]
821             if $module eq 'perl';
822 71         202 local $@;
823 71         243 my $ver = eval {
824 71         383 my $file = _installed_file_for_module($module);
825 71         1946 MM->parse_version($file);
826             };
827              
828 71 100       10015 if ( !defined $ver )
829             {
830 58         367 $ver = $Module::CoreList::version{$]}{$module};
831             }
832              
833 71         576 return $ver;
834             }
835              
836             sub _load_meta
837             {
838 81     81   307 my $target = shift;
839 81         239 my $cache = shift;
840 81         298 my $my = shift;
841              
842 81 100       740 my $prefix = $my ? 'MYMETA' : 'META';
843              
844 81         291 my $meta;
845              
846 81         904 foreach my $file ( "$prefix.json", "$prefix.yml" )
847             {
848 108         536 $meta = eval { CPAN::Meta->load_file($file) };
  108         2439  
849             last
850 108 100       6907801 if defined $meta;
851             }
852              
853 81         642 return $meta;
854             }
855              
856             sub _phase_prereq
857             {
858 149     149   387 my $target = shift;
859 149         333 my $cache = shift;
860 149         787 my $phase = shift;
861              
862 149         1394 my $prereqs = $target->{meta}->effective_prereqs;
863 149         420719 my @result;
864              
865 149         1154 my $requirements = $prereqs->requirements_for( $phase, "requires" );
866 149         7023 my $reqs = $requirements->as_string_hash;
867 149         11376 for my $module ( sort keys %$reqs )
868             {
869 275         523 my $is_core;
870              
871 275 100       1112 if ( exists $Module::CoreList::version{$]}{$module} )
872             {
873 218         951 my $version = $Module::CoreList::version{$]}{$module};
874 218         1092 $is_core = $requirements->accepts_module( $module, $version );
875             }
876              
877 275 100 100     12517 push @result, [ $module, $reqs->{$module} ]
878             if $module ne 'perl' && !$is_core;
879             }
880              
881 149         3686 return @result;
882             }
883              
884             sub _installed_file_for_module
885             {
886 71     71   165 my $prereq = shift;
887 71         383 my $file = "$prereq.pm";
888 71         635 $file =~ s{::}{/}g;
889              
890 71         668 state $archname = $Config{archname};
891 71         249 state $perlver = $Config{version};
892              
893 71         642 for my $dir (
894             "$dest_lib/$archname",
895             "$dest_lib",
896             )
897             {
898 142         2171 my $tmp = File::Spec->catfile( $dir, $file );
899 142 100       2383 return $tmp
900             if -r $tmp;
901             }
902             }
903              
904             sub _should_install
905             {
906 94     94   274 my $target = shift;
907              
908             return 1
909 94 100       548 unless defined $target->{module};
910              
911 50         212 my $module = $target->{module};
912 50         383 my $ver = _get_mod_ver($module);
913              
914 50         250 $target->{installed_version} = $ver;
915              
916 50 100       341 return 1
917             if !defined $ver;
918              
919 20         125 my $msg = 'Up to date';
920              
921             $msg = 'Installed'
922 20 100       117 if $target->{was_installed};
923              
924 20 100       116 if ( !$target->{update} )
925             {
926 6         37 my $constraint = $target->{constraint};
927 6   100     219 my $prereq = CPAN::Meta::Prereqs->new(
928             { runtime => { requires => { $module => $constraint // 0 } } } );
929 6         1851 my $req = $prereq->requirements_for( 'runtime', 'requires' );
930              
931 6 50       338 if ( $req->accepts_module( $module, $ver ) )
932             {
933             success(
934             $target->{key},
935 6         637 _target_line( $target, $msg )
936             );
937 6         36 _complete($target);
938 6         134 return;
939             }
940             }
941              
942 14 100 100     268 if ( defined $target->{version} && $target->{version} eq $ver )
943             {
944             success(
945             $target->{key},
946 1         23 _target_line( $target, $msg )
947             );
948 1         16 _complete($target);
949 1         14 return;
950             }
951              
952 13         117 return 1;
953             }
954              
955             sub _source_translate
956             {
957 44     44   142 my $src_name = shift;
958 44         125 my $opts = shift;
959 44         170 my $sources = $opts->{source};
960              
961 44         105 my $new_src;
962              
963 44 50       392 if ( ref $sources eq 'HASH' )
964             {
965 44         167 $new_src = $sources->{$src_name};
966             }
967              
968 44 50       306 if ( ref $sources eq 'CODE' )
969             {
970 0         0 $new_src = $sources->($src_name);
971             }
972              
973 44 50 66     308 if ( $opts->{'only-sources'} && !defined $new_src )
974             {
975 0 0       0 if ( exists $Module::CoreList::version{$]}{$src_name} )
976             {
977 0         0 return $src_name;
978             }
979              
980 0         0 croak "Unable to locate $src_name from the sources list\n";
981             }
982              
983 44 100       276 return defined $new_src ? $new_src : $src_name;
984             }
985              
986             sub _complete
987             {
988 40     40   166 my $target = shift;
989 40         172 $target->{state} = $COMPLETE;
990              
991             # If we are marking complete because the installed version is the Core
992             # version, mark that it "was_installed"
993 40 100 66     527 if ( exists $target->{installed_version} && !$target->{was_installed} )
994             {
995 25         132 my $module = $target->{module};
996 25         98 my $ver = $target->{installed_version};
997              
998             $target->{was_installed} = 1
999 25 100       257 if $ver eq $Module::CoreList::version{$]}{$module};
1000             }
1001              
1002 40 50 33     363 if ( exists $target->{inital_version}
1003             && !defined $target->{inital_version} )
1004             {
1005             # If the module was initally not installed but now is, we probbaly
1006             # installed it by another package name, so mark it as was_installed
1007             $target->{was_installed} = 1
1008 0 0       0 if defined _get_mod_ver( $target->{module} );
1009             }
1010              
1011 40         129 return;
1012             }
1013              
1014             sub _failed
1015             {
1016 10     10   38 my $target = shift;
1017 10         54 $target->{state} = $FAILED;
1018 10         29 return;
1019             }
1020              
1021             sub _name_target
1022             {
1023 490     490   1378 my $target = shift;
1024 490   66     5423 return $target->{name} || $target->{module} || $target->{src_name};
1025             }
1026              
1027             sub _target_line
1028             {
1029 480     480   1111 my $target = shift;
1030 480         1776 my $status = shift;
1031              
1032 480         2007 my $line = sprintf( '%-13s %s', $status, _name_target($target) );
1033              
1034 480         1727 return $line;
1035             }
1036              
1037             1;
1038             __END__