File Coverage

blib/lib/App/MechaCPAN/Deploy.pm
Criterion Covered Total %
statement 114 124 91.9
branch 19 30 63.3
condition 5 6 83.3
subroutine 14 15 93.3
pod 1 3 33.3
total 153 178 85.9


line stmt bran cond sub pod time code
1             package App::MechaCPAN::Deploy;
2              
3 21     21   142 use strict;
  21         56  
  21         644  
4 21     21   123 use warnings;
  21         57  
  21         642  
5 20     20   101 use autodie;
  20         47  
  20         165  
6 20     20   98496 use Carp;
  20         639  
  20         1253  
7 20     20   120 use CPAN::Meta;
  20         44  
  20         568  
8 20     20   111 use List::Util qw/reduce/;
  20         49  
  20         1004  
9 20     20   107 use App::MechaCPAN;
  20         46  
  20         12834  
10              
11             our @args = (
12             'skip-perl!',
13             'update!',
14             );
15              
16             sub go
17             {
18 5     5 1 19 my $class = shift;
19 5         15 my $opts = shift;
20 5   100     45 my $src = shift || '.';
21              
22 5         18 my $file = $src;
23              
24 5 100       97 if ( -d $file )
25             {
26 3         14 $file = "$file/cpanfile";
27             }
28              
29 5 50       72 if ( !-e $file )
30             {
31 0         0 croak "Could not find cpanfile ($file)";
32             }
33              
34 5 50       61 if ( !-f $file )
35             {
36 0         0 croak "cpanfile must be a regular file";
37             }
38              
39 5         39 my $prereq = parse_cpanfile($file);
40 5         44 my @phases = qw/configure build test runtime/;
41              
42 5         19 my @acc = map {%$_} map { values %{ $prereq->{$_} } } @phases;
  7         32  
  20         37  
  20         87  
43 5         16 my @reqs;
44 5         26 while (@acc)
45             {
46 7         39 push @reqs, [ splice( @acc, 0, 2 ) ];
47             }
48              
49 5 100       102 if ( -f "$file.snapshot" )
50             {
51 2         22 my $snapshot_info = parse_snapshot("$file.snapshot");
52 2         10 my %srcs;
53 2         14 foreach my $dist ( values %$snapshot_info )
54             {
55 2         9 my $src = $dist->{pathname};
56 2         7 foreach my $provide ( keys %{ $dist->{provides} } )
  2         12  
57             {
58 2 50       17 if ( exists $srcs{$provide} )
59             {
60 0         0 die
61             "Found dumplicate distributions ($src and $srcs{$provide}) that provides the same module ($provide)\n";
62             }
63 2         14 $srcs{$provide} = $src;
64             }
65             }
66              
67 2 50       22 if ( ref $opts->{source} eq 'HASH' )
68             {
69 0         0 %srcs = ( %srcs, %{ $opts->{source} } );
  0         0  
70             }
71 2         12 $opts->{source} = \%srcs;
72 2         13 $opts->{update} = 1;
73 2         19 $opts->{'only-sources'} = 1;
74             }
75              
76 5         17 my $result;
77 5   100     59 $opts->{update} //= 0;
78              
79 5 50       23 if ( !$opts->{'skip-perl'} )
80             {
81 0         0 $result = App::MechaCPAN::Perl->go($opts);
82 0 0       0 return $result if $result;
83             }
84              
85 5         85 $result = App::MechaCPAN::Install->go( $opts, @reqs );
86 5 50       31 return $result if $result;
87              
88 5         124 return 0;
89             }
90              
91             my $sandbox_num = 1;
92              
93             sub parse_cpanfile
94             {
95 6     6 0 3150 my $file = shift;
96              
97 6         47 my $result = { runtime => {} };
98              
99 6         32 $result->{current} = $result->{runtime};
100              
101             my $methods = {
102             on => sub
103             {
104 4     4   15 my ( $phase, $code ) = @_;
105 4   50     45 local $result->{current} = $result->{$phase} //= {};
106 4         18 $code->();
107             },
108 0     0   0 feature => sub {...},
109 6         108 };
110              
111 6         39 foreach my $type (qw/requires recommends suggests conflicts/)
112             {
113             $methods->{$type} = sub
114             {
115 15     15   48 my ( $module, $ver ) = @_;
116 15 100       77 if ( $module eq 'perl' )
117             {
118 6         30 $result->{perl} = $ver;
119 6         22 return;
120             }
121 9         56 $result->{current}->{$type}->{$module} = $ver;
122 24         170 };
123             }
124              
125 6         68 open my $code_fh, '<', $file;
126 6         8604 my $code = do { local $/; <$code_fh> };
  6         33  
  6         169  
127              
128 6         42 my $pkg = __PACKAGE__ . "::Sandbox$sandbox_num";
129 6         20 $sandbox_num++;
130              
131 6         44 foreach my $method ( keys %$methods )
132             {
133 20     20   137 no strict 'refs';
  20         65  
  20         8080  
134 36         85 *{"${pkg}::${method}"} = $methods->{$method};
  36         249  
135             }
136              
137 6         24 local $@;
138 6         59 my $sandbox = join(
139             "\n",
140             qq[package $pkg;],
141             qq[no warnings;],
142             qq[# line 1 "$file"],
143             qq[$code],
144             qq[return 1;],
145             );
146              
147 6     4   605 my $no_error = eval $sandbox;
  4         48  
  4         15  
  4         1576  
148              
149 6 50       48 croak $@
150             unless $no_error;
151              
152 6         21 delete $result->{current};
153              
154 6         93 return $result;
155             }
156              
157             my $snapshot_re = qr/^\# carton snapshot format: version 1\.0/;
158              
159             sub parse_snapshot
160             {
161 3     3 0 2762 my $file = shift;
162              
163 3         15 my $result = {};
164              
165 3         28 open my $snap_fh, '<', $file;
166              
167 3 50       2616 if ( my $line = <$snap_fh> !~ $snapshot_re )
168             {
169 0         0 die "File doesn't looks like a carton snapshot: $file";
170             }
171              
172 3         15 my @stack = ($result);
173 3         12 my $prefix = '';
174 3         26 while ( my $line = <$snap_fh> )
175             {
176 42         96 chomp $line;
177              
178 42 100       499 if ( $line =~ m/^ \Q$prefix\E (\S+?) :? $/xms )
179             {
180 12         63 my $new_depth = {};
181 12         59 $stack[0]->{$1} = $new_depth;
182 12         34 unshift @stack, $new_depth;
183 12         36 $prefix = ' ' x $#stack;
184 12         60 next;
185             }
186              
187 30 100       341 if ( $line =~ m/^ \Q$prefix\E (\S+?) (?: :? \s (.*) )? $/xms )
188             {
189 27         130 $stack[0]->{$1} = $2;
190 27         131 next;
191             }
192              
193 3 50       48 if ( $line !~ m/^ \Q$prefix\E /xms )
194             {
195 3         11 shift @stack;
196 3         14 $prefix = ' ' x $#stack;
197 3         13 redo;
198             }
199              
200 0         0 die "Unable to parse snapshot (line $.)\n";
201             }
202              
203 3         41 return $result->{DISTRIBUTIONS};
204             }
205              
206             1;
207             __END__