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   680808 use 5.006;
  9         108  
3             BEGIN {
4 9 50   9   232 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   70 use Config ();
  9         31  
  9         1569  
12              
13             our $VERSION = '2.000027';
14             $VERSION =~ tr/_//d;
15              
16             BEGIN {
17             *_WIN32 = ($^O eq 'MSWin32' || $^O eq 'NetWare' || $^O eq 'symbian')
18 9 50 33 9   169 ? 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     4935 ? 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   2677 if (!$_PERL) {
39             # untaint and validate
40 2         73 ($_PERL, my $exe) = $^X =~ /((?:.*$_DIR_SPLIT)?(.+))/;
41 2 50       18 $_PERL = 'perl'
42             if $exe !~ /perl/;
43 2 50 0     10 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         9 $_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   74 no warnings 'redefine';
  9         24  
  9         50673  
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   346 if (_USE_FSPEC) {
91 270         1042 require File::Spec;
92 270         1869 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   28 if (_USE_FSPEC) {
103 18         103 require File::Spec;
104 18         249 File::Spec->file_name_is_absolute($_[0]);
105             }
106             else {
107             $_[0] =~ $_ROOT;
108             }
109             }
110              
111             sub _rel2abs {
112 16     16   41 my ($dir, $base) = @_;
113 16 50       45 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   5582 my ($class, @args) = @_;
133 14 50       58 if ($0 eq '-') {
134 0         0 push @args, @ARGV;
135 0         0 require Cwd;
136             }
137              
138 14         52 my @steps;
139             my %opts;
140 14         0 my %attr;
141 14         0 my $shelltype;
142              
143 14         41 while (@args) {
144 15         31 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       198 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       5 my $path = defined $1 ? $1 : shift @args;
172 1         5 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         6 $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         74 push @steps, ['activate', $arg, \%opts];
194             }
195             }
196 14 50       42 if (!@steps) {
197 0         0 push @steps, ['activate', undef, \%opts];
198             }
199              
200 14         49 my $self = $class->new(%attr);
201              
202 14         49 for (@steps) {
203 14         36 my ($method, @args) = @$_;
204 14         49 $self = $self->$method(@args);
205             }
206              
207 14 50       63 if ($0 eq '-') {
208 0         0 print $self->environment_vars_string($shelltype);
209 0         0 exit 0;
210             }
211             else {
212 14         56 $self->setup_local_lib;
213             }
214             }
215              
216             sub new {
217 20     20 1 46 my $class = shift;
218 20         60 bless {@_}, $class;
219             }
220              
221             sub clone {
222 16     16 1 47 my $self = shift;
223 16         202 bless {%$self, @_}, ref $self;
224             }
225              
226 54   100 54 1 343 sub inc { $_[0]->{inc} ||= \@INC }
227 28   100 28 1 145 sub libs { $_[0]->{libs} ||= [ \'PERL5LIB' ] }
228 28   100 28 1 184 sub bins { $_[0]->{bins} ||= [ \'PATH' ] }
229 50   100 50 1 255 sub roots { $_[0]->{roots} ||= [ \'PERL_LOCAL_LIB_ROOT' ] }
230 14   50 14 1 148 sub extra { $_[0]->{extra} ||= {} }
231 12     12 0 77 sub quiet { $_[0]->{quiet} }
232              
233             sub _as_list {
234 76     76   117 my $list = shift;
235             grep length, map {
236 76 50       202 !(ref $_ && ref $_ eq 'SCALAR') ? $_ : (
237 194 100 66     1241 defined $ENV{$$_} ? split(/\Q$_path_sep/, $ENV{$$_})
    100          
238             : ()
239             )
240             } ref $list ? @$list : $list;
241             }
242             sub _remove_from {
243 12     12   31 my ($list, @remove) = @_;
244 12 50       25 return @$list
245             if !@remove;
246 12         20 my %remove = map { $_ => 1 } @remove;
  21         79  
247 12         26 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 55523 my ($class, $path) = @_;
260 41         188 return _catdir($path, 'bin');
261             }
262             sub install_base_perl_path {
263 84     84 1 20784 my ($class, $path) = @_;
264 84         235 return _catdir($path, 'lib', 'perl5');
265             }
266             sub install_base_arch_path {
267 1     1 0 3 my ($class, $path) = @_;
268 1         4 _catdir($class->install_base_perl_path($path), $_archname);
269             }
270              
271             sub lib_paths_for {
272 36     36 1 75 my ($class, $path) = @_;
273 36         86 my $base = $class->install_base_perl_path($path);
274 36         116 return map { _catdir($base, @$_) } @_lib_subdirs;
  144         287  
275             }
276              
277             sub _mm_escape_path {
278 22     22   54 my $path = shift;
279 22         93 $path =~ s/\\/\\\\/g;
280 22 50       82 if ($path =~ s/ /\\ /g) {
281 0         0 $path = qq{"$path"};
282             }
283 22         122 return $path;
284             }
285              
286             sub _mb_escape_path {
287 20     20   43 my $path = shift;
288 20         50 $path =~ s/\\/\\\\/g;
289 20         156 return qq{"$path"};
290             }
291              
292             sub installer_options_for {
293 20     20 1 161234 my ($class, $path) = @_;
294             return (
295 20 50       141 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 1270 my ($self) = @_;
304 22 100       66 $self = ref $self ? $self : $self->new;
305              
306             return grep {
307             # screen out entries that aren't actually reflected in @INC
308 22         58 my $active_ll = $self->install_base_perl_path($_);
  26         59  
309 26         49 grep { $_ eq $active_ll } @{$self->inc};
  440         671  
  26         49  
310             } _as_list($self->roots);
311             }
312              
313              
314             sub deactivate {
315 3     3 1 7 my ($self, $path) = @_;
316 3 50       10 $self = $self->new unless ref $self;
317 3         8 $path = $self->resolve_path($path);
318 3         11 $path = $self->normalize_path($path);
319              
320 3         8 my @active_lls = $self->active_paths;
321              
322 3 50       6 if (!grep { $_ eq $path } @active_lls) {
  6         17  
323 0         0 warn "Tried to deactivate inactive local::lib '$path'\n";
324 0         0 return $self;
325             }
326              
327 3         9 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         15 $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 40 my ($self, $path, $opts) = @_;
368 13   50     49 $opts ||= {};
369 13 50       45 $self = $self->new unless ref $self;
370 13         39 $path = $self->resolve_path($path);
371             $self->ensure_dir_structure_for($path, { quiet => $self->quiet })
372 13 100       65 unless $opts->{no_create};
373              
374 13         49 $path = $self->normalize_path($path);
375              
376 13         39 my @active_lls = $self->active_paths;
377              
378 13 100       97 if (grep { $_ eq $path } @active_lls[1 .. $#active_lls]) {
  2         17  
379 2         8 $self = $self->deactivate($path);
380             }
381              
382 13         25 my %args;
383 13 100 66     93 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         48 libs => [ $self->install_base_perl_path($path), @{$self->libs} ],
387 11         29 inc => [ $self->lib_paths_for($path), @{$self->inc} ],
388 11         36 roots => [ $path, @{$self->roots} ],
  11         32  
389             );
390             }
391              
392 13         50 $args{extra} = { $self->installer_options_for($path) };
393              
394 13         57 $self->clone(%args);
395             }
396              
397             sub normalize_path {
398 29     29 0 91159 my ($self, $path) = @_;
399 29 50 0     132 $path = ( Win32::GetShortPathName($path) || $path )
400             if $^O eq 'MSWin32';
401 29         96 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 30 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         31 %{$self->extra},
  14         46  
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 23 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       569 require Carp::Heavy if $INC{'Carp.pm'};
442              
443 14         234 $self->setup_env_hash;
444 14         30 @INC = @{$self->inc};
  14         33  
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 22 my $self = shift;
453 14         45 my %env = $self->build_environment_vars;
454 14         56 for my $key (keys %env) {
455 70 50       131 if (defined $env{$key}) {
456 70         306 $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   839167 my ($self, $shelltype, $envs) = @_;
489 56         255 my @envs = @$envs;
490              
491 56         253 my $build_method = "build_${shelltype}_env_declaration";
492              
493 56         318 my $out = '';
494 56         267 while (@envs) {
495 56         198 my ($name, $value) = (shift(@envs), shift(@envs));
496 56 0 66     563 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         367 $out .= $self->$build_method($name, $value);
505             }
506 56         174 my $wrap_method = "wrap_${shelltype}_output";
507 56 50       426 if ($self->can($wrap_method)) {
508 0         0 return $self->$wrap_method($out);
509             }
510 56         194 return $out;
511             }
512              
513             sub build_bourne_env_declaration {
514 56     56 0 176 my ($class, $name, $args) = @_;
515 56         942 my $value = $class->_interpolate($args, '${%s:-}', qr/["\\\$!`]/, '\\%s');
516              
517 56 50       233 if (!defined $value) {
518 0         0 return qq{unset $name;\n};
519             }
520              
521 56         684 $value =~ s/(^|\G|$_path_sep)\$\{$name:-\}$_path_sep/$1\${$name}\${$name:+$_path_sep}/g;
522 56         310 $value =~ s/$_path_sep\$\{$name:-\}$/\${$name:+$_path_sep\${$name}}/;
523              
524 56         537 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   558 my ($class, $args, $var_pat, $escape, $escape_pat) = @_;
613             return
614 56 50       254 unless defined $args;
615 56 100       334 my @args = ref $args ? @$args : $args;
616             return
617 56 50       200 unless @args;
618 56         229 my @vars = map { $$_ } grep { ref $_ eq 'SCALAR' } @args;
  28         119  
  84         450  
619             my $string = join $_path_sep, map {
620 56 100       164 ref $_ eq 'SCALAR' ? sprintf($var_pat, $$_) : do {
  84         385  
621 56         516 s/($escape)/sprintf($escape_pat, $1)/ge; $_;
  24         179  
  56         310  
622             };
623             } @args;
624 56 50       270 return wantarray ? ($string, \@vars) : $string;
625             }
626              
627             sub pipeline;
628              
629             sub pipeline {
630 51     51 0 245 my @methods = @_;
631 51         76 my $last = pop(@methods);
632 51 100       111 if (@methods) {
633             \sub {
634 34     34   85 my ($obj, @args) = @_;
635 34         93 $obj->${pipeline @methods}(
  34         73  
636             $obj->$last(@args)
637             );
638 34         196 };
639             } else {
640             \sub {
641 17     17   59 shift->$last(@_);
642 17         68 };
643             }
644             }
645              
646             sub resolve_path {
647 16     16 1 34 my ($class, $path) = @_;
648              
649 16         27 $path = $class->${pipeline qw(
  16         34  
650             resolve_relative_path
651             resolve_home_path
652             resolve_empty_path
653             )}($path);
654              
655 16         60 $path;
656             }
657              
658             sub resolve_empty_path {
659 18     18 1 126 my ($class, $path) = @_;
660 18 100       43 if (defined $path) {
661 17         53 $path;
662             } else {
663 1         6 '~/perl5';
664             }
665             }
666              
667             sub resolve_home_path {
668 16     16 1 29 my ($class, $path) = @_;
669 16 50       60 $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 35 my ($class, $path) = @_;
693 16         40 _rel2abs($path);
694             }
695              
696             sub ensure_dir_structure_for {
697 22     22 1 10024 my ($class, $path, $opts) = @_;
698 22   100     71 $opts ||= {};
699 22         38 my @dirs;
700 22         76 foreach my $dir (
701             $class->lib_paths_for($path),
702             $class->install_base_bin_path($path),
703             ) {
704 110         267 my $d = $dir;
705 110         1336 while (!-d $d) {
706 135         445 push @dirs, $d;
707 135         581 require File::Basename;
708 135         4918 $d = File::Basename::dirname($d);
709             }
710             }
711              
712             warn "Attempting to create directory ${path}\n"
713 22 100 100     196 if !$opts->{quiet} && @dirs;
714              
715 22         50 my %seen;
716 22         46 foreach my $dir (reverse @dirs) {
717             next
718 135 100       496 if $seen{$dir}++;
719              
720 61 50 33     3098 mkdir $dir
721             or -d $dir
722             or die "Unable to create $dir: $!"
723             }
724 22         132 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 191414 ? 'powershell.exe'
    0 0        
    0 0        
    50 0        
737             : 'sh';
738              
739 4         26 for ($shellbin) {
740             return
741 4 50       139 /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__