aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2024-05-08 17:19:12 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2024-05-08 17:19:12 -0400
commit22b1f0a5eada61410bf9fd7cb68e2a4d1c25666d (patch)
tree1cc08eeb2c9d292ef6497112a46df3e72681fe5f
parent3752e818b5a5a3a315d05be202137add74b9d265 (diff)
downloadstasis-22b1f0a5eada61410bf9fd7cb68e2a4d1c25666d.tar.gz
Generate symbolic links to "latest" deliveries
* Generate top-level README based on delivery metadata, not file names. * Copy contents of [temporary_omc_root_dir]/output/ instead of merging the entire directory tree * Free resources where possible * Default destination directory is now "output" (was NULL) * Generated top-level README is now an easy-to-read table (was a basic list)
-rw-r--r--src/omc_indexer.c208
1 files changed, 170 insertions, 38 deletions
diff --git a/src/omc_indexer.c b/src/omc_indexer.c
index 054a729..ebf3ba6 100644
--- a/src/omc_indexer.c
+++ b/src/omc_indexer.c
@@ -142,6 +142,7 @@ int indexer_get_files(struct StrList **out, const char *path, const char *patter
if (!(*out)) {
(*out) = strlist_init();
if (!(*out)) {
+ guard_strlist_free(&list);
return -1;
}
}
@@ -158,21 +159,45 @@ int indexer_get_files(struct StrList **out, const char *path, const char *patter
}
if (no_match >= strlist_count(list)) {
fprintf(stderr, "no files matching the pattern: %s\n", userpattern);
+ guard_strlist_free(&list);
return -1;
}
+ guard_strlist_free(&list);
return 0;
}
int get_latest_rc(struct Delivery ctx[], size_t nelem) {
int result = 0;
for (size_t i = 0; i < nelem; i++) {
- if (ctx[i].meta.rc > result) {
+ if (&ctx[i] && ctx[i].meta.rc > result) {
result = ctx[i].meta.rc;
}
}
return result;
}
+struct Delivery **get_latest_deliveries(struct Delivery ctx[], size_t nelem) {
+ struct Delivery **result = NULL;
+ int latest = 0;
+ size_t n = 0;
+
+ result = calloc(nelem + 1, sizeof(result));
+ if (!result) {
+ fprintf(stderr, "Unable to allocate %zu bytes for result delivery array: %s\n", nelem * sizeof(result), strerror(errno));
+ return NULL;
+ }
+
+ latest = get_latest_rc(ctx, nelem);
+ for (size_t i = 0; i < nelem; i++) {
+ if (ctx[i].meta.rc == latest) {
+ result[n] = &ctx[i];
+ n++;
+ }
+ }
+
+ return result;
+}
+
int micromamba(const char *write_to, const char *prefix, char *command, ...) {
struct utsname sys;
uname(&sys);
@@ -239,62 +264,152 @@ int indexer_conda(struct Delivery *ctx) {
return status;
}
-int indexer_readmes(struct Delivery ctx[], size_t nelem) {
- // Find unique architecture identifiers
+static struct StrList *get_architectures(struct Delivery ctx[], size_t nelem) {
struct StrList *architectures = strlist_init();
for (size_t i = 0; i < nelem; i++) {
if (!strstr_array(architectures->data, ctx[i].system.arch)) {
strlist_append(&architectures, ctx[i].system.arch);
}
}
+ return architectures;
+}
- // Find unique platform identifiers
+static struct StrList *get_platforms(struct Delivery ctx[], size_t nelem) {
struct StrList *platforms = strlist_init();
for (size_t i = 0; i < nelem; i++) {
if (!strstr_array(platforms->data, ctx[i].system.platform[DELIVERY_PLATFORM_RELEASE])) {
strlist_append(&platforms, ctx[i].system.platform[DELIVERY_PLATFORM_RELEASE]);
}
}
+ return platforms;
+}
- struct StrList *python_versions = strlist_init();
- for (size_t i = 0; i < nelem; i++) {
- if (!strstr_array(python_versions->data, ctx[i].meta.python_compact)) {
- strlist_append(&python_versions, ctx[i].meta.python_compact);
- }
- }
- strlist_reverse(python_versions);
+int indexer_symlinks(struct Delivery ctx[], size_t nelem) {
+ struct Delivery **data = NULL;
+ data = get_latest_deliveries(ctx, nelem);
+ //int latest = get_latest_rc(ctx, nelem);
+
+ if (!pushd(ctx->storage.delivery_dir)) {
+ for (size_t i = 0; i < nelem; i++) {
+ char link_name_spec[PATH_MAX];
+ char link_name_readme[PATH_MAX];
+
+ char file_name_spec[PATH_MAX];
+ char file_name_readme[PATH_MAX];
+
+ if (!data[i]) {
+ continue;
+ }
+ sprintf(link_name_spec, "latest-py%s-%s-%s.yml", data[i]->meta.python_compact, data[i]->system.platform[DELIVERY_PLATFORM_RELEASE], data[i]->system.arch);
+ sprintf(file_name_spec, "%s.yml", data[i]->info.release_name);
+
+ sprintf(link_name_readme, "README-py%s-%s-%s.md", data[i]->meta.python_compact, data[i]->system.platform[DELIVERY_PLATFORM_RELEASE], data[i]->system.arch);
+ sprintf(file_name_readme, "README-%s.md", data[i]->info.release_name);
- FILE *indexfp;
- char readmefile[PATH_MAX] = {0};
- sprintf(readmefile, "%s/README.md", ctx->storage.delivery_dir);
+ if (!access(link_name_spec, F_OK)) {
+ if (unlink(link_name_spec)) {
+ fprintf(stderr, "Unable to remove spec link: %s\n", link_name_spec);
+ }
+ }
+ if (!access(link_name_readme, F_OK)) {
+ if (unlink(link_name_readme)) {
+ fprintf(stderr, "Unable to remove readme link: %s\n", link_name_readme);
+ }
+ }
- indexfp = fopen(readmefile, "w+");
- if (!indexfp) {
- fprintf(stderr, "Unable to open %s for writing\n", readmefile);
+ if (globals.verbose) {
+ printf("%s -> %s\n", file_name_spec, link_name_spec);
+ }
+ if (symlink(file_name_spec, link_name_spec)) {
+ fprintf(stderr, "Unable to link %s as %s\n", file_name_spec, link_name_spec);
+ }
+
+ if (globals.verbose) {
+ printf("%s -> %s\n", file_name_readme, link_name_readme);
+ }
+ if (symlink(file_name_readme, link_name_readme)) {
+ fprintf(stderr, "Unable to link %s as %s\n", file_name_readme, link_name_readme);
+ }
+ }
+ popd();
+ } else {
+ fprintf(stderr, "Unable to enter delivery directory: %s\n", ctx->storage.delivery_dir);
+ guard_free(data);
return -1;
}
- fprintf(indexfp, "# %s %s\n", ctx->meta.name, ctx->meta.version);
- int latest = get_latest_rc(ctx, nelem);
- for (size_t i = 0; i < strlist_count(python_versions); i++) {
- struct StrList *files = NULL;
- char *python_version = strlist_item(python_versions, i);
- fprintf(indexfp, "## py%s\n", python_version);
- if (indexer_get_files(&files, ctx->storage.delivery_dir, "README-*-%d-*py%s*.md", latest, python_version)) {
- fprintf(stderr, "Unable to list directory\n");
+ // "latest" is an array of pointers to ctx[]. Do not free the contents of the array.
+ guard_free(data);
+ return 0;
+}
+
+int indexer_readmes(struct Delivery ctx[], size_t nelem) {
+ struct Delivery **latest = NULL;
+ latest = get_latest_deliveries(ctx, nelem);
+
+ char indexfile[PATH_MAX] = {0};
+ sprintf(indexfile, "%s/README.md", ctx->storage.delivery_dir);
+
+ if (!pushd(ctx->storage.delivery_dir)) {
+ FILE *indexfp;
+ indexfp = fopen(indexfile, "w+");
+ if (!indexfp) {
+ fprintf(stderr, "Unable to open %s for writing\n", indexfile);
return -1;
}
- for (size_t x = 0; x < strlist_count(files); x++) {
- char *fname = strlist_item(files, x);
- if (globals.verbose) {
- puts(fname);
+ struct StrList *archs = get_architectures(*latest, nelem);
+ struct StrList *platforms = get_platforms(*latest, nelem);
+
+ fprintf(indexfp, "# %s-%s\n\n", ctx->meta.name, ctx->meta.version);
+ for (size_t p = 0; p < strlist_count(platforms); p++) {
+ char *platform = strlist_item(platforms, p);
+ for (size_t a = 0; a < strlist_count(archs); a++) {
+ char *arch = strlist_item(archs, a);
+ int have_combo = 0;
+ for (size_t i = 0; i < nelem; i++) {
+ if (strstr(latest[i]->system.platform[DELIVERY_PLATFORM_RELEASE], platform) && strstr(latest[i]->system.arch, arch)) {
+ have_combo = 1;
+ }
+ }
+ if (!have_combo) {
+ continue;
+ }
+ fprintf(indexfp, "## %s-%s\n\n", platform, arch);
+
+ fprintf(indexfp, "|Release|Info|Receipt|\n");
+ fprintf(indexfp, "|----|----|----|\n");
+ for (size_t i = 0; i < nelem; i++) {
+ char link_name[PATH_MAX];
+ char readme_name[PATH_MAX];
+ char conf_name[PATH_MAX];
+ char conf_name_relative[PATH_MAX];
+ if (!latest[i]) {
+ continue;
+ }
+ sprintf(link_name, "latest-py%s-%s-%s.yml", latest[i]->meta.python_compact, latest[i]->system.platform[DELIVERY_PLATFORM_RELEASE], latest[i]->system.arch);
+ sprintf(readme_name, "README-py%s-%s-%s.md", latest[i]->meta.python_compact, latest[i]->system.platform[DELIVERY_PLATFORM_RELEASE], latest[i]->system.arch);
+ sprintf(conf_name, "%s.ini", latest[i]->info.release_name);
+ sprintf(conf_name_relative, "../config/%s-rendered.ini", latest[i]->info.release_name);
+ if (strstr(link_name, platform) && strstr(link_name, arch)) {
+ fprintf(indexfp, "|[%s](%s)|[%s](%s)|[%s](%s)|\n", link_name, link_name, readme_name, readme_name, conf_name, conf_name_relative);
+ }
+ }
+ fprintf(indexfp, "\n");
}
- fprintf(indexfp, "- [%s](%s)\n", fname, fname);
+ fprintf(indexfp, "\n");
}
-
- guard_strlist_free(&files);
+ guard_strlist_free(&archs);
+ guard_strlist_free(&platforms);
+ fclose(indexfp);
+ popd();
+ } else {
+ fprintf(stderr, "Unable to enter delivery directory: %s\n", ctx->storage.delivery_dir);
+ guard_free(latest);
+ return -1;
}
- fclose(indexfp);
+
+ // "latest" is an array of pointers to ctxs[]. Do not free the contents of the array.
+ guard_free(latest);
return 0;
}
@@ -353,6 +468,10 @@ int main(int argc, char *argv[]) {
}
}
+ if (isempty(destdir)) {
+ destdir = strdup("output");
+ }
+
if (!rootdirs || !rootdirs_total) {
fprintf(stderr, "You must specify at least one OMC root directory to index\n");
exit(1);
@@ -386,10 +505,14 @@ int main(int argc, char *argv[]) {
struct Delivery ctx;
memset(&ctx, 0, sizeof(ctx));
+ printf(BANNER, VERSION, AUTHOR);
+
indexer_init_dirs(&ctx, workdir);
- msg(OMC_MSG_L1, "Merging delivery root %s\n", rootdirs_total > 1 ? "directories" : "directory");
- if (indexer_combine_rootdirs(&ctx, workdir, rootdirs, rootdirs_total)) {
+ msg(OMC_MSG_L1, "%s delivery root %s\n",
+ rootdirs_total > 1 ? "Merging" : "Indexing",
+ rootdirs_total > 1 ? "directories" : "directory");
+ if (indexer_combine_rootdirs(workdir, rootdirs, rootdirs_total)) {
SYSERROR("%s", "Copy operation failed");
rmtree(workdir);
}
@@ -424,16 +547,22 @@ int main(int argc, char *argv[]) {
indexer_load_metadata(&local[i], path);
}
- msg(OMC_MSG_L1, "Indexing README files\n");
+ msg(OMC_MSG_L1, "Generating links to latest release iteration\n");
+ if (indexer_symlinks(local, strlist_count(metafiles))) {
+ SYSERROR("%s", "Link generation failed");
+ exit(1);
+ }
+
+ msg(OMC_MSG_L1, "Generating README.md\n");
if (indexer_readmes(local, strlist_count(metafiles))) {
- SYSERROR("%s", "README file indexing operation failed");
+ SYSERROR("%s", "README indexing operation failed");
exit(1);
}
msg(OMC_MSG_L1, "Copying indexed delivery to '%s'\n", destdir);
char cmd[PATH_MAX];
memset(cmd, 0, sizeof(cmd));
- sprintf(cmd, "rsync -ah%s --delete --exclude 'tmp/' --exclude 'tools/' '%s/' '%s/'", globals.verbose ? "v" : "q", workdir, destdir);
+ sprintf(cmd, "rsync -ah%s --delete --exclude 'tmp/' --exclude 'tools/' '%s/output/' '%s/'", globals.verbose ? "v" : "q", workdir, destdir);
guard_free(destdir);
if (globals.verbose) {
@@ -451,6 +580,9 @@ int main(int argc, char *argv[]) {
SYSERROR("Failed to remove work directory: %s", strerror(errno));
}
+ guard_strlist_free(&metafiles);
+ delivery_free(&ctx);
+ globals_free();
msg(OMC_MSG_L1, "Done!\n");
return 0;
} \ No newline at end of file