From a9bde31203476b5fb0ee4512f98bf34cdada34b6 Mon Sep 17 00:00:00 2001 From: Frankie Robertson Date: Wed, 25 Dec 2024 12:13:25 +0200 Subject: [PATCH] Add the :execute method to activate! and withenv --- src/env.jl | 89 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 23 deletions(-) diff --git a/src/env.jl b/src/env.jl index 19dd705..8e6fd31 100644 --- a/src/env.jl +++ b/src/env.jl @@ -4,40 +4,83 @@ This file defines functions for interacting with the environment, such as `withe """ """ - activate!(env) + activate!(env; method=:simple) -"Activate" the Conda environment by modifying the given dict of environment variables. +"Activate" the Conda environment by modifying the given dict of environment variables. When `method` is `:simple`, the environment variables corresponding to meaning any activation hooks provided by conda packages will not be run. + +An experimental `method` of `:execute` is available. In this case, the Conda environment will be activated in a bash subshell, meaning all the activation hooks will be run. All environment variables updated or created in this subshell are then changed in the current process. This method requires `bash` to be available, and has only been tested on Linux. """ -function activate!(e) +function activate!(e; method=:simple) backend() in (:Null, :Current) && return e - old_path = get(e, "PATH", "") - d = envdir() - path_sep = Sys.iswindows() ? ';' : ':' - new_path = join(bindirs(), path_sep) - if backend() == :MicroMamba - e["MAMBA_ROOT_PREFIX"] = MicroMamba.root_dir() - new_path = "$(new_path)$(path_sep)$(dirname(MicroMamba.executable()))" - end - if old_path != "" - new_path = "$(new_path)$(path_sep)$(old_path)" + if method == :simple + old_path = get(e, "PATH", "") + d = envdir() + path_sep = Sys.iswindows() ? ';' : ':' + new_path = join(bindirs(), path_sep) + if backend() == :MicroMamba + e["MAMBA_ROOT_PREFIX"] = MicroMamba.root_dir() + new_path = "$(new_path)$(path_sep)$(dirname(MicroMamba.executable()))" + end + if old_path != "" + new_path = "$(new_path)$(path_sep)$(old_path)" + end + e["PATH"] = new_path + e["CONDA_PREFIX"] = d + e["CONDA_DEFAULT_ENV"] = d + e["CONDA_SHLVL"] = "1" + e["CONDA_PROMPT_MODIFIER"] = "($d) " + e + elseif method == :execute + d = envdir() + hook = join(conda_cmd(`shell hook -s bash -r $d`).exec, " ") + activate = join(conda_cmd(`shell activate -s bash -p $d`).exec, " ") + steps = [ + "env", + "echo __65ab376884d7456ca97187d18a182250__", + "eval \"\$($hook)\"", + "eval \"\$($activate)\"", + "env" + ] + steps = join(steps, " && ") + cmd = `bash --norc --noprofile -c $steps` + out = read(cmd, String) + before_env = [] + after_env = [] + is_before = true + for line in split(out, '\n') + if line == "__65ab376884d7456ca97187d18a182250__" + is_before = false + end + if occursin("=", line) + bits = split(line, '=', limit=2) + if is_before + push!(before_env, bits) + else + push!(after_env, bits) + end + end + end + for (k, v) in after_env + if haskey(e, k) + if e[k] != v + e[k] = v + end + else + e[k] = v + end + end end - e["PATH"] = new_path - e["CONDA_PREFIX"] = d - e["CONDA_DEFAULT_ENV"] = d - e["CONDA_SHLVL"] = "1" - e["CONDA_PROMPT_MODIFIER"] = "($d) " - e end """ - withenv(f::Function) + withenv(f::Function, method=:simple) -Call `f()` while the Conda environment is active. +Call `f()` while the Conda environment is active. See `activate!()` for details of the `method` argument. """ -function withenv(f::Function) +function withenv(f::Function; method=:simple) old_env = copy(ENV) # shell("activate") - activate!(ENV) + activate!(ENV; method=method) frozen = STATE.frozen STATE.frozen = true try