diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2024-05-08 17:19:12 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2024-05-08 17:19:12 -0400 |
commit | 22b1f0a5eada61410bf9fd7cb68e2a4d1c25666d (patch) | |
tree | 1cc08eeb2c9d292ef6497112a46df3e72681fe5f | |
parent | 3752e818b5a5a3a315d05be202137add74b9d265 (diff) | |
download | ohmycal-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.c | 208 |
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 |