diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/core/conda.c | 95 | ||||
| -rw-r--r-- | src/lib/core/delivery.c | 16 | ||||
| -rw-r--r-- | src/lib/core/delivery_build.c | 79 | ||||
| -rw-r--r-- | src/lib/core/delivery_install.c | 18 | 
4 files changed, 123 insertions, 85 deletions
| 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; | 
