diff options
| author | Joseph Hunkeler <jhunkeler@gmail.com> | 2026-06-12 01:47:00 -0400 |
|---|---|---|
| committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2026-06-12 01:47:00 -0400 |
| commit | 024a7bf4978f7aeccbbb5b31e52cb4126b70335b (patch) | |
| tree | d508db51fd65dbfdcb50b6135e7f97a53a69b0e7 /src | |
| parent | f1b331947e72bf59efe8babf4befb76b49ea6d2e (diff) | |
| download | stasis-024a7bf4978f7aeccbbb5b31e52cb4126b70335b.tar.gz | |
Add support for modern versions of conda and mamba
* Boa is dead, but we can still use it if conda is old enough
* Also because boa is dead we purge it from the list if the conda version is too new
* Initial environment activation changed as well, but still compatible with older versions of conda
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/core/conda.c | 76 |
1 files changed, 54 insertions, 22 deletions
diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c index b1be3c9..6e9389f 100644 --- a/src/lib/core/conda.c +++ b/src/lib/core/conda.c @@ -268,14 +268,22 @@ int conda_exec(const char *args) { }; char conda_as[10] = {0}; + const char *last_mamba_command = NULL; safe_strncpy(conda_as, "conda", sizeof(conda_as)); for (size_t i = 0; mamba_commands[i] != NULL; i++) { if (startswith(args, mamba_commands[i])) { + last_mamba_command = mamba_commands[i]; safe_strncpy(conda_as, "mamba", sizeof(conda_as)); break; } } + const int boa_present = find_program("boa") != NULL; + if (!boa_present) { + if (last_mamba_command && !strcmp(last_mamba_command, "build")) { + safe_strncpy(conda_as, "conda", sizeof(conda_as)); + } + } const char *command_fmt = "%s %s"; const int len = snprintf(NULL, 0, command_fmt, conda_as, args); @@ -358,15 +366,12 @@ static int env0_to_runtime(const char *logfile) { int conda_activate(const char *root, const char *env_name) { const char *init_script_conda = "/etc/profile.d/conda.sh"; - const char *init_script_mamba = "/etc/profile.d/mamba.sh"; char path_conda[PATH_MAX] = {0}; - char path_mamba[PATH_MAX] = {0}; char logfile[PATH_MAX] = {0}; struct Process proc = {0}; // Where to find conda's init scripts snprintf(path_conda, sizeof(path_conda), "%s%s", root, init_script_conda); - snprintf(path_mamba, sizeof(path_mamba), "%s%s", root, init_script_mamba); // Set the path to our stdout log // Emulate mktemp()'s behavior. Give us a unique file name, but don't use @@ -390,12 +395,6 @@ int conda_activate(const char *root, const char *env_name) { return -1; } - if (access(path_mamba, F_OK) < 0) { - SYSERROR("mamba is missing: %s, %s", path_mamba, strerror(errno)); - remove(logfile); - return -1; - } - // Fully activate conda and record its effect on the runtime environment char command[PATH_MAX * 3]; const char *conda_shlvl_str = getenv("CONDA_SHLVL"); @@ -417,20 +416,19 @@ int conda_activate(const char *root, const char *env_name) { snprintf(command, sizeof(command), "set -a\n" "source %s\n" - "__conda_exe() (\n" - " \"$CONDA_PYTHON_EXE\" \"$CONDA_EXE\" $_CE_M $_CE_CONDA \"$@\"\n" - ")\n\n" - "export -f __conda_exe\n" - "source %s\n" - "__mamba_exe() (\n" - " \\local MAMBA_CONDA_EXE_BACKUP=$CONDA_EXE\n" - " \\local MAMBA_EXE=$(\\dirname \"${CONDA_EXE}\")/mamba\n" - " \"$CONDA_PYTHON_EXE\" \"$MAMBA_EXE\" $_CE_M $_CE_CONDA \"$@\"\n" - ")\n\n" - "export -f __mamba_exe\n" + "tempfile=$(mktemp)\n" + "chmod 600 \"${tempfile}\"\n" + "%s/bin/mamba shell init --shell bash --dry-run 2>/dev/null\\\n" + "| (ignore=1; \\\n" + " while read line; do \\\n" + " if [[ \"$line\" == \"#\"* ]]; then ignore=0; fi; \\\n" + " if (( ignore == 0 )); then echo $line; fi; \\\n" + " done) 1> \"${tempfile}\"\n" + "source \"${tempfile}\"\n" + "rm -f \"${tempfile}\"\n" "%s\n" "conda activate %s 1>&2\n" - "env -0\n", path_conda, path_mamba, conda_shlvl ? "conda deactivate" : ":", env_name); + "env -0\n", path_conda, root, conda_shlvl ? "conda deactivate" : ":", env_name); int retval = shell(&proc, command); if (retval) { @@ -524,6 +522,29 @@ int conda_setup_headless(struct CondaCapabilities *cc) { size_t total = 0; const char *cmd_fmt = "'%s'"; if (globals.conda_packages && strlist_count(globals.conda_packages)) { + // Push or pop build packages based on capabilities + size_t boa_index = 0; + const int boa_requested = strlist_contains(globals.conda_packages, "boa", &boa_index); + if (boa_requested && !cc->require_boa) { + SYSWARN("Removing boa from global package list due to incompatible conda version (too new): %s", cc->conda_version); + strlist_remove(globals.conda_packages, boa_index); + } else if (!boa_requested && cc->require_boa) { + SYSWARN("Adding boa to global package list"); + strlist_append(&globals.conda_packages, "boa"); + } + + if (cc->require_boa) { + if (!boa_requested) { + SYSWARN("Adding boa to global package list"); + strlist_append(&globals.conda_packages, "boa"); + } + } else { + if (boa_requested) { + SYSWARN("Removing boa from global package list due to incompatible conda version (too new): %s", cc->conda_version); + strlist_remove(globals.conda_packages, boa_index); + } + } + memset(cmd, 0, sizeof(cmd)); safe_strncpy(cmd, "install ", sizeof(cmd)); @@ -661,7 +682,18 @@ int conda_env_remove(char *name) { int conda_env_export(char *name, char *output_dir, char *output_filename) { char env_command[PATH_MAX]; - snprintf(env_command, sizeof(env_command), "env export -n %s -f %s/%s.yml", name, output_dir, output_filename); + int vr = 0; + const char *env_format = NULL; + char *version = shell_output("conda --version", &vr); + if (version) { + const size_t v_offset = strlen("conda "); + if (version_compare(GT, version + v_offset, "25.1.0")) { + env_format = "--format=yml"; + } + guard_free(version); + } + + snprintf(env_command, sizeof(env_command), "env export %s -n %s -f %s/%s.yml", env_format ? env_format : "", name, output_dir, output_filename); return conda_exec(env_command); } |
