File Coverage

blib/lib/Carmel/Builder.pm
Criterion Covered Total %
statement 33 110 30.0
branch 0 28 0.0
condition 0 17 0.0
subroutine 11 22 50.0
pod 0 10 0.0
total 44 187 23.5


line stmt bran cond sub pod time code
1             package Carmel::Builder;
2 1     1   6 use strict;
  1         1  
  1         22  
3 1     1   5 use warnings;
  1         1  
  1         45  
4             use Class::Tiny qw( snapshot cpanfile cpanfile_path repository_base collect_artifact ), {
5 0         0 mirror => sub { $_[0]->build_mirror },
6 1     1   457 };
  1         1621  
  1         6  
7              
8 1     1   852 use Carmel;
  1         2  
  1         17  
9 1     1   711 use Path::Tiny;
  1         11886  
  1         64  
10 1     1   512 use File::pushd;
  1         18550  
  1         56  
11 1     1   353 use Carmel::Lock;
  1         3  
  1         26  
12 1     1   445 use Carton::Dist;
  1         26661  
  1         36  
13 1     1   526 use CPAN::DistnameInfo;
  1         809  
  1         88  
14 1     1   446 use Menlo::Index::Mirror;
  1         104368  
  1         32  
15 1     1   480 use HTTP::Tinyish;
  1         866  
  1         1015  
16              
17             sub tempdir {
18 0     0 0   my $self = shift;
19 0   0       $self->{tempdir} ||= $self->build_tempdir;
20             }
21              
22             sub build_tempdir {
23 0     0 0   my %opts = ();
24             $opts{CLEANUP} = $ENV{PERL_FILE_TEMP_CLEANUP}
25 0 0         if exists $ENV{PERL_FILE_TEMP_CLEANUP};
26              
27 0           Path::Tiny->tempdir(%opts);
28             }
29              
30             sub build_mirror {
31 0     0 0   my $self = shift;
32              
33             # FIXME: we could set the mirror option to $self->cpanfile in the caller
34 0 0         my $cpanfile = $self->cpanfile_path
35             or die "Can't locate 'cpanfile' to load module list.\n";
36              
37             # one mirror for now
38 0           Module::CPANfile->load($cpanfile)->mirrors->[0];
39             }
40              
41             sub install {
42 0     0 0   my($self, @args) = @_;
43              
44 0           my @cmd;
45 0 0         if ($self->cpanfile) {
46 0           my $path = Path::Tiny->tempfile;
47 0           $self->cpanfile->save($path);
48 0           @cmd = ("--cpanfile", $path, "--installdeps", ".");
49             } else {
50 0           @cmd = @args;
51             }
52              
53 0 0         if ($self->snapshot) {
54 0           my $path = Path::Tiny->tempfile;
55 0           $self->snapshot->write_index($path);
56 0           unshift @cmd,
57             "--mirror-index", $path,
58             "--cascade-search",
59             }
60              
61 0           local $ENV{PERL_CPANM_HOME} = $self->tempdir;
62 0           local $ENV{PERL_CPANM_OPT};
63              
64 0           my $mirror = $self->mirror;
65              
66 0           my $lock = Carmel::Lock->new(path => $self->repository_base->child('run'));
67 0           $lock->acquire;
68              
69             # cleanup perl5 in case it was left from previous runs
70 0           my $lib = $self->repository_base->child('perl5');
71 0           $lib->remove_tree({ safe => 0 });
72              
73 0           require Menlo::CLI::Compat;
74              
75 0           my $cli = Menlo::CLI::Compat->new;
76 0 0         $cli->parse_options(
    0          
77             ($Carmel::DEBUG ? () : "--quiet"),
78             ($mirror ? ("-M", $mirror) : ("--mirror", "https://cpan.metacpan.org/")),
79             "--notest",
80             "--save-dists", $self->repository_base->child('cache'),
81             "-L", $lib,
82             "--no-static-install",
83             @cmd,
84             );
85              
86 0           $cli->run;
87              
88 0           my @artifacts;
89 0           for my $ent ($self->tempdir->child("latest-build")->children) {
90 0 0 0       next unless $ent->is_dir && $ent->child("blib/meta/install.json")->exists;
91 0           push @artifacts, $self->collect_artifact->($ent);
92             }
93              
94 0           $lib->remove_tree({ safe => 0 });
95              
96 0           return @artifacts;
97             }
98              
99             sub search_module {
100 0     0 0   my($self, $module, $version) = @_;
101              
102 0           local $ENV{PERL_CPANM_HOME} = $self->tempdir;
103 0           local $ENV{PERL_CPANM_OPT};
104              
105 0           my $cli = $self->cached_cli;
106              
107 0 0 0       if ($version && $version =~ /==|<|!/) {
108 0 0         my $dist = $cli->search_module($module, $version)
109             or return;
110              
111             return Carton::Dist->new(
112             name => $dist->{distvname},
113             pathname => $dist->{pathname},
114             provides => {
115             $dist->{module} => {
116             version => $dist->{module_version},
117             },
118             },
119             version => $dist->{version},
120 0           );
121             } else {
122 0 0         my $res = $self->index->search_packages({ package => $module })
123             or return;
124              
125 0           (my $path = $res->{uri}) =~ s!^cpan:///distfile/!!;
126 0           my $info = CPAN::DistnameInfo->new($path);
127              
128             return Carton::Dist->new(
129             name => $info->distvname,
130             pathname => $info->pathname,
131             provides => {
132             $res->{package} => {
133             version => $res->{version},
134             },
135             },
136 0           version => $info->version,
137             );
138             }
139             }
140              
141             sub cached_cli {
142 0     0 0   my $self = shift;
143 0   0       $self->{cli} ||= $self->build_cli();
144             }
145              
146             sub build_cli {
147 0     0 0   my $self = shift;
148              
149 0           my $mirror = $self->mirror;
150              
151 0           require Menlo::CLI::Compat;
152              
153 0           my $cli = Menlo::CLI::Compat->new;
154 0 0         $cli->parse_options(
    0          
155             ($Carmel::DEBUG ? () : "--quiet"),
156             ($mirror ? ("-M", $mirror) : ()),
157             "--info",
158             "--save-dists", $self->repository_base->child('cache'),
159             ".",
160             );
161              
162             # This needs to be done to setup http backends for mirror #52
163 0           $cli->setup_home;
164 0           $cli->init_tools;
165              
166 0           return $cli;
167             }
168              
169             sub index {
170 0     0 0   my $self = shift;
171 0   0       $self->{index} ||= $self->build_index;
172             }
173              
174             sub build_index {
175 0     0 0   my $self = shift;
176              
177 0   0       my $mirror = $self->mirror || "https://cpan.metacpan.org/";
178              
179             # Use $cli->mirror to support file: URLs
180             return Menlo::Index::Mirror->new({
181             mirror => $mirror,
182 0     0     fetcher => sub { $self->cached_cli->mirror(@_) },
183 0           });
184             }
185              
186             sub rollout {
187 0     0 0   my($self, $install_base, $artifacts) = @_;
188              
189 0           require ExtUtils::Install;
190 0           require ExtUtils::InstallPaths;
191              
192 0           for my $artifact (@$artifacts) {
193 0           my $dir = pushd $artifact->path;
194              
195 0           my $paths = ExtUtils::InstallPaths->new(install_base => $install_base);
196              
197 0           printf "Installing %s to %s\n", $artifact->distname, $install_base;
198              
199             # ExtUtils::Install writes to STDOUT
200 0           open my $fh, ">", \my $output;
201 0 0         my $old; $old = select $fh unless $Carmel::DEBUG;
  0            
202              
203 0           my %result;
204 0           ExtUtils::Install::install([
205             from_to => $paths->install_map,
206             verbose => 0,
207             dry_run => 0,
208             uninstall_shadows => 0,
209             skip => undef,
210             always_copy => 1,
211             result => \%result,
212             ]);
213              
214 0 0         select $old unless $Carmel::DEBUG;
215             }
216             }
217              
218             1;