detect powershell
[p5sagit/local-lib.git] / lib / local / lib.pm
index f735680..d65df50 100644 (file)
@@ -15,6 +15,7 @@ sub import {
   my ($class, @args) = @_;
 
   my @steps;
+  my %opts;
 
   while (@args) {
     my $arg = shift @args;
@@ -40,6 +41,13 @@ DEATH
     elsif ( $arg eq '--deactivate-all' ) {
       push @steps, ['deactivate_all'];
     }
+    elsif ( $arg =~ /^--shelltype(?:=(.*))?$/ ) {
+      my $shell = defined $1 ? $1 : shift @args;
+      $opts{shelltype} = $shell;
+    }
+    elsif ( $arg eq '--no-create' ) {
+      $opts{no_create} = 1;
+    }
     elsif ( $arg =~ /^--/ ) {
       die "Unknown import argument: $arg";
     }
@@ -51,7 +59,7 @@ DEATH
     push @steps, ['activate', undef];
   }
 
-  my $self = $class->new;
+  my $self = $class->new(%opts);
 
   for (@steps) {
     my ($method, @args) = @$_;
@@ -83,6 +91,7 @@ sub bins { $_[0]->{bins}   ||= [ \'PATH' ] }
 sub roots { $_[0]->{roots} ||= [ \'PERL_LOCAL_LIB_ROOT' ] }
 sub extra { $_[0]->{extra} ||= {} }
 sub shelltype { $_[0]->{shelltype} ||= $_[0]->guess_shelltype }
+sub no_create { $_[0]->{no_create} }
 
 my $_archname = $Config{archname};
 my $_version  = $Config{version};
@@ -175,7 +184,7 @@ sub deactivate {
 
   if (!grep { $_ eq $path } @active_lls) {
     warn "Tried to deactivate inactive local::lib '$path'\n";
-    return;
+    return $self;
   }
 
   my %args = (
@@ -215,7 +224,8 @@ sub activate {
   my ($self, $path) = @_;
   $self = $self->new unless ref $self;
   $path = $self->resolve_path($path);
-  $self->ensure_dir_structure_for($path);
+  $self->ensure_dir_structure_for($path)
+    unless $self->no_create;
 
   my @active_lls = $self->active_paths;
 
@@ -236,9 +246,11 @@ sub activate {
 }
 
 sub _legacy {
-  my ($self, $path, $deactivating) = @_;
+  my ($self, $path) = @_;
   $self = $self->new unless ref $self;
-  $self = $self->${\($deactivating ? 'deactivate' : 'activate')}($path) if defined $path;
+  if (defined $path) {
+    $self = $self->activate($path);
+  }
   $self;
 }
 
@@ -298,6 +310,10 @@ sub environment_vars_string_for {
         && ${$value->[0]} eq $name) {
       next;
     }
+    if (!ref $value
+        && $value eq $ENV{$name}) {
+      next;
+    }
     $out .= $self->$build_method($name, $value);
   }
   return $out;
@@ -327,9 +343,19 @@ sub build_cmd_env_declaration {
   my $value = $class->_interpolate($args, '%', '%');
   $value =~ s/"/\\"/g
     if defined $value;
-  return defined($value) ? qq{set ${name} "${value}"\n} : qq{set ${name}=\n};
+  return qq{set $name=} . (defined($value) ? qq{"$value"} : '') . "\n";
+}
+sub build_powershell_env_declaration {
+  my ($class, $name, $args) = @_;
+  my $value = $class->_interpolate($args, '$env:');
+  if (defined $value) {
+    $value =~ s/"/\\"/g;
+    return qq{\$env:$name = "$value"\n};
+  }
+  return "Remove-Item Env:\\$name\n";
 }
 
+
 sub _interpolate {
   my ($class, $args, $start, $end) = @_;
   return
@@ -494,38 +520,26 @@ ok(-d 't/var/splat');
 =cut
 
 sub guess_shelltype {
-  my $shellbin = 'sh';
-  if(defined $ENV{'SHELL'}) {
-      my @shell_bin_path_parts = File::Spec->splitpath($ENV{'SHELL'});
-      $shellbin = $shell_bin_path_parts[-1];
+  my $shellbin
+    = defined $ENV{SHELL}
+      ? (File::Spec->splitpath($ENV{SHELL}))[-1]
+    : ( $^O eq 'MSWin32' && exists $ENV{'!EXITCODE'} )
+      ? 'bash'
+    : ( $^O eq 'MSWin32' && $ENV{PROMPT} && $ENV{COMSPEC} )
+      ? (File::Spec->splitpath($ENV{COMSPEC}))[-1]
+    : ( $^O eq 'MSWin32' && !$ENV{PROMPT} )
+      ? 'powershell.exe'
+    : 'sh';
+
+  for ($shellbin) {
+    return
+        /csh/             ? 'csh'
+      : /command\.com/    ? 'cmd'
+      : /cmd\.exe/        ? 'cmd'
+      : /4nt\.exe/        ? 'cmd'
+      : /powershell\.exe/ ? 'powershell'
+                          : 'bourne';
   }
-  my $shelltype = do {
-      local $_ = $shellbin;
-      if(/csh/) {
-          'csh'
-      } else {
-          'bourne'
-      }
-  };
-
-  # Both Win32 and Cygwin have $ENV{COMSPEC} set.
-  if (defined $ENV{'COMSPEC'} && $^O ne 'cygwin') {
-      my @shell_bin_path_parts = File::Spec->splitpath($ENV{'COMSPEC'});
-      $shellbin = $shell_bin_path_parts[-1];
-         $shelltype = do {
-                 local $_ = $shellbin;
-                 if(/command\.com/) {
-                         'cmd'
-                 } elsif(/cmd\.exe/) {
-                         'cmd'
-                 } elsif(/4nt\.exe/) {
-                         'cmd'
-                 } else {
-                         $shelltype
-                 }
-         };
-  }
-  return $shelltype;
 }
 
 1;
@@ -775,6 +789,17 @@ was added by C<local::lib>, instead of adding it.
 Remove all directories that were added to search paths by C<local::lib> from the
 search paths.
 
+=head2 --shelltype
+
+Specify the shell type to use for output.  By default, the shell will be
+detected based on the environment.  Should be one of: C<bourne>, C<csh>,
+C<cmd>, or C<powershell>.
+
+=head2 --no-create
+
+Prevents C<local::lib> from creating directories when activating dirs.  This is
+likely to cause issues on Win32 systems.
+
 =head1 METHODS
 
 =head2 ensure_dir_structure_for
@@ -807,7 +832,7 @@ given path as the base directory.
 
 =over 4
 
-=item Arguments: $path, $interpolate
+=item Arguments: $path
 
 =item Return value: %environment_vars