File Coverage

blib/lib/local/lib.pm
Criterion Covered Total %
statement 201 340 59.1
branch 71 168 42.2
condition 30 79 37.9
subroutine 46 63 73.0
pod 27 43 62.7
total 375 693 54.1


line stmt bran cond sub pod time code
1             package local::lib;
2 9     9   478807 use 5.006;
  9         92  
3             BEGIN {
4 9 50   9   165 if ($ENV{RELEASE_TESTING}) {
5 0         0 require strict;
6 0         0 strict->import;
7 0         0 require warnings;
8 0         0 warnings->import;
9             }
10             }
11 9     9   50 use Config ();
  9         20  
  9         1052  
12              
13             our $VERSION = '2.000029';
14             $VERSION =~ tr/_//d;
15              
16             BEGIN {
17             *_WIN32 = ($^O eq 'MSWin32' || $^O eq 'NetWare' || $^O eq 'symbian')
18 9 50 33 9   123 ? sub(){1} : sub(){0};
19             # punt on these systems
20             *_USE_FSPEC = ($^O eq 'MacOS' || $^O eq 'VMS' || $INC{'File/Spec.pm'})
21 9 50 33     3515 ? sub(){1} : sub(){0};
22             }
23             my $_archname = $Config::Config{archname};
24             my $_version = $Config::Config{version};
25             my @_inc_version_list = reverse split / /, $Config::Config{inc_version_list};
26             my $_path_sep = $Config::Config{path_sep};
27              
28             our $_DIR_JOIN = _WIN32 ? '\\' : '/';
29             our $_DIR_SPLIT = (_WIN32 || $^O eq 'cygwin') ? qr{[\\/]}
30             : qr{/};
31             our $_ROOT = _WIN32 ? do {
32             my $UNC = qr{[\\/]{2}[^\\/]+[\\/][^\\/]+};
33             qr{^(?:$UNC|[A-Za-z]:|)$_DIR_SPLIT};
34             } : qr{^/};
35             our $_PERL;
36              
37             sub _perl {
38 2 50   2   1157 if (!$_PERL) {
39             # untaint and validate
40 2         44 ($_PERL, my $exe) = $^X =~ /((?:.*$_DIR_SPLIT)?(.+))/;
41 2 50       13 $_PERL = 'perl'
42             if $exe !~ /perl/;
43 2 50 0     7 if (_is_abs($_PERL)) {
    0          
    0          
44             }
45             elsif (-x $Config::Config{perlpath}) {
46 0         0 $_PERL = $Config::Config{perlpath};
47             }
48             elsif ($_PERL =~ $_DIR_SPLIT && -x $_PERL) {
49 0         0 $_PERL = _rel2abs($_PERL);
50             }
51             else {
52             ($_PERL) =
53 0         0 map { /(.*)/ }
54 0         0 grep { -x $_ }
55 0         0 map { ($_, _WIN32 ? ("$_.exe") : ()) }
56 0         0 map { join($_DIR_JOIN, $_, $_PERL) }
57 0         0 split /\Q$_path_sep\E/, $ENV{PATH};
58             }
59             }
60 2         6 $_PERL;
61             }
62              
63             sub _cwd {
64 0 0   0   0 if (my $cwd
    0          
    0          
65             = defined &Cwd::sys_cwd ? \&Cwd::sys_cwd
66             : defined &Cwd::cwd ? \&Cwd::cwd
67             : undef
68             ) {
69 9     9   54 no warnings 'redefine';
  9         20  
  9         37697  
70 0         0 *_cwd = $cwd;
71 0         0 goto &$cwd;
72             }
73 0         0 my $drive = shift;
74 0         0 return Win32::GetCwd()
75             if _WIN32 && defined &Win32::GetCwd && !$drive;
76 0         0 local @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};
77 0         0 delete @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};
78 0 0       0 my $cmd = $drive ? "eval { Cwd::getdcwd(q($drive)) }"
79             : 'getcwd';
80 0         0 my $perl = _perl;
81 0         0 my $cwd = `"$perl" -MCwd -le "print $cmd"`;
82 0         0 chomp $cwd;
83 0 0 0     0 if (!length $cwd && $drive) {
84 0         0 $cwd = $drive;
85             }
86 0         0 $cwd =~ s/$_DIR_SPLIT?$/$_DIR_JOIN/;
87 0         0 $cwd;
88             }
89              
90             sub _catdir {
91 270     270   291 if (_USE_FSPEC) {
92 270         745 require File::Spec;
93 270         1392 File::Spec->catdir(@_);
94             }
95             else {
96             my $dir = join($_DIR_JOIN, @_);
97             $dir =~ s{($_DIR_SPLIT)(?:\.?$_DIR_SPLIT)+}{$1}g;
98             $dir;
99             }
100             }
101              
102             sub _is_abs {
103 18     18   20 if (_USE_FSPEC) {
104 18         74 require File::Spec;
105 18         186 File::Spec->file_name_is_absolute($_[0]);
106             }
107             else {
108             $_[0] =~ $_ROOT;
109             }
110             }
111              
112             sub _rel2abs {
113 16     16   30 my ($dir, $base) = @_;
114 16 50       37 return $dir
115             if _is_abs($dir);
116              
117 0 0       0 $base = _WIN32 && $dir =~ s/^([A-Za-z]:)// ? _cwd("$1")
118             : $base ? _rel2abs($base)
119             : _cwd;
120 0         0 return _catdir($base, $dir);
121             }
122              
123             our $_DEVNULL;
124             sub _devnull {
125 0   0 0   0 return $_DEVNULL ||=
126             _USE_FSPEC ? (require File::Spec, File::Spec->devnull)
127             : _WIN32 ? 'nul'
128             : $^O eq 'os2' ? '/dev/nul'
129             : '/dev/null';
130             }
131              
132             sub import {
133 14     14   4565 my ($class, @args) = @_;
134 14 50       48 if ($0 eq '-') {
135 0         0 push @args, @ARGV;
136 0         0 require Cwd;
137             }
138              
139 14         39 my @steps;
140             my %opts;
141 14         0 my %attr;
142 14         0 my $shelltype;
143              
144 14         28 while (@args) {
145 15         24 my $arg = shift @args;
146             # check for lethal dash first to stop processing before causing problems
147             # the fancy dash is U+2212 or \xE2\x88\x92
148 15 50       126 if ($arg =~ /\xE2\x88\x92/) {
    50          
    100          
    50          
    50          
    100          
    50          
    50          
    50          
149 0         0 die <<'DEATH';
150             WHOA THERE! It looks like you've got some fancy dashes in your commandline!
151             These are *not* the traditional -- dashes that software recognizes. You
152             probably got these by copy-pasting from the perldoc for this module as
153             rendered by a UTF8-capable formatter. This most typically happens on an OS X
154             terminal, but can happen elsewhere too. Please try again after replacing the
155             dashes with normal minus signs.
156             DEATH
157             }
158             elsif ($arg eq '--self-contained') {
159 0         0 die <<'DEATH';
160             FATAL: The local::lib --self-contained flag has never worked reliably and the
161             original author, Mark Stosberg, was unable or unwilling to maintain it. As
162             such, this flag has been removed from the local::lib codebase in order to
163             prevent misunderstandings and potentially broken builds. The local::lib authors
164             recommend that you look at the lib::core::only module shipped with this
165             distribution in order to create a more robust environment that is equivalent to
166             what --self-contained provided (although quite possibly not what you originally
167             thought it provided due to the poor quality of the documentation, for which we
168             apologise).
169             DEATH
170             }
171             elsif( $arg =~ /^--deactivate(?:=(.*))?$/ ) {
172 1 50       4 my $path = defined $1 ? $1 : shift @args;
173 1         4 push @steps, ['deactivate', $path];
174             }
175             elsif ( $arg eq '--deactivate-all' ) {
176 0         0 push @steps, ['deactivate_all'];
177             }
178             elsif ( $arg =~ /^--shelltype(?:=(.*))?$/ ) {
179 0 0       0 $shelltype = defined $1 ? $1 : shift @args;
180             }
181             elsif ( $arg eq '--no-create' ) {
182 1         4 $opts{no_create} = 1;
183             }
184             elsif ( $arg eq '--quiet' ) {
185 0         0 $attr{quiet} = 1;
186             }
187             elsif ( $arg eq '--always' ) {
188 0         0 $attr{always} = 1;
189             }
190             elsif ( $arg =~ /^--/ ) {
191 0         0 die "Unknown import argument: $arg";
192             }
193             else {
194 13         63 push @steps, ['activate', $arg, \%opts];
195             }
196             }
197 14 50       26 if (!@steps) {
198 0         0 push @steps, ['activate', undef, \%opts];
199             }
200              
201 14         39 my $self = $class->new(%attr);
202              
203 14         29 for (@steps) {
204 14         35 my ($method, @args) = @$_;
205 14         51 $self = $self->$method(@args);
206             }
207              
208 14 50       39 if ($0 eq '-') {
209 0         0 print $self->environment_vars_string($shelltype);
210 0         0 exit 0;
211             }
212             else {
213 14         48 $self->setup_local_lib;
214             }
215             }
216              
217             sub new {
218 20     20 1 33 my $class = shift;
219 20         43 bless {@_}, $class;
220             }
221              
222             sub clone {
223 16     16 1 21 my $self = shift;
224 16         141 bless {%$self, @_}, ref $self;
225             }
226              
227 54   100 54 1 269 sub inc { $_[0]->{inc} ||= \@INC }
228 28   100 28 1 109 sub libs { $_[0]->{libs} ||= [ \'PERL5LIB' ] }
229 28   100 28 1 129 sub bins { $_[0]->{bins} ||= [ \'PATH' ] }
230 50   100 50 1 191 sub roots { $_[0]->{roots} ||= [ \'PERL_LOCAL_LIB_ROOT' ] }
231 14   50 14 1 106 sub extra { $_[0]->{extra} ||= {} }
232 12     12 0 54 sub quiet { $_[0]->{quiet} }
233              
234             sub _as_list {
235 76     76   101 my $list = shift;
236             grep length, map {
237 76 50       136 !(ref $_ && ref $_ eq 'SCALAR') ? $_ : (
238 194 100 66     887 defined $ENV{$$_} ? split(/\Q$_path_sep/, $ENV{$$_})
    100          
239             : ()
240             )
241             } ref $list ? @$list : $list;
242             }
243             sub _remove_from {
244 12     12   22 my ($list, @remove) = @_;
245 12 50       20 return @$list
246             if !@remove;
247 12         15 my %remove = map { $_ => 1 } @remove;
  21         52  
248 12         16 grep !$remove{$_}, _as_list($list);
249             }
250              
251             my @_lib_subdirs = (
252             [$_version, $_archname],
253             [$_version],
254             [$_archname],
255             (map [$_], @_inc_version_list),
256             [],
257             );
258              
259             sub install_base_bin_path {
260 41     41 1 64454 my ($class, $path) = @_;
261 41         135 return _catdir($path, 'bin');
262             }
263             sub install_base_perl_path {
264 84     84 1 26861 my ($class, $path) = @_;
265 84         190 return _catdir($path, 'lib', 'perl5');
266             }
267             sub install_base_arch_path {
268 1     1 0 3 my ($class, $path) = @_;
269 1         3 _catdir($class->install_base_perl_path($path), $_archname);
270             }
271              
272             sub lib_paths_for {
273 36     36 1 62 my ($class, $path) = @_;
274 36         74 my $base = $class->install_base_perl_path($path);
275 36         90 return map { _catdir($base, @$_) } @_lib_subdirs;
  144         212  
276             }
277              
278             sub _mm_escape_path {
279 22     22   44 my $path = shift;
280 22         66 $path =~ s/\\/\\\\/g;
281 22 50       65 if ($path =~ s/ /\\ /g) {
282 0         0 $path = qq{"$path"};
283             }
284 22         119 return $path;
285             }
286              
287             sub _mb_escape_path {
288 20     20   29 my $path = shift;
289 20         38 $path =~ s/\\/\\\\/g;
290 20         130 return qq{"$path"};
291             }
292              
293             sub installer_options_for {
294 20     20 1 139377 my ($class, $path) = @_;
295             return (
296 20 50       94 PERL_MM_OPT =>
    50          
297             defined $path ? "INSTALL_BASE="._mm_escape_path($path) : undef,
298             PERL_MB_OPT =>
299             defined $path ? "--install_base "._mb_escape_path($path) : undef,
300             );
301             }
302              
303             sub active_paths {
304 22     22 1 655 my ($self) = @_;
305 22 100       49 $self = ref $self ? $self : $self->new;
306              
307             return grep {
308             # screen out entries that aren't actually reflected in @INC
309 22         58 my $active_ll = $self->install_base_perl_path($_);
  26         43  
310 26         31 grep { $_ eq $active_ll } @{$self->inc};
  440         492  
  26         42  
311             } _as_list($self->roots);
312             }
313              
314              
315             sub deactivate {
316 3     3 1 6 my ($self, $path) = @_;
317 3 50       8 $self = $self->new unless ref $self;
318 3         6 $path = $self->resolve_path($path);
319 3         7 $path = $self->normalize_path($path);
320              
321 3         7 my @active_lls = $self->active_paths;
322              
323 3 50       6 if (!grep { $_ eq $path } @active_lls) {
  6         12  
324 0         0 warn "Tried to deactivate inactive local::lib '$path'\n";
325 0         0 return $self;
326             }
327              
328 3         7 my %args = (
329             bins => [ _remove_from($self->bins,
330             $self->install_base_bin_path($path)) ],
331             libs => [ _remove_from($self->libs,
332             $self->install_base_perl_path($path)) ],
333             inc => [ _remove_from($self->inc,
334             $self->lib_paths_for($path)) ],
335             roots => [ _remove_from($self->roots, $path) ],
336             );
337              
338 3         14 $args{extra} = { $self->installer_options_for($args{roots}[0]) };
339              
340 3         10 $self->clone(%args);
341             }
342              
343             sub deactivate_all {
344 0     0 1 0 my ($self) = @_;
345 0 0       0 $self = $self->new unless ref $self;
346              
347 0         0 my @active_lls = $self->active_paths;
348              
349 0         0 my %args;
350 0 0       0 if (@active_lls) {
351 0         0 %args = (
352             bins => [ _remove_from($self->bins,
353             map $self->install_base_bin_path($_), @active_lls) ],
354             libs => [ _remove_from($self->libs,
355             map $self->install_base_perl_path($_), @active_lls) ],
356             inc => [ _remove_from($self->inc,
357             map $self->lib_paths_for($_), @active_lls) ],
358             roots => [ _remove_from($self->roots, @active_lls) ],
359             );
360             }
361              
362 0         0 $args{extra} = { $self->installer_options_for(undef) };
363              
364 0         0 $self->clone(%args);
365             }
366              
367             sub activate {
368 13     13 1 30 my ($self, $path, $opts) = @_;
369 13   50     27 $opts ||= {};
370 13 50       27 $self = $self->new unless ref $self;
371 13         35 $path = $self->resolve_path($path);
372             $self->ensure_dir_structure_for($path, { quiet => $self->quiet })
373 13 100       49 unless $opts->{no_create};
374              
375 13         39 $path = $self->normalize_path($path);
376              
377 13         38 my @active_lls = $self->active_paths;
378              
379 13 100       38 if (grep { $_ eq $path } @active_lls[1 .. $#active_lls]) {
  2         16  
380 2         6 $self = $self->deactivate($path);
381             }
382              
383 13         29 my %args;
384 13 100 66     66 if ($opts->{always} || !@active_lls || $active_lls[0] ne $path) {
      100        
385             %args = (
386 11         35 bins => [ $self->install_base_bin_path($path), @{$self->bins} ],
387 11         38 libs => [ $self->install_base_perl_path($path), @{$self->libs} ],
388 11         23 inc => [ $self->lib_paths_for($path), @{$self->inc} ],
389 11         34 roots => [ $path, @{$self->roots} ],
  11         28  
390             );
391             }
392              
393 13         35 $args{extra} = { $self->installer_options_for($path) };
394              
395 13         51 $self->clone(%args);
396             }
397              
398             sub normalize_path {
399 29     29 0 93877 my ($self, $path) = @_;
400 29 50 0     99 $path = ( Win32::GetShortPathName($path) || $path )
401             if $^O eq 'MSWin32';
402 29         68 return $path;
403             }
404              
405             sub build_environment_vars_for {
406 0     0 1 0 my $self = $_[0]->new->activate($_[1], { always => 1 });
407 0         0 $self->build_environment_vars;
408             }
409             sub build_activate_environment_vars_for {
410 0     0 0 0 my $self = $_[0]->new->activate($_[1], { always => 1 });
411 0         0 $self->build_environment_vars;
412             }
413             sub build_deactivate_environment_vars_for {
414 0     0 0 0 my $self = $_[0]->new->deactivate($_[1]);
415 0         0 $self->build_environment_vars;
416             }
417             sub build_deact_all_environment_vars_for {
418 0     0 0 0 my $self = $_[0]->new->deactivate_all;
419 0         0 $self->build_environment_vars;
420             }
421             sub build_environment_vars {
422 14     14 1 16 my $self = shift;
423             (
424             PATH => join($_path_sep, _as_list($self->bins)),
425             PERL5LIB => join($_path_sep, _as_list($self->libs)),
426             PERL_LOCAL_LIB_ROOT => join($_path_sep, _as_list($self->roots)),
427 14         28 %{$self->extra},
  14         27  
428             );
429             }
430              
431             sub setup_local_lib_for {
432 0     0 0 0 my $self = $_[0]->new->activate($_[1]);
433 0         0 $self->setup_local_lib;
434             }
435              
436             sub setup_local_lib {
437 14     14 1 17 my $self = shift;
438              
439             # if Carp is already loaded, ensure Carp::Heavy is also loaded, to avoid
440             # $VERSION mismatch errors (Carp::Heavy loads Carp, so we do not need to
441             # check in the other direction)
442 14 50       419 require Carp::Heavy if $INC{'Carp.pm'};
443              
444 14         173 $self->setup_env_hash;
445 14         22 @INC = @{$self->inc};
  14         22  
446             }
447              
448             sub setup_env_hash_for {
449 0     0 1 0 my $self = $_[0]->new->activate($_[1]);
450 0         0 $self->setup_env_hash;
451             }
452             sub setup_env_hash {
453 14     14 1 21 my $self = shift;
454 14         38 my %env = $self->build_environment_vars;
455 14         47 for my $key (keys %env) {
456 70 50       96 if (defined $env{$key}) {
457 70         203 $ENV{$key} = $env{$key};
458             }
459             else {
460 0         0 delete $ENV{$key};
461             }
462             }
463             }
464              
465             sub print_environment_vars_for {
466 0     0 1 0 print $_[0]->environment_vars_string_for(@_[1..$#_]);
467             }
468              
469             sub environment_vars_string_for {
470 0     0 0 0 my $self = $_[0]->new->activate($_[1], { always => 1});
471 0         0 $self->environment_vars_string;
472             }
473             sub environment_vars_string {
474 0     0 1 0 my ($self, $shelltype) = @_;
475              
476 0   0     0 $shelltype ||= $self->guess_shelltype;
477              
478 0         0 my $extra = $self->extra;
479             my @envs = (
480             PATH => $self->bins,
481             PERL5LIB => $self->libs,
482             PERL_LOCAL_LIB_ROOT => $self->roots,
483 0         0 map { $_ => $extra->{$_} } sort keys %$extra,
  0         0  
484             );
485 0         0 $self->_build_env_string($shelltype, \@envs);
486             }
487              
488             sub _build_env_string {
489 56     56   807356 my ($self, $shelltype, $envs) = @_;
490 56         214 my @envs = @$envs;
491              
492 56         209 my $build_method = "build_${shelltype}_env_declaration";
493              
494 56         274 my $out = '';
495 56         215 while (@envs) {
496 56         159 my ($name, $value) = (shift(@envs), shift(@envs));
497 56 0 66     399 if (
      33        
      33        
      0        
498             ref $value
499             && @$value == 1
500             && ref $value->[0]
501             && ref $value->[0] eq 'SCALAR'
502 0         0 && ${$value->[0]} eq $name) {
503 0         0 next;
504             }
505 56         464 $out .= $self->$build_method($name, $value);
506             }
507 56         152 my $wrap_method = "wrap_${shelltype}_output";
508 56 50       301 if ($self->can($wrap_method)) {
509 0         0 return $self->$wrap_method($out);
510             }
511 56         164 return $out;
512             }
513              
514             sub build_bourne_env_declaration {
515 56     56 0 180 my ($class, $name, $args) = @_;
516 56         851 my $value = $class->_interpolate($args, '${%s:-}', qr/["\\\$!`]/, '\\%s');
517              
518 56 50       208 if (!defined $value) {
519 0         0 return qq{unset $name;\n};
520             }
521              
522 56         410 $value =~ s/(^|\G|$_path_sep)\$\{$name:-\}$_path_sep/$1\${$name}\${$name:+$_path_sep}/g;
523 56         224 $value =~ s/$_path_sep\$\{$name:-\}$/\${$name:+$_path_sep\${$name}}/;
524              
525 56         322 qq{${name}="$value"; export ${name};\n}
526             }
527              
528             sub build_csh_env_declaration {
529 0     0 0 0 my ($class, $name, $args) = @_;
530 0         0 my ($value, @vars) = $class->_interpolate($args, '${%s}', qr/["\$]/, '"\\%s"');
531 0 0       0 if (!defined $value) {
532 0         0 return qq{unsetenv $name;\n};
533             }
534              
535 0         0 my $out = '';
536 0         0 for my $var (@vars) {
537 0         0 $out .= qq{if ! \$?$name setenv $name '';\n};
538             }
539              
540 0         0 my $value_without = $value;
541 0 0       0 if ($value_without =~ s/(?:^|$_path_sep)\$\{$name\}(?:$_path_sep|$)//g) {
542 0         0 $out .= qq{if "\${$name}" != '' setenv $name "$value";\n};
543 0         0 $out .= qq{if "\${$name}" == '' };
544             }
545 0         0 $out .= qq{setenv $name "$value_without";\n};
546 0         0 return $out;
547             }
548              
549             sub build_cmd_env_declaration {
550 0     0 0 0 my ($class, $name, $args) = @_;
551 0         0 my $value = $class->_interpolate($args, '%%%s%%', qr(%), '%s');
552 0 0       0 if (!$value) {
553 0         0 return qq{\@set $name=\n};
554             }
555              
556 0         0 my $out = '';
557 0         0 my $value_without = $value;
558 0 0       0 if ($value_without =~ s/(?:^|$_path_sep)%$name%(?:$_path_sep|$)//g) {
559 0         0 $out .= qq{\@if not "%$name%"=="" set "$name=$value"\n};
560 0         0 $out .= qq{\@if "%$name%"=="" };
561             }
562 0         0 $out .= qq{\@set "$name=$value_without"\n};
563 0         0 return $out;
564             }
565              
566             sub build_powershell_env_declaration {
567 0     0 0 0 my ($class, $name, $args) = @_;
568 0         0 my $value = $class->_interpolate($args, '$env:%s', qr/["\$]/, '`%s');
569              
570 0 0       0 if (!$value) {
571 0         0 return qq{Remove-Item -ErrorAction 0 Env:\\$name;\n};
572             }
573              
574 0         0 my $maybe_path_sep = qq{\$(if("\$env:$name"-eq""){""}else{"$_path_sep"})};
575 0         0 $value =~ s/(^|\G|$_path_sep)\$env:$name$_path_sep/$1\$env:$name"+$maybe_path_sep+"/g;
576 0         0 $value =~ s/$_path_sep\$env:$name$/"+$maybe_path_sep+\$env:$name+"/;
577              
578 0         0 qq{\$env:$name = \$("$value");\n};
579             }
580             sub wrap_powershell_output {
581 0     0 0 0 my ($class, $out) = @_;
582 0   0     0 return $out || " \n";
583             }
584              
585             sub build_fish_env_declaration {
586 0     0 0 0 my ($class, $name, $args) = @_;
587 0         0 my $value = $class->_interpolate($args, '$%s', qr/[\\"'$ ]/, '\\%s');
588 0 0       0 if (!defined $value) {
589 0         0 return qq{set -e $name;\n};
590             }
591              
592             # fish has special handling for PATH, CDPATH, and MANPATH. They are always
593             # treated as arrays, and joined with ; when storing the environment. Other
594             # env vars can be arrays, but will be joined without a separator. We only
595             # really care about PATH, but might as well make this routine more general.
596 0 0       0 if ($name =~ /^(?:CD|MAN)?PATH$/) {
597 0         0 $value =~ s/$_path_sep/ /g;
598 0 0       0 my $silent = $name =~ /^(?:CD)?PATH$/ ? " 2>"._devnull : '';
599 0         0 return qq{set -x $name $value$silent;\n};
600             }
601              
602 0         0 my $out = '';
603 0         0 my $value_without = $value;
604 0 0       0 if ($value_without =~ s/(?:^|$_path_sep)\$$name(?:$_path_sep|$)//g) {
605 0         0 $out .= qq{set -q $name; and set -x $name $value;\n};
606 0         0 $out .= qq{set -q $name; or };
607             }
608 0         0 $out .= qq{set -x $name $value_without;\n};
609 0         0 $out;
610             }
611              
612             sub _interpolate {
613 56     56   370 my ($class, $args, $var_pat, $escape, $escape_pat) = @_;
614             return
615 56 50       247 unless defined $args;
616 56 100       222 my @args = ref $args ? @$args : $args;
617             return
618 56 50       144 unless @args;
619 56         405 my @vars = map { $$_ } grep { ref $_ eq 'SCALAR' } @args;
  28         142  
  84         360  
620             my $string = join $_path_sep, map {
621 56 100       123 ref $_ eq 'SCALAR' ? sprintf($var_pat, $$_) : do {
  84         435  
622 56         381 s/($escape)/sprintf($escape_pat, $1)/ge; $_;
  24         175  
  56         182  
623             };
624             } @args;
625 56 50       213 return wantarray ? ($string, \@vars) : $string;
626             }
627              
628             sub pipeline;
629              
630             sub pipeline {
631 51     51 0 156 my @methods = @_;
632 51         57 my $last = pop(@methods);
633 51 100       79 if (@methods) {
634             \sub {
635 34     34   58 my ($obj, @args) = @_;
636 34         76 $obj->${pipeline @methods}(
  34         63  
637             $obj->$last(@args)
638             );
639 34         138 };
640             } else {
641             \sub {
642 17     17   38 shift->$last(@_);
643 17         53 };
644             }
645             }
646              
647             sub resolve_path {
648 16     16 1 25 my ($class, $path) = @_;
649              
650 16         19 $path = $class->${pipeline qw(
  16         31  
651             resolve_relative_path
652             resolve_home_path
653             resolve_empty_path
654             )}($path);
655              
656 16         42 $path;
657             }
658              
659             sub resolve_empty_path {
660 18     18 1 115 my ($class, $path) = @_;
661 18 100       41 if (defined $path) {
662 17         28 $path;
663             } else {
664 1         5 '~/perl5';
665             }
666             }
667              
668             sub resolve_home_path {
669 16     16 1 29 my ($class, $path) = @_;
670 16 50       54 $path =~ /^~([^\/]*)/ or return $path;
671 0         0 my $user = $1;
672 0         0 my $homedir = do {
673 0 0 0     0 if (! length($user) && defined $ENV{HOME}) {
674 0         0 $ENV{HOME};
675             }
676             else {
677 0         0 require File::Glob;
678 0         0 File::Glob::bsd_glob("~$user", File::Glob::GLOB_TILDE());
679             }
680             };
681 0 0       0 unless (defined $homedir) {
682 0         0 require Carp; require Carp::Heavy;
  0         0  
683 0 0       0 Carp::croak(
684             "Couldn't resolve homedir for "
685             .(defined $user ? $user : 'current user')
686             );
687             }
688 0         0 $path =~ s/^~[^\/]*/$homedir/;
689 0         0 $path;
690             }
691              
692             sub resolve_relative_path {
693 16     16 1 28 my ($class, $path) = @_;
694 16         31 _rel2abs($path);
695             }
696              
697             sub ensure_dir_structure_for {
698 22     22 1 4883 my ($class, $path, $opts) = @_;
699 22   100     72 $opts ||= {};
700 22         27 my @dirs;
701 22         57 foreach my $dir (
702             $class->lib_paths_for($path),
703             $class->install_base_bin_path($path),
704             ) {
705 110         204 my $d = $dir;
706 110         953 while (!-d $d) {
707 135         305 push @dirs, $d;
708 135         434 require File::Basename;
709 135         3539 $d = File::Basename::dirname($d);
710             }
711             }
712              
713             warn "Attempting to create directory ${path}\n"
714 22 100 100     138 if !$opts->{quiet} && @dirs;
715              
716 22         40 my %seen;
717 22         38 foreach my $dir (reverse @dirs) {
718             next
719 135 100       337 if $seen{$dir}++;
720              
721 61 50 33     2189 mkdir $dir
722             or -d $dir
723             or die "Unable to create $dir: $!"
724             }
725 22         121 return;
726             }
727              
728             sub guess_shelltype {
729             my $shellbin
730             = defined $ENV{SHELL} && length $ENV{SHELL}
731             ? ($ENV{SHELL} =~ /([\w.]+)$/)[-1]
732             : ( $^O eq 'MSWin32' && exists $ENV{'!EXITCODE'} )
733             ? 'bash'
734             : ( $^O eq 'MSWin32' && $ENV{PROMPT} && $ENV{COMSPEC} )
735             ? ($ENV{COMSPEC} =~ /([\w.]+)$/)[-1]
736             : ( $^O eq 'MSWin32' && !$ENV{PROMPT} )
737 4 0 33 4 0 163152 ? 'powershell.exe'
    0 0        
    0 0        
    50 0        
738             : 'sh';
739              
740 4         19 for ($shellbin) {
741             return
742 4 50       83 /csh$/ ? 'csh'
    50          
    50          
    50          
    50          
    50          
743             : /fish$/ ? 'fish'
744             : /command(?:\.com)?$/i ? 'cmd'
745             : /cmd(?:\.exe)?$/i ? 'cmd'
746             : /4nt(?:\.exe)?$/i ? 'cmd'
747             : /powershell(?:\.exe)?$/i ? 'powershell'
748             : 'bourne';
749             }
750             }
751              
752             1;
753             __END__