diff options
| author | Joseph Hunkeler <jhunkeler@gmail.com> | 2024-10-04 18:35:04 -0400 | 
|---|---|---|
| committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2024-10-04 18:35:04 -0400 | 
| commit | 3fa05b5a2f0cda51897162666fb300d2d063b22f (patch) | |
| tree | 8a4e4f4b286b81e886544d490926509a777a3ebc | |
| parent | 64e91d99e8e391b1789f9cc326f21f0c52fd3ac6 (diff) | |
| download | stasis-3fa05b5a2f0cda51897162666fb300d2d063b22f.tar.gz | |
Add function delivery_overlay_packages_from_env()
* Add helper function have_spec_in_config()
| -rw-r--r-- | include/delivery.h | 2 | ||||
| -rw-r--r-- | src/delivery_install.c | 95 | 
2 files changed, 97 insertions, 0 deletions
| diff --git a/include/delivery.h b/include/delivery.h index 6da890a..15cde13 100644 --- a/include/delivery.h +++ b/include/delivery.h @@ -419,4 +419,6 @@ int filter_repo_tags(char *repo, struct StrList *patterns);   */  int delivery_exists(struct Delivery *ctx); +int delivery_overlay_packages_from_env(struct Delivery *ctx, const char *env_name); +  #endif //STASIS_DELIVERY_H diff --git a/src/delivery_install.c b/src/delivery_install.c index ae31cb9..1fc6030 100644 --- a/src/delivery_install.c +++ b/src/delivery_install.c @@ -11,6 +11,101 @@ static struct Test *requirement_from_test(struct Delivery *ctx, const char *name      return result;  } +static char *have_spec_in_config(struct Delivery *ctx, const char *name) { +    for (size_t x = 0; x < strlist_count(ctx->conda.pip_packages); x++) { +        char *config_spec = strlist_item(ctx->conda.pip_packages, x); +        char *op = find_version_spec(config_spec); +        char package[255] = {0}; +        if (op) { +            strncpy(package, config_spec, op - config_spec); +        } else { +            strncpy(package, config_spec, sizeof(package) - 1); +        } +        if (strncmp(package, name, strlen(package)) == 0) { +            return config_spec; +        } +    } +    return NULL; +} + +int delivery_overlay_packages_from_env(struct Delivery *ctx, const char *env_name) { +    char *current_env = conda_get_active_environment(); +    int need_restore = current_env && strcmp(env_name, current_env) != 0; + +    conda_activate(ctx->storage.conda_install_prefix, env_name); +    // Retrieve a listing of python packages installed under "env_name" +    int freeze_status = 0; +    char *freeze_output = shell_output("python -m pip freeze", &freeze_status); +    if (freeze_status) { +        guard_free(freeze_output); +        guard_free(current_env); +        return -1; +    } + +    if (need_restore) { +        // Restore the original conda environment +        conda_activate(ctx->storage.conda_install_prefix, current_env); +    } +    guard_free(current_env); + +    struct StrList *frozen_list = strlist_init(); +    strlist_append_tokenize(frozen_list, freeze_output, LINE_SEP); +    guard_free(freeze_output); + +    struct StrList *new_list = strlist_init(); + +    // - consume package specs that have no test blocks. +    // - these will be third-party packages like numpy, scipy, etc. +    // - and they need to be present at the head of the list so they +    //   get installed first. +    for (size_t i = 0; i < strlist_count(ctx->conda.pip_packages); i++) { +        char *spec = strlist_item(ctx->conda.pip_packages, i); +        char spec_name[255] = {0}; +        char *op = find_version_spec(spec); +        if (op) { +            strncpy(spec_name, spec, op - spec); +        } else { +            strncpy(spec_name, spec, sizeof(spec_name) - 1); +        } +        struct Test *test_block = requirement_from_test(ctx, spec_name); +        if (!test_block) { +            printf("using spec from config without test: %s\n", spec); +            strlist_append(&new_list, spec); +        } +    } + +    // now consume packages that have a test block +    // if the ini provides a spec, override the environment's version. +    // otherwise, use the spec derived from the environment +    for (size_t i = 0; i < strlist_count(frozen_list); i++) { +        char *frozen_spec = strlist_item(frozen_list, i); +        char frozen_name[255] = {0}; +        char *op = find_version_spec(frozen_spec); +        // we only care about packages with specs here. if something else arrives, ignore it +        if (op) { +            strncpy(frozen_name, frozen_spec, op - frozen_spec); +        } else { +            strncpy(frozen_name, frozen_spec, sizeof(frozen_name) - 1); +        } +        struct Test *test = requirement_from_test(ctx, frozen_name); +        if (test && strcmp(test->name, frozen_name) == 0) { +            char *config_spec = have_spec_in_config(ctx, frozen_name); +            if (config_spec) { +                printf("using spec from config: %s\n", config_spec); +                strlist_append(&new_list, config_spec); +            } else { +                printf("using spec from environment: %s\n", frozen_spec); +                strlist_append(&new_list, frozen_spec); +            } +        } +    } +    guard_strlist_free(&ctx->conda.pip_packages); +    ctx->conda.pip_packages = strlist_copy(new_list); +    guard_strlist_free(&new_list); +    guard_strlist_free(&frozen_list); +    return 0; +} +  int delivery_install_packages(struct Delivery *ctx, char *conda_install_dir, char *env_name, int type, struct StrList **manifest) {      char cmd[PATH_MAX];      char pkgs[STASIS_BUFSIZ]; | 
