diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2023-12-10 00:32:20 -0500 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2023-12-10 00:32:20 -0500 |
commit | 6ea9b0e2fa675bfdb74b9c3efece2086321f7fca (patch) | |
tree | bc8066ccabe63c53df194fbcb84ecb241316f5df /src | |
parent | 4c3594a243ca43bd3d0bfca3728d4606a6b4e980 (diff) | |
download | stasis-6ea9b0e2fa675bfdb74b9c3efece2086321f7fca.tar.gz |
Add JFrog CLI integration
Diffstat (limited to 'src')
-rw-r--r-- | src/artifactory.c | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/src/artifactory.c b/src/artifactory.c new file mode 100644 index 0000000..48bc943 --- /dev/null +++ b/src/artifactory.c @@ -0,0 +1,394 @@ +#include "artifactory.h" + +extern struct OMC_GLOBAL globals; + +int artifactory_download_cli(char *dest, + char *jfrog_artifactory_base_url, + char *jfrog_artifactory_product, + char *cli_major_ver, + char *version, + char *os, + char *arch, + char *remote_filename) { + char url[PATH_MAX] = {0}; + char path[PATH_MAX] = {0}; + char os_ident[OMC_NAME_MAX] = {0}; + char arch_ident[OMC_NAME_MAX] = {0}; + + // convert platform string to lower-case + strcpy(os_ident, os); + tolower_s(os_ident); + + // translate OS identifier + if (!strcmp(os_ident, "darwin") || startswith(os_ident, "macos")) { + strcpy(os_ident, "mac"); + } else if (!strcmp(os_ident, "linux")) { + strcpy(os_ident, "linux"); + } else { + fprintf(stderr, "%s: unknown operating system: %s\n", __FUNCTION__, os_ident); + return -1; + } + + // translate ARCH identifier + strcpy(arch_ident, arch); + if (startswith(arch_ident, "i") && endswith(arch_ident, "86")) { + strcpy(arch_ident, "386"); + } else if (!strcmp(arch_ident, "amd64") || !strcmp(arch_ident, "x86_64") || !strcmp(arch_ident, "x64")) { + strcpy(arch_ident, "amd64"); + } else if (!strcmp(arch_ident, "arm64") || !strcmp(arch_ident, "aarch64")) { + strcpy(arch_ident, "arm64"); + } else { + fprintf(stderr, "%s: unknown architecture: %s\n", __FUNCTION__, arch_ident); + return -1; + } + + snprintf(url, sizeof(url) - 1, "%s/%s/%s/%s/%s-%s-%s/%s", + jfrog_artifactory_base_url, // https://releases.jfrog.io/artifactory + jfrog_artifactory_product, // jfrog-cli + cli_major_ver, // v\d+(-jf)? + version, // 1.2.3 + jfrog_artifactory_product, // ... + os_ident, // ... + arch_ident, // jfrog-cli-linux-x86_64 + remote_filename); // jf + strcpy(path, dest); + + if (mkdirs(path, 0755)) { + fprintf(stderr, "%s: %s: %s", __FUNCTION__, path, strerror(errno)); + return -1; + } + sprintf(path + strlen(path), "/%s", remote_filename); + if (download(url, path)) { + fprintf(stderr, "%s: download failed: %s\n", __FUNCTION__, url); + } + chmod(path, 0755); + return 0; +} + +void jfrt_register_opt_str(char *jfrt_val, const char *opt_name, struct StrList **opt_map) { + char data[OMC_BUFSIZ]; + memset(data, 0, sizeof(data)); + + if (jfrt_val == NULL) { + // no data + return; + } + snprintf(data, sizeof(data) - 1, "--%s=%s", opt_name, jfrt_val); + strlist_append(*opt_map, data); +} + +void jfrt_register_opt_bool(bool jfrt_val, const char *opt_name, struct StrList **opt_map) { + char data[OMC_BUFSIZ]; + memset(data, 0, sizeof(data)); + + if (jfrt_val == false) { + // option will not be used + return; + } + snprintf(data, sizeof(data) - 1, "--%s", opt_name); + strlist_append(*opt_map, data); +} + +void jfrt_register_opt_int(int jfrt_val, const char *opt_name, struct StrList **opt_map) { + char data[OMC_BUFSIZ]; + memset(data, 0, sizeof(data)); + + if (jfrt_val == 0) { + // option will not be used + return; + } + snprintf(data, sizeof(data) - 1, "--%s=%d", opt_name, jfrt_val); + strlist_append(*opt_map, data); +} + +void jfrt_register_opt_long(long jfrt_val, const char *opt_name, struct StrList **opt_map) { + char data[OMC_BUFSIZ]; + memset(data, 0, sizeof(data)); + + if (jfrt_val == 0) { + // option will not be used + return; + } + snprintf(data, sizeof(data) - 1, "--%s=%ld", opt_name, jfrt_val); + strlist_append(*opt_map, data); +} + +void jfrt_upload_set_defaults(struct JFRT_Upload *ctx) { + memset(ctx, 0, sizeof(*ctx)); + ctx->recursive = true; + ctx->threads = 3; + ctx->retries = 3; +} + +static int auth_required(char *cmd) { + const char *modes[] = { + "rt build-collect-env", + NULL, + }; + for (size_t i = 0; modes[i] != NULL; i++) { + if (!startswith(cmd, modes[i])) { + return 1; + } + } + return 0; +} + +int jfrog_cli(struct JFRT_Auth *auth, char *args) { + struct Process proc; + char cmd[OMC_BUFSIZ]; + char cmd_redacted[OMC_BUFSIZ]; + int status; + + memset(&proc, 0, sizeof(proc)); + memset(cmd, 0, sizeof(cmd)); + memset(cmd_redacted, 0, sizeof(cmd_redacted)); + + struct StrList *arg_map = strlist_init(); + if (!arg_map) { + return -1; + } + + char *auth_args = NULL; + if (auth_required(args)) { + // String options + jfrt_register_opt_str(auth->url, "url", &arg_map); + jfrt_register_opt_str(auth->user, "user", &arg_map); + jfrt_register_opt_str(auth->access_token, "access-token", &arg_map); + jfrt_register_opt_str(auth->password, "password", &arg_map); + jfrt_register_opt_str(auth->ssh_key_path, "ssh-key-path", &arg_map); + jfrt_register_opt_str(auth->ssh_passphrase, "ssh-passphrase", &arg_map); + jfrt_register_opt_str(auth->client_cert_key_path, "client-cert-key-path", &arg_map); + jfrt_register_opt_str(auth->client_cert_path, "client-cert-path", &arg_map); + jfrt_register_opt_bool(auth->insecure_tls, "insecure-tls", &arg_map); + jfrt_register_opt_str(auth->server_id, "server-id", &arg_map); + } + + auth_args = join(arg_map->data, " "); + if (!auth_args) { + return -1; + } + + snprintf(cmd, sizeof(cmd) - 1, "jf %s %s", args, auth_args); + strcpy(cmd_redacted, cmd); + + const char *redactable[] = { + "--access-token=", + "--ssh-key-path=", + "--ssh-passphrase=", + "--client-cert-key-path", + "--client-cert-path", + "--password=", + NULL, + }; + for (size_t i = 0; redactable[i] != NULL; i++) { + char *thing = strstr(cmd_redacted, redactable[i]); + if (thing) { + thing += strlen(redactable[i]); + while (*thing != '\0' && !isspace(*thing)) { + *thing = 'x'; + ++thing; + } + } + } + guard_free(auth_args) + guard_strlist_free(arg_map) + + msg(OMC_MSG_L2, "Executing: %s\n", cmd_redacted); + + if (!globals.verbose) { + strcpy(proc.stdout, "/dev/null"); + strcpy(proc.stderr, "/dev/null"); + } + status = shell2(&proc, cmd); + return status; +} + +int jfrog_cli_rt(struct JFRT_Auth *auth, char *args) { + char cmd[OMC_BUFSIZ]; + memset(cmd, 0, sizeof(cmd)); + snprintf(cmd, sizeof(cmd) - 1, "rt %s", args); + return jfrog_cli(auth, args); +} + +int jfrog_cli_rt_build_collect_env(struct JFRT_Auth *auth, char *build_name, long build_number) { + char cmd[OMC_BUFSIZ]; + memset(cmd, 0, sizeof(cmd)); + snprintf(cmd, sizeof(cmd) - 1, "rt build-collect-env %s %ld", build_name, build_number); + return jfrog_cli(auth, cmd); +} + +int jfrog_cli_rt_build_publish(struct JFRT_Auth *auth, char *build_name, long build_number) { + char cmd[OMC_BUFSIZ]; + memset(cmd, 0, sizeof(cmd)); + snprintf(cmd, sizeof(cmd) - 1, "rt build-publish %s %ld", build_name, build_number); + return jfrog_cli(auth, cmd); +} + +int jfrog_cli_rt_ping(struct JFRT_Auth *auth) { + char cmd[OMC_BUFSIZ]; + memset(cmd, 0, sizeof(cmd)); + + snprintf(cmd, sizeof(cmd) - 1, "rt ping"); + return jfrog_cli_rt(auth, cmd); +} + +int jfrog_cli_rt_download(struct JFRT_Auth *auth, struct JFRT_Download *ctx, char *repo_path, char *dest) { + char cmd[OMC_BUFSIZ]; + memset(cmd, 0, sizeof(cmd)); + + if (isempty(repo_path)) { + fprintf(stderr, "repo_path argument must be a valid artifactory repository path\n"); + return -1; + } + + // dest is an optional argument, therefore may be NULL or an empty string + + struct StrList *arg_map = strlist_init(); + if (!arg_map) { + return -1; + } + + jfrt_register_opt_str(ctx->archive_entries, "archive-entries", &arg_map); + jfrt_register_opt_str(ctx->build, "build", &arg_map); + jfrt_register_opt_str(ctx->build_name, "build-name", &arg_map); + jfrt_register_opt_str(ctx->bundle, "bundle", &arg_map); + jfrt_register_opt_str(ctx->exclude_artifacts, "exclude-artifacts", &arg_map); + jfrt_register_opt_str(ctx->exclude_props, "exclude-props", &arg_map); + jfrt_register_opt_str(ctx->exclusions, "exclusions", &arg_map); + jfrt_register_opt_str(ctx->gpg_key, "gpg-key", &arg_map); + jfrt_register_opt_str(ctx->include_deps, "include-deps", &arg_map); + jfrt_register_opt_str(ctx->include_dirs, "include-dirs", &arg_map); + jfrt_register_opt_str(ctx->module, "module", &arg_map); + jfrt_register_opt_str(ctx->project, "project", &arg_map); + jfrt_register_opt_str(ctx->props, "props", &arg_map); + jfrt_register_opt_str(ctx->sort_by, "sort-by", &arg_map); + jfrt_register_opt_str(ctx->sort_order, "sort-order", &arg_map); + jfrt_register_opt_str(ctx->spec, "spec", &arg_map); + jfrt_register_opt_str(ctx->spec_vars, "spec-vars", &arg_map); + + jfrt_register_opt_bool(ctx->detailed_summary, "detailed-summary", &arg_map); + jfrt_register_opt_bool(ctx->dry_run, "dry-run", &arg_map); + jfrt_register_opt_bool(ctx->explode, "explode", &arg_map); + jfrt_register_opt_bool(ctx->fail_no_op, "fail-no-op", &arg_map); + jfrt_register_opt_bool(ctx->flat, "flat", &arg_map); + jfrt_register_opt_bool(ctx->quiet, "quiet", &arg_map); + jfrt_register_opt_bool(ctx->recursive, "recursive", &arg_map); + jfrt_register_opt_bool(ctx->retries, "retries", &arg_map); + jfrt_register_opt_bool(ctx->retry_wait_time, "retry-wait-time", &arg_map); + jfrt_register_opt_bool(ctx->skip_checksum, "skip-checksum", &arg_map); + + jfrt_register_opt_long(ctx->build_number, "build-number", &arg_map); + jfrt_register_opt_int(ctx->limit, "limit", &arg_map); + jfrt_register_opt_int(ctx->min_split, "min-split", &arg_map); + jfrt_register_opt_int(ctx->offset, "offset", &arg_map); + jfrt_register_opt_int(ctx->split_count, "split-count", &arg_map); + jfrt_register_opt_int(ctx->sync_deletes, "sync-deletes", &arg_map); + jfrt_register_opt_int(ctx->threads, "threads", &arg_map); + jfrt_register_opt_int(ctx->validate_symlinks, "validate-symlinks", &arg_map); + + char *args = join(arg_map->data, " "); + if (!args) { + return -1; + } + + snprintf(cmd, sizeof(cmd) - 1, "rt download %s '%s' %s", args, repo_path, dest ? dest : ""); + guard_free(args) + guard_strlist_free(arg_map) + + int status = jfrog_cli_rt(auth, cmd); + return status; +} + +int jfrog_cli_rt_upload(struct JFRT_Auth *auth, struct JFRT_Upload *ctx, char *src, char *repo_path) { + char cmd[OMC_BUFSIZ]; + memset(cmd, 0, sizeof(cmd)); + + if (isempty(src)) { + fprintf(stderr, "src argument must be a valid file system path\n"); + return -1; + } + + if (isempty(repo_path)) { + fprintf(stderr, "repo_path argument must be a valid artifactory repository path\n"); + return -1; + } + + struct StrList *arg_map = strlist_init(); + if (!arg_map) { + return -1; + } + + // String options + jfrt_register_opt_str(ctx->build_name, "build-name", &arg_map); + jfrt_register_opt_str(ctx->exclusions, "exclusions", &arg_map); + jfrt_register_opt_str(ctx->module, "module", &arg_map); + jfrt_register_opt_str(ctx->regexp, "regexp", &arg_map); + jfrt_register_opt_str(ctx->spec, "spec", &arg_map); + jfrt_register_opt_str(ctx->spec_vars, "spec-vars", &arg_map); + jfrt_register_opt_str(ctx->project, "project", &arg_map); + jfrt_register_opt_str(ctx->target_props, "target-props", &arg_map); + + // Boolean options + jfrt_register_opt_bool(ctx->quiet, "quiet", &arg_map); + jfrt_register_opt_bool(ctx->ant, "ant", &arg_map); + jfrt_register_opt_bool(ctx->archive, "archive", &arg_map); + jfrt_register_opt_bool(ctx->deb, "deb", &arg_map); + jfrt_register_opt_bool(ctx->detailed_summary, "detailed-summary", &arg_map); + jfrt_register_opt_bool(ctx->dry_run, "dry-run", &arg_map); + jfrt_register_opt_bool(ctx->explode, "explode", &arg_map); + jfrt_register_opt_bool(ctx->fail_no_op, "fail-no-op", &arg_map); + jfrt_register_opt_bool(ctx->flat, "flat", &arg_map); + jfrt_register_opt_bool(ctx->include_dirs, "include-dirs", &arg_map); + jfrt_register_opt_bool(ctx->recursive, "recursive", &arg_map); + jfrt_register_opt_bool(ctx->symlinks, "symlinks", &arg_map); + jfrt_register_opt_bool(ctx->sync_deletes, "sync-deletes", &arg_map); + + // Integer options + jfrt_register_opt_long(ctx->build_number, "build-number", &arg_map); + jfrt_register_opt_int(ctx->retries, "retries", &arg_map); + jfrt_register_opt_int(ctx->retry_wait_time, "retry-wait-time", &arg_map); + jfrt_register_opt_int(ctx->threads, "threads", &arg_map); + + char *args = join(arg_map->data, " "); + if (!args) { + return -1; + } + + char *new_src = NULL; + char *base = NULL; + if (ctx->workaround_parent_only) { + struct StrList *components = strlist_init(); + + strlist_append_tokenize(components, src, "/"); + int max_components = (int) strlist_count(components); + for (int i = 0; i < max_components; i++) { + if (strstr(components->data[i], "*")) { + max_components = i; + break; + } + } + base = join(&components->data[max_components], "/"); + guard_free(components->data[max_components]); + new_src = join(components->data, "/"); + } + + if (new_src) { + if (base) { + src = base; + } else { + strcat(src, "/"); + } + pushd(new_src); + } + + snprintf(cmd, sizeof(cmd) - 1, "rt upload %s '%s' %s", args, src, repo_path); + guard_free(args) + guard_strlist_free(arg_map) + + int status = jfrog_cli_rt(auth, cmd); + if (new_src) { + popd(); + } + + return status; +}
\ No newline at end of file |