File Coverage

blib/lib/App/Virtualenv.pm
Criterion Covered Total %
statement 40 193 20.7
branch 0 84 0.0
condition 0 96 0.0
subroutine 13 24 54.1
pod 11 11 100.0
total 64 408 15.6


line stmt bran cond sub pod time code
1             package App::Virtualenv;
2             =head1 NAME
3              
4             App::Virtualenv - Perl virtual environment
5              
6             =head1 VERSION
7              
8             version 2.06
9              
10             =head1 ABSTRACT
11              
12             Perl virtual environment
13              
14             #!/bin/sh
15             perl -MApp::Virtualenv -erun -- environment_path
16              
17             See also: L
18              
19             =head1 DESCRIPTION
20              
21             App::Virtualenv is a Perl package to create isolated Perl virtual environments, like Python virtual environment.
22              
23             =cut
24 1     1   24791 use strict;
  1         3  
  1         39  
25 1     1   6 use warnings;
  1         2  
  1         38  
26 1     1   36 use v5.10.1;
  1         10  
27 1     1   8 use feature qw(switch);
  1         1  
  1         163  
28 1     1   957 no if ($] >= 5.018), 'warnings' => 'experimental';
  1         11  
  1         8  
29 1     1   86 use Config;
  1         2  
  1         51  
30 1     1   836 use FindBin;
  1         1327  
  1         60  
31 1     1   6 use File::Basename;
  1         2  
  1         64  
32 1     1   720 use File::Copy;
  1         5583  
  1         80  
33 1     1   8 use Cwd;
  1         1  
  1         74  
34 1     1   752 use ExtUtils::Installed;
  1         110674  
  1         34  
35 1     1   440 use Lazy::Utils;
  1         36829  
  1         128  
36              
37              
38             BEGIN
39             {
40 1     1   7 require Exporter;
41 1         2 our $VERSION = '2.06';
42 1         6 our @ISA = qw(Exporter);
43 1         15 our @EXPORT = qw(main run);
44 1         2289 our @EXPORT_OK = qw();
45             }
46              
47              
48             =head2 Functions
49              
50             =head3 sh(@args)
51              
52             runs shell program defined in SHELL environment variable, otherwise /bin/sh
53              
54             @args: I
55              
56             return value: I
57              
58             =cut
59             sub sh
60             {
61 0     0 1   my (@args) = @_;
62 0 0         return _system((defined $ENV{SHELL})? $ENV{SHELL}: "/bin/sh", @args);
63             }
64              
65             =head3 perl(@args)
66              
67             runs Perl interpreter
68              
69             @args: I
70              
71             return value: I
72              
73             =cut
74             sub perl
75             {
76 0     0 1   my (@args) = @_;
77 0           return _system($Config{perlpath}, @args);
78             }
79              
80             =head3 activate($virtualenvPath)
81              
82             activates Perl virtual environment
83              
84             $virtualenvPath: I
85              
86             return value: I
87              
88             =cut
89             sub activate
90             {
91 0     0 1   my ($virtualenvPath) = @_;
92 0 0 0       return unless defined($virtualenvPath) and length($virtualenvPath) > 0 and -d "$virtualenvPath/lib/perl5";
      0        
93 0           $virtualenvPath = Cwd::realpath($virtualenvPath);
94              
95 0           deactivate(1);
96              
97 0           $ENV{_OLD_PERL_VIRTUAL_ENV} = $ENV{PERL_VIRTUAL_ENV};
98 0           $ENV{PERL_VIRTUAL_ENV} = $virtualenvPath;
99              
100 0           $ENV{_OLD_PERL_VIRTUAL_PATH} = $ENV{PATH};
101 0 0         $ENV{PATH} = "$virtualenvPath/bin".((defined $ENV{PATH})? ":${ENV{PATH}}": "");
102              
103 0           $ENV{_OLD_PERL_VIRTUAL_PERL5LIB} = $ENV{PERL5LIB};
104 0 0         $ENV{PERL5LIB} = "$virtualenvPath/lib/perl5".((defined $ENV{PERL5LIB})? ":${ENV{PERL5LIB}}": "");
105              
106 0           $ENV{_OLD_PERL_VIRTUAL_PERL_LOCAL_LIB_ROOT} = $ENV{PERL_LOCAL_LIB_ROOT};
107 0           $ENV{PERL_LOCAL_LIB_ROOT} = "$virtualenvPath";
108              
109 0           $ENV{_OLD_PERL_VIRTUAL_PERL_MB_OPT} = $ENV{PERL_MB_OPT};
110 0           $ENV{PERL_MB_OPT} = "--install_base \"$virtualenvPath\"";
111              
112 0           $ENV{_OLD_PERL_VIRTUAL_PERL_MM_OPT} = $ENV{PERL_MM_OPT};
113 0           $ENV{PERL_MM_OPT} = "INSTALL_BASE=$virtualenvPath";
114              
115 0           $ENV{_OLD_PERL_VIRTUAL_PS1} = $ENV{PS1};
116 0 0         $ENV{PS1} = "(".basename($virtualenvPath).") ".((defined $ENV{PS1})? $ENV{PS1}: "");
117              
118 0           return $virtualenvPath;
119             }
120              
121             =head3 deactivate($nondestructive)
122              
123             deactivates Perl virtual environment
124              
125             $nondestructive: I
126              
127             return value: I
128              
129             =cut
130             sub deactivate
131             {
132 0     0 1   my ($nondestructive) = @_;
133              
134 0 0         $nondestructive = not defined($ENV{PERL_VIRTUAL_ENV}) if not defined($nondestructive);
135              
136 0 0 0       $ENV{PERL_VIRTUAL_ENV} = $ENV{_OLD_PERL_VIRTUAL_ENV} if defined($ENV{_OLD_PERL_VIRTUAL_ENV}) or not $nondestructive;
137 0           undef $ENV{_OLD_PERL_VIRTUAL_ENV};
138              
139 0 0 0       $ENV{PATH} = $ENV{_OLD_PERL_VIRTUAL_PATH} if defined($ENV{_OLD_PERL_VIRTUAL_PATH}) or not $nondestructive;
140 0           undef $ENV{_OLD_PERL_VIRTUAL_PATH};
141              
142 0 0 0       $ENV{PERL5LIB} = $ENV{_OLD_PERL_VIRTUAL_PERL5LIB} if defined($ENV{_OLD_PERL_VIRTUAL_PERL5LIB}) or not $nondestructive;
143 0           undef $ENV{_OLD_PERL_VIRTUAL_PERL5LIB};
144              
145 0 0 0       $ENV{PERL_LOCAL_LIB_ROOT} = $ENV{_OLD_PERL_VIRTUAL_PERL_LOCAL_LIB_ROOT} if defined($ENV{_OLD_PERL_VIRTUAL_PERL_LOCAL_LIB_ROOT}) or not $nondestructive;
146 0           undef $ENV{_OLD_PERL_VIRTUAL_PERL_LOCAL_LIB_ROOT};
147              
148 0 0 0       $ENV{PERL_MB_OPT} = $ENV{_OLD_PERL_VIRTUAL_PERL_MB_OPT} if defined($ENV{_OLD_PERL_VIRTUAL_PERL_MB_OPT}) or not $nondestructive;
149 0           undef $ENV{_OLD_PERL_VIRTUAL_PERL_MB_OPT};
150              
151 0 0 0       $ENV{PERL_MM_OPT} = $ENV{_OLD_PERL_VIRTUAL_PERL_MM_OPT} if defined($ENV{_OLD_PERL_VIRTUAL_PERL_MM_OPT}) or not $nondestructive;
152 0           undef $ENV{_OLD_PERL_VIRTUAL_PERL_MM_OPT};
153              
154 0 0 0       $ENV{PS1} = $ENV{_OLD_PERL_VIRTUAL_PS1} if defined($ENV{_OLD_PERL_VIRTUAL_PS1}) or not $nondestructive;
155 0           undef $ENV{_OLD_PERL_VIRTUAL_PS1};
156              
157 0           return 1;
158             }
159              
160             =head3 create($virtualenvPath, $empty)
161              
162             creates Perl virtual environment
163              
164             $virtualenvPath: I
165              
166             $empty: I
167              
168             return value: I
169              
170             =cut
171             sub create
172             {
173 0     0 1   my ($virtualenvPath, $empty) = @_;
174 0 0 0       return unless defined($virtualenvPath) and length($virtualenvPath) > 0;
175 0           $virtualenvPath = Cwd::realpath($virtualenvPath);
176 0           say "Creating Perl virtual environment: $virtualenvPath";
177              
178 0           deactivate();
179 0           $ENV{PERL_MM_USE_DEFAULT} = 1;
180 0           $ENV{NONINTERACTIVE_TESTING} = 1;
181 0           $ENV{AUTOMATED_TESTING} = 1;
182              
183 0           require local::lib;
184 0           local::lib->import($virtualenvPath);
185              
186 0           activate($virtualenvPath);
187              
188 0 0         perl("-MCPAN", "-e exit(defined(CPAN::Shell->force('install', 'CPAN'))? 0: 1);") unless $empty;
189              
190 0           my $pkgPath = dirname(__FILE__);
191              
192 0           say "Copying... bin/activate";
193 0           copy("$pkgPath/Virtualenv/activate", "$virtualenvPath/bin/activate");
194 0           chmod(0644, "$virtualenvPath/bin/activate");
195              
196 0           say "Copying... bin/sh.pl";
197 0           copy("$pkgPath/Virtualenv/sh.pl", "$virtualenvPath/bin/sh.pl");
198 0           chmod(0755, "$virtualenvPath/bin/sh.pl");
199              
200 0           say "Copying... bin/perl.pl";
201 0           file_put_contents("$virtualenvPath/bin/perl.pl", "#!".shellmeta($Config{perlpath})."\n".file_get_contents("$pkgPath/Virtualenv/perl.pl"));
202 0           chmod(0755, "$virtualenvPath/bin/perl.pl");
203 0           symlink("perl.pl", "$virtualenvPath/bin/perl");
204              
205 0           say "Copying... bin/virtualenv.pl";
206 0           copy("$pkgPath/Virtualenv/virtualenv.pl", "$virtualenvPath/bin/virtualenv.pl");
207 0           chmod(0755, "$virtualenvPath/bin/virtualenv.pl");
208 0           symlink("virtualenv.pl", "$virtualenvPath/bin/virtualenv");
209              
210 0           return $virtualenvPath;
211             }
212              
213             =head3 findVirtualenvPath($virtualenvPath)
214              
215             finds Perl virtual environment path by $virtualenvPath argument or activated virtual environment or running script or PERL5LIB environment variable
216              
217             $virtualenvPath: I
218              
219             return value: I
220              
221             =cut
222             sub findVirtualenvPath
223             {
224 0     0 1   my ($virtualenvPath) = @_;
225 0 0 0       $virtualenvPath = $ENV{PERL_VIRTUAL_ENV} if not (defined($virtualenvPath) and length($virtualenvPath) > 0 and -d "$virtualenvPath/lib/perl5");
      0        
226 0 0 0       $virtualenvPath = "${FindBin::Bin}/.." if not (defined($virtualenvPath) and length($virtualenvPath) > 0 and -d "$virtualenvPath/lib/perl5") and ${FindBin::Bin} !~ qr'^(/usr/|/bin/)' and -d "${FindBin::Bin}/../lib/perl5";
      0        
227 0 0         for (split(":", defined($ENV{PERL5LIB})? $ENV{PERL5LIB}: ""))
228             {
229 0 0 0       last if defined($virtualenvPath) and length($virtualenvPath) > 0 and -d "$virtualenvPath/lib/perl5";
      0        
230 0           $virtualenvPath = "$_/../..";
231             }
232 0 0 0       return if not (defined($virtualenvPath) and length($virtualenvPath) > 0 and -d "$virtualenvPath/lib/perl5");
      0        
233 0           return $virtualenvPath;
234             }
235              
236             =head3 activate2($virtualenvPath, $inform)
237              
238             activates Perl virtual environment by findVirtualenvPath function
239              
240             $virtualenvPath: I
241              
242             $inform: I
243              
244             return value: I
245              
246             =cut
247             sub activate2
248             {
249 0     0 1   my ($virtualenvPath, $inform) = @_;
250 0           my $oldVirtualenvPath = $ENV{PERL_VIRTUAL_ENV};
251 0           $virtualenvPath = activate(findVirtualenvPath($virtualenvPath));
252 0 0         if ($inform)
253             {
254 0 0         if (defined($virtualenvPath))
255             {
256 0 0 0       say STDERR "Perl virtual environment path: $virtualenvPath" if not defined $oldVirtualenvPath or $oldVirtualenvPath ne $virtualenvPath;
257             } else
258             {
259 0           say STDERR "Perl virtual environment is not activated";
260             }
261             }
262 0           return $virtualenvPath;
263             }
264              
265             =head3 getInc($virtualenvPath)
266              
267             gets array ref of include paths given virtual environment path or sitelib paths
268              
269             $virtualenvPath: I
270              
271             return value: I
272              
273             =cut
274             sub getInc
275             {
276 0     0 1   my ($virtualenvPath) = @_;
277 0           my $perl5lib;
278 0 0 0       $perl5lib = "$virtualenvPath/lib/perl5" if defined($virtualenvPath) and length($virtualenvPath) > 0 and -d "$virtualenvPath/lib/perl5";
      0        
279 0 0         my $inc = [(defined($perl5lib)? ("$perl5lib/$Config{version}/$Config{archname}", "$perl5lib/$Config{version}", "$perl5lib/$Config{archname}", "$perl5lib"): ($Config{sitearch}, $Config{sitelib}))];
280 0 0 0       @$inc = map(((length($_) < 1 or substr($_, -1, 1) ne "/")? "$_/": $_), @$inc);
281 0           return $inc;
282             }
283              
284             =head3 list(%params)
285              
286             lists packages or modules or files by given %params
287              
288             %params: I
289              
290             =over
291              
292             one: I
293              
294             detail: I
295              
296             =back
297              
298             return value: I
299              
300             =cut
301             sub list
302             {
303 0     0 1   my %params = @_;
304 0           my $inc = getInc(activate2(undef, 1));
305 0           my $inst = ExtUtils::Installed->new(inc_override => $inc, extra_libs =>[]);
306 0           my @packages = sort({lc($a) cmp lc($b)} $inst->modules());
  0            
307 0 0 0       for my $packageName (grep({ my $package = $_; not defined($params{packages}) or not @{$params{packages}} or grep($_ eq $package, @{$params{packages}}) } @packages))
  0            
  0            
  0            
308             {
309 0 0         next if $packageName eq 'Perl';
310 0           my $version = $inst->version($packageName);
311 0 0         $version = "0" if not $version;
312 0 0         if ($params{detail})
313             {
314 0 0         say sprintf("%-40s %10s", $packageName, $version) unless $params{one};
315 0           my @files = sort({lc($a) cmp lc($b)} $inst->files($packageName, "all"));
  0            
316 0           my $packlist_file = $inst->packlist($packageName)->packlist_file();
317 0 0         unshift @files, $packlist_file if defined($packlist_file);
318 0           for my $file (@files)
319             {
320 0           my $incPath = (grep($file =~ /^\Q$_\E/, @$inc))[0];
321 0 0         my $relPath = ($file =~ /^\Q$incPath\E(.*)\.pm$/)[0] if defined($incPath);
322 0           given ($params{detail})
323             {
324             when ("module")
325 0           {
326 0 0         if (defined($relPath))
327             {
328 0           my $module = $relPath;
329 0           $module =~ s/\//::/g;
330 0 0         print " " unless $params{one};
331 0           say $module;
332             }
333             }
334             when ("file")
335 0           {
336 0 0         print " " unless $params{one};
337 0           say $file;
338             }
339             }
340             }
341 0           next;
342             }
343 0 0         if ($params{one})
344             {
345 0           say $packageName;
346 0           next;
347             }
348 0           say sprintf("%-40s %10s", $packageName, $version);
349             }
350 0           return 1;
351             }
352              
353             =head3 main(@argv)
354              
355             App::Virtualenv main function to run on command-line
356              
357             See also: L
358              
359             @argv: I
360              
361             return value: I
362              
363             =cut
364             sub main
365             {
366 0     0 1   my (@argv) = @_;
367 0           my $args = commandArgs({ valuableArgs => 0, noCommand => 1 }, @argv);
368 0           my $cmd;
369 0           for my $arg (grep(/^\-/, keys %$args))
370             {
371 0           my $newcmd;
372 0 0 0       $newcmd = $arg if
      0        
      0        
      0        
373             $arg =~ /^\-(h|\-help)$/ or
374             $arg =~ /^\-(c|\-create)$/ or
375             $arg =~ /^\-(l|\-list)$/ or
376             $arg =~ /^\-(m|\-list-modules)$/ or
377             $arg =~ /^\-(f|\-list-files)$/;
378 0 0         if (defined($newcmd))
379             {
380 0 0         die "Argument $newcmd doesn't use with $cmd.\n" if defined($cmd);
381 0           $cmd = $newcmd;
382             }
383             }
384 0 0         $cmd = "-c" unless defined($cmd);
385 0           given ($cmd)
386             {
387             when (/^\-(h|\-help)$/)
388 0           {
389 0           my @lines = getPodText(dirname(__FILE__)."/Virtualenv/virtualenv.pl", "ABSTRACT");
390 0           $lines[0] = "virtualenv.pl";
391 0           say join("\n", @lines);
392             }
393             when (/^\-(c|\-create)$/)
394 0           {
395 0 0 0       die "Perl virtual environment path must be specified.\n" unless defined($args->{parameters}->[0]) and length($args->{parameters}->[0]) > 0;
396 0   0       create($args->{parameters}->[0], (exists($args->{'-e'}) or exists($args->{'--empty'})));
397             }
398             when (/^\-(l|\-list)$/)
399 0           {
400 0   0       list(one => (exists($args->{'-1'}) or exists($args->{'--one'})), packages => $args->{parameters});
401             }
402             when (/^\-(m|\-list-modules)$/)
403 0           {
404 0   0       list(one => (exists($args->{'-1'}) or exists($args->{'--one'})), packages => $args->{parameters}, detail => 'module');
405             }
406             when (/^\-(f|\-list-files)$/)
407 0           {
408 0   0       list(one => (exists($args->{'-1'}) or exists($args->{'--one'})), packages => $args->{parameters}, detail => 'file');
409             }
410             }
411 0           return 0;
412             }
413              
414             =head3 run
415              
416             runs App::Virtualenv by main function with command-line arguments by @ARGV
417              
418             return value: I
419              
420             =cut
421             sub run
422             {
423 0     0 1   exit main(@ARGV);
424             }
425              
426              
427             1;
428             __END__