diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/core/conda.c | 91 | ||||
-rw-r--r-- | src/lib/core/delivery.c | 16 |
2 files changed, 61 insertions, 46 deletions
diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c index 25069f8..8fb45cf 100644 --- a/src/lib/core/conda.c +++ b/src/lib/core/conda.c @@ -78,13 +78,27 @@ int pip_exec(const char *args) { return system(command); } -int pip_index_provides(const char *index_url, const char *spec) { +static const char *PKG_ERROR_STR[] = { + "success", + "[internal] unhandled package manager mode", + "[internal] unable to create temporary log for process output", + "package manager encountered an error at runtime", + "package manager received a signal", + "package manager failed to execute", +}; + +const char *pkg_index_provides_strerror(int code) { + code = -code - (-PKG_INDEX_PROVIDES_ERROR_MESSAGE_OFFSET); + return PKG_ERROR_STR[code]; +} + +int pkg_index_provides(int mode, const char *index, const char *spec) { char cmd[PATH_MAX] = {0}; char spec_local[255] = {0}; if (isempty((char *) spec)) { // NULL or zero-length; no package spec means there's nothing to do. - return -1; + return PKG_NOT_FOUND; } // Normalize the local spec string @@ -98,22 +112,36 @@ int pip_index_provides(const char *index_url, const char *spec) { if (logfd < 0) { perror(logfile); remove(logfile); // fail harmlessly if not present - return -1; + return PKG_INDEX_PROVIDES_E_INTERNAL_LOG_HANDLE; } - int status = 0; struct Process proc; memset(&proc, 0, sizeof(proc)); proc.redirect_stderr = 1; strcpy(proc.f_stdout, logfile); - // Do an installation in dry-run mode to see if the package exists in the given index. - snprintf(cmd, sizeof(cmd) - 1, "python -m pip install --dry-run --no-cache --no-deps --index-url=%s '%s'", index_url, spec_local); - status = shell(&proc, cmd); + if (mode == PKG_USE_PIP) { + // Do an installation in dry-run mode to see if the package exists in the given index. + strncpy(cmd, "python -m pip install --dry-run --no-cache --no-deps ", sizeof(cmd) - 1); + if (index) { + snprintf(cmd + strlen(cmd), (sizeof(cmd) - 1) - strlen(cmd), "--index-url='%s' ", index); + } + snprintf(cmd + strlen(cmd), (sizeof(cmd) - 1) - strlen(cmd), "'%s' ", spec_local); + } else if (mode == PKG_USE_CONDA) { + strncpy(cmd, "mamba search ", sizeof(cmd) - 1); + if (index) { + snprintf(cmd + strlen(cmd), (sizeof(cmd) - 1) - strlen(cmd), "--channel '%s' ", index); + } + snprintf(cmd + strlen(cmd), (sizeof(cmd) - 1) - strlen(cmd), "'%s' ", spec_local); + } else { + return PKG_INDEX_PROVIDES_E_INTERNAL_MODE_UNKNOWN; + } // Print errors only when shell() itself throws one - // If some day we want to see the errors thrown by pip too, use this condition instead: (status != 0) + // If some day we want to see the errors thrown by pip too, use this + // condition instead: (status != 0) + status = shell(&proc, cmd); if (status < 0) { FILE *fp = fdopen(logfd, "r"); if (!fp) { @@ -131,7 +159,25 @@ int pip_index_provides(const char *index_url, const char *spec) { } } remove(logfile); - return proc.returncode == 0; + + if (WTERMSIG(proc.returncode)) { + // This gets its own return value because if the external program + // received a signal, even its status is zero, it's not reliable + return PKG_INDEX_PROVIDES_E_MANAGER_SIGNALED; + } + + if (status < 0) { + return PKG_INDEX_PROVIDES_E_MANAGER_EXEC; + } else if (WEXITSTATUS(proc.returncode) > 1) { + // Pip and conda both return 2 on argument parsing errors + return PKG_INDEX_PROVIDES_E_MANAGER_RUNTIME; + } else if (WEXITSTATUS(proc.returncode) == 1) { + // Pip and conda both return 1 when a package is not found. + // Unfortunately this applies to botched version specs, too. + return PKG_NOT_FOUND; + } else { + return PKG_FOUND; + } } int conda_exec(const char *args) { @@ -440,33 +486,6 @@ char *conda_get_active_environment() { return result; } -int conda_provides(const char *spec) { - struct Process proc; - memset(&proc, 0, sizeof(proc)); - - // Short circuit: - // Running "mamba search" without an argument will print every package in - // all channels, then return "found". Prevent this. - // No data implies "not found". - if (isempty((char *) spec)) { - return 0; - } - - strcpy(proc.f_stdout, "/dev/null"); - strcpy(proc.f_stderr, "/dev/null"); - - // It's worth noting the departure from using conda_exec() here: - // conda_exec() expects the program output to be visible to the user. - // For this operation we only need the exit value. - char cmd[PATH_MAX] = {0}; - snprintf(cmd, sizeof(cmd) - 1, "mamba search %s", spec); - if (shell(&proc, cmd) < 0) { - fprintf(stderr, "shell: %s", strerror(errno)); - return -1; - } - return proc.returncode == 0; // 0=not_found, 1=found -} - int conda_index(const char *path) { char command[PATH_MAX]; sprintf(command, "index %s", path); diff --git a/src/lib/core/delivery.c b/src/lib/core/delivery.c index 5645dcc..ada708d 100644 --- a/src/lib/core/delivery.c +++ b/src/lib/core/delivery.c @@ -254,20 +254,16 @@ void delivery_defer_packages(struct Delivery *ctx, int type) { int upstream_exists = 0; if (DEFER_PIP == type) { - upstream_exists = pip_index_provides(PYPI_INDEX_DEFAULT, name); + upstream_exists = pkg_index_provides(PKG_USE_PIP, PYPI_INDEX_DEFAULT, name); } else if (DEFER_CONDA == type) { - upstream_exists = conda_provides(name); - } else { - fprintf(stderr, "\nUnknown package type: %d\n", type); - exit(1); + upstream_exists = pkg_index_provides(PKG_USE_CONDA, NULL, name); } - if (upstream_exists < 0) { - fprintf(stderr, "%s's existence command failed for '%s'\n" - "(This may be due to a network/firewall issue!)\n", mode, name); + if (PKG_INDEX_PROVIDES_FAILED(upstream_exists)) { + fprintf(stderr, "%s's existence command failed for '%s': %s\n", + mode, name, pkg_index_provides_strerror(upstream_exists)); exit(1); - } - if (!upstream_exists) { + } else if (upstream_exists == PKG_NOT_FOUND) { build_for_host = 1; } else { build_for_host = 0; |