Auto activate of virtualenv in terminal for projects with Python Virtualenv interpreters (PY-10498)

This commit is contained in:
Dmitry Trofimov
2016-09-01 21:58:10 +02:00
parent f59ce78a2e
commit 2b5babe3da
11 changed files with 225 additions and 41 deletions

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="python-community" />
<orderEntry type="module" module-name="terminal" />
<orderEntry type="library" scope="TEST" name="JUnit4" level="project" />
<orderEntry type="library" scope="TEST" name="mockito" level="project" />
<orderEntry type="module" module-name="core-api" />
<orderEntry type="module" module-name="projectModel-api" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
<orderEntry type="module" module-name="lang-api" />
</component>
</module>

View File

@@ -0,0 +1,11 @@
<idea-plugin version="2" xmlns:xi="http://www.w3.org/2001/XInclude">
<name>Python Terminal</name>
<id>org.jetbrains.plugins.python-terminal</id>
<version>VERSION</version>
<vendor>JetBrains</vendor>
<depends>com.intellij.modules.python</depends>
<xi:include href="/META-INF/python-terminal-plugin.xml" xpointer="xpointer(/idea-plugin/*)"/>
</idea-plugin>

View File

@@ -0,0 +1,7 @@
<idea-plugin version="2">
<extensions defaultExtensionNs="org.jetbrains.plugins.terminal">
<localTerminalCustomizer implementation="com.jetbrains.python.sdk.PyVirtualEnvTerminalCustomizer"/>
</extensions>
</idea-plugin>

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.sdk
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.util.SystemInfo
import com.intellij.util.EnvironmentUtil
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor
import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor
import org.jetbrains.plugins.terminal.LocalTerminalCustomizer
import java.io.File
/**
* @author traff
*/
class PyVirtualEnvTerminalCustomizer : LocalTerminalCustomizer() {
override fun customizeCommandAndEnvironment(project: Project,
command: Array<out String>,
envs: MutableMap<String, String>): Array<out String> {
val sdk: Sdk? = findSdk(project)
if (sdk != null && PythonSdkType.isVirtualEnv(sdk) && SystemInfo.isUnix) {
// in case of virtualenv sdk on unix we activate virtualenv
val path = sdk.homePath
if (path != null) {
val shellPath = command[0]
val shellName = File(shellPath).name
if (shellName == "bash" || shellName == "sh") {
//for bash and sh we pass activate script to jediterm shell integration (see jediterm-sh.in)
findActivateScript(path, shellPath)?.let { activate -> envs.put("JEDITERM_SOURCE", activate) }
}
else {
//for other shells we read envs from activate script by the default shell and pass it to the process
val pyVirtualEnvReader = PyVirtualEnvReader(path)
pyVirtualEnvReader.activate?.let { envs.putAll(pyVirtualEnvReader.readShellEnv()) }
}
}
}
// for some reason virtualenv isn't activated in the rcfile for the login shell, so we make it non-login
return command.filter { arg -> arg != "--login" }.toTypedArray()
}
private fun findSdk(project: Project): Sdk? {
for (m in ModuleManager.getInstance(project).modules) {
val sdk: Sdk? = PythonSdkType.findPythonSdk(m)
if (sdk != null && !PythonSdkType.isRemote(sdk)) {
return sdk
}
}
return null
}
override fun getDefaultFolder(): String? {
return null
}
}
class PyVirtualEnvReader(virtualEnvSdkPath: String) : EnvironmentUtil.ShellEnvReader() {
val activate = findActivateScript(virtualEnvSdkPath, shell)
override fun getShellProcessCommand(): MutableList<String>? {
return if (activate != null) mutableListOf(shell, "--rcfile", activate, "-i")
else super.getShellProcessCommand()
}
}
private fun findActivateScript(path: String?, shellPath: String): String? {
val shellName = File(shellPath).name
val activate = 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
}