File Coverage

lib/App/p5stack.pm
Criterion Covered Total %
statement 76 179 42.4
branch 15 58 25.8
condition 2 3 66.6
subroutine 14 24 58.3
pod 0 2 0.0
total 107 266 40.2


line stmt bran cond sub pod time code
1             package App::p5stack;
2             # ABSTRACT: manage your dependencies and perl requirements locally
3              
4 2     2   26127 use strict;
  2         5  
  2         47  
5 2     2   9 use warnings;
  2         4  
  2         50  
6              
7 2     2   17 use Cwd;
  2         2  
  2         126  
8 2     2   222103 use File::Which;
  2         1841  
  2         152  
9 2     2   14 use File::Basename;
  2         5  
  2         206  
10 2     2   1325 use File::Spec::Functions;
  2         1446  
  2         231  
11 2     2   14 use File::Path qw/make_path/;
  2         5  
  2         161  
12 2     2   3100 use Path::Tiny;
  2         25301  
  2         115  
13 2     2   485392 use Archive::Tar;
  2         362709  
  2         141  
14 2     2   2030 use Data::Dumper;
  2         13323  
  2         121  
15 2     2   1322 use YAML;
  2         14535  
  2         4595  
16              
17             sub new {
18 2     2 0 2951 my ($class, @argv) = @_;
19 2         9 my $self = bless {}, $class;
20              
21 2         12 $self->{orig_argv} = [@argv];
22 2 50       10 $self->{command} = @argv ? lc shift @argv : '';
23 2         7 $self->{argv} = [@argv];
24              
25             # handle config
26 2         10 $self->_do_config;
27              
28 2         51 return $self;
29             }
30              
31             sub run {
32 0     0 0 0 my ($self) = @_;
33              
34 0 0       0 if ($self->{command} eq 'setup') { $self->_do_setup; }
  0 0       0  
    0          
    0          
    0          
35 0         0 elsif ($self->{command} eq 'perl') { $self->_do_perl; }
36 0         0 elsif ($self->{command} eq 'cpanm') { $self->_do_cpanm; }
37 0         0 elsif ($self->{command} eq 'bin') { $self->_do_bin; }
38 0         0 elsif ($self->{command} eq 'run') { $self->_do_run; }
39 0         0 else { $self->_do_help; }
40             }
41              
42             sub _do_config {
43 2     2   4 my ($self) = @_;
44              
45             # set some defaults
46 2         7 $self->{perl} = 'system';
47 2         6 $self->{deps} = 'dzil';
48 2         4 $self->{skip_install} = 1;
49 2         18 $self->{p5stack_root} = catfile($ENV{HOME},'.p5stack');
50 2         13 $self->{perls_root} = catfile($ENV{HOME},'.p5stack','perls');
51 2         5 $self->{perl_version} = '5.20.3';
52              
53             # guess stuff from context
54 2 50       46 $self->{deps} = 'cpanfile' if -e 'cpanfile';
55              
56             # read config from file if available
57 2         3 my $file;
58 2 50       31 -e 'p5stack.yml' and $file = 'p5stack.yml';
59 2 50       182 -e "$ENV{HOME}.p5stack/p5stack.yml" and $file = "$ENV{HOME}.p5stack/p5stack.yml"; # FIXME
60 2 100       8 $ENV{P5STACKCFG} and $file = $ENV{P5STACKCFG};
61              
62 2         5 my $config;
63 2 100       8 if ($file) {
64 1         11 my $yaml = path($file)->slurp_utf8;
65 1         3032 $config = Load $yaml;
66             }
67              
68             # FIXME re-factor after logic is more stable
69 2 50       18859 if ( file_name_is_absolute($config->{perl}) ) {
70 0         0 $self->{perl_version} = _get_perl_version($config->{perl});
71 0         0 $self->{perl} = $config->{perl};
72             }
73 2 50       43 if ( $self->{perl} eq 'system' ) {
74 2         14 $self->{perl} = which 'perl';
75 2         318 $self->{perl_version} = _get_perl_version($self->{perl});
76             }
77 2 100 66     71 if ( exists($config->{perl}) and $config->{perl} =~ m/^[\d\.]+$/ ) {
78 1         13 $self->{perl_version} = $config->{perl};
79 1         22 my $perl = catfile($self->{perls_root},$config->{perl},'bin','perl');
80 1         6 $self->{perl} = $perl;
81              
82 1 50       122 $self->{skip_install} = 0 unless -e $perl;
83             }
84 2         15 for (qw/deps/) {
85 2 100       26 $self->{$_} = $config->{$_} if exists $config->{$_};
86             }
87              
88             # set more stuff
89 2         39 $self->{home} = getcwd;
90 2         59 $self->{local_lib} = catfile($self->{home},'.local',$self->{perl_version});
91 2         23 $self->{local_bin} = catfile($self->{home},'.local',$self->{perl_version},'bin');
92 2         16 $self->{Ilib} = catfile($self->{home},'.local',$self->{perl_version},'lib','perl5');
93 2         31 $self->{log_file} = catfile($self->{p5stack_root},'p5stack-setup.log');
94             }
95              
96             sub _do_setup {
97 0     0   0 my ($self) = @_;
98              
99 0 0       0 make_path($self->{p5stack_root}) unless -e $self->{p5stack_root};
100              
101 0         0 _log('Hammering setup ...');
102 0         0 _log("Tail ".catfile('$HOME','.p5stack','p5stack-setup.log')." to follow the process ...");
103              
104 0         0 $self->_do_install_perl_release;
105              
106 0         0 system "curl -s -L https://cpanmin.us | $self->{perl} - -l $self->{local_lib} --reinstall --no-sudo App::cpanminus local::lib > $self->{log_file} 2>&1";
107 0         0 $self->{cpanm_flag} = $? >> 8;
108              
109 0         0 _log("Getting dependencies info using '$self->{deps}' ...");
110 0         0 _log('Installing dependencies ...');
111 0         0 my $cpanm = $self->_get_cpanm;
112              
113 0 0       0 if ($self->{deps} eq 'dzil') {
114              
115 0 0       0 unless (-e catfile($self->{home},'dist.ini')) {
116 0         0 _log('Configuration is set to use "dzil" to gather dependencies information, but no "dist.ini" file was found in current directory.. exiting.');
117 0         0 exit;
118             }
119              
120 0         0 my $dzil = which 'dzil';
121 0 0       0 if ($dzil) {
122 0         0 system "$dzil listdeps | $cpanm --no-sudo -l $self->{local_lib}";
123 0         0 $self->{cpanm_flag} = $? >> 8;
124             }
125             else {
126 0         0 $self->_do_cpanm("Dist::Zilla");
127 0         0 my $bin = catfile($self->{local_bin}, 'dzil');
128 0         0 my @env = ("PERL5LIB=$self->{Ilib}", "PATH=$self->{local_bin}:\$PATH");
129 0         0 system join(' ', @env, "$bin listdeps | $cpanm --no-sudo -l $self->{local_lib}");
130 0         0 $self->{cpanm_flag} = $? >> 8;
131             }
132             }
133 0 0       0 if ($self->{deps} eq 'cpanfile') {
134 0 0       0 unless (-e catfile($self->{home},'cpanfile')) {
135 0         0 _log('Configuration is set to use "cpanfile" to gather dependencies information, but no "cpanfile" file was found in current directory.. exiting.');
136 0         0 exit;
137             }
138 0         0 $self->_do_cpanm("--installdeps .");
139             }
140              
141 0 0       0 if ($self->{cpanm_flag}) {
142 0         0 print "[p5stack] Warning, cpanm may have failed to install something!\n";
143             }
144 0         0 print "[p5stack] Setup done, use 'p5stack perl' to run your application.\n";
145             }
146              
147             sub _get_cpanm {
148 0     0   0 my ($self) = @_;
149              
150 0         0 my $cpanm = catfile($self->{local_lib}, 'bin', 'cpanm');
151 0 0       0 $cpanm = which 'cpanm' unless $cpanm; # FIXME default to system?
152              
153 0         0 return $cpanm;
154             }
155              
156             sub _do_install_perl_release {
157 0     0   0 my ($self) = @_;
158              
159 0 0       0 if (-e $self->{perl}) {
160 0         0 _log("Found $self->{perl_version} release using it.");
161 0         0 return;
162             }
163              
164 0         0 my $curl = which 'curl'; # TODO failsafe to wget ?
165 0         0 my $file = join '', 'perl-', $self->{perl_version}, '.tar.gz';
166 0         0 my $dest = catfile($self->{perls_root}, $file);
167 0         0 my $url = join '', 'http://www.cpan.org/src/5.0/', $file;
168              
169 0         0 _log("Downloading $self->{perl_version} release ...");
170 0 0       0 make_path(dirname($dest)) unless -e dirname($dest);
171 0 0       0 system "$curl -s -o $dest $url" unless -e $dest;
172              
173 0         0 my $curr = getcwd;
174 0         0 chdir $self->{perls_root};
175              
176 0         0 _log("Extracting $self->{perl_version} release ...");
177 0         0 Archive::Tar->extract_archive($file);
178              
179 0         0 chdir catfile($self->{perls_root}, "perl-$self->{perl_version}");
180            
181 0         0 _log("Configuring $self->{perl_version} release ...");
182 0         0 my $prefix = catfile($self->{perls_root}, $self->{perl_version});
183 0         0 system "sh Configure -de -Dprefix=$prefix > $self->{log_file} 2>&1";
184              
185 0         0 _log("Building $self->{perl_version} release ...");
186 0         0 system "make >> $self->{log_file} 2>&1";
187              
188 0         0 _log("Testing $self->{perl_version} release ...");
189 0         0 system "make test >> $self->{log_file} 2>&1";
190              
191 0         0 _log("Installing $self->{perl_version} release ...");
192 0         0 system "make install >> $self->{log_file} 2>&1";
193              
194             }
195              
196             sub _do_perl {
197 0     0   0 my ($self) = @_;
198              
199             my $run = join(' ',$self->{perl}, "-I $self->{Ilib}",
200 0         0 "-Mlocal::lib", @{$self->{argv}});
  0         0  
201              
202 0         0 system $run;
203             }
204              
205             sub _do_cpanm {
206 0     0   0 my ($self, @args) = @_;
207 0 0       0 @args = @{$self->{argv}} unless @args;
  0         0  
208              
209 0         0 my $cpanm = $self->_get_cpanm;
210 0         0 my $log = "";
211 0 0       0 $log = ">> $self->{log_file} 2>&1" if $self->{command} eq 'setup';
212 0         0 my $run = join ' ', $cpanm, "--no-sudo", "-L $self->{local_lib}", @args, $log;
213              
214 0         0 system $run;
215 0         0 $self->{cpanm_flag} = $? >> 8;
216             }
217              
218             sub _do_bin {
219 0     0   0 my ($self) = @_;
220              
221 0         0 my @argv = @{ $self->{argv} };
  0         0  
222 0         0 my $bin = catfile($self->{local_bin}, shift @argv);
223 0         0 my @env = ("PERL5LIB=$self->{Ilib}", "PATH=$self->{local_bin}:\$PATH");
224 0         0 my $run = join ' ', @env, $bin, @argv;
225              
226 0         0 system $run;
227             }
228              
229             sub _do_run {
230 0     0   0 my ($self) = @_;
231              
232 0         0 my @argv = @{ $self->{argv} };
  0         0  
233 0         0 my $comm = shift @argv;
234 0         0 my @env = ("PERL5LIB=$self->{Ilib}", "PATH=$self->{local_bin}:\$PATH");
235 0         0 my $run = join ' ', @env, $comm, @argv;
236              
237 0         0 system $run;
238             }
239              
240             sub _get_perl_version {
241 2     2   29 my ($perl) = @_;
242              
243 2         22496 my $version = `$perl -e 'print \$^V'`;
244 2         77 $version =~ s/^v//;
245              
246 2         45 return $version;
247             }
248              
249             sub _log {
250 0     0     my ($msg) = @_;
251              
252             # FIXME smaller timestamp
253 0           my $now = localtime;
254 0           $now =~ s/\s\d+$//;
255 0           $now =~ s/^\w+/-/;
256              
257 0           print "[p5stack $now] $msg\n";
258             }
259              
260             sub _do_help {
261 0     0     print "Usage:\n",
262             " \$ p5stack setup # setup env in current directory\n",
263             " \$ p5stack perl [args] # run a program\n",
264             " \$ p5stack bin [args] # execute a locally installed bin file\n",
265             " \$ p5stack run [args] # setup env and run an arbitrary command\n",
266             " \$ p5stack cpanm [args] # execute local env cpanm\n";
267             }
268              
269             1;
270              
271             __END__