File Coverage

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


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