Conda.psm1 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. param([parameter(Position=0,Mandatory=$false)] [Hashtable] $CondaModuleArgs=@{})
  2. # Defaults from before we had arguments.
  3. if (-not $CondaModuleArgs.ContainsKey('ChangePs1')) {
  4. $CondaModuleArgs.ChangePs1 = $True
  5. }
  6. ## ENVIRONMENT MANAGEMENT ######################################################
  7. <#
  8. .SYNOPSIS
  9. Obtains a list of valid conda environments.
  10. .EXAMPLE
  11. Get-CondaEnvironment
  12. .EXAMPLE
  13. genv
  14. #>
  15. function Get-CondaEnvironment {
  16. [CmdletBinding()]
  17. param();
  18. begin {}
  19. process {
  20. # NB: the JSON output of conda env list does not include the names
  21. # of each env, so we need to parse the fragile output instead.
  22. & $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA env list | `
  23. Where-Object { -not $_.StartsWith("#") } | `
  24. Where-Object { -not $_.Trim().Length -eq 0 } | `
  25. ForEach-Object {
  26. $envLine = $_ -split "\s+";
  27. $Active = $envLine[1] -eq "*";
  28. [PSCustomObject] @{
  29. Name = $envLine[0];
  30. Active = $Active;
  31. Path = if ($Active) {$envLine[2]} else {$envLine[1]};
  32. } | Write-Output;
  33. }
  34. }
  35. end {}
  36. }
  37. <#
  38. .SYNOPSIS
  39. Activates a conda environment, placing its commands and packages at
  40. the head of $Env:PATH.
  41. .EXAMPLE
  42. Enter-CondaEnvironment base
  43. .EXAMPLE
  44. etenv base
  45. .NOTES
  46. This command does not currently support activating environments stored
  47. in a non-standard location.
  48. #>
  49. function Enter-CondaEnvironment {
  50. [CmdletBinding()]
  51. param(
  52. [Parameter(Mandatory=$false)][switch]$Stack,
  53. [Parameter(Position=0)][string]$Name
  54. );
  55. begin {
  56. If ($Stack) {
  57. $activateCommand = (& $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA shell.powershell activate --stack $Name | Out-String);
  58. } Else {
  59. $activateCommand = (& $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA shell.powershell activate $Name | Out-String);
  60. }
  61. Write-Verbose "[conda shell.powershell activate $Name]`n$activateCommand";
  62. Invoke-Expression -Command $activateCommand;
  63. }
  64. process {}
  65. end {}
  66. }
  67. <#
  68. .SYNOPSIS
  69. Deactivates the current conda environment, if any.
  70. .EXAMPLE
  71. Exit-CondaEnvironment
  72. .EXAMPLE
  73. exenv
  74. #>
  75. function Exit-CondaEnvironment {
  76. [CmdletBinding()]
  77. param();
  78. begin {
  79. $deactivateCommand = (& $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA shell.powershell deactivate | Out-String);
  80. # If deactivate returns an empty string, we have nothing more to do,
  81. # so return early.
  82. if ($deactivateCommand.Trim().Length -eq 0) {
  83. return;
  84. }
  85. Write-Verbose "[conda shell.powershell deactivate]`n$deactivateCommand";
  86. Invoke-Expression -Command $deactivateCommand;
  87. }
  88. process {}
  89. end {}
  90. }
  91. ## CONDA WRAPPER ###############################################################
  92. <#
  93. .SYNOPSIS
  94. conda is a tool for managing and deploying applications, environments
  95. and packages.
  96. .PARAMETER Command
  97. Subcommand to invoke.
  98. .EXAMPLE
  99. conda install toolz
  100. #>
  101. function Invoke-Conda() {
  102. # Don't use any explicit args here, we'll use $args and tab completion
  103. # so that we can capture everything, INCLUDING short options (e.g. -n).
  104. if ($Args.Count -eq 0) {
  105. # No args, just call the underlying conda executable.
  106. & $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA;
  107. }
  108. else {
  109. $Command = $Args[0];
  110. if ($Args.Count -ge 2) {
  111. $OtherArgs = $Args[1..($Args.Count - 1)];
  112. } else {
  113. $OtherArgs = @();
  114. }
  115. switch ($Command) {
  116. "activate" {
  117. Enter-CondaEnvironment @OtherArgs;
  118. }
  119. "deactivate" {
  120. Exit-CondaEnvironment;
  121. }
  122. default {
  123. # There may be a command we don't know want to handle
  124. # differently in the shell wrapper, pass it through
  125. # verbatim.
  126. & $Env:CONDA_EXE $Env:_CE_M $Env:_CE_CONDA $Command @OtherArgs;
  127. }
  128. }
  129. }
  130. }
  131. ## TAB COMPLETION ##############################################################
  132. # We borrow the approach used by posh-git, in which we override any existing
  133. # functions named TabExpansion, look for commands we can complete on, and then
  134. # default to the previously defined TabExpansion function for everything else.
  135. if (Test-Path Function:\TabExpansion) {
  136. # Since this technique is common, we encounter an infinite loop if it's
  137. # used more than once unless we give our backup a unique name.
  138. Rename-Item Function:\TabExpansion CondaTabExpansionBackup
  139. }
  140. function Expand-CondaEnv() {
  141. param(
  142. [string]
  143. $Filter
  144. );
  145. $ValidEnvs = Get-CondaEnvironment;
  146. $ValidEnvs `
  147. | Where-Object { $_.Name -like "$filter*" } `
  148. | ForEach-Object { $_.Name } `
  149. | Write-Output;
  150. $ValidEnvs `
  151. | Where-Object { $_.Path -like "$filter*" } `
  152. | ForEach-Object { $_.Path } `
  153. | Write-Output;
  154. }
  155. function Expand-CondaSubcommands() {
  156. param(
  157. [string]
  158. $Filter
  159. );
  160. $ValidCommands = Invoke-Conda shell.powershell commands;
  161. # Add in the commands defined within this wrapper, filter, sort, and return.
  162. $ValidCommands + @('activate', 'deactivate') `
  163. | Where-Object { $_ -like "$Filter*" } `
  164. | Sort-Object `
  165. | Write-Output;
  166. }
  167. function TabExpansion($line, $lastWord) {
  168. $lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart()
  169. switch -regex ($lastBlock) {
  170. # Pull out conda commands we recognize first before falling through
  171. # to the general patterns for conda itself.
  172. "^conda activate (.*)" { Expand-CondaEnv $lastWord; break; }
  173. "^etenv (.*)" { Expand-CondaEnv $lastWord; break; }
  174. # If we got down to here, check arguments to conda itself.
  175. "^conda (.*)" { Expand-CondaSubcommands $lastWord; break; }
  176. # Finally, fall back on existing tab expansion.
  177. default {
  178. if (Test-Path Function:\CondaTabExpansionBackup) {
  179. CondaTabExpansionBackup $line $lastWord
  180. }
  181. }
  182. }
  183. }
  184. ## PROMPT MANAGEMENT ###########################################################
  185. <#
  186. .SYNOPSIS
  187. Modifies the current prompt to show the currently activated conda
  188. environment, if any.
  189. .EXAMPLE
  190. Add-CondaEnvironmentToPrompt
  191. Causes the current session's prompt to display the currently activated
  192. conda environment.
  193. #>
  194. if ($CondaModuleArgs.ChangePs1) {
  195. # We use the same procedure to nest prompts as we did for nested tab completion.
  196. if (Test-Path Function:\prompt) {
  197. Rename-Item Function:\prompt CondaPromptBackup
  198. } else {
  199. function CondaPromptBackup() {
  200. # Restore a basic prompt if the definition is missing.
  201. "PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) ";
  202. }
  203. }
  204. function global:prompt() {
  205. if ($Env:CONDA_PROMPT_MODIFIER) {
  206. $Env:CONDA_PROMPT_MODIFIER | Write-Host -NoNewline
  207. }
  208. CondaPromptBackup;
  209. }
  210. }
  211. ## ALIASES #####################################################################
  212. New-Alias conda Invoke-Conda -Force
  213. New-Alias genv Get-CondaEnvironment -Force
  214. New-Alias etenv Enter-CondaEnvironment -Force
  215. New-Alias exenv Exit-CondaEnvironment -Force
  216. ## EXPORTS ###################################################################
  217. Export-ModuleMember `
  218. -Alias * `
  219. -Function `
  220. Invoke-Conda, `
  221. Get-CondaEnvironment, `
  222. Enter-CondaEnvironment, Exit-CondaEnvironment, `
  223. TabExpansion, prompt