arn*_*trm 10 python tcl virtualenv modulefile
我正在尝试为创建python的程序编写模块文件virtualenv.为了启动它virtualenv,它需要首先运行/programs/program-env/bin/activate.我该怎么做modulefile?任何帮助将不胜感激.
注意:我尝试将上面的行放在文件中,但它不起作用.
谢谢,
编辑:
我写一个modulefile加载程序只能在运行virtualenv.通常,这些模块文件将设置变量名称和/或将bin目录添加到路径.由于上述包装有些不同,我不知道如何进行.可以在此处找到示例模块文件.
这是一个稍微更完整的答案,建立在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)
这意味着如果foo和bar都是使用virtualenvs的模块文件,第二个foo remove将deactivate bar.
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)
我不知道如何反转操作(这是模块的一部分).
基于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)
分号是必不可少的。
您还没有非常清楚地解释您要做什么,但鉴于您在标题中提到了 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)