aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2024-08-17 01:55:09 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2024-08-17 20:40:37 -0400
commit27c4a23727c981505724db7a21bcfdc5db56dfe8 (patch)
tree35d0cb60d3237bd3fd783a7daaf535c9d90bafaf
parenta7568dc03c1c6851ff6c690e8e35ade9a3199c4a (diff)
downloadstasis-27c4a23727c981505724db7a21bcfdc5db56dfe8.tar.gz
Add python_package_exists() function
* Poll pypi.org or compatible index to see if a package exists * Returns non-zero on success
-rw-r--r--include/conda.h4
-rw-r--r--src/conda.c66
2 files changed, 70 insertions, 0 deletions
diff --git a/include/conda.h b/include/conda.h
index d439371..169bc58 100644
--- a/include/conda.h
+++ b/include/conda.h
@@ -7,6 +7,7 @@
#include "core.h"
#define CONDA_INSTALL_PREFIX "conda"
+#define PYPI_INDEX_DEFAULT "https://pypi.org/simple"
struct MicromambaInfo {
char *micromamba_prefix;
@@ -181,4 +182,7 @@ int conda_env_export(char *name, char *output_dir, char *output_filename);
* @return exit code from "conda"
*/
int conda_index(const char *path);
+
+int python_package_exists(const char *index_url, const char *name, const char *version);
+
#endif //STASIS_CONDA_H
diff --git a/src/conda.c b/src/conda.c
index 6ed96c7..3e8b783 100644
--- a/src/conda.c
+++ b/src/conda.c
@@ -79,6 +79,72 @@ int pip_exec(const char *args) {
return system(command);
}
+int python_package_exists(const char *index_url, const char *name, const char *version) {
+ char cmd[PATH_MAX] = {0};
+ char name_local[255];
+ char version_local[255] = {0};
+ char spec[255] = {0};
+
+ if (isempty((char *) name) < 0) {
+ // no package name means nothing to do.
+ return -1;
+ }
+
+ // Fix up the package name
+ strncpy(name_local, name, sizeof(name_local) - 1);
+ tolower_s(name_local);
+ lstrip(name_local);
+ strip(name_local);
+
+ if (version) {
+ // Fix up the package version
+ strncpy(version_local, version, sizeof(version_local) - 1);
+ tolower_s(version_local);
+ lstrip(version_local);
+ strip(version_local);
+ sprintf(spec, "==%s", version);
+ }
+
+ char logfile[] = "/tmp/STASIS-package_exists.XXXXXX";
+ int logfd = mkstemp(logfile);
+ if (logfd < 0) {
+ perror(logfile);
+ return -1;
+ }
+
+
+ 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-deps --index-url=%s %s%s", index_url, name_local, spec);
+ status = shell(&proc, cmd);
+
+ // 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 (status < 0) {
+ FILE *fp = fdopen(logfd, "r");
+ if (!fp) {
+ remove(logfile);
+ return -1;
+ } else {
+ char line[BUFSIZ] = {0};
+ fflush(stdout);
+ fflush(stderr);
+ while (fgets(line, sizeof(line) - 1, fp) != NULL) {
+ fprintf(stderr, "%s", line);
+ }
+ fflush(stderr);
+ fclose(fp);
+ remove(logfile);
+ }
+ }
+ return proc.returncode == 0;
+}
+
int conda_exec(const char *args) {
char command[PATH_MAX];
const char *mamba_commands[] = {