File Coverage

lib/App/p5stack.pm
Criterion Covered Total %
statement 75 167 44.9
branch 15 54 27.7
condition 2 3 66.6
subroutine 14 24 58.3
pod 0 2 0.0
total 106 250 42.4


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