|
param([parameter(Position=0,Mandatory=$false)] [Hashtable] $CondaModuleArgs=@{}) |
|
|
|
# Defaults from before we had arguments. |
|
if (-not $CondaModuleArgs.ContainsKey('ChangePs1')) { |
|
$CondaModuleArgs.ChangePs1 = $True |
|
} |
|
|
|
## ENVIRONMENT MANAGEMENT ###################################################### |
|
|
|
<# |
|
.SYNOPSIS |
|
Obtains a list of valid conda environments. |
|
|
|
.EXAMPLE |
|
Get-CondaEnvironment |
|
|
|
.EXAMPLE |
|
genv |
|
#> |
|
function Get-CondaEnvironment { |
|
[CmdletBinding()] |
|
param(); |
|
|
|
begin {} |
|
|
|
process { |
|
# NB: the JSON output of conda env list does not include the names |
|
# of each env, so we need to parse the fragile output instead. |
|
& $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA env list | ` |
|
Where-Object { -not $_.StartsWith("#") } | ` |
|
Where-Object { -not $_.Trim().Length -eq 0 } | ` |
|
ForEach-Object { |
|
$envLine = $_ -split "\s+"; |
|
$Active = $envLine[1] -eq "*"; |
|
[PSCustomObject] @{ |
|
Name = $envLine[0]; |
|
Active = $Active; |
|
Path = if ($Active) {$envLine[2]} else {$envLine[1]}; |
|
} | Write-Output; |
|
} |
|
} |
|
|
|
end {} |
|
} |
|
|
|
<# |
|
.SYNOPSIS |
|
Activates a conda environment, placing its commands and packages at |
|
the head of $Env:PATH. |
|
|
|
.EXAMPLE |
|
Enter-CondaEnvironment base |
|
|
|
.EXAMPLE |
|
etenv base |
|
|
|
.NOTES |
|
This command does not currently support activating environments stored |
|
in a non-standard location. |
|
#> |
|
function Enter-CondaEnvironment { |
|
[CmdletBinding()] |
|
param( |
|
[Parameter(Mandatory=$false)][switch]$Stack, |
|
[Parameter(Position=0)][string]$Name |
|
); |
|
|
|
begin { |
|
If ($Stack) { |
|
$activateCommand = (& $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA shell.powershell activate --stack $Name | Out-String); |
|
} Else { |
|
$activateCommand = (& $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA shell.powershell activate $Name | Out-String); |
|
} |
|
|
|
Write-Verbose "[conda shell.powershell activate $Name]`n$activateCommand"; |
|
Invoke-Expression -Command $activateCommand; |
|
} |
|
|
|
process {} |
|
|
|
end {} |
|
|
|
} |
|
|
|
<# |
|
.SYNOPSIS |
|
Deactivates the current conda environment, if any. |
|
|
|
.EXAMPLE |
|
Exit-CondaEnvironment |
|
|
|
.EXAMPLE |
|
exenv |
|
#> |
|
function Exit-CondaEnvironment { |
|
[CmdletBinding()] |
|
param(); |
|
|
|
begin { |
|
$deactivateCommand = (& $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA shell.powershell deactivate | Out-String); |
|
|
|
# If deactivate returns an empty string, we have nothing more to do, |
|
# so return early. |
|
if ($deactivateCommand.Trim().Length -eq 0) { |
|
return; |
|
} |
|
Write-Verbose "[conda shell.powershell deactivate]`n$deactivateCommand"; |
|
Invoke-Expression -Command $deactivateCommand; |
|
} |
|
process {} |
|
end {} |
|
} |
|
|
|
## CONDA WRAPPER ############################################################### |
|
|
|
<# |
|
.SYNOPSIS |
|
conda is a tool for managing and deploying applications, environments |
|
and packages. |
|
|
|
.PARAMETER Command |
|
Subcommand to invoke. |
|
|
|
.EXAMPLE |
|
conda install toolz |
|
#> |
|
function Invoke-Conda() { |
|
# Don't use any explicit args here, we'll use $args and tab completion |
|
# so that we can capture everything, INCLUDING short options (e.g. -n). |
|
if ($Args.Count -eq 0) { |
|
# No args, just call the underlying conda executable. |
|
& $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA; |
|
} |
|
else { |
|
$Command = $Args[0]; |
|
if ($Args.Count -ge 2) { |
|
$OtherArgs = $Args[1..($Args.Count - 1)]; |
|
} else { |
|
$OtherArgs = @(); |
|
} |
|
switch ($Command) { |
|
"activate" { |
|
Enter-CondaEnvironment @OtherArgs; |
|
} |
|
"deactivate" { |
|
Exit-CondaEnvironment; |
|
} |
|
|
|
default { |
|
# There may be a command we don't know want to handle |
|
# differently in the shell wrapper, pass it through |
|
# verbatim. |
|
& $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA $Command @OtherArgs; |
|
} |
|
} |
|
} |
|
} |
|
|
|
## TAB COMPLETION ############################################################## |
|
# We borrow the approach used by posh-git, in which we override any existing |
|
# functions named TabExpansion, look for commands we can complete on, and then |
|
# default to the previously defined TabExpansion function for everything else. |
|
|
|
if (Test-Path Function:\TabExpansion) { |
|
# Since this technique is common, we encounter an infinite loop if it's |
|
# used more than once unless we give our backup a unique name. |
|
Rename-Item Function:\TabExpansion CondaTabExpansionBackup |
|
} |
|
|
|
function Expand-CondaEnv() { |
|
param( |
|
[string] |
|
$Filter |
|
); |
|
|
|
$ValidEnvs = Get-CondaEnvironment; |
|
$ValidEnvs ` |
|
| Where-Object { $_.Name -like "$filter*" } ` |
|
| ForEach-Object { $_.Name } ` |
|
| Write-Output; |
|
$ValidEnvs ` |
|
| Where-Object { $_.Path -like "$filter*" } ` |
|
| ForEach-Object { $_.Path } ` |
|
| Write-Output; |
|
|
|
} |
|
|
|
function Expand-CondaSubcommands() { |
|
param( |
|
[string] |
|
$Filter |
|
); |
|
|
|
$ValidCommands = Invoke-Conda shell.powershell commands; |
|
|
|
# Add in the commands defined within this wrapper, filter, sort, and return. |
|
$ValidCommands + @('activate', 'deactivate') ` |
|
| Where-Object { $_ -like "$Filter*" } ` |
|
| Sort-Object ` |
|
| Write-Output; |
|
|
|
} |
|
|
|
function TabExpansion($line, $lastWord) { |
|
$lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart() |
|
|
|
switch -regex ($lastBlock) { |
|
# Pull out conda commands we recognize first before falling through |
|
# to the general patterns for conda itself. |
|
"^conda activate (.*)" { Expand-CondaEnv $lastWord; break; } |
|
"^etenv (.*)" { Expand-CondaEnv $lastWord; break; } |
|
|
|
# If we got down to here, check arguments to conda itself. |
|
"^conda (.*)" { Expand-CondaSubcommands $lastWord; break; } |
|
|
|
# Finally, fall back on existing tab expansion. |
|
default { |
|
if (Test-Path Function:\CondaTabExpansionBackup) { |
|
CondaTabExpansionBackup $line $lastWord |
|
} |
|
} |
|
} |
|
} |
|
|
|
## PROMPT MANAGEMENT ########################################################### |
|
|
|
<# |
|
.SYNOPSIS |
|
Modifies the current prompt to show the currently activated conda |
|
environment, if any. |
|
.EXAMPLE |
|
Add-CondaEnvironmentToPrompt |
|
|
|
Causes the current session's prompt to display the currently activated |
|
conda environment. |
|
#> |
|
if ($CondaModuleArgs.ChangePs1) { |
|
# We use the same procedure to nest prompts as we did for nested tab completion. |
|
if (Test-Path Function:\prompt) { |
|
Rename-Item Function:\prompt CondaPromptBackup |
|
} else { |
|
function CondaPromptBackup() { |
|
# Restore a basic prompt if the definition is missing. |
|
"PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "; |
|
} |
|
} |
|
|
|
function global:prompt() { |
|
if ($Env:CONDA_PROMPT_MODIFIER) { |
|
$Env:CONDA_PROMPT_MODIFIER | Write-Host -NoNewline |
|
} |
|
CondaPromptBackup; |
|
} |
|
} |
|
|
|
## ALIASES ##################################################################### |
|
|
|
New-Alias conda Invoke-Conda -Force |
|
New-Alias genv Get-CondaEnvironment -Force |
|
New-Alias etenv Enter-CondaEnvironment -Force |
|
New-Alias exenv Exit-CondaEnvironment -Force |
|
|
|
## EXPORTS ################################################################### |
|
|
|
Export-ModuleMember ` |
|
-Alias * ` |
|
-Function ` |
|
Invoke-Conda, ` |
|
Get-CondaEnvironment, ` |
|
Enter-CondaEnvironment, Exit-CondaEnvironment, ` |
|
TabExpansion, prompt |
|
|