File Coverage

blib/lib/App/MechaCPAN/Install.pm
Criterion Covered Total %
statement 465 483 96.2
branch 137 164 83.5
condition 39 53 73.5
subroutine 46 46 100.0
pod 1 1 100.0
total 688 747 92.1


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