2 * Copyright 2000-2016 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.jetbrains.python.run
18 import com.intellij.openapi.diagnostic.Logger
19 import com.intellij.openapi.util.SystemInfo
20 import com.intellij.openapi.util.io.FileUtil
21 import com.intellij.util.EnvironmentUtil
22 import com.intellij.util.LineSeparator
30 class PyVirtualEnvReader(val virtualEnvSdkPath: String) : EnvironmentUtil.ShellEnvReader() {
31 private val LOG = Logger.getInstance("#com.jetbrains.python.run.PyVirtualEnvReader")
33 val activate = findActivateScript(virtualEnvSdkPath, shell)
35 override fun getShell(): String? {
36 if (File("/bin/bash").exists()) {
40 if (File("/bin/sh").exists()) {
44 return super.getShell();
48 override fun readShellEnv(): MutableMap<String, String> {
49 if (SystemInfo.isUnix) {
50 return super.readShellEnv()
53 if (activate != null) {
54 return readVirtualEnvOnWindows(activate);
57 LOG.error("Can't find activate script for $virtualEnvSdkPath")
58 return mutableMapOf();
63 private fun readVirtualEnvOnWindows(activate: String): MutableMap<String, String> {
64 val activateFile = FileUtil.createTempFile("pycharm-virualenv-activate.", ".bat", false)
65 val envFile = FileUtil.createTempFile("pycharm-virualenv-envs.", ".tmp", false)
67 FileUtil.copy(File(activate), activateFile);
68 FileUtil.appendToFile(activateFile, "\n\nset")
69 val command = listOf<String>(activateFile.path, ">", envFile.absolutePath)
71 return runProcessAndReadEnvs(command, envFile, LineSeparator.CRLF.separatorString)
74 FileUtil.delete(activateFile)
75 FileUtil.delete(envFile)
80 override fun getShellProcessCommand(): MutableList<String>? {
83 if (shellPath == null || !File(shellPath).canExecute()) {
84 throw Exception("shell:" + shellPath)
87 return if (activate != null)
88 if (File(shellPath).name == "bash") {
89 mutableListOf(shellPath, "--rcfile", activate, "-i")
92 mutableListOf(shellPath, "-i", "-c", "source '$activate'")
94 else super.getShellProcessCommand()
99 fun findActivateScript(path: String?, shellPath: String?): String? {
100 val shellName = if (shellPath != null) File(shellPath).name else null
101 val activate = if (SystemInfo.isWindows) File(File(path).parentFile, "activate.bat")
102 else if (shellName == "fish" || shellName == "csh") File(File(path).parentFile, "activate." + shellName)
103 else File(File(path).parentFile, "activate")
105 return if (activate.exists()) activate.absolutePath else null