Fix conda env auto activation in the terminal (PY-21643)
authorDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Tue, 6 Dec 2016 15:07:14 +0000 (16:07 +0100)
committerDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Tue, 6 Dec 2016 15:19:08 +0000 (16:19 +0100)
python/python-terminal/src/com/jetbrains/python/sdk/PyVirtualEnvTerminalCustomizer.kt
python/src/com/jetbrains/python/run/PyVirtualEnvReader.kt
python/src/com/jetbrains/python/sdk/PythonSdkType.java

index f05678cddaaae1dac66ad979e3842c5abf881c47..a4b0ed7d88a438fd030c1a8d8d48489d1eb8abc4 100644 (file)
@@ -52,9 +52,11 @@ class PyVirtualEnvTerminalCustomizer : LocalTerminalCustomizer() {
         val shellName = File(shellPath).name
 
         if (shellName == "bash" || (SystemInfo.isMac && shellName == "sh") || (shellName == "zsh") ||
-          ((shellName == "fish") && PythonSdkType.isVirtualEnv(sdk))) { //fish shell works only for virtualenv and not for conda
+            ((shellName == "fish") && PythonSdkType.isVirtualEnv(sdk))) { //fish shell works only for virtualenv and not for conda
           //for bash we pass activate script to jediterm shell integration (see jediterm-bash.in) to source it there
-          findActivateScript(path, shellPath)?.let { activate -> envs.put("JEDITERM_SOURCE", activate) }
+          findActivateScript(path, shellPath)?.let { activate ->
+            envs.put("JEDITERM_SOURCE", if (activate.second != null) "${activate.first} ${activate.second}" else activate.first)
+          }
         }
         else {
           //for other shells we read envs from activate script by the default shell and pass them to the process
@@ -63,7 +65,8 @@ class PyVirtualEnvTerminalCustomizer : LocalTerminalCustomizer() {
             // we add only envs that are setup by the activate script, because adding other variables from the different shell
             // can break the actual shell
             envs.putAll(reader.readShellEnv().mapKeys { k -> k.key.toUpperCase() }.filterKeys { k ->
-              k in arrayOf("PATH", "PS1", "VIRTUAL_ENV", "PYTHONHOME", "PROMPT", "_OLD_VIRTUAL_PROMPT", "_OLD_VIRTUAL_PYTHONHOME", "_OLD_VIRTUAL_PATH")
+              k in arrayOf("PATH", "PS1", "VIRTUAL_ENV", "PYTHONHOME", "PROMPT", "_OLD_VIRTUAL_PROMPT", "_OLD_VIRTUAL_PYTHONHOME",
+                           "_OLD_VIRTUAL_PATH")
             })
           }
         }
index 9aa8a7ccf0d36110cef478723de9d46865e9b7ec..961577934eb045d3ef7c4878b1d93d697d46206c 100644 (file)
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.SystemInfo
 import com.intellij.openapi.util.io.FileUtil
 import com.intellij.util.EnvironmentUtil
 import com.intellij.util.LineSeparator
+import com.jetbrains.python.sdk.PythonSdkType
 import java.io.File
 
 /**
@@ -30,7 +31,8 @@ import java.io.File
 class PyVirtualEnvReader(val virtualEnvSdkPath: String) : EnvironmentUtil.ShellEnvReader() {
   private val LOG = Logger.getInstance("#com.jetbrains.python.run.PyVirtualEnvReader")
 
-  val activate = findActivateScript(virtualEnvSdkPath, shell)
+  // in case of Conda we need to pass an argument to an activate script that tells which exactly environment to activate
+  val activate: Pair<String, String?>? = findActivateScript(virtualEnvSdkPath, shell)
 
   override fun getShell(): String? {
     if (File("/bin/bash").exists()) {
@@ -60,13 +62,15 @@ class PyVirtualEnvReader(val virtualEnvSdkPath: String) : EnvironmentUtil.ShellE
     }
   }
 
-  private fun readVirtualEnvOnWindows(activate: String): MutableMap<String, String> {
+  private fun readVirtualEnvOnWindows(activate: Pair<String, String?>): MutableMap<String, String> {
     val activateFile = FileUtil.createTempFile("pycharm-virualenv-activate.", ".bat", false)
     val envFile = FileUtil.createTempFile("pycharm-virualenv-envs.", ".tmp", false)
     try {
-      FileUtil.copy(File(activate), activateFile);
+      FileUtil.copy(File(activate.first), activateFile);
       FileUtil.appendToFile(activateFile, "\n\nset")
-      val command = listOf<String>(activateFile.path, ">", envFile.absolutePath)
+
+      val command = if (activate.second != null) listOf<String>(activateFile.path, activate.second!!, ">", envFile.absolutePath)
+      else listOf<String>(activateFile.path, ">", envFile.absolutePath)
 
       return runProcessAndReadEnvs(command, envFile, LineSeparator.CRLF.separatorString)
     }
@@ -84,18 +88,25 @@ class PyVirtualEnvReader(val virtualEnvSdkPath: String) : EnvironmentUtil.ShellE
       throw Exception("shell:" + shellPath)
     }
 
-    return if (activate != null)
-      mutableListOf(shellPath, "-c", ". '$activate'")
+    return if (activate != null) {
+      val activateArg = if (activate.second != null) "'${activate.first}' '${activate.second}'" else "'${activate.first}'"
+      mutableListOf(shellPath, "-c", ". $activateArg")
+    }
     else super.getShellProcessCommand()
   }
 
 }
 
-fun findActivateScript(path: String?, shellPath: String?): String? {
+fun findActivateScript(path: String?, shellPath: String?): Pair<String, String?>? {
   val shellName = if (shellPath != null) File(shellPath).name else null
   val activate = if (SystemInfo.isWindows) File(File(path).parentFile, "activate.bat")
   else if (shellName == "fish" || shellName == "csh") File(File(path).parentFile, "activate." + shellName)
   else File(File(path).parentFile, "activate")
 
-  return if (activate.exists()) activate.absolutePath else null
+  return if (activate.exists()) {
+    val sdk = PythonSdkType.findSdkByPath(path)
+    if (sdk != null && PythonSdkType.isCondaVirtualEnv(sdk)) Pair(activate.absolutePath, File(path).parentFile.parent)
+    else Pair(activate.absolutePath, null)
+  }
+  else null
 }
\ No newline at end of file
index 6e72a55782c88021f7e0788b12047b7478216f72..ad437e20a644b6c7af2399b56ac34be95af2708c 100644 (file)
@@ -312,7 +312,7 @@ public final class PythonSdkType extends SdkType {
     return path != null && getVirtualEnvRoot(path) != null;
   }
 
-  public static boolean isCondaVirtualEnv(Sdk sdk) {
+  public static boolean isCondaVirtualEnv(@NotNull Sdk sdk) {
     final String path = sdk.getHomePath();
     return path != null && PyCondaPackageManagerImpl.isCondaVEnv(sdk);
   }