【发布时间】:2022-01-16 12:03:47
【问题描述】:
我正在尝试从 Go os/exec Command 和 Run 方法“激活”(或者更确切地说是伪激活)python 虚拟环境以用于其他命令执行。我知道每个命令执行实际上都是一次隔离运行,因此不会保留环境变量等,因此我一直在尝试手动重新创建激活期间发生的环境更改。
根据docs,这应该是可能的:
您不需要特别激活环境; 激活只是将虚拟环境的二进制目录添加到您的路径中,以便“python”调用虚拟环境的 Python 解释器,您可以运行已安装的脚本,而无需使用它们的完整路径。但是,所有安装在虚拟环境应该可以在不激活的情况下运行,并自动使用虚拟环境的 Python 运行。
但是,当我在 Go 中尝试此操作时,我无法让命令在虚拟环境中运行 - 例如,pip install requests 始终安装到全局 pip 缓存。以下是我正在使用的代码:
func Run(cmd *exec.Cmd) (exitCode int, err error) {
cmdErr := cmd.Run()
if cmdErr != nil {
exitCode, err = getExitCode(cmdErr)
}
return exitCode, err
}
func getExitCode(exitError error) (rc int, err error) {
if exitErrorOnly, ok := exitError.(*exec.ExitError); ok {
waitStatus := exitErrorOnly.Sys().(syscall.WaitStatus)
rc = waitStatus.ExitStatus()
} else {
err = fmt.Errorf("could not get exit code, using default")
}
return rc, err
}
func main() {
// using pre-existing venv for testing
const venv = "C:\\Users\\acalder\\Projects\\go\\runinvenv\\venv"
cmd := exec.Command("pip", "install", "requests")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = append(os.Environ(),
// these were the only ones i could see changing on 'activation'
"VIRTUAL_ENV=" + venv,
"PATH=" + venv + "\\Scripts;" + os.Getenv("PATH"),
)
exitCode, err := Run(cmd)
fmt.Println("exitCode:", exitCode)
fmt.Println("err:", err)
}
正如我在下面的评论中提到的那样;不幸的是,在查找PATH 时,LookPath 似乎总是使用os.Environ() 而不是cmd.Env。因此,如果您想避免将cmd.Path 指定给可执行文件,您将不得不修改操作系统环境本身。使用 maxm 的建议,这是我想出的解决方案 - 它实际上与 venv/Scripts/Activate 和 venv/Scripts/Deactivate 文件非常相似:
// file: venv_run_windows.go
func activateVenv(old_path, venv_path string) (err error) {
err = os.Setenv("PATH", filepath.Join(venv_path, "Scripts") + ";" + old_path)
if err != nil {
return err
}
return os.Setenv("VIRTUAL_ENV", venv_path)
}
func deactivateVenv(old_path string) (err error) {
err = os.Setenv("PATH", old_path)
if err != nil {
return err
}
return os.Unsetenv("VIRTUAL_ENV")
}
func VenvRun(cmd *exec.Cmd) (exitCode int, err error){
old_path := os.Getenv("PATH")
err = activateVenv(old_path, venv)
if (err != nil) {
return exitCode, err
}
defer deactivateVenv(old_path)
return Run(cmd)
}
【问题讨论】:
标签: go environment-variables python-venv