File Coverage

blib/lib/Shipwright/Source/Base.pm
Criterion Covered Total %
statement 55 367 14.9
branch 3 188 1.6
condition 0 71 0.0
subroutine 16 29 55.1
pod 5 5 100.0
total 79 660 11.9


line stmt bran cond sub pod time code
1             package Shipwright::Source::Base;
2              
3 3     3   1404 use warnings;
  3         4  
  3         94  
4 3     3   13 use strict;
  3         3  
  3         85  
5 3     3   12 use File::Spec::Functions qw/catfile catdir/;
  3         5  
  3         142  
6 3     3   1915 use File::Slurp;
  3         11920  
  3         207  
7 3     3   7069 use Module::CoreList;
  3         99423  
  3         31  
8 3     3   1403 use Shipwright::Source;
  3         5  
  3         47  
9 3     3   196 use Shipwright::Util;
  3         4  
  3         358  
10 3     3   15 use Cwd qw/getcwd/;
  3         3  
  3         126  
11 3     3   735 use File::Copy::Recursive qw/rcopy/;
  3         4874  
  3         129  
12 3     3   15 use UNIVERSAL::require;
  3         4  
  3         22  
13              
14 3     3   56 use base qw/Shipwright::Base/;
  3         4  
  3         894  
15             __PACKAGE__->mk_accessors(
16             qw/source directory scripts_directory download_directory follow
17             min_perl_version map_path skip map skip_recommends skip_all_recommends
18             skip_installed include_dual_lifed
19             keep_build_requires name log url_path version_path branches_path version
20             skip_all_test_requires skip_all_build_requires installed
21             /
22             );
23              
24             =head1 NAME
25              
26             Shipwright::Source::Base - Base class of source
27              
28             =head1 SYNOPSIS
29              
30             =head1 METHODS
31              
32             =head2 new
33              
34             =cut
35              
36             sub new {
37 10     10 1 18 my $class = shift;
38 10         152 my $self = {@_};
39 10         22 bless $self, $class;
40 10         74 $self->log( Log::Log4perl->get_logger( ref $self ) );
41 10         2583 return $self;
42             }
43              
44             =head2 run
45              
46             =cut
47              
48             sub run {
49 0     0 1 0 my $self = shift;
50 0         0 my %args = @_;
51 0         0 for ( $self->_cmd ) {
52 0 0       0 if ( ref $_ eq 'CODE' ) {
53 0         0 $_->();
54             }
55             else {
56 0         0 run_cmd($_);
57             }
58             }
59 0 0       0 $self->_copy( %{ $args{copy} } ) if $args{copy};
  0         0  
60             }
61              
62             # you should subclass this method.
63 0     0   0 sub _cmd { }
64              
65             sub _follow {
66 0     0   0 my $self = shift;
67 0         0 my $path = shift;
68 0         0 my $cwd = getcwd;
69 0         0 my $require_path = catfile( $path, '__require.yml' );
70 0         0 my $map = {};
71 0         0 my $url = {};
72              
73              
74 0 0       0 unless ( $self->min_perl_version ) {
75 3     3   17 no warnings 'once';
  3         5  
  3         5899  
76 0         0 require Config;
77 0         0 require version;
78 0         0 my $version = version->new( $Config::Config{version} );
79 0         0 $self->min_perl_version( $version->numify );
80             }
81              
82 0 0       0 if ( -e $self->map_path ) {
83 0         0 $map = load_yaml_file( $self->map_path );
84             }
85              
86 0 0       0 if ( -e $self->url_path ) {
87 0         0 $url = load_yaml_file( $self->url_path );
88             }
89              
90 0         0 my @types = qw/requires configure_requires/;
91              
92 0         0 my $reverse_map = { reverse %$map };
93 0   0     0 my $skip_recommends = $self->skip_recommends->{ $self->name }
94             || ( $reverse_map->{ $self->name }
95             && $self->skip_recommends->{ $reverse_map->{ $self->name } } )
96             || $self->skip_all_recommends;
97 0 0       0 push @types, 'recommends' unless $skip_recommends;
98 0 0       0 push @types, 'test_requires' unless $self->skip_all_test_requires;
99 0 0       0 push @types, 'build_requires' unless $self->skip_all_build_requires;
100              
101 0 0       0 if ( !-e $require_path ) {
102              
103             # if not found, we'll create one according to Build.PL or Makefile.PL
104 0         0 my $require = {};
105 0         0 chdir catdir($path);
106              
107 0         0 my $run_failed;
108 0 0       0 if ( $path =~ /\bcpan-Bundle-(.*)/ ) {
    0          
    0          
109 0         0 $self->log->info("$path is a CPAN Bundle distribution");
110              
111 0         0 my $file = $1;
112 0         0 $file =~ s!-!/!;
113 0         0 $file .= '.pm';
114              
115             # so it's a bundle module
116 0 0       0 open my $fh, '<', 'MANIFEST' or confess_or_die "no manifest found: $!";
117 0         0 while (<$fh>) {
118 0         0 chomp;
119 0 0       0 if (/$file/) {
120 0         0 $file = $_;
121 0         0 last;
122             }
123             }
124 0 0       0 open $fh, '<', $file or confess_or_die "can't open $file: $!";
125 0         0 my $flip;
126 0         0 while (<$fh>) {
127 0         0 chomp;
128 0 0       0 next if /^\s*$/;
129              
130 0 0       0 if (/^=head1\s+CONTENTS/) {
    0          
131 0         0 $flip = 1;
132 0         0 next;
133             }
134             elsif (/^=(?!head1\s+CONTENTS)/) {
135 0         0 $flip = 0;
136             }
137              
138 0 0       0 next unless $flip;
139 0         0 my $info;
140 0 0       0 if (/(.*?)-/) {
141              
142             # things following '-' are comments which we don't want here
143 0         0 $info = $1;
144             }
145             else {
146 0         0 $info = $_;
147             }
148 0         0 my ( $module, $version ) = split /\s+/, $info;
149 0   0     0 $require->{requires}{$module} = $version || 0;
150             }
151              
152             }
153             elsif ( -e 'Build.PL' ) {
154 0         0 $self->log->info("$path is a Module::Build based distribution");
155              
156 0         0 run_cmd(
157             [
158             $^X, '-Mversion',
159             '-MModule::Build', '-MShipwright::Util::CleanINC',
160             'Build.PL'
161             ],
162             1, # don't die if this fails
163             );
164 0 0 0     0 run_cmd( [ $^X, 'Build.PL' ] ) if $? || !-e 'Build';
165 0 0       0 if ( -e catfile( '_build', 'prereqs' ) ) {
166 0 0       0 my $source = read_file( catfile( '_build', 'prereqs' ) )
167             or confess_or_die "can't read _build/prereqs: $!";
168 0         0 my $eval = '$require = ' . $source;
169 0 0       0 eval "$eval;1" or confess_or_die "eval error: $@"; ## no critic
170             }
171             else {
172             # could be something else, e.g. Module::Build::Tiny
173 0         0 $run_failed = 1;
174             }
175              
176 0         0 run_cmd(
177             [ $^X, 'Build', 'realclean', '--allow_mb_mismatch', 1 ] );
178             }
179             elsif ( -e 'Makefile.PL' ) {
180 0 0       0 my $makefile = read_file('Makefile.PL')
181             or confess_or_die "can't read Makefile.PL: $!";
182 0 0       0 if ( $makefile =~ /inc::Module::Install/ ) {
183 0         0 $self->log->info(
184             "$path is a Module::Install based distribution");
185              
186             # in case people call another file, which contains
187             # keywords like requires, features, etc
188             # see Task::Plack for a real example
189 0         0 while ( $makefile =~ /(do\s+(['"])(.*?)\2\s*;\s*$)/m ) {
190 0         0 my $line = $1;
191 0         0 my $content = read_file($3);
192 0         0 $content =~ s/^__END__$ .*//xsmg;
193 0         0 $makefile =~ s/$line/$content;/;
194             }
195              
196             # PREREQ_PM in Makefile is not good enough for inc::Module::Install, which
197             # will omit features(..). we'll put deps in features(...) into recommends part
198              
199 0         0 $makefile =~ s/^\s*requires(?!\w)/shipwright_requires/mg;
200 0         0 $makefile =~ s/^\s*build_requires(?!\w)/shipwright_build_requires/mg;
201 0         0 $makefile =~ s/^\s*configure_requires(?!\w)/shipwright_configure_requires/mg;
202 0         0 $makefile =~
203             s/^\s*test_requires(?!\w)/shipwright_test_requires/mg;
204 0         0 $makefile =~ s/^\s*recommends(?!\w)/shipwright_recommends/mg;
205 0         0 $makefile =~ s/^\s*features(?!\w)/shipwright_features/mg;
206 0         0 $makefile =~ s/^\s*feature(?!\w)/shipwright_feature/mg;
207 0         0 $makefile =~
208             s/^\s*requires_from(?!\w)/shipwright_requires_from/mg;
209 0         0 $makefile =~
210             s/^\s*test_requires_from(?!\w)/shipwright_test_requires_from/mg;
211 0         0 my $shipwright_makefile = <<'EOF';
212             use Data::Dumper;
213             my $shipwright_req = {};
214              
215             sub _shipwright_requires {
216             my $type = shift;
217             my %req = @_;
218             for my $name ( keys %req ) {
219             $shipwright_req->{$type}{$name} = $req{$name};
220             }
221             }
222              
223             sub shipwright_requires {
224             _shipwright_requires( 'requires', @_ == 1 ? ( @_, 0 ) : @_ );
225             goto &requires;
226             }
227              
228             sub shipwright_build_requires {
229             _shipwright_requires( 'build_requires', @_ == 1 ? ( @_, 0 ) : @_ );
230             goto &build_requires;
231             }
232              
233             sub shipwright_configure_requires {
234             _shipwright_requires( 'configure_requires', @_ == 1 ? ( @_, 0 ) : @_ );
235             goto &configure_requires;
236             }
237              
238             sub shipwright_test_requires {
239             _shipwright_requires( 'test_requires', @_ == 1 ? ( @_, 0 ) : @_ );
240             goto &test_requires;
241             }
242              
243             sub _shipwright_requires_from {
244             my $type = shift;
245             my $file = shift;
246              
247             open my $fh, '<', $file or return;
248             my $content = do { local $/; <$fh> };
249             # the following lines in this sub are mostly stolen from Module::Install::Metadata
250             my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg;
251              
252             while ( @requires ) {
253             my $module = shift @requires;
254             my $version = shift @requires;
255             _shipwright_requires( $type, $module, $version || 0 );
256             }
257             }
258              
259             sub shipwright_test_requires_from {
260             _shipwright_requires_from( 'test_requires', @_ );
261             goto &test_requires_from;
262             }
263              
264             sub shipwright_requires_from {
265             _shipwright_requires_from( 'requires', @_ );
266             goto &requires_from;
267             }
268              
269             sub shipwright_recommends {
270             _shipwright_requires( 'recommends', @_ == 1 ? ( @_, 0 ) : @_ );
271             goto &recommends;
272             }
273              
274             sub shipwright_feature {
275             my ( $name, @mods ) = @_;
276             my $type = $name && $name ne '-core' ? 'recommends' : 'requires';
277             for ( my $i = 0 ; $i < @mods ; $i++ ) {
278             if ( $mods[$i] eq '-default' ) {
279             $i++; # skip the -default value
280             }
281             elsif ( $mods[ $i + 1 ] =~ /^[\d\.]*$/ ) {
282              
283             # index $i+1 is a version
284             $shipwright_req->{$type}{ $mods[$i] } = $mods[ $i + 1 ] || 0;
285             $i++;
286             }
287             else {
288             $shipwright_req->{$type}{ $mods[$i] } = 0;
289             }
290             }
291             goto &feature;
292             }
293              
294             sub shipwright_features {
295             my @args = @_;
296             while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) {
297             my $type = $name && $name ne '-core' ? 'recommends' : 'requires';
298             for ( my $i = 0; $i < @$mods; $i++ ) {
299             if ( $mods->[$i] eq '-default' ) {
300             $i++;
301             next;
302             }
303              
304             if ( ref $mods->[$i] eq 'ARRAY' ) {
305             # this happends when
306             # features(
307             # 'Date loading' => [
308             # -default => 0,
309             # recommends( 'DateTime' )
310             # ],
311             # );
312             for ( my $j = 0; $j < @{$mods->[$i]}; $j++ ) {
313             if ( ref $mods->[$i][$j] eq 'ARRAY' ) {
314             $shipwright_req->{$type}{$mods->[$i][$j][0]}
315             = $mods->[$i][$j][1] || 0;
316             }
317             elsif ( $mods->[$i][$j+1] =~ /^[\d\.]*$/ ) {
318             $shipwright_req->{$type}{$mods->[$i][$j]}
319             = $mods->[$i][$j+1] || 0;
320             $j++;
321             }
322             else {
323             $shipwright_req->{$type}{$mods->[$i][$j]} = 0;
324             }
325             }
326            
327             next;
328             }
329              
330             if ( $mods->[$i+1] =~ /^[\d\.]*$/ ) {
331             # index $i+1 is a version
332             $shipwright_req->{$type}{$mods->[$i]} = $mods->[$i+1] || 0;
333             $i++;
334             }
335             else {
336             $shipwright_req->{$type}{$mods->[$i]} = 0;
337             }
338             }
339             }
340            
341             goto &features;
342             }
343              
344             END {
345             open my $tmp_fh, '>', 'shipwright_prereqs';
346             print $tmp_fh Data::Dumper->Dump( [$shipwright_req], [qw/require/] );
347             }
348              
349             EOF
350              
351 0         0 $shipwright_makefile .= $makefile;
352 0         0 write_file( 'shipwright_makefile.pl', $shipwright_makefile );
353              
354 0         0 run_cmd(
355             [
356             $^X,
357             '-Mversion',
358             '-MShipwright::Util::CleanINC',
359             'shipwright_makefile.pl'
360             ],
361             1, # don't die if this fails
362             );
363 0 0 0     0 run_cmd( [ $^X, 'shipwright_makefile.pl' ] )
364             if $? || !-e 'Makefile';
365 0 0       0 my $prereqs = read_file( catfile('shipwright_prereqs') )
366             or confess_or_die "can't read prereqs: $!";
367 0 0       0 eval "$prereqs;1;" or confess_or_die "eval error: $@"; ## no critic
368              
369 0 0       0 if ( -e 'META.yml' ) {
370              
371             # if there's META.yml, let's find more about it
372 0 0       0 my $meta = load_yaml_file('META.yml')
373             or confess_or_die "can't read META.yml: $!";
374              
375             # Module::Install will make test_requires into build_requires
376 0         0 for ( keys %{ $require->{test_requires} } ) {
  0         0  
377 0 0       0 delete $meta->{build_requires}{$_}
378             if exists $meta->{build_requires}{$_};
379             }
380              
381 0   0     0 $require ||= {};
382 0 0       0 $require->{requires} = {
383 0 0       0 %{ $meta->{requires} || {} },
384 0         0 %{ $require->{requires} || {} },
385             };
386 0 0       0 $require->{recommends} = {
387 0 0       0 %{ $meta->{recommends} || {} },
388 0         0 %{ $require->{recommends} || {} },
389             };
390 0 0       0 $require->{build_requires} = {
391 0 0       0 %{ $meta->{build_requires} || {} },
392 0 0       0 %{ $meta->{configure_requires} || {} },
393 0         0 %{ $require->{build_requires} || {} },
394             };
395 0 0       0 $require->{test_requires} = {
396 0 0       0 %{ $meta->{test_rquires} || {} },
397 0         0 %{ $require->{test_requires} || {} },
398             };
399              
400             }
401              
402 0         0 unlink 'shipwright_makefile.pl', 'shipwright_prereqs';
403             }
404             else {
405              
406             # we extract the deps from Makefile
407 0         0 run_cmd(
408             [
409             $^X,
410             '-MShipwright::Util::CleanINC',
411             'Makefile.PL'
412             ],
413             1, # don't die if this fails
414             );
415 0 0 0     0 run_cmd( [ $^X, 'Makefile.PL' ] )
416             if $? || !-e 'Makefile';
417              
418 0         0 my @makefile = read_file('Makefile');
419 0         0 my ($source) = grep { /PREREQ_PM/ } @makefile;
  0         0  
420 0 0 0     0 if ( $source && $source =~ /({.*})/ ) {
421 0         0 my $eval .= '$require = ' . $1;
422 0         0 $eval =~ s/([\w:]+)=>/'$1'=>/g;
423 0 0       0 eval "$eval;1" or confess_or_die "eval error: $@"; ## no critic
424              
425 0         0 for ( keys %$require ) {
426 0         0 $require->{requires}{$_} = delete $require->{$_};
427             }
428             }
429              
430 0         0 my %requires_map = (
431             PREREQ_PM => 'requires',
432             BUILD_REQUIRES => 'build_requires',
433             TEST_REQUIRES => 'test_requires',
434             CONFIGURE_REQUIRES => 'configure_requires',
435             );
436              
437 0         0 for my $item ( keys %requires_map ) {
438 0         0 my ($source) = grep { /$item/ } @makefile;
  0         0  
439 0 0 0     0 if ( $source && $source =~ /({.*})/ ) {
440 0         0 my $tmp_requires;
441 0         0 my $eval .= '$tmp_requires = ' . $1;
442 0         0 $eval =~ s/([\w:]+)=>/'$1'=>/g;
443 0 0       0 eval "$eval;1" or confess_or_die "eval error: $@"; ## no critic
444              
445 0   0     0 $require->{$requires_map{$item}} ||= {};
446 0         0 for ( keys %$tmp_requires ) {
447 0         0 $require->{$requires_map{$item}}{$_} = delete $tmp_requires->{$_};
448             }
449             }
450             }
451              
452             }
453 0         0 run_cmd(
454             [ $ENV{SHIPWRIGHT_MAKE}, 'clean' ] );
455 0         0 unlink 'Makefile.old';
456             }
457              
458 0 0       0 if ( $run_failed ) {
459             # read "require" from META.yml instead
460 0 0       0 my $meta = load_yaml_file('META.yml') or confess_or_die "can't read META.yml: $!";
461 0         0 for my $type ( keys %$meta ) {
462 0 0       0 next unless $type =~ /requires|recommends/;
463 0         0 $require->{$type} = $meta->{$type};
464             }
465             }
466              
467 0         0 for my $type ( @types ) {
468 0 0       0 next unless $require->{$type};
469 0         0 for my $module ( keys %{ $require->{$type} } ) {
  0         0  
470 0         0 $require->{$type}{$module}{version} =
471             delete $require->{$type}{$module};
472             }
473             }
474              
475 0 0       0 dump_yaml_file( $require_path, $require )
476             or confess_or_die "can't dump __require.yml: $!";
477             }
478              
479 0 0       0 if ( my $require = load_yaml_file($require_path) ) {
480              
481             # if not have 'requires' key, all the keys in $require are supposed to be
482             # requires type
483 0 0       0 if ( !$require->{requires} ) {
484 0         0 for my $module ( keys %$require ) {
485 0         0 $require->{requires}{$module}{version} =
486             delete $require->{$module};
487             }
488             }
489              
490 0         0 for my $type ( @types ) {
491 0         0 for my $module ( keys %{ $require->{$type} } ) {
  0         0  
492              
493             #$module shouldn't be undefined, but it _indeed_ happens in reality sometimes
494 0 0       0 next unless $module;
495             # we don't want to require perl
496 0 0       0 if ( $module eq 'perl' ) {
497 0         0 delete $require->{$type}{$module};
498 0         0 next;
499             }
500              
501 0 0       0 my $version =
502             ref $require->{$type}{$module}
503             ? $require->{$type}{$module}{version}
504             : $require->{$type}{$module};
505 0   0     0 $version ||= 0;
506 0         0 $version =~ s!^\D+!!; # some may contain '>' or '>='
507 0 0 0     0 if ( !$self->include_dual_lifed
      0        
      0        
      0        
508             && Module::CoreList->first_release( $module, $version )
509             && Module::CoreList->first_release( $module, $version ) <= $self->min_perl_version
510             && ( !Module::CoreList->removed_from($module) || Module::CoreList->removed_from($module) > $self->min_perl_version) )
511             {
512 0         0 $self->log->info("skipping $module because it's in core");
513 0         0 delete $require->{$type}{$module};
514 0         0 next;
515             }
516              
517 0 0       0 if ( $self->skip_installed ) {
518 0 0       0 if ( $module->require ) {
519 0         0 $self->log->info("found installed $module");
520 3     3   20 no strict 'refs'; ## no critic
  3         4  
  3         5460  
521 0         0 require version;
522 0         0 my $installed_version = ${ $module . '::VERSION' };
  0         0  
523 0 0 0     0 if ( $installed_version
524             && version->parse($installed_version) >=
525             version->parse($version) )
526             {
527 0         0 $self->log->info(
528             "skipping $module because it's installed" );
529 0         0 delete $require->{$type}{$module};
530 0         0 next;
531             }
532             }
533             }
534              
535 0         0 my $name = $module;
536              
537 0 0 0     0 if ( $self->_is_skipped($module)
538             && !$self->_is_installed($module) )
539             {
540              
541             # skipped contains all modules imported before,
542             # so we need to check if they are imported ones
543 0         0 delete $require->{$type}{$module};
544 0         0 next;
545             }
546             else {
547              
548 0         0 opendir my $dir, $self->directory;
549 0         0 my @sources = readdir $dir;
550 0         0 close $dir;
551              
552             #reload map
553 0 0       0 if ( -e $self->map_path ) {
554 0         0 $map = load_yaml_file( $self->map_path );
555             }
556              
557 0 0 0     0 if ( $map->{$module} && $map->{$module} =~ /^cpan-/ ) {
558 0         0 $name = $map->{$module};
559             }
560             else {
561              
562             # assuming it's a CPAN module
563 0         0 $name =~ s/::/-/g;
564 0 0       0 $name = 'cpan-' . $name unless $name =~ /^cpan-/;
565             }
566              
567 0 0       0 unless ( grep { $name eq $_ } @sources ) {
  0         0  
568 0         0 my $s;
569 0         0 my $cwd = getcwd;
570 0         0 chdir $self->directory;
571 0 0 0     0 if ( $require->{$type}{$module}{source}
572             && $require->{$type}{$module}{source} ne 'CPAN' )
573             {
574 0         0 $s = Shipwright::Source->new(
575             %$self,
576             source => $require->{$type}{$module}{source},
577             name => $name,
578             version => undef,
579             _path => undef,
580             );
581             }
582             else {
583 0         0 $s = Shipwright::Source->new(
584             %$self,
585             source => "cpan:$module",
586             version => undef,
587             name => '', # cpan name is automaticaly fixed.
588             _path => undef,
589             );
590             }
591 0 0       0 unless ($s->run()) {
592             # if run returns false, we should skip trying to install it.
593             # this lets us skip explicit dependencies that are actually part of the perl core
594 0         0 delete $require->{$type}{$module};
595 0         0 chdir $cwd;
596 0         0 next;
597              
598             }
599 0         0 chdir $cwd;
600             }
601              
602             # reload map
603 0 0       0 if ( -e $self->map_path ) {
604 0         0 $map = load_yaml_file( $self->map_path );
605             }
606              
607             }
608              
609             # convert required module name to dist name like cpan-Jifty-DBI
610 0 0 0     0 if ( $map->{$module} && $map->{$module} =~ /^cpan-/ ) {
611 0         0 $require->{$type}{ $map->{$module} } =
612             delete $require->{$type}{$module};
613             }
614             else {
615 0         0 $require->{$type}{$name} =
616             delete $require->{$type}{$module};
617             }
618             }
619             }
620             # don't keep recommends info if we skip them, so we won't encounter
621             # them when update later
622 0 0       0 $require->{recommends} = {} if $skip_recommends;
623 0 0       0 $require->{test_requires} = {} if $self->skip_all_test_requires;
624 0 0       0 $require->{build_requires} = {} if $self->skip_all_build_requires;
625              
626 0         0 dump_yaml_file( $require_path, $require );
627             }
628             else {
629 0         0 confess_or_die "invalid __require.yml in $path";
630             }
631              
632             # go back to the cwd before we run _follow
633 0         0 chdir $cwd;
634             }
635              
636             sub _update_map {
637 0     0   0 my $self = shift;
638 0         0 my $module = shift;
639 0         0 my $dist = shift;
640              
641 0         0 my $map = {};
642 0 0       0 if ( -e $self->map_path ) {
643 0         0 $map = load_yaml_file( $self->map_path );
644             }
645 0 0       0 return if $map->{$module};
646              
647 0         0 $map->{$module} = $dist;
648 0         0 dump_yaml_file( $self->map_path, $map );
649             }
650              
651             sub _update_url {
652 0     0   0 my $self = shift;
653 0         0 my $name = shift;
654 0         0 my $url = shift;
655              
656 0         0 my $map = {};
657 0 0 0     0 if ( -e $self->url_path && !-z $self->url_path ) {
658 0         0 $map = load_yaml_file( $self->url_path );
659             }
660 0         0 $map->{$name} = $url;
661 0         0 dump_yaml_file( $self->url_path, $map );
662             }
663              
664             sub _update_version {
665 0     0   0 my $self = shift;
666 0         0 my $name = shift;
667 0         0 my $version = shift;
668              
669 0         0 my $map = {};
670 0 0 0     0 if ( -e $self->version_path && !-z $self->version_path ) {
671 0         0 $map = load_yaml_file( $self->version_path );
672             }
673 0         0 $map->{$name} = $version;
674 0         0 dump_yaml_file( $self->version_path, $map );
675             }
676              
677             sub _update_branches {
678 0     0   0 my $self = shift;
679 0         0 my $name = shift;
680 0         0 my $branches = shift;
681              
682 0         0 my $map = {};
683 0 0 0     0 if ( -e $self->version_path && !-z $self->branches_path ) {
684 0         0 $map = load_yaml_file( $self->branches_path );
685             }
686 0         0 $map->{$name} = $branches;
687 0         0 dump_yaml_file( $self->branches_path, $map );
688             }
689              
690             sub _is_skipped {
691 0     0   0 my $self = shift;
692 0         0 my $module = shift;
693 0         0 my $skip;
694              
695 0 0       0 if ( $self->skip ) {
696 0 0       0 if ( $self->skip->{$module} ) {
  0 0       0  
697 0         0 $skip = 1;
698             }
699 0         0 elsif ( grep { /-/ } keys %{ $self->skip } ) {
700              
701             # so we have a dist skip, we need to resolve the $module to the dist name
702 0         0 my $source = Shipwright::Source->new( source => "cpan:$module" );
703 0         0 $source->_run;
704 0         0 my $name = $source->name;
705 0         0 my ($name_without_prefix) = $name =~ /^cpan-(.*)/;
706 0 0 0     0 $skip = 1
707             if $self->skip->{$name} || $self->skip->{$name_without_prefix};
708             }
709              
710 0         0 my @spaces = grep { /::$/ } keys %{$self->skip};
  0         0  
  0         0  
711 0         0 for my $space ( @spaces ) {
712             # we want to skip both Foo and Foo::*
713 0 0       0 if ( "${module}::" =~ /^$space/ ) {
714 0         0 $skip = 1;
715 0         0 last;
716             }
717             }
718              
719 0 0       0 if ($skip) {
720 0         0 $self->log->info("skipping $module");
721 0         0 return 1;
722             }
723             }
724              
725 0         0 return;
726             }
727              
728             sub _is_installed {
729 0     0   0 my $self = shift;
730 0         0 my $module = shift;
731 0         0 my $installed;
732              
733 0         0 my $name = $module;
734 0 0       0 if ( $module !~ /-/ ) {
735 0         0 my $source = Shipwright::Source->new( source => "cpan:$module" );
736 0         0 $source->_run;
737 0         0 $name = $source->name;
738             }
739              
740 0         0 return $self->installed->{$name};
741             }
742              
743             sub _copy {
744 0     0   0 my $self = shift;
745 0         0 my %file = @_;
746 0         0 for ( keys %file ) {
747 0 0       0 if ( $file{$_} ) {
748             my $cmd = sub {
749 0   0 0   0 rcopy(
750             $file{$_},
751             catfile(
752             $self->directory,
753             $self->name || $self->just_name( $self->path ), $_
754             )
755             );
756 0         0 };
757 0         0 run_cmd($cmd);
758             }
759             }
760             }
761              
762             =head2 just_name
763              
764             trim the version stuff from dist name
765              
766             =cut
767              
768             sub just_name {
769 3     3 1 6 my $self = shift;
770 3         4 my $name = shift;
771              
772 3         13 $name =~ s/(?:tar\.bz2|zip)$/tar.gz/; # CPAN::DistnameInfo likes .tar.gz
773              
774 3 50       23 $name .= '.tar.gz' unless $name =~ /(tar\.gz|tgz)$/;
775              
776 3         16 require CPAN::DistnameInfo;
777 3         16 my $info = CPAN::DistnameInfo->new($name);
778 3         157 my $dist = $info->dist;
779 3         32 return $dist;
780             }
781              
782             =head2 just_version
783              
784             return version
785              
786             =cut
787              
788             sub just_version {
789 0     0 1 0 my $self = shift;
790 0         0 my $name = shift;
791 0 0       0 $name .= '.tar.gz' unless $name =~ /\.(tar\.gz|tgz|tar\.bz2|zip)$/;
792              
793 0         0 require CPAN::DistnameInfo;
794 0         0 my $info = CPAN::DistnameInfo->new($name);
795 0         0 my $version = $info->version;
796 0 0       0 $version =~ s/^v// if $version;
797 0         0 return $version;
798             }
799              
800             =head2 is_compressed
801              
802             return true if the source is compressed file, i.e. tar.gz(tgz) and tar.bz2
803              
804             =cut
805              
806             sub is_compressed {
807 9     9 1 7466 my $self = shift;
808 9 100       90 return 1 if $self->source =~ m{\.(tar.(gz|bz2)|tgz|zip)$};
809 5         24 return;
810             }
811              
812             sub _lwp_get {
813 0     0     my $self = shift;
814 0           my $source = shift;
815 0           require LWP::UserAgent;
816 0           my $ua = LWP::UserAgent->new;
817 0           $ua->env_proxy();
818 0 0         $ua->timeout( $ENV{SHIPWRIGHT_LWP_TIMEOUT} )
819             if $ENV{SHIPWRIGHT_LWP_TIMEOUT};
820              
821 0 0         if ( -e $self->source ) {
822 0           my $size = -s $self->source;
823 0           my $res = $ua->head($source);
824 0 0 0       if ( $res->is_success
825             && $res->header('content-length') == $size )
826             {
827 0           return 1;
828             }
829             }
830              
831 0           my $response = $ua->get($source);
832              
833 0 0         if ( $response->is_success ) {
834 0 0         open my $fh, '>', $self->source
835             or confess_or_die "can't open file " . $self->source . ": $!";
836 0           print $fh $response->content;
837             }
838             else {
839 0           confess_or_die "failed to get $source: " . $response->status_line;
840             }
841             }
842              
843             1;
844              
845             __END__