aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2023-12-10 01:00:28 -0500
committerJoseph Hunkeler <jhunkeler@gmail.com>2023-12-10 01:00:28 -0500
commitcc9ef66ca505b5872d153afd105b3ef7b08c03c9 (patch)
tree07b4126e35fc08275448bee437b35898e7050dae
parent78e838e95f14679ef2d8397977de0f6e645ceb12 (diff)
downloadstasis-cc9ef66ca505b5872d153afd105b3ef7b08c03c9.tar.gz
Too many changes to count
* Artifactory test integration * guard_free() all pointers * Remove semicolons from macro calls * Add conda_fresh_start to delete conda at start up (or not) * Use generated archives from github instead of the raw repository url. For now anyway. * Add delivery_runtime_show() to dump the runtime environment * Fix release output names to include the target architecture. This format will change agan soon. * Prevent bogus delivery definitions from going too far into the build process before encountering a failure. * Detect OS and architecture * Ensure the user's TMPDIR is usable before going too far into the process * Refactor omc output directory names
-rw-r--r--include/deliverable.h17
-rw-r--r--src/deliverable.c468
2 files changed, 409 insertions, 76 deletions
diff --git a/include/deliverable.h b/include/deliverable.h
index b585054..135a14c 100644
--- a/include/deliverable.h
+++ b/include/deliverable.h
@@ -11,8 +11,8 @@
#include "ini.h"
#include "environment.h"
#include "conda.h"
+#include "artifactory.h"
-#define DELIVERY_DIR "delivery"
#define DELIVERY_PLATFORM_MAX 4
#define DELIVERY_PLATFORM_MAXLEN 65
#define DELIVERY_PLATFORM 0
@@ -45,7 +45,10 @@ struct Delivery {
* \brief Storage paths
*/
struct Storage {
+ char *root; ///< Top-level storage area
+ char *tmpdir; ///< Temporary storage area (within root)
char *delivery_dir; ///< Delivery artifact output directory
+ char *tools_dir; ///< Tools storage
char *conda_install_prefix; ///< Path to install Conda
char *conda_artifact_dir; ///< Base path to store compiled conda packages
char *conda_staging_dir; ///< Base path to copy compiled conda packages
@@ -157,6 +160,12 @@ void delivery_conda_show(struct Delivery *ctx);
void delivery_tests_show(struct Delivery *ctx);
/**
+ * Print Delivery initial runtime environment
+ * @param ctx pointner to Delivery context
+ */
+void delivery_runtime_show(struct Delivery *ctx);
+
+/**
* Build Conda recipes associated with the Delivery
* @param ctx pointer to Delivery context
* @return 0 on success
@@ -278,4 +287,10 @@ void delivery_install_conda(char *install_script, char *conda_install_dir);
// helper function
void delivery_gather_tool_versions(struct Delivery *ctx);
+// helper function
+int delivery_init_tmpdir(struct Delivery *ctx);
+
+int delivery_init_artifactory(struct Delivery *ctx);
+
+int delivery_artifact_upload(struct Delivery *ctx);
#endif //OMC_DELIVERABLE_H
diff --git a/src/deliverable.c b/src/deliverable.c
index fda4354..e6704d9 100644
--- a/src/deliverable.c
+++ b/src/deliverable.c
@@ -1,7 +1,7 @@
-//
-// Created by jhunk on 10/5/23.
-//
+#define _GNU_SOURCE
+#include <sys/statvfs.h>
+#include "omc.h"
#include "deliverable.h"
#include "str.h"
#include "strlist.h"
@@ -33,7 +33,7 @@ extern struct OMC_GLOBAL globals;
if (rtevnop) { \
strip(rtevnop); \
strlist_append_tokenize(X->DEST, rtevnop, TOK); \
- free(rtevnop); \
+ guard_free(rtevnop) \
} else { \
rtevnop = NULL; \
} \
@@ -48,27 +48,84 @@ extern struct OMC_GLOBAL globals;
if (rtevnop) { \
strip(rtevnop); \
strlist_append_tokenize(X.DEST, rtevnop, TOK); \
- free(rtevnop); \
+ guard_free(rtevnop) \
} else { \
rtevnop = NULL; \
} \
}
-#define conv_bool(X, DEST) X->DEST = val.as_bool;
-#define guard_runtime_free(X) if (X) { runtime_free(X); X = NULL; }
-#define guard_strlist_free(X) if (X) { strlist_free(X); X = NULL; }
-#define guard_free(X) if (X) { free(X); X = NULL; }
+#define conv_bool_stackvar(X, DEST) X.DEST = val.as_bool;
+
+int delivery_init_tmpdir(struct Delivery *ctx) {
+ char *tmpdir = NULL;
+ char *x = NULL;
+ int unusable = 0;
+ errno = 0;
+
+ x = getenv("TMPDIR");
+ if (x) {
+ guard_free(ctx->storage.tmpdir)
+ tmpdir = strdup(x);
+ } else {
+ tmpdir = ctx->storage.tmpdir;
+ }
+
+ if (!tmpdir) {
+ // memory error
+ return -1;
+ }
+
+ // If the directory doesn't exist, create it
+ if (access(tmpdir, F_OK) < 0) {
+ if (mkdirs(tmpdir, 0755) < 0) {
+ msg(OMC_MSG_ERROR | OMC_MSG_L1, "Unable to create temporary storage directory: %s (%s)\n", tmpdir, strerror(errno));
+ goto l_delivery_init_tmpdir_fatal;
+ }
+ }
+
+ // If we can't read, write, or execute, then die
+ if (access(tmpdir, R_OK | W_OK | X_OK) < 0) {
+ msg(OMC_MSG_ERROR | OMC_MSG_L1, "%s requires at least 0755 permissions.\n");
+ goto l_delivery_init_tmpdir_fatal;
+ }
+
+ struct statvfs st;
+ if (statvfs(tmpdir, &st) < 0) {
+ goto l_delivery_init_tmpdir_fatal;
+ }
+
+ // If we can't execute programs, or write data to the file system at all, then die
+ if ((st.f_flag & ST_NOEXEC) != 0) {
+ msg(OMC_MSG_ERROR | OMC_MSG_L1, "%s is mounted with noexec\n", tmpdir);
+ goto l_delivery_init_tmpdir_fatal;
+ }
+ if ((st.f_flag & ST_RDONLY) != 0) {
+ msg(OMC_MSG_ERROR | OMC_MSG_L1, "%s is mounted read-only\n", tmpdir);
+ goto l_delivery_init_tmpdir_fatal;
+ }
+
+ ctx->storage.tmpdir = strdup(tmpdir);
+ globals.tmpdir = strdup(tmpdir);
+ return unusable;
+
+ l_delivery_init_tmpdir_fatal:
+ unusable = 1;
+ return unusable;
+}
void delivery_free(struct Delivery *ctx) {
- guard_free(ctx->system.arch);
+ guard_free(ctx->system.arch)
guard_free(ctx->meta.name)
guard_free(ctx->meta.version)
guard_free(ctx->meta.codename)
guard_free(ctx->meta.mission)
guard_free(ctx->meta.python)
guard_free(ctx->meta.mission)
- guard_free(ctx->meta.python_compact);
+ guard_free(ctx->meta.python_compact)
guard_runtime_free(ctx->runtime.environ)
+ guard_free(ctx->storage.root)
+ guard_free(ctx->storage.tmpdir)
guard_free(ctx->storage.delivery_dir)
+ guard_free(ctx->storage.tools_dir);
guard_free(ctx->storage.conda_install_prefix)
guard_free(ctx->storage.conda_artifact_dir)
guard_free(ctx->storage.conda_staging_dir)
@@ -85,8 +142,8 @@ void delivery_free(struct Delivery *ctx) {
guard_free(ctx->conda.installer_version)
guard_free(ctx->conda.installer_platform)
guard_free(ctx->conda.installer_arch)
- guard_free(ctx->conda.tool_version);
- guard_free(ctx->conda.tool_build_version);
+ guard_free(ctx->conda.tool_version)
+ guard_free(ctx->conda.tool_build_version)
guard_strlist_free(ctx->conda.conda_packages)
guard_strlist_free(ctx->conda.conda_packages_defer)
guard_strlist_free(ctx->conda.pip_packages)
@@ -104,23 +161,107 @@ void delivery_free(struct Delivery *ctx) {
}
void delivery_init_dirs(struct Delivery *ctx) {
- mkdirs("build/recipes", 0755);
- mkdirs("build/sources", 0755);
- mkdirs("build/testing", 0755);
- ctx->storage.build_dir = realpath("build", NULL);
- ctx->storage.build_recipes_dir = realpath("build/recipes", NULL);
- ctx->storage.build_sources_dir = realpath("build/sources", NULL);
- ctx->storage.build_testing_dir = realpath("build/testing", NULL);
-
- mkdirs("output/omc", 0755);
- mkdirs("output/packages/conda", 0755);
- mkdirs("output/packages/wheels", 0755);
- ctx->storage.delivery_dir = realpath("output/omc", NULL);
- ctx->storage.conda_artifact_dir = realpath("output/packages/conda", NULL);
- ctx->storage.wheel_artifact_dir = realpath("output/packages/wheels", NULL);
-
- mkdirs(CONDA_INSTALL_PREFIX, 0755);
- ctx->storage.conda_install_prefix = realpath(CONDA_INSTALL_PREFIX, NULL);
+ mkdirs("omc/tmp", 0755);
+ mkdirs("omc/tools/bin", 0755);
+ mkdirs("omc/build", 0755);
+ mkdirs("omc/build/recipes", 0755);
+ mkdirs("omc/build/sources", 0755);
+ mkdirs("omc/build/testing", 0755);
+ mkdirs("omc/output", 0755);
+ mkdirs("omc/output/delivery", 0755);
+ mkdirs("omc/output/packages/conda", 0755);
+ mkdirs("omc/output/packages/wheels", 0755);
+ ctx->storage.root = realpath("omc", NULL);
+ ctx->storage.tmpdir = realpath("omc/tmp", NULL);
+ if (delivery_init_tmpdir(ctx)) {
+ msg(OMC_MSG_ERROR | OMC_MSG_L1, "Set $TMPDIR to a location other than %s\n", globals.tmpdir);
+ if (globals.tmpdir)
+ guard_free(globals.tmpdir)
+ exit(1);
+ }
+
+ ctx->storage.tools_dir = realpath("omc/tools", NULL);
+ ctx->storage.build_dir = realpath("omc/build", NULL);
+ ctx->storage.build_recipes_dir = realpath("omc/build/recipes", NULL);
+ ctx->storage.build_sources_dir = realpath("omc/build/sources", NULL);
+ ctx->storage.build_testing_dir = realpath("omc/build/testing", NULL);
+ ctx->storage.delivery_dir = realpath("omc/output/delivery", NULL);
+ ctx->storage.conda_artifact_dir = realpath("omc/output/packages/conda", NULL);
+ ctx->storage.wheel_artifact_dir = realpath("omc/output/packages/wheels", NULL);
+
+ // Override installation prefix using global configuration key
+ if (globals.conda_install_prefix && strlen(globals.conda_install_prefix)) {
+ // user wants a specific path
+ globals.conda_fresh_start = false;
+ /*
+ if (mkdirs(globals.conda_install_prefix, 0755)) {
+ msg(OMC_MSG_ERROR | OMC_MSG_L1, "Unable to create directory: %s: %s\n",
+ strerror(errno), globals.conda_install_prefix);
+ exit(1);
+ }
+ */
+ /*
+ ctx->storage.conda_install_prefix = realpath(globals.conda_install_prefix, NULL);
+ if (!ctx->storage.conda_install_prefix) {
+ msg(OMC_MSG_ERROR | OMC_MSG_L1, "realpath(): Conda installation prefix reassignment failed\n");
+ exit(1);
+ }
+ */
+ ctx->storage.conda_install_prefix = strdup(globals.conda_install_prefix);
+ } else {
+ // install conda under the OMC tree
+ mkdirs("omc/tools/conda", 0755);
+ ctx->storage.conda_install_prefix = realpath("omc/tools/conda", NULL);
+ }
+}
+
+int delivery_init_platform(struct Delivery *ctx) {
+ msg(OMC_MSG_L2, "Setting architecture\n");
+ char archsuffix[20];
+ struct utsname uts;
+ if (uname(&uts)) {
+ msg(OMC_MSG_ERROR | OMC_MSG_L2, "uname() failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ ctx->system.arch = strdup(uts.machine);
+ if (!ctx->system.arch) {
+ // memory error
+ return -1;
+ }
+
+ if (!strcmp(ctx->system.arch, "x86_64")) {
+ strcpy(archsuffix, "64");
+ } else {
+ strcpy(archsuffix, ctx->system.arch);
+ }
+
+ msg(OMC_MSG_L2, "Setting platform\n");
+ strcpy(ctx->system.platform[DELIVERY_PLATFORM], uts.sysname);
+ if (!strcmp(ctx->system.platform[DELIVERY_PLATFORM], "Darwin")) {
+ sprintf(ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR], "osx-%s", archsuffix);
+ strcpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER], "MacOSX");
+ strcpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], "macos");
+ } else if (!strcmp(ctx->system.platform[DELIVERY_PLATFORM], "Linux")) {
+ sprintf(ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR], "linux-%s", archsuffix);
+ strcpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER], "Linux");
+ strcpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], "linux");
+ } else {
+ // Not explicitly supported systems
+ strcpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR], ctx->system.platform[DELIVERY_PLATFORM]);
+ strcpy(ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER], ctx->system.platform[DELIVERY_PLATFORM]);
+ strcpy(ctx->system.platform[DELIVERY_PLATFORM_RELEASE], ctx->system.platform[DELIVERY_PLATFORM]);
+ tolower_s(ctx->system.platform[DELIVERY_PLATFORM_RELEASE]);
+ }
+
+ // Declare some important bits as environment variables
+ setenv("OMC_ARCH", ctx->system.arch, 1);
+ setenv("OMC_PLATFORM", ctx->system.platform[DELIVERY_PLATFORM], 1);
+ setenv("OMC_CONDA_ARCH", ctx->system.arch, 1);
+ setenv("OMC_CONDA_PLATFORM", ctx->system.platform[DELIVERY_PLATFORM_CONDA_INSTALLER], 1);
+ setenv("OMC_CONDA_PLATFORM_SUBDIR", ctx->system.platform[DELIVERY_PLATFORM_CONDA_SUBDIR], 1);
+
+ return 0;
}
int delivery_init(struct Delivery *ctx, struct INIFILE *ini, struct INIFILE *cfg) {
@@ -141,18 +282,43 @@ int delivery_init(struct Delivery *ctx, struct INIFILE *ini, struct INIFILE *cfg
conv_str(ctx, storage.wheel_staging_dir)
getter(cfg, "default", "wheel_staging_url", INIVAL_TYPE_STR)
conv_str(ctx, storage.wheel_staging_url)
+ getter(cfg, "default", "conda_fresh_start", INIVAL_TYPE_BOOL)
+ conv_bool_stackvar(globals, conda_fresh_start)
// Below can also be toggled by command-line arguments
getter(cfg, "default", "continue_on_error", INIVAL_TYPE_BOOL)
- globals.continue_on_error = val.as_bool;
+ conv_bool_stackvar(globals, continue_on_error)
getter(cfg, "default", "always_update_base_environment", INIVAL_TYPE_BOOL)
- globals.always_update_base_environment = val.as_bool;
+ conv_bool_stackvar(globals, always_update_base_environment)
+ getter(cfg, "default", "conda_install_prefix", INIVAL_TYPE_STR)
+ conv_str_stackvar(globals, conda_install_prefix)
getter(cfg, "default", "conda_packages", INIVAL_TYPE_STR_ARRAY)
conv_strlist_stackvar(globals, conda_packages, "\n")
getter(cfg, "default", "pip_packages", INIVAL_TYPE_STR_ARRAY)
conv_strlist_stackvar(globals, pip_packages, "\n")
+ // Configure jfrog cli downloader
+ getter(cfg, "jfrog_cli_download", "url", INIVAL_TYPE_STR)
+ conv_str_stackvar(globals, jfrog.jfrog_artifactory_base_url)
+ getter(cfg, "jfrog_cli_download", "product", INIVAL_TYPE_STR);
+ conv_str_stackvar(globals, jfrog.jfrog_artifactory_product)
+ getter(cfg, "jfrog_cli_download", "version_series", INIVAL_TYPE_STR)
+ conv_str_stackvar(globals, jfrog.cli_major_ver)
+ getter(cfg, "jfrog_cli_download", "version", INIVAL_TYPE_STR)
+ conv_str_stackvar(globals, jfrog.version)
+ getter(cfg, "jfrog_cli_download", "filename", INIVAL_TYPE_STR)
+ conv_str_stackvar(globals, jfrog.remote_filename)
}
+
+ // Configure architecture and platform information
+ delivery_init_platform(ctx);
+
+ // Create OMC directory structure
delivery_init_dirs(ctx);
+ // add tools to PATH
+ char pathvar_tmp[OMC_BUFSIZ];
+ sprintf(pathvar_tmp, "%s/bin:%s", ctx->storage.tools_dir, getenv("PATH"));
+ setenv("PATH", pathvar_tmp, 1);
+
// Populate runtime variables first they may be interpreted by other
// keys in the configuration
rt = runtime_copy(__environ);
@@ -224,18 +390,21 @@ int delivery_init(struct Delivery *ctx, struct INIFILE *ini, struct INIFILE *cfg
for (size_t z = 0, i = 0; i < ini->section_count; i++ ) {
if (startswith(ini->section[i]->key, "test:")) {
val.as_char_p = strchr(ini->section[i]->key, ':') + 1;
+ if (val.as_char_p && isempty(val.as_char_p)) {
+ return 1;
+ }
conv_str(ctx, tests[z].name)
- getter(ini, ini->section[i]->key, "version", INIVAL_TYPE_STR)
+ getter_required(ini, ini->section[i]->key, "version", INIVAL_TYPE_STR)
conv_str(ctx, tests[z].version)
- getter(ini, ini->section[i]->key, "repository", INIVAL_TYPE_STR)
+ getter_required(ini, ini->section[i]->key, "repository", INIVAL_TYPE_STR)
conv_str(ctx, tests[z].repository)
- getter(ini, ini->section[i]->key, "script", INIVAL_TYPE_STR)
+ getter_required(ini, ini->section[i]->key, "script", INIVAL_TYPE_STR)
conv_str_noexpand(ctx, tests[z].script)
- getter(ini, ini->section[i]->key, "build_recipe", INIVAL_TYPE_STR);
+ getter(ini, ini->section[i]->key, "build_recipe", INIVAL_TYPE_STR)
conv_str(ctx, tests[z].build_recipe)
z++;
@@ -249,17 +418,17 @@ int delivery_init(struct Delivery *ctx, struct INIFILE *ini, struct INIFILE *cfg
if (!strcasecmp(ctx->meta.mission, "hst") && ctx->meta.final) {
memset(env_date, 0, sizeof(env_date));
strftime(env_date, sizeof(env_date) - 1, "%Y%m%d", ctx->info.time_info);
- snprintf(env_name, sizeof(env_name) - 1, "%s_%s_%s_py%s_final",
- ctx->meta.name, env_date, ctx->system.platform[DELIVERY_PLATFORM_RELEASE], ctx->meta.python_compact);
+ snprintf(env_name, sizeof(env_name) - 1, "%s_%s_%s_%s_py%s_final",
+ ctx->meta.name, env_date, ctx->system.platform[DELIVERY_PLATFORM_RELEASE], ctx->system.arch, ctx->meta.python_compact);
} else if (!strcasecmp(ctx->meta.mission, "hst")) {
- snprintf(env_name, sizeof(env_name) - 1, "%s_%s_%s_py%s_rc%d",
- ctx->meta.name, ctx->meta.codename, ctx->system.platform[DELIVERY_PLATFORM_RELEASE], ctx->meta.python_compact, ctx->meta.rc);
+ snprintf(env_name, sizeof(env_name) - 1, "%s_%s_%s_%s_py%s_rc%d",
+ ctx->meta.name, ctx->meta.codename, ctx->system.platform[DELIVERY_PLATFORM_RELEASE], ctx->system.arch, ctx->meta.python_compact, ctx->meta.rc);
} else if (!strcasecmp(ctx->meta.mission, "jwst") && ctx->meta.final) {
- snprintf(env_name, sizeof(env_name), "%s_%s_%s_py%s_final",
- ctx->meta.name, ctx->meta.version, ctx->system.platform[DELIVERY_PLATFORM_RELEASE], ctx->meta.python_compact);
+ snprintf(env_name, sizeof(env_name), "%s_%s_%s_%s_py%s_final",
+ ctx->meta.name, ctx->meta.version, ctx->system.platform[DELIVERY_PLATFORM_RELEASE], ctx->system.arch, ctx->meta.python_compact);
} else if (!strcasecmp(ctx->meta.mission, "jwst")) {
- snprintf(env_name, sizeof(env_name) - 1, "%s_%s_py%s_rc%d",
- ctx->meta.name, ctx->meta.version, ctx->meta.python_compact, ctx->meta.rc);
+ snprintf(env_name, sizeof(env_name) - 1, "%s_%s_%s_%s_py%s_rc%d",
+ ctx->meta.name, ctx->meta.version, ctx->system.platform[DELIVERY_PLATFORM_RELEASE], ctx->system.arch, ctx->meta.python_compact, ctx->meta.rc);
}
if (strlen(env_name)) {
@@ -270,7 +439,7 @@ int delivery_init(struct Delivery *ctx, struct INIFILE *ini, struct INIFILE *cfg
}
void delivery_meta_show(struct Delivery *ctx) {
- printf("====DELIVERY====\n");
+ printf("\n====DELIVERY====\n");
printf("%-20s %-10s\n", "Target Python:", ctx->meta.python);
printf("%-20s %-10s\n", "Name:", ctx->meta.name);
printf("%-20s %-10s\n", "Mission:", ctx->meta.mission);
@@ -288,8 +457,8 @@ void delivery_meta_show(struct Delivery *ctx) {
}
void delivery_conda_show(struct Delivery *ctx) {
- printf("====CONDA====\n");
- printf("%-20s %-10s\n", "Installer:", ctx->conda.installer_baseurl);
+ printf("\n====CONDA====\n");
+ printf("%-20s %-10s\n", "Prefix:", ctx->storage.conda_install_prefix);
puts("Native Packages:");
for (size_t i = 0; i < strlist_count(ctx->conda.conda_packages); i++) {
@@ -311,17 +480,38 @@ void delivery_conda_show(struct Delivery *ctx) {
}
void delivery_tests_show(struct Delivery *ctx) {
- printf("====TESTS====\n");
+ printf("\n====TESTS====\n");
for (size_t i = 0; i < sizeof(ctx->tests) / sizeof(ctx->tests[0]); i++) {
if (!ctx->tests[i].name) {
continue;
}
- printf("%-20s %-10s %s\n", ctx->tests[i].name,
+ printf("%-20s %-20s %s\n", ctx->tests[i].name,
ctx->tests[i].version,
ctx->tests[i].repository);
}
}
+void delivery_runtime_show(struct Delivery *ctx) {
+ printf("\n====RUNTIME====\n");
+ struct StrList *rt = NULL;
+ rt = strlist_copy(ctx->runtime.environ);
+ if (!rt) {
+ // no data
+ return;
+ }
+ strlist_sort(rt, OMC_SORT_ALPHA);
+ size_t total = strlist_count(rt);
+ for (size_t i = 0; i < total; i++) {
+ char *item = strlist_item(rt, i);
+ if (!item) {
+ // not supposed to occur
+ msg(OMC_MSG_WARN | OMC_MSG_L1, "Encountered unexpected NULL at record %zu of %zu of runtime array.\n", i);
+ return;
+ }
+ printf("%s\n", item);
+ }
+}
+
int delivery_build_recipes(struct Delivery *ctx) {
for (size_t i = 0; i < sizeof(ctx->tests) / sizeof(ctx->tests[0]); i++) {
char *recipe_dir = NULL;
@@ -346,9 +536,13 @@ int delivery_build_recipes(struct Delivery *ctx) {
char recipe_git_url[PATH_MAX];
char recipe_git_rev[PATH_MAX];
- sprintf(recipe_version, "{%% set version = GIT_DESCRIBE_TAG ~ \".dev\" ~ GIT_DESCRIBE_NUMBER ~ \"+\" ~ GIT_DESCRIBE_HASH %%}");
- sprintf(recipe_git_url, " git_url: %s", ctx->tests[i].repository);
- sprintf(recipe_git_rev, " git_rev: %s", ctx->tests[i].version);
+ //sprintf(recipe_version, "{%% set version = GIT_DESCRIBE_TAG ~ \".dev\" ~ GIT_DESCRIBE_NUMBER ~ \"+\" ~ GIT_DESCRIBE_HASH %%}");
+ //sprintf(recipe_git_url, " git_url: %s", ctx->tests[i].repository);
+ //sprintf(recipe_git_rev, " git_rev: %s", ctx->tests[i].version);
+ // TODO: Conditionally download archives if github.com is the origin. Else, use raw git_* keys ^^^
+ sprintf(recipe_version, "{%% set version = \"%s\" %%}", ctx->tests[i].version);
+ sprintf(recipe_git_url, " url: %s/archive/refs/tags/{{ version }}.tar.gz", ctx->tests[i].repository);
+ strcpy(recipe_git_rev, "");
sprintf(recipe_buildno, " number: 0");
//file_replace_text("meta.yaml", "{% set version = ", recipe_version);
@@ -361,7 +555,8 @@ int delivery_build_recipes(struct Delivery *ctx) {
} else {
file_replace_text("meta.yaml", "{% set version = ", recipe_version);
file_replace_text("meta.yaml", " url:", recipe_git_url);
- file_replace_text("meta.yaml", " sha256:", recipe_git_rev);
+ //file_replace_text("meta.yaml", " sha256:", recipe_git_rev);
+ file_replace_text("meta.yaml", " sha256:", "\n");
file_replace_text("meta.yaml", " number:", recipe_buildno);
}
@@ -379,7 +574,7 @@ int delivery_build_recipes(struct Delivery *ctx) {
}
}
if (recipe_dir) {
- free(recipe_dir);
+ guard_free(recipe_dir)
}
}
return 0;
@@ -646,19 +841,23 @@ void delivery_install_conda(char *install_script, char *conda_install_dir) {
struct Process proc;
memset(&proc, 0, sizeof(proc));
- if (!access(conda_install_dir, F_OK)) {
- // directory exists so remove it
- if (rmtree(conda_install_dir)) {
- perror("unable to remove previous installation");
- exit(1);
- }
- }
+ if (globals.conda_fresh_start) {
+ if (!access(conda_install_dir, F_OK)) {
+ // directory exists so remove it
+ if (rmtree(conda_install_dir)) {
+ perror("unable to remove previous installation");
+ exit(1);
+ }
- // Proceed with the installation
- // -b = batch mode (non-interactive)
- if (shell_safe(&proc, (char *[]) {find_program("bash"), install_script, "-b", "-p", conda_install_dir, NULL})) {
- fprintf(stderr, "conda installation failed\n");
- exit(1);
+ // Proceed with the installation
+ // -b = batch mode (non-interactive)
+ if (shell_safe(&proc, (char *[]) {find_program("bash"), install_script, "-b", "-p", conda_install_dir, NULL})) {
+ fprintf(stderr, "conda installation failed\n");
+ exit(1);
+ }
+ }
+ } else {
+ msg(OMC_MSG_L3, "Conda removal disabled by configuration\n");
}
}
@@ -681,6 +880,7 @@ void delivery_conda_enable(struct Delivery *ctx, char *conda_install_dir) {
conda_setup_headless();
}
+
void delivery_defer_packages(struct Delivery *ctx, int type) {
struct StrList *dataptr = NULL;
struct StrList *deferred = NULL;
@@ -714,9 +914,12 @@ void delivery_defer_packages(struct Delivery *ctx, int type) {
msg(OMC_MSG_L3, "package '%s': ", name);
// Compile a list of packages that are *also* to be tested.
+ char *version;
for (size_t x = 0; x < sizeof(ctx->tests) / sizeof(ctx->tests[0]); x++) {
+ version = NULL;
if (ctx->tests[x].name) {
if (startswith(ctx->tests[x].name, name)) {
+ version = ctx->tests[x].version;
ignore_pkg = 1;
z++;
break;
@@ -725,6 +928,12 @@ void delivery_defer_packages(struct Delivery *ctx, int type) {
}
if (ignore_pkg) {
+ char build_at[PATH_MAX];
+ if (DEFER_CONDA == type) {
+ sprintf(build_at, "%s=%s", name, version);
+ name = build_at;
+ }
+
printf("BUILD FOR HOST\n");
strlist_append(deferred, name);
} else {
@@ -803,12 +1012,10 @@ void delivery_rewrite_spec(struct Delivery *ctx, char *filename) {
}
for (size_t i = 0; contents[i] != NULL; i++) {
- free(contents[i]);
+ guard_free(contents[i])
}
- free(contents);
- contents = NULL;
- free(header);
- header = NULL;
+ guard_free(contents)
+ guard_free(header)
fflush(tp);
fclose(tp);
@@ -817,10 +1024,15 @@ void delivery_rewrite_spec(struct Delivery *ctx, char *filename) {
fprintf(stderr, "%s: could not rename '%s' to '%s'\n", strerror(errno), tempfile, filename);
exit(1);
}
+ remove(tempfile);
// Replace "local" channel with the staging URL
- sprintf(output, " - %s", ctx->storage.conda_staging_url);
- file_replace_text(filename, " - local", output);
+ if (ctx->storage.conda_staging_url) {
+ sprintf(output, " - %s", ctx->storage.conda_staging_url);
+ file_replace_text(filename, " - local", output);
+ } else {
+ msg(OMC_MSG_WARN, "conda_staging_url is not configured. References to \"local\" channel will not be replaced\n", filename);
+ }
// Rewrite tested packages to point to tested code, at a defined verison
for (size_t i = 0; i < strlist_count(ctx->conda.pip_packages_defer); i++) {
@@ -893,7 +1105,7 @@ void delivery_tests_run(struct Delivery *ctx) {
git_clone(&proc, ctx->tests[i].repository, destdir, ctx->tests[i].version);
if (pushd(destdir)) {
- COE_CHECK_ABORT(!globals.continue_on_error, "Unable to enter repository directory\n");
+ COE_CHECK_ABORT(!globals.continue_on_error, "Unable to enter repository directory\n")
} else {
#if 1
int status;
@@ -906,7 +1118,7 @@ void delivery_tests_run(struct Delivery *ctx) {
sprintf(cmd, "set -x ; %s", ctx->tests[i].script);
status = shell2(&proc, cmd);
if (status) {
- COE_CHECK_ABORT(!globals.continue_on_error, "Test failure");
+ COE_CHECK_ABORT(!globals.continue_on_error, "Test failure")
}
popd();
#else
@@ -929,3 +1141,109 @@ void delivery_gather_tool_versions(struct Delivery *ctx) {
if (ctx->conda.tool_build_version)
strip(ctx->conda.tool_version);
}
+
+int delivery_init_artifactory(struct Delivery *ctx) {
+ char dest[PATH_MAX] = {0};
+ char filepath[PATH_MAX] = {0};
+ snprintf(dest, sizeof(dest) - 1, "%s/bin", ctx->storage.tools_dir);
+ snprintf(filepath, sizeof(dest) - 1, "%s/bin/jf", ctx->storage.tools_dir);
+
+ if (!access(filepath, F_OK)) {
+ // already have it
+ goto delivery_init_artifactory_envsetup;
+ }
+ int status = artifactory_download_cli(dest,
+ globals.jfrog.jfrog_artifactory_base_url,
+ globals.jfrog.jfrog_artifactory_product,
+ globals.jfrog.cli_major_ver,
+ globals.jfrog.version,
+ ctx->system.platform[DELIVERY_PLATFORM],
+ ctx->system.arch,
+ globals.jfrog.remote_filename);
+
+ delivery_init_artifactory_envsetup:
+ // CI (ridiculously generic, why?) disables interactive prompts and progress bar output
+ setenv("CI", "1", 1);
+
+ // JFROG_CLI_HOME_DIR is where .jfrog is stored
+ char path[PATH_MAX] = {0};
+ snprintf(path, sizeof(path) - 1, "%s/.jfrog", ctx->storage.build_dir);
+ setenv("JFROG_CLI_HOME_DIR", path, 1);
+
+ // JFROG_CLI_TEMP_DIR is where the obvious is stored
+ setenv("JFROG_CLI_TEMP_DIR", ctx->storage.tmpdir, 1);
+ return status;
+}
+
+
+int delivery_artifact_upload(struct Delivery *ctx) {
+ struct JFRT_Auth auth_ctx;
+ memset(&auth_ctx, 0, sizeof(auth_ctx));
+ struct JFRT_Upload upload_ctx;
+ jfrt_upload_set_defaults(&upload_ctx);
+
+ char *url = getenv("OMC_JF_ARTIFACTORY_URL");
+ char *user = getenv("OMC_JF_USER");
+ char *access_token = getenv("OMC_JF_ACCESS_TOKEN");
+ char *password = getenv("OMC_JF_PASSWORD");
+ char *ssh_key_path = getenv("OMC_JF_SSH_KEY_PATH");
+ char *ssh_passphrase = getenv("OMC_JF_SSH_PASSPHRASE");
+
+ if (!url) {
+ fprintf(stderr, "Artifactory URL is not configured:\n");
+ fprintf(stderr, "please set OMC_JF_ARTIFACTORY_URL\n");
+ return -1;
+ }
+ auth_ctx.url = url;
+
+ if (access_token) {
+ auth_ctx.user = NULL;
+ auth_ctx.access_token = access_token;
+ auth_ctx.password = NULL;
+ auth_ctx.ssh_key_path = NULL;
+ } else if (user && password) {
+ auth_ctx.user = user;
+ auth_ctx.password = password;
+ auth_ctx.access_token = NULL;
+ auth_ctx.ssh_key_path = NULL;
+ } else if (ssh_key_path) {
+ auth_ctx.user = NULL;
+ auth_ctx.ssh_key_path = ssh_key_path;
+ if (ssh_passphrase) {
+ auth_ctx.ssh_passphrase = ssh_passphrase;
+ }
+ auth_ctx.password = NULL;
+ auth_ctx.access_token = NULL;
+ } else {
+ fprintf(stderr, "Artifactory authentication is not configured:\n");
+ fprintf(stderr, "set OMC_JF_USER and OMC_JF_PASSWORD\n");
+ fprintf(stderr, "set OMC_JF_ACCESS_TOKEN\nor\n");
+ fprintf(stderr, "set OMC_JF_SSH_KEY_PATH and OMC_JF_SSH_KEY_PASSPHRASE\n");
+ return -1;
+ }
+
+ upload_ctx.workaround_parent_only = true;
+ upload_ctx.build_name = strdup(ctx->info.release_name);
+ upload_ctx.build_number = ctx->info.time_now;
+
+ char files[PATH_MAX];
+ int status = 0;
+
+ if (jfrog_cli_rt_ping(&auth_ctx)) {
+ fprintf(stderr, "Unable to contact artifactory server: %s\n", url);
+ return -1;
+ }
+
+ jfrog_cli_rt_build_collect_env(&auth_ctx, upload_ctx.build_name, upload_ctx.build_number);
+
+ strcpy(files, "omc/sources/**/results.xml");
+ status += jfrog_cli_rt_upload(&auth_ctx, &upload_ctx, files, "omc/delivery/results");
+ strcpy(files, "omc/output/delivery/*.yml");
+ status += jfrog_cli_rt_upload(&auth_ctx, &upload_ctx, files, "omc/delivery/");
+ strcpy(files, "omc/output/packages/*");
+ status += jfrog_cli_rt_upload(&auth_ctx, &upload_ctx, files, "omc/packages/");
+
+ jfrog_cli_rt_build_publish(&auth_ctx, upload_ctx.build_name, upload_ctx.build_number);
+
+ return status;
+}