Как загрузить virtualenv с помощью файла модуля среды (скрипт tcl)?
Я пытаюсь написать файл модуля для программы, которая создает Python virtualenv
, Для того, чтобы начать virtualenv
нужно сначала запустить /programs/program-env/bin/activate
, Как мне сделать это в modulefile
? Любая помощь будет оценена.
Примечание: я попытался просто вставить вышеупомянутую строку в файл, и это не сработало.
Спасибо,
Редактировать:
Я пишу файл модуля для загрузки программы, которая может работать только в virtualenv
, Обычно эти файлы модулей устанавливают имена переменных и / или добавляют каталог bin в путь. Поскольку вышеупомянутый пакет несколько отличается, я не знаю, как поступить. Пример файла модуля можно найти здесь.
4 ответа
Вот немного более полный ответ, основанный на ответах 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
есть какая-то ужасная логика, когда 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
Это означает, что если foo
а также bar
оба модульные файлы используют virtualenvs, второй foo remove
будут deactivate
bar
,
Система Modules довольно странная, поскольку она действительно создает набор инструкций, которые оцениваются вызывающей оболочкой. Это означает, что обычные способы ведения дел Tcl часто не совсем верны; это вызывающий должен бежать /programs/program-env/bin/activate
, а не сценарий Tcl.
Первое, что нужно попробовать:
system "/programs/program-env/bin/activate"
Однако, глядя между строк в FAQ, я вижу, что вам, вероятно, потребуется сделать это (с охраной):
if {[module-info mode] == "load"} {
puts stdout "/programs/program-env/bin/activate"
}
Я понятия не имею, как отменить операцию (которая является частью точки модуля).
Основываясь на ответе Donal Fellows и документах, это можно сделать с помощью:
if { [ module-info mode load ] } {
puts stdout "/programs/program-env/bin/activate;"
} elseif { [ module-info mode remove ] } {
puts stdout "deactivate;"
}
Точка с запятой имеет важное значение.
Вы не очень четко объяснили, что вы пытаетесь сделать, но учитывая ваше упоминание сценария tcl в заголовке, я предполагаю, что вы пишете сценарий Tcl, который должен загружать среду virtualenv для манипулирования сценарием python с использованием конфигурации virtualenv. Скрипты активации - это скрипты bash, которые в конечном итоге устанавливают текущую среду. Вы не можете просто отправить их в Tcl, поскольку Tcl не является оболочкой Bourne. Однако вы можете создать подпроцесс оболочки и прочитать его окружение и сравнить его со средой, измененной после выбора сценария активации. Если ваш tcl-скрипт применяет различия к своей среде, результирующий Tcl-процесс будет эквивалентен оболочке bash после выбора сценария активации.
Вот пример. Если вы запустите это как 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
}