如何使用环境模块文件(tcl脚本)加载virtualenv?

arn*_*trm 10 python tcl virtualenv modulefile

我正在尝试为创建python的程序编写模块文件virtualenv.为了启动它virtualenv,它需要首先运行/programs/program-env/bin/activate.我该怎么做modulefile?任何帮助将不胜感激.

注意:我尝试将上面的行放在文件中,但它不起作用.

谢谢,

编辑:

我写一个modulefile加载程序只能在运行virtualenv.通常,这些模块文件将设置变量名称和/或将bin目录添加到路径.由于上述包装有些不同,我不知道如何进行.可以在此处找到示例模块文件.

Yos*_*ian 9

这是一个稍微更完整的答案,建立在Donal和betapatch的答案之上,它允许您在两个执行类似操作的模块之间进行交换:

if { [module-info mode load] || [module-info mode switch2] } {
    puts stdout "source /programs/program-env/bin/activate;"
} elseif { [module-info mode remove] && ![module-info mode switch3] } {
    puts stdout "deactivate;"
}
Run Code Online (Sandbox Code Playgroud)

首先,你需要使用source .../activate而不仅仅是.../activate.

其次,ping模块modules时有一些可怕的逻辑swap.如果你想module swap foo bar(删除foo并加载bar它的位置),它实际上执行以下操作:

foo: switch1 # prep for remove
foo: remove  # actually remove
bar: switch2 # load new module
foo: switch3 # cleanup
foo: remove  # happens at the same time as foo switch3
Run Code Online (Sandbox Code Playgroud)

这意味着如果foobar都是使用virtualenvs的模块文件,第二个foo removedeactivate bar.


Don*_*ows 5

Modules系统非常奇怪,因为它真正做的是创建一组由调用shell评估的指令.这意味着正常的Tcl做事方式往往不太正确; 需要运行的是调用/programs/program-env/bin/activate,而不是Tcl脚本.

首先要尝试的是:

system "/programs/program-env/bin/activate"
Run Code Online (Sandbox Code Playgroud)

但是,在常见问题解答中查看这些内容,我发现您可能需要执行此操作(使用警卫):

if {[module-info mode] == "load"} {
    puts stdout "/programs/program-env/bin/activate"
}
Run Code Online (Sandbox Code Playgroud)

我不知道如何反转操作(这是模块的一部分).


bet*_*tch 5

基于Donal Fellows答案和文档,可以使用以下方法完成:

if { [ module-info mode load ] } {
    puts stdout "/programs/program-env/bin/activate;"
} elseif { [ module-info mode remove ] } {
    puts stdout "deactivate;"
}
Run Code Online (Sandbox Code Playgroud)

分号是必不可少的。


pat*_*yts 0

您还没有非常清楚地解释您要做什么,但鉴于您在标题中提到了 tcl 脚本,我假设您正在编写一个 Tcl 脚本,该脚本需要加载 virtualenv 环境以使用 virtualenv 配置操作 python 脚本。激活脚本是最终设置当前环境的 bash 脚本。您不能简单地将这些源代码导入到 Tcl 中,因为 Tcl 不是 Bourne shell。但是,您可以创建一个 shell 子进程并读取其环境,并将其与获取激活脚本后更改的环境进行比较。如果您的 tcl 脚本将差异应用到其自己的环境中,则生成的 Tcl 进程将相当于获取激活脚本后的 bash shell。

这是一个例子。如果您运行此命令,tclsh scriptname bin/activate它会打印环境,其中现在将包含激活脚本中的其他设置。在我对 Linux 机器的测试中,这添加了一个 VIRTUAL_ENV 变量并修改了 PS1 和 PATH。

#!/usr/bin/env tclsh
# Load a virtualenv script in a subshell and apply the environment
# changes to the current process environment.

proc read_env {chan varname} {
    upvar #0 $varname E
    set len [gets $chan line]
    if {$len < 0} {
        fileevent $chan readable {}
        set ::completed 1
    } else {
        set pos [string first = $line]
        set key [string range $line 0 [expr {$pos - 1}]]
        set val [string range $line [expr {$pos + 1}] end]
        set E($key) $val
    }
}

proc read_shell_env {varname cmd} {
    set shell [open |[list /bin/bash] "r+"]
    fconfigure $shell -buffering line -encoding utf-8 -blocking 0
    fileevent $shell readable [list read_env $shell $varname]
    puts $shell $cmd
    flush $shell
    vwait ::completed
    close $shell
    return
}

proc update_env {key val} {
    global env
    set env($key) $val
}

proc load_virtualenv {filename} {
    array set ::envA {}
    array set ::envB {}
    read_shell_env ::envA "printenv; exit 0"
    read_shell_env ::envB "source \"$filename\"; printenv; exit 0"

    set keys [lsort [array names ::envA]]
    foreach k [lsort [array names ::envB]] {
        if {[info exists ::envA($k)]} {
            if {$::envA($k) ne $::envB($k)} {
                update_env $k $::envB($k)
            }
        } else {
            update_env $k $::envB($k)
        }
    }
    unset ::envA
    unset ::envB
    return
}

proc main {filename} {
    global env
    load_virtualenv $filename
    foreach key [lsort [array names env]] {
        puts "$key=$env($key)"
    }
    return 0
}

if {!$tcl_interactive} {
    set r [catch [linsert $argv 0 main] err]
    if {$r} {puts stderr $err}
    exit $r
}
Run Code Online (Sandbox Code Playgroud)