aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@users.noreply.github.com>2024-10-25 10:07:09 -0400
committerGitHub <noreply@github.com>2024-10-25 10:07:09 -0400
commitec55ea8fc503ad3fb53635d7e9e6d58a63c6684a (patch)
tree4091bf12e12c9923040dfb22601735688d988158 /src
parent7729d546d2dbda85ca1d86a913e97b51487355ba (diff)
parente1cfdd3202fbf0a7cb11b8c72ee7ba2cb934d76f (diff)
downloadstasis-ec55ea8fc503ad3fb53635d7e9e6d58a63c6684a.tar.gz
Merge pull request #64 from jhunkeler/combine-provides
Combine functions: pip_index_provides and conda_index_provides
Diffstat (limited to 'src')
-rw-r--r--src/cli/stasis/system_requirements.c2
-rw-r--r--src/cli/stasis/system_requirements.h2
-rw-r--r--src/lib/core/conda.c95
-rw-r--r--src/lib/core/delivery.c16
-rw-r--r--src/lib/core/delivery_build.c79
-rw-r--r--src/lib/core/delivery_install.c18
6 files changed, 125 insertions, 87 deletions
diff --git a/src/cli/stasis/system_requirements.c b/src/cli/stasis/system_requirements.c
index 4554b93..53ebbf7 100644
--- a/src/cli/stasis/system_requirements.c
+++ b/src/cli/stasis/system_requirements.c
@@ -67,7 +67,7 @@ void check_requirements(struct Delivery *ctx) {
check_system_env_requirements();
}
-char *check_pathvar(struct Delivery *ctx) {
+void check_pathvar(struct Delivery *ctx) {
char *pathvar = NULL;
pathvar = getenv("PATH");
if (!pathvar) {
diff --git a/src/cli/stasis/system_requirements.h b/src/cli/stasis/system_requirements.h
index 4c2231a..3a6fa25 100644
--- a/src/cli/stasis/system_requirements.h
+++ b/src/cli/stasis/system_requirements.h
@@ -8,6 +8,6 @@
void check_system_env_requirements();
void check_system_requirements(struct Delivery *ctx);
void check_requirements(struct Delivery *ctx);
-char *check_pathvar(struct Delivery *ctx);
+void check_pathvar(struct Delivery *ctx);
#endif //STASIS_SYSTEM_REQUIREMENTS_H
diff --git a/src/lib/core/conda.c b/src/lib/core/conda.c
index 25069f8..5954f20 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) {
@@ -167,7 +213,6 @@ int conda_exec(const char *args) {
}
int conda_activate(const char *root, const char *env_name) {
- int fd = -1;
FILE *fp = NULL;
const char *init_script_conda = "/etc/profile.d/conda.sh";
const char *init_script_mamba = "/etc/profile.d/mamba.sh";
@@ -185,7 +230,8 @@ int conda_activate(const char *root, const char *env_name) {
// Emulate mktemp()'s behavior. Give us a unique file name, but don't use
// the file handle at all. We'll open it as a FILE stream soon enough.
sprintf(logfile, "%s/%s", globals.tmpdir, "shell_XXXXXX");
- fd = mkstemp(logfile);
+
+ int fd = mkstemp(logfile);
if (fd < 0) {
perror(logfile);
return -1;
@@ -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;
diff --git a/src/lib/core/delivery_build.c b/src/lib/core/delivery_build.c
index b4d610a..615fa76 100644
--- a/src/lib/core/delivery_build.c
+++ b/src/lib/core/delivery_build.c
@@ -140,48 +140,59 @@ struct StrList *delivery_build_wheels(struct Delivery *ctx) {
return NULL;
}
- for (size_t i = 0; i < sizeof(ctx->tests) / sizeof(ctx->tests[0]); i++) {
- if (!ctx->tests[i].build_recipe && ctx->tests[i].repository) { // build from source
- char srcdir[PATH_MAX];
- char wheeldir[PATH_MAX];
- memset(srcdir, 0, sizeof(srcdir));
- memset(wheeldir, 0, sizeof(wheeldir));
+ for (size_t p = 0; p < strlist_count(ctx->conda.pip_packages_defer); p++) {
+ char name[100] = {0};
+ char *fullspec = strlist_item(ctx->conda.pip_packages_defer, p);
+ strncpy(name, fullspec, sizeof(name) - 1);
+ char *spec = find_version_spec(name);
+ if (spec) {
+ *spec = '\0';
+ }
- sprintf(srcdir, "%s/%s", ctx->storage.build_sources_dir, ctx->tests[i].name);
- git_clone(&proc, ctx->tests[i].repository, srcdir, ctx->tests[i].version);
+ for (size_t i = 0; i < sizeof(ctx->tests) / sizeof(ctx->tests[0]); i++) {
+ if ((ctx->tests[i].name && !strcmp(name, ctx->tests[i].name)) && (!ctx->tests[i].build_recipe && ctx->tests[i].repository)) { // build from source
+ char srcdir[PATH_MAX];
+ char wheeldir[PATH_MAX];
+ memset(srcdir, 0, sizeof(srcdir));
+ memset(wheeldir, 0, sizeof(wheeldir));
- if (ctx->tests[i].repository_remove_tags && strlist_count(ctx->tests[i].repository_remove_tags)) {
- filter_repo_tags(srcdir, ctx->tests[i].repository_remove_tags);
- }
+ sprintf(srcdir, "%s/%s", ctx->storage.build_sources_dir, ctx->tests[i].name);
+ git_clone(&proc, ctx->tests[i].repository, srcdir, ctx->tests[i].version);
- if (!pushd(srcdir)) {
- char dname[NAME_MAX];
- char outdir[PATH_MAX];
- char cmd[PATH_MAX * 2];
- memset(dname, 0, sizeof(dname));
- memset(outdir, 0, sizeof(outdir));
- memset(cmd, 0, sizeof(outdir));
-
- strcpy(dname, ctx->tests[i].name);
- tolower_s(dname);
- sprintf(outdir, "%s/%s", ctx->storage.wheel_artifact_dir, dname);
- if (mkdirs(outdir, 0755)) {
- fprintf(stderr, "failed to create output directory: %s\n", outdir);
- guard_strlist_free(&result);
- return NULL;
+ if (ctx->tests[i].repository_remove_tags && strlist_count(ctx->tests[i].repository_remove_tags)) {
+ filter_repo_tags(srcdir, ctx->tests[i].repository_remove_tags);
}
- sprintf(cmd, "-m build -w -o %s", outdir);
- if (python_exec(cmd)) {
- fprintf(stderr, "failed to generate wheel package for %s-%s\n", ctx->tests[i].name, ctx->tests[i].version);
+ if (!pushd(srcdir)) {
+ char dname[NAME_MAX];
+ char outdir[PATH_MAX];
+ char cmd[PATH_MAX * 2];
+ memset(dname, 0, sizeof(dname));
+ memset(outdir, 0, sizeof(outdir));
+ memset(cmd, 0, sizeof(outdir));
+
+ strcpy(dname, ctx->tests[i].name);
+ tolower_s(dname);
+ sprintf(outdir, "%s/%s", ctx->storage.wheel_artifact_dir, dname);
+ if (mkdirs(outdir, 0755)) {
+ fprintf(stderr, "failed to create output directory: %s\n", outdir);
+ guard_strlist_free(&result);
+ return NULL;
+ }
+
+ sprintf(cmd, "-m build -w -o %s", outdir);
+ if (python_exec(cmd)) {
+ fprintf(stderr, "failed to generate wheel package for %s-%s\n", ctx->tests[i].name,
+ ctx->tests[i].version);
+ guard_strlist_free(&result);
+ return NULL;
+ }
+ popd();
+ } else {
+ fprintf(stderr, "Unable to enter source directory %s: %s\n", srcdir, strerror(errno));
guard_strlist_free(&result);
return NULL;
}
- popd();
- } else {
- fprintf(stderr, "Unable to enter source directory %s: %s\n", srcdir, strerror(errno));
- guard_strlist_free(&result);
- return NULL;
}
}
}
diff --git a/src/lib/core/delivery_install.c b/src/lib/core/delivery_install.c
index 76c3f4a..098e6f4 100644
--- a/src/lib/core/delivery_install.c
+++ b/src/lib/core/delivery_install.c
@@ -3,9 +3,21 @@
static struct Test *requirement_from_test(struct Delivery *ctx, const char *name) {
struct Test *result = NULL;
for (size_t i = 0; i < sizeof(ctx->tests) / sizeof(ctx->tests[0]); i++) {
- if (ctx->tests[i].name && !strcmp(name, ctx->tests[i].name)) {
- result = &ctx->tests[i];
- break;
+ char *package_name = strdup(name);
+ if (package_name) {
+ char *spec = find_version_spec(package_name);
+ if (spec) {
+ *spec = '\0';
+ }
+
+ if (ctx->tests[i].name && !strcmp(package_name, ctx->tests[i].name)) {
+ result = &ctx->tests[i];
+ break;
+ }
+ guard_free(package_name);
+ } else {
+ SYSERROR("unable to allocate memory for package name: %s", name);
+ return NULL;
}
}
return result;