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

时间:2014-04-05 18:40:53

标签: python tcl virtualenv modulefile

我正在尝试为创建python virtualenv的程序编写模块文件。要启动virtualenv,首先需要运行/programs/program-env/bin/activate。我如何在modulefile中执行此操作? 任何帮助将不胜感激。

注意:我尝试将上面一行放在文件中,但它没有用。

谢谢,

编辑:

我正在编写modulefile来加载只能在virtualenv中运行的程序。通常,这些模块文件将设置变量名称和/或将bin目录添加到路径。由于上述包装有所不同,我不知道如何继续。可以找到示例模块文件here

3 个答案:

答案 0 :(得分:8)

这是一个稍微更完整的答案,建立在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;"
}

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

其次,当modules ping模块时,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

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

答案 1 :(得分:4)

根据Donal Fellows的回答和文件可以完成:

if { [ module-info mode load ] } {
    puts stdout "/programs/program-env/bin/activate;"
} elseif { [ module-info mode remove ] } {
    puts stdout "deactivate;"
}

分号是必不可少的。

答案 2 :(得分: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
}