diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2024-12-18 10:54:52 -0500 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2024-12-18 11:11:53 -0500 |
commit | 54ac1e2e256252ec75fbdfe668a3328fb5d02c31 (patch) | |
tree | 787308045ca6bbfade19062e6764876db1fac00d | |
parent | 07011c46bdaee9efb1b643415e15c9be9ff12f03 (diff) | |
download | stasis-54ac1e2e256252ec75fbdfe668a3328fb5d02c31.tar.gz |
Add (conda|pip)_packages_purge configuration keys and driver
-rw-r--r-- | README.md | 20 | ||||
-rw-r--r-- | src/cli/stasis/stasis_main.c | 30 | ||||
-rw-r--r-- | src/lib/delivery/delivery_install.c | 58 | ||||
-rw-r--r-- | src/lib/delivery/delivery_populate.c | 8 | ||||
-rw-r--r-- | src/lib/delivery/include/delivery.h | 14 |
5 files changed, 118 insertions, 12 deletions
@@ -246,15 +246,17 @@ All configuration section names and keys are _case-sensitive_. ### conda -| Key | Type | Purpose | Required | -|--------------------|--------|----------------------------|----------| -| installer_name | String | Conda distribution name | Y | -| installer_version | String | Conda distribution version | Y | -| installer_platform | String | Conda target platform | Y | -| installer_arch | String | Conda target architecture | Y | -| installer_baseurl | String | Conda installer URL | Y | -| conda_packages | List | Conda packages to install | N | -| pip_packages | List | Pypi packages to install | N | +| Key | Type | Purpose | Required | +|----------------------|--------|----------------------------|----------| +| installer_name | String | Conda distribution name | Y | +| installer_version | String | Conda distribution version | Y | +| installer_platform | String | Conda target platform | Y | +| installer_arch | String | Conda target architecture | Y | +| installer_baseurl | String | Conda installer URL | Y | +| conda_packages | List | Conda packages to install | N | +| conda_packages_purge | List | Conda packages to remove | N | +| pip_packages | List | Pypi packages to install | N | +| pip_packages_purge | List | Conda packages to remove | N | ### runtime diff --git a/src/cli/stasis/stasis_main.c b/src/cli/stasis/stasis_main.c index dc4e2d1..61f198e 100644 --- a/src/cli/stasis/stasis_main.c +++ b/src/cli/stasis/stasis_main.c @@ -390,6 +390,20 @@ int main(int argc, char *argv[]) { } if (!isempty(ctx.meta.based_on)) { + if (ctx.conda.conda_packages_purge && strlist_count(ctx.conda.conda_packages_purge)) { + msg(STASIS_MSG_L2, "Purging conda packages\n"); + if (delivery_purge_packages(&ctx, env_name_testing, PKG_USE_CONDA)) { + msg(STASIS_MSG_ERROR | STASIS_MSG_L2, "unable to purge requested conda packages from %s\n", env_name_testing); + exit(1); + } + } + if (ctx.conda.pip_packages_purge && strlist_count(ctx.conda.pip_packages_purge)) { + msg(STASIS_MSG_L2, "Purging pip packages\n"); + if (delivery_purge_packages(&ctx, env_name_testing, PKG_USE_PIP)) { + msg(STASIS_MSG_ERROR | STASIS_MSG_L2, "unable to purge requested pip packages from %s\n", env_name_testing); + exit(1); + } + } msg(STASIS_MSG_L1, "Generating package overlay from environment: %s\n", env_name); if (delivery_overlay_packages_from_env(&ctx, env_name)) { msg(STASIS_MSG_L2 | STASIS_MSG_ERROR, "%s", "Failed to generate package overlay. Resulting environment integrity cannot be guaranteed.\n"); @@ -462,6 +476,22 @@ int main(int argc, char *argv[]) { msg(STASIS_MSG_L3, "No deferred conda packages\n"); } + if (ctx.conda.conda_packages_purge && strlist_count(ctx.conda.conda_packages_purge)) { + msg(STASIS_MSG_L2, "Purging conda packages\n"); + if (delivery_purge_packages(&ctx, env_name, PKG_USE_CONDA)) { + msg(STASIS_MSG_ERROR | STASIS_MSG_L2, "unable to purge requested conda packages\n"); + exit(1); + } + } + + if (ctx.conda.pip_packages_purge && strlist_count(ctx.conda.pip_packages_purge)) { + msg(STASIS_MSG_L2, "Purging pip packages\n"); + if (delivery_purge_packages(&ctx, env_name, PKG_USE_PIP)) { + msg(STASIS_MSG_ERROR | STASIS_MSG_L2, "unable to purge requested pip packages"); + exit(1); + } + } + msg(STASIS_MSG_L2, "Installing pip packages\n"); if (strlist_count(ctx.conda.pip_packages)) { if (delivery_install_packages(&ctx, ctx.storage.conda_install_prefix, env_name, INSTALL_PKG_PIP, (struct StrList *[]) {ctx.conda.pip_packages, NULL})) { diff --git a/src/lib/delivery/delivery_install.c b/src/lib/delivery/delivery_install.c index a348346..77bd60b 100644 --- a/src/lib/delivery/delivery_install.c +++ b/src/lib/delivery/delivery_install.c @@ -122,6 +122,64 @@ int delivery_overlay_packages_from_env(struct Delivery *ctx, const char *env_nam return 0; } +int delivery_purge_packages(struct Delivery *ctx, const char *env_name, int use_pkg_manager) { + int status = 0; + char subcommand[100] = {0}; + char package_manager[100] = {0}; + typedef int (fnptr)(const char *); + + const char *current_env = conda_get_active_environment(); + if (current_env) { + conda_activate(globals.conda_install_prefix, env_name); + } + + struct StrList *list = NULL; + fnptr *fn = NULL; + switch (use_pkg_manager) { + case PKG_USE_CONDA: + fn = conda_exec; + list = ctx->conda.conda_packages_purge; + strcpy(package_manager, "conda"); + // conda is already configured for "always_yes" + strcpy(subcommand, "remove"); + break; + case PKG_USE_PIP: + fn = pip_exec; + list = ctx->conda.pip_packages_purge; + strcpy(package_manager, "pip"); + // avoid user prompt to remove packages + strcpy(subcommand, "uninstall -y"); + break; + default: + SYSERROR("Unknown package manager: %d", use_pkg_manager); + status = -1; + break; + } + + for (size_t i = 0; i < strlist_count(list); i++) { + char *package = strlist_item(list, i); + char *command = NULL; + if (asprintf(&command, "%s '%s'", subcommand, package) < 0) { + SYSERROR("%s", "Unable to allocate bytes for removal command"); + status = -1; + break; + } + + if (fn(command)) { + SYSERROR("%s removal operation failed", package_manager); + guard_free(command); + status = 1; + break; + } + } + + if (current_env) { + conda_activate(globals.conda_install_prefix, current_env); + } + + return status; +} + 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]; diff --git a/src/lib/delivery/delivery_populate.c b/src/lib/delivery/delivery_populate.c index 8b683e1..e9aea89 100644 --- a/src/lib/delivery/delivery_populate.c +++ b/src/lib/delivery/delivery_populate.c @@ -150,11 +150,13 @@ int populate_delivery_ini(struct Delivery *ctx, int render_mode) { ctx->conda.installer_arch = ini_getval_str(ini, "conda", "installer_arch", render_mode, &err); ctx->conda.installer_baseurl = ini_getval_str(ini, "conda", "installer_baseurl", render_mode, &err); ctx->conda.conda_packages = ini_getval_strlist(ini, "conda", "conda_packages", LINE_SEP, render_mode, &err); - ctx->conda.pip_packages = ini_getval_strlist(ini, "conda", "pip_packages", LINE_SEP, render_mode, &err); - normalize_ini_list(&ini, &ctx->conda.conda_packages, "conda", "conda_packages", render_mode); + ctx->conda.conda_packages_purge = ini_getval_strlist(ini, "conda", "conda_packages_purge", LINE_SEP, render_mode, &err); + normalize_ini_list(&ini, &ctx->conda.conda_packages_purge, "conda", "conda_package_purge", render_mode); + ctx->conda.pip_packages = ini_getval_strlist(ini, "conda", "pip_packages", LINE_SEP, render_mode, &err); normalize_ini_list(&ini, &ctx->conda.pip_packages, "conda", "pip_packages", render_mode); - + ctx->conda.pip_packages_purge = ini_getval_strlist(ini, "conda", "pip_packages_purge", LINE_SEP, render_mode, &err); + normalize_ini_list(&ini, &ctx->conda.pip_packages_purge, "conda", "pip_packages_purge", render_mode); // Delivery metadata consumed populate_mission_ini(&ctx, render_mode); diff --git a/src/lib/delivery/include/delivery.h b/src/lib/delivery/include/delivery.h index a3843f5..26a5499 100644 --- a/src/lib/delivery/include/delivery.h +++ b/src/lib/delivery/include/delivery.h @@ -141,8 +141,10 @@ struct Delivery { char *tool_build_version; ///< Installed version of "build" package struct StrList *conda_packages; ///< Conda packages to deliver struct StrList *conda_packages_defer; ///< Conda recipes to be built for delivery + struct StrList *conda_packages_purge; ///< Conda packages to remove from a delivery (for: based_on) struct StrList *pip_packages; ///< Python packages to install (pip) struct StrList *pip_packages_defer; ///< Python packages to be built for delivery + struct StrList *pip_packages_purge; ///< Python packages to remove from a delivery (for: based_on) struct StrList *wheels_packages; ///< Wheel packages built for delivery } conda; @@ -445,4 +447,16 @@ int delivery_overlay_packages_from_env(struct Delivery *ctx, const char *env_nam */ int delivery_series_sync(struct Delivery *ctx); +/** + * Remove packages from an environment + * @param ctx Delivery context + * @param env_name Name of conda environment + * @param use_pkg_manager PKG_USE_PIP + * @param use_pkg_manager PKG_USE_CONDA + * @returns -1 on error + * @returns 0 on success + * @returns >0 on failure + */ +int delivery_purge_packages(struct Delivery *ctx, const char *env_name, int use_pkg_manager); + #endif //STASIS_DELIVERY_H |