aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2024-03-04 08:48:28 -0500
committerJoseph Hunkeler <jhunkeler@gmail.com>2024-03-04 08:48:28 -0500
commit239330330a8fc49c6806cccdc17a910d23d22952 (patch)
tree0e2a3e2e852cafd718556bb31ab58ffc0968504c
parent39861d1872731119795f954acc0412af64cd539d (diff)
downloadstasis-239330330a8fc49c6806cccdc17a910d23d22952.tar.gz
Prototypes documentation
Includes minor changes: * Rename jfrt_upload_set_defaults to jfrt_upload_init * Move jfrt_auth_init to artifactory.c * Adds missing error handling to git_describe and git_rev_parse
-rw-r--r--README.md2
-rw-r--r--docs/Doxyfile16
-rw-r--r--include/artifactory.h55
-rw-r--r--include/copy.h42
-rw-r--r--include/deliverable.h23
-rw-r--r--include/docker.h70
-rw-r--r--include/download.h5
-rw-r--r--include/recipe.h62
-rw-r--r--include/template.h5
-rw-r--r--include/utils.h172
-rw-r--r--src/artifactory.c55
-rw-r--r--src/deliverable.c55
-rw-r--r--src/utils.c56
13 files changed, 479 insertions, 139 deletions
diff --git a/README.md b/README.md
index 6a49237..7991953 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,3 @@
-# OH MY CAL
-
OMC aims to consolidate the steps required to build, test, and deploy calibration pipelines and other software suites maintained by engineers at the Space Telescope Science Institute.
# Requirements
diff --git a/docs/Doxyfile b/docs/Doxyfile
index bef5a97..d6509e6 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -124,7 +124,7 @@ WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
-INPUT = src include
+INPUT = README.md src include
INPUT_ENCODING = UTF-8
INPUT_FILE_ENCODING =
FILE_PATTERNS = *.c \
@@ -190,7 +190,7 @@ INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
-USE_MDFILE_AS_MAINPAGE =
+USE_MDFILE_AS_MAINPAGE = README.md
FORTRAN_COMMENT_AFTER = 72
#---------------------------------------------------------------------------
# Configuration options related to source browsing
@@ -308,7 +308,7 @@ RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
-GENERATE_MAN = NO
+GENERATE_MAN = YES
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_SUBDIR =
@@ -346,7 +346,7 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
-MACRO_EXPANSION = NO
+MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
@@ -366,14 +366,14 @@ EXTERNAL_PAGES = YES
# Configuration options related to diagram generator tools
#---------------------------------------------------------------------------
HIDE_UNDOC_RELATIONS = YES
-HAVE_DOT = NO
+HAVE_DOT = YES
DOT_NUM_THREADS = 0
DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
DOT_FONTPATH =
CLASS_GRAPH = YES
-COLLABORATION_GRAPH = YES
+COLLABORATION_GRAPH = NO
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
@@ -381,8 +381,8 @@ DOT_UML_DETAILS = NO
DOT_WRAP_THRESHOLD = 17
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
-INCLUDED_BY_GRAPH = YES
-CALL_GRAPH = NO
+INCLUDED_BY_GRAPH = NO
+CALL_GRAPH = YES
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
diff --git a/include/artifactory.h b/include/artifactory.h
index c8ce6d3..0883eef 100644
--- a/include/artifactory.h
+++ b/include/artifactory.h
@@ -130,10 +130,10 @@ int artifactory_download_cli(char *dest,
*
* ```c
* struct JFRT_Auth auth_ctx;
- * memset(auth_ctx, 0, sizeof(auth_context);
* auth_ctx.user = strdup("myuser");
* auth_ctx.password = strdup("mypassword");
* auth_ctx.url = strdup("https://myserver.tld/artifactory");
+ * jfrt_auth_init(&auth_ctx);
*
* if (jfrog_cli(&auth_ctx, "ping") {
* fprintf(stderr, "Failed to ping artifactory server: %s\n", auth_ctx.url);
@@ -152,10 +152,10 @@ int jfrog_cli(struct JFRT_Auth *auth, char *args);
*
* ```c
* struct JFRT_Auth auth_ctx;
- * memset(auth_ctx, 0, sizeof(auth_context);
* auth_ctx.user = strdup("myuser");
* auth_ctx.password = strdup("mypassword");
* auth_ctx.url = strdup("https://myserver.tld/artifactory");
+ * jfrt_auth_init(&auth_ctx);
*
* if (jfrog_cli_ping(&auth_ctx)) {
* fprintf(stderr, "Failed to ping artifactory server: %s\n", auth_ctx.url);
@@ -173,13 +173,13 @@ int jfrog_cli_rt_ping(struct JFRT_Auth *auth);
*
* ```c
* struct JFRT_Auth auth_ctx;
- * memset(auth_ctx, 0, sizeof(auth_context);
* auth_ctx.user = strdup("myuser");
* auth_ctx.password = strdup("mypassword");
* auth_ctx.url = strdup("https://myserver.tld/artifactory");
+ * jfrt_auth_init(&auth_ctx);
*
* struct JFRT_Upload upload_ctx;
- * jfrt_upload_set_defaults(&upload_ctx);
+ * jfrt_upload_init(&upload_ctx);
*
* if (jfrt_cli_rt_upload(&auth_ctx, &upload_ctx,
* "local/files_*.ext", "repo_name/ext_files/")) {
@@ -201,10 +201,10 @@ int jfrog_cli_rt_upload(struct JFRT_Auth *auth, struct JFRT_Upload *ctx, char *s
*
* ```c
* struct JFRT_Auth auth_ctx;
- * memset(auth_ctx, 0, sizeof(auth_context);
* auth_ctx.user = strdup("myuser");
* auth_ctx.password = strdup("mypassword");
* auth_ctx.url = strdup("https://myserver.tld/artifactory");
+ * jfrt_auth_init(&auth_ctx);
*
* struct JFRT_Download download_ctx;
* memset(download_ctx, 0, sizeof(download_ctx));
@@ -229,10 +229,10 @@ int jfrog_cli_rt_download(struct JFRT_Auth *auth, struct JFRT_Download *ctx, cha
*
* ```c
* struct JFRT_Auth auth_ctx;
- * memset(auth_ctx, 0, sizeof(auth_context);
* auth_ctx.user = strdup("myuser");
* auth_ctx.password = strdup("mypassword");
* auth_ctx.url = strdup("https://myserver.tld/artifactory");
+ * jfrt_auth_init(&auth_ctx);
*
* if (jfrog_cli_rt_build_collect_env(&auth_ctx, "mybuildname", "1.2.3+gabcdef")) {
* fprintf(stderr, "Failed to collect runtime data for Artifactory build object\n");
@@ -252,10 +252,10 @@ int jfrog_cli_rt_build_collect_env(struct JFRT_Auth *auth, char *build_name, cha
*
* ```c
* struct JFRT_Auth auth_ctx;
- * memset(auth_ctx, 0, sizeof(auth_context);
* auth_ctx.user = strdup("myuser");
* auth_ctx.password = strdup("mypassword");
* auth_ctx.url = strdup("https://myserver.tld/artifactory");
+ * jfrt_auth_init(&auth_ctx);
*
* if (jfrog_cli_rt_build_collect_env(&auth_ctx, "mybuildname", "1.2.3+gabcdef")) {
* fprintf(stderr, "Failed to collect runtime data for Artifactory build object\n");
@@ -276,9 +276,48 @@ int jfrog_cli_rt_build_collect_env(struct JFRT_Auth *auth, char *build_name, cha
int jfrog_cli_rt_build_publish(struct JFRT_Auth *auth, char *build_name, char *build_number);
/**
+ * Configure JFrog CLI authentication according to OMC specs
+ *
+ * This function will use the OMC_JF_* environment variables to configure the authentication
+ * context. With this in mind, if an OMC_JF_* environment variable is not defined, the original value of
+ * the structure member will be used instead.
+ *
+ * Use OMC_JF_* variables to configure context
+ *
+ * ```c
+ * struct JFRT_Auth auth_ctx;
+ * jfrt_auth_init(&ctx);
+ * ```
+ *
+ * Use your own input, but let the environment take over when variables are defined
+ *
+ * ```c
+ * struct JFRT_Auth auth_ctx;
+ * auth_ctx.user = strdup("myuser");
+ * auth_ctx.password = strdup("mypassword");
+ * auth_ctx.url = strdup("https://myserver.tld/artifactory");
+ * jfrt_auth_init(&auth_ctx);
+ * ```
+ *
+ * Use your own input without OMC's help. Purely an illustrative example.
+ *
+ * ```c
+ * struct JFRT_Auth auth_ctx;
+ * memset(auth_ctx, 0, sizeof(auth_ctx));
+ * auth_ctx.user = strdup("myuser");
+ * auth_ctx.password = strdup("mypassword");
+ * auth_ctx.url = strdup("https://myserver.tld/artifactory");
+ * ```
+ *
+ * @param auth_ctx
+ * @return
+ */
+int jfrt_auth_init(struct JFRT_Auth *auth_ctx);
+
+/**
* Zero-out and apply likely defaults to a JFRT_Upload structure
* @param ctx JFRT_Upload structure
*/
-void jfrt_upload_set_defaults(struct JFRT_Upload *ctx);
+void jfrt_upload_init(struct JFRT_Upload *ctx);
#endif //OMC_ARTIFACTORY_H \ No newline at end of file
diff --git a/include/copy.h b/include/copy.h
index 9e8bc11..5a53d7d 100644
--- a/include/copy.h
+++ b/include/copy.h
@@ -1,3 +1,4 @@
+//! @file copy.h
#ifndef OMC_COPY_H
#include <stdio.h>
@@ -12,8 +13,49 @@
#define CT_OWNER 1 << 1
#define CT_PERM 1 << 2
+/**
+ * Recursively copy a directory, or a single file
+ *
+ * ```c
+ * if (copytree("/source/path", "/destination/path", CT_PERM | CT_OWNER)) {
+ * fprintf(stderr, "Unable to copy files\n");
+ * exit(1);
+ * }
+ * ```
+ *
+ * @param srcdir source file or directory path
+ * @param destdir destination directory
+ * @param op CT_OWNER (preserve ownership)
+ * @param op CT_PERM (preserve permission bits)
+ * @return 0 on success, -1 on error
+ */
int copytree(const char *srcdir, const char *destdir, unsigned op);
+
+/**
+ * Create all leafs in directory path
+ * @param _path directory path to create
+ * @param mode mode_t permissions
+ * @return
+ */
int mkdirs(const char *_path, mode_t mode);
+
+/**
+ * Copy a single file
+ *
+ * ```c
+ * if (copy2("/source/path/example.txt", "/destination/path/example.txt", CT_PERM | CT_OWNER)) {
+ * fprintf(stderr, "Unable to copy file\n");
+ * exit(1);
+ * }
+ * ```
+ *
+ *
+ * @param src source file path
+ * @param dest destination file path
+ * @param op CT_OWNER (preserve ownership)
+ * @param op CT_PERM (preserve permission bits)
+ * @return 0 on success, -1 on error
+ */
int copy2(const char *src, const char *dest, unsigned op);
#endif // OMC_COPY_H \ No newline at end of file
diff --git a/include/deliverable.h b/include/deliverable.h
index 63adef1..1fbbd54 100644
--- a/include/deliverable.h
+++ b/include/deliverable.h
@@ -323,17 +323,18 @@ void delivery_install_conda(char *install_script, char *conda_install_dir);
* Generate a formatted release string
*
* Formatters:
- * %n = Delivery Name
- * %c = Delivery Codename (HST mission, only)
- * %m = Mission
- * %R = Delivery Revision number (or "final")
- * %r = Delivery Revision number
- * %v = Delivery Version
- * %P = Python version (i.e. 3.9.1)
- * %p = Compact Python version (i.e. 3.9.1 -> 39)
- * %a = System architecture name
- * %o = System platform name
- * %t = Delivery timestamp (Unix Epoch)
+ *
+ * - `%%n` = Delivery Name
+ * - `%%c` = Delivery Codename (HST mission, only)
+ * - `%%m` = Mission
+ * - `%%R` = Delivery Revision number (or "final")
+ * - `%%r` = Delivery Revision number
+ * - `%%v` = Delivery Version
+ * - `%%P` = Python version (i.e. 3.9.1)
+ * - `%%p` = Compact Python version (i.e. 3.9.1 -> 39)
+ * - `%%a` = System architecture name
+ * - `%%o` = System platform name
+ * - `%%t` = Delivery timestamp (Unix Epoch)
*
* @param ctx pointer to Delivery context
* @param dest NULL pointer to string, or initialized string
diff --git a/include/docker.h b/include/docker.h
index 03f5d0d..3c7dff6 100644
--- a/include/docker.h
+++ b/include/docker.h
@@ -1,20 +1,82 @@
+//! @file docker.h
#ifndef OMC_DOCKER_H
#define OMC_DOCKER_H
+//! Flag to squelch output from docker_exec()
#define OMC_DOCKER_QUIET 1 << 1
+//! Flag for older style docker build
#define OMC_DOCKER_BUILD 1 << 1
+//! Flag for docker buildx
#define OMC_DOCKER_BUILD_X 1 << 2
struct DockerCapabilities {
- int podman;
- int build;
- int available;
- int usable;
+ int podman; //!< Is "docker" really podman?
+ int build; //!< Is a build plugin available?
+ int available; //!< Is a "docker" program available?
+ int usable; //!< Is docker in a usable state for the current user?
};
+/**
+ * Determine the state of docker on the system
+ *
+ * ```c
+ * struct DockerCapabilities docker_is;
+ * if (!docker_capable(&docker_is)) {
+ * fprintf(stderr, "%s is %savailable, and %susable\n",
+ * docker_is.podman ? "Podman" : "Docker",
+ * docker_is.available ? "" : "not ",
+ * docker_is.usable ? "" : "not ");
+ * exit(1);
+ * }
+ * ```
+ *
+ * @param result DockerCapabilities struct
+ * @return 1 on success, 0 on error
+ */
int docker_capable(struct DockerCapabilities *result);
+
+/**
+ * Execute a docker command
+ *
+ * Use the `OMC_DOCKER_QUIET` flag to suppress all output from stdout and stderr.
+ *
+ * ```c
+ * if (docker_exec("run --rm -t ubuntu:latest /bin/bash -c 'echo Hello world'", 0)) {
+ * fprintf(stderr, "Docker hello world failed\n");
+ * exit(1);
+ * }
+ * ```
+ *
+ * @param args arguments to pass to docker
+ * @param flags
+ * @return exit code from "docker"
+ */
int docker_exec(const char *args, unsigned flags);
+
+/**
+ * Build a docker image
+ *
+ * ```c
+ * struct DockerCapabilities docker_is;
+ * docker_capable(&docker_is);
+ *
+ * if (docker_is.usable) {
+ * printf("Building docker image\n");
+ * if (docker_build("path/to/Dockerfile/dir")) {
+ * fprintf("Docker build failed\n");
+ * exit(1);
+ * }
+ * } else {
+ * fprintf(stderr, "No usable docker installation available\n");
+ * }
+ * ```
+ *
+ * @param dirpath
+ * @param args
+ * @param engine
+ * @return
+ */
int docker_build(const char *dirpath, const char *args, int engine);
int docker_script(const char *image, char *data, unsigned flags);
int docker_save(const char *image, const char *destdir);
diff --git a/include/download.h b/include/download.h
index 440c749..568809e 100644
--- a/include/download.h
+++ b/include/download.h
@@ -1,7 +1,4 @@
-//
-// Created by jhunk on 10/5/23.
-//
-
+//! @file download.h
#ifndef OMC_DOWNLOAD_H
#define OMC_DOWNLOAD_H
diff --git a/include/recipe.h b/include/recipe.h
index f4c63c1..f1b4df1 100644
--- a/include/recipe.h
+++ b/include/recipe.h
@@ -1,20 +1,72 @@
-//
-// Created by jhunk on 10/7/23.
-//
-
+//! @file recipe.h
#ifndef OMC_RECIPE_H
#define OMC_RECIPE_H
#include "str.h"
#include "utils.h"
-#define RECIPE_DIR "recipes"
+//! Unable to determine recipe repo type
#define RECIPE_TYPE_UNKNOWN 0
+//! Recipe repo is from conda-forge
#define RECIPE_TYPE_CONDA_FORGE 1
+//! Recipe repo is from astroconda
#define RECIPE_TYPE_ASTROCONDA 2
+//! Recipe repo provides the required build configurations but doesn't match conda-forge or astroconda's signature
#define RECIPE_TYPE_GENERIC 3
+/**
+ * Download a Conda package recipe
+ *
+ * ```c
+ * char *recipe = NULL;
+ *
+ * if (recipe_clone("base/dir", "https://github.com/example/repo", "branch", &recipe)) {
+ * fprintf(stderr, "Failed to clone conda recipe\n");
+ * exit(1);
+ * } else {
+ * chdir(recipe);
+ * }
+ * ```
+ *
+ * @param recipe_dir path to store repository
+ * @param url remote address of git repository
+ * @param gitref branch/tag/commit
+ * @param result absolute path to downloaded repository
+ * @return exit code from "git", -1 on error
+ */
int recipe_clone(char *recipe_dir, char *url, char *gitref, char **result);
+
+/**
+ * Determine the layout/type of repository path
+ *
+ * ```c
+ * if (recipe_clone("base/dir", "https://github.com/example/repo", "branch", &recipe)) {
+ * fprintf(stderr, "Failed to clone conda recipe\n");
+ * exit(1);
+ * }
+ *
+ * int recipe_type;
+ * recipe_type = recipe_get_type(recipe);
+ * switch (recipe_type) {
+ * case RECIPE_TYPE_CONDA_FORGE:
+ * // do something specific for conda-forge directory structure
+ * break;
+ * case RECIPE_TYPE_ASTROCONDA:
+ * // do something specific for astroconda directory structure
+ * break;
+ * case RECIPE_TYPE_GENERIC:
+ * // do something specific for a directory containing a meta.yaml config
+ * break;
+ * case RECIPE_TYPE_UNKNOWN:
+ * default:
+ * // the structure is foreign or the path doesn't contain a conda recipe
+ * break;
+ * }
+ * ```
+ *
+ * @param repopath path to git repository containing conda recipe(s)
+ * @return One of RECIPE_TYPE_UNKNOWN, RECIPE_TYPE_CONDA_FORGE, RECIPE_TYPE_ASTROCONDA, RECIPE_TYPE_GENERIC
+ */
int recipe_get_type(char *repopath);
#endif //OMC_RECIPE_H
diff --git a/include/template.h b/include/template.h
index b12208f..116960f 100644
--- a/include/template.h
+++ b/include/template.h
@@ -1,7 +1,4 @@
-//
-// Created by jhunk on 12/17/23.
-//
-
+//! @file template.h
#ifndef OMC_TEMPLATE_H
#define OMC_TEMPLATE_H
diff --git a/include/utils.h b/include/utils.h
index 52f4f2d..71d3f8b 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -1,3 +1,4 @@
+//! @file utils.h
#ifndef OMC_UTILS_H
#define OMC_UTILS_H
#include <stdio.h>
@@ -23,35 +24,204 @@
typedef int (ReaderFn)(size_t line, char **);
+/**
+ * Change directory. Push path on directory stack.
+ *
+ * ```c
+ * pushd("/somepath");
+ *
+ * FILE fp = fopen("somefile", "w"); // i.e. /somepath/somefile
+ * fprintf(fp, "Hello world.\n");
+ * fclose(fp);
+ *
+ * popd();
+ * ```
+ *
+ * @param path of directory
+ * @return 0 on success, -1 on error
+ */
int pushd(const char *path);
+
+/**
+ * Return from directory. Pop last path from directory stack.
+ *
+ * @see pushd
+ * @return 0 on success, -1 if stack is empty
+ */
int popd(void);
+
+/**
+ * Expand "~" to the user's home directory
+ *
+ * ```c
+ * char *home = expandpath("~"); // == /home/username
+ * char *config = expandpath("~/.config"); // == /home/username/.config
+ * char *nope = expandpath("/tmp/test"); // == /tmp/test
+ * char *nada = expandpath("/~/broken"); // == /~/broken
+ *
+ * free(home);
+ * free(config);
+ * free(nope);
+ * free(nada);
+ * ```
+ *
+ * @param _path (Must start with a `~`)
+ * @return success=expanded path or original path, failure=NULL
+ */
char *expandpath(const char *_path);
+
+/**
+ * Remove a directory tree recursively
+ *
+ * ```c
+ * mkdirs("a/b/c");
+ * rmtree("a");
+ * // a/b/c is removed
+ * ```
+ *
+ * @param _path
+ * @return 0 on success, -1 on error
+ */
int rmtree(char *_path);
+
+
char **file_readlines(const char *filename, size_t start, size_t limit, ReaderFn *readerFn);
+
+/**
+ * Strip directory from file name
+ * Note: Caller is responsible for freeing memory
+ *
+ * @param _path
+ * @return success=file name, failure=NULL
+ */
char *path_basename(char *path);
+
+/**
+ * Return parent directory of file, or the parent of a directory
+ *
+ * @param path
+ * @return success=directory, failure=empty string
+ */
+char *path_dirname(char *path);
+
+/**
+ * Scan PATH directories for a named program
+ * @param name program name
+ * @return path to program, or NULL on error
+ */
char *find_program(const char *name);
+
+/**
+ * Create an empty file, or update modified timestamp on an existing file
+ * @param filename file to touch
+ * @return 0 on success, 1 on error
+ */
int touch(const char *filename);
+
+/**
+ * Clone a git repository
+ *
+ * ```c
+ * struct Process proc;
+ * memset(proc, 0, sizeof(proc));
+ *
+ * if (git_clone(&proc, "https://github.com/myuser/myrepo", "./repos", "unstable_branch")) {
+ * fprintf(stderr, "Failed to clone repository\n");
+ * exit(1);
+ * }
+ *
+ * if (pushd("./repos/myrepo")) {
+ * fprintf(stderr, "Unable to enter repository directory\n");
+ * } else {
+ * // do something with repository
+ * popd();
+ * }
+ * ```
+ *
+ * @see pushd
+ *
+ * @param proc Process struct
+ * @param url URL (or file system path) of repoistory to clone
+ * @param destdir destination directory
+ * @param gitref commit/branch/tag of checkout (NULL will use HEAD of default branch for repo)
+ * @return exit code from "git"
+ */
int git_clone(struct Process *proc, char *url, char *destdir, char *gitref);
+
+/**
+ * Git describe wrapper
+ * @param path to repository
+ * @return output from "git describe", or NULL on error
+ */
char *git_describe(const char *path);
+
+/**
+ * Git rev-parse wrapper
+ * @param path to repository
+ * @param args to pass to git rev-parse
+ * @return output from "git rev-parse", or NULL on error
+ */
char *git_rev_parse(const char *path, char *args);
+
+/**
+ * Helper function to initialize simple OMC internal path strings
+ *
+ * ```c
+ * char *mypath = NULL;
+ *
+ * if (path_store(&mypath, PATH_MAX, "/some", "path")) {
+ * fprintf(stderr, "Unable to allocate memory for path elements\n");
+ * exit(1);
+ * }
+ * // mypath is allocated to size PATH_MAX and contains the string: /some/path
+ * // base+path will truncate at maxlen - 1
+ * ```
+ *
+ * @param destptr address of destination string pointer
+ * @param maxlen maximum length of the path
+ * @param base path
+ * @param path to append to base
+ * @return 0 on success, -1 on error
+ */
int path_store(char **destptr, size_t maxlen, const char *base, const char *path);
#define OMC_MSG_SUCCESS 0
+//! Suppress printing of the message text
#define OMC_MSG_NOP 1 << 0
+//! The message is an error
#define OMC_MSG_ERROR 1 << 1
+//! The message is a warning
#define OMC_MSG_WARN 1 << 2
+//! The message will be indented once
#define OMC_MSG_L1 1 << 3
+//! The message will be indented twice
#define OMC_MSG_L2 1 << 4
+//! The message will be indented thrice
#define OMC_MSG_L3 1 << 5
-#define OMC_MSG_RESTRICT 1 << 6 ///< Restrict to verbose mode
+//! The message will only be printed in verbose mode
+#define OMC_MSG_RESTRICT 1 << 6
void msg(unsigned type, char *fmt, ...);
+
+// Enter an interactive shell that ends the program on-exit
void debug_shell();
+
/**
* Creates a temporary file returning an open file pointer via @a fp, and the
* path to the file. The caller is responsible for closing @a fp and
* free()ing the returned file path.
+ *
+ * ```c
+ * FILE *fp = NULL;
+ * char *tempfile = xmkstemp(&fp, "r+");
+ * if (!fp || !tempfile) {
+ * fprintf(stderr, "Failed to generate temporary file for read/write\n");
+ * exit(1);
+ * }
+ * ```
+ *
* @param fp pointer to FILE (to be initialized)
+ * @param mode fopen() style file mode string
* @return system path to the temporary file
* @return NULL on failure
*/
diff --git a/src/artifactory.c b/src/artifactory.c
index 55cb7dd..39a662d 100644
--- a/src/artifactory.c
+++ b/src/artifactory.c
@@ -115,7 +115,7 @@ void jfrt_register_opt_long(long jfrt_val, const char *opt_name, struct StrList
strlist_append(*opt_map, data);
}
-void jfrt_upload_set_defaults(struct JFRT_Upload *ctx) {
+void jfrt_upload_init(struct JFRT_Upload *ctx) {
memset(ctx, 0, sizeof(*ctx));
ctx->recursive = true;
ctx->threads = 3;
@@ -135,6 +135,59 @@ static int auth_required(char *cmd) {
return 0;
}
+int jfrt_auth_init(struct JFRT_Auth *auth_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");
+ char *client_cert_key_path = getenv("OMC_JF_CLIENT_CERT_KEY_PATH");
+ char *client_cert_path = getenv("OMC_JF_CLIENT_CERT_PATH");
+
+ 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 if (client_cert_key_path && client_cert_path) {
+ auth_ctx->user = NULL;
+ auth_ctx->password = NULL;
+ auth_ctx->access_token = NULL;
+ auth_ctx->ssh_key_path = NULL;
+ auth_ctx->client_cert_key_path = client_cert_key_path;
+ auth_ctx->client_cert_path = client_cert_path;
+ } else {
+ fprintf(stderr, "Artifactory authentication is not configured:\n");
+ fprintf(stderr, "set OMC_JF_USER and OMC_JF_PASSWORD\n");
+ fprintf(stderr, "or, set OMC_JF_ACCESS_TOKEN\n");
+ fprintf(stderr, "or, set OMC_JF_SSH_KEY_PATH and OMC_JF_SSH_KEY_PASSPHRASE\n");
+ fprintf(stderr, "or, set OMC_JF_CLIENT_CERT_KEY_PATH and OMC_JF_CLIENT_CERT_PATH\n");
+ return -1;
+ }
+ return 0;
+}
+
int jfrog_cli(struct JFRT_Auth *auth, char *args) {
struct Process proc;
char cmd[OMC_BUFSIZ];
diff --git a/src/deliverable.c b/src/deliverable.c
index b935b64..f9c53ba 100644
--- a/src/deliverable.c
+++ b/src/deliverable.c
@@ -1433,59 +1433,6 @@ int delivery_init_artifactory(struct Delivery *ctx) {
return status;
}
-int jfrt_auth_init(struct JFRT_Auth *auth_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");
- char *client_cert_key_path = getenv("OMC_JF_CLIENT_CERT_KEY_PATH");
- char *client_cert_path = getenv("OMC_JF_CLIENT_CERT_PATH");
-
- 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 if (client_cert_key_path && client_cert_path) {
- auth_ctx->user = NULL;
- auth_ctx->password = NULL;
- auth_ctx->access_token = NULL;
- auth_ctx->ssh_key_path = NULL;
- auth_ctx->client_cert_key_path = client_cert_key_path;
- auth_ctx->client_cert_path = client_cert_path;
- } else {
- fprintf(stderr, "Artifactory authentication is not configured:\n");
- fprintf(stderr, "set OMC_JF_USER and OMC_JF_PASSWORD\n");
- fprintf(stderr, "or, set OMC_JF_ACCESS_TOKEN\n");
- fprintf(stderr, "or, set OMC_JF_SSH_KEY_PATH and OMC_JF_SSH_KEY_PASSPHRASE\n");
- fprintf(stderr, "or, set OMC_JF_CLIENT_CERT_KEY_PATH and OMC_JF_CLIENT_CERT_PATH\n");
- return -1;
- }
- return 0;
-}
-
int delivery_artifact_upload(struct Delivery *ctx) {
int status = 0;
@@ -1493,7 +1440,7 @@ int delivery_artifact_upload(struct Delivery *ctx) {
if (!ctx->deploy[i].files || !ctx->deploy[i].dest) {
break;
}
- jfrt_upload_set_defaults(&ctx->deploy[i].upload_ctx);
+ jfrt_upload_init(&ctx->deploy[i].upload_ctx);
char *repo = getenv("OMC_JF_REPO");
if (repo) {
diff --git a/src/utils.c b/src/utils.c
index 2b4d275..b669e1c 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -69,25 +69,6 @@ int rmtree(char *_path) {
return status;
}
-/**
- * Expand "~" to the user's home directory
- *
- * Example:
- * ~~~{.c}
- * char *home = expandpath("~"); // == /home/username
- * char *config = expandpath("~/.config"); // == /home/username/.config
- * char *nope = expandpath("/tmp/test"); // == /tmp/test
- * char *nada = expandpath("/~/broken"); // == /~/broken
- *
- * free(home);
- * free(config);
- * free(nope);
- * free(nada);
- * ~~~
- *
- * @param _path (Must start with a `~`)
- * @return success=expanded path or original path, failure=NULL
- */
char *expandpath(const char *_path) {
if (_path == NULL) {
return NULL;
@@ -146,13 +127,6 @@ char *expandpath(const char *_path) {
return strdup(result);
}
-/**
- * Strip directory from file name
- * Note: Caller is responsible for freeing memory
- *
- * @param _path
- * @return success=file name, failure=NULL
- */
char *path_basename(char *path) {
char *result = NULL;
char *last = NULL;
@@ -168,12 +142,6 @@ char *path_basename(char *path) {
return result;
}
-/**
- * Return parent directory of file, or the parent of a directory
- *
- * @param path
- * @return success=directory, failure=empty string
- */
char *path_dirname(char *path) {
if (!path) {
return "";
@@ -374,11 +342,18 @@ int git_clone(struct Process *proc, char *url, char *destdir, char *gitref) {
char *git_describe(const char *path) {
- pushd(path);
static char version[NAME_MAX];
FILE *pp;
- pp = popen("git describe --first-parent --always --tags", "r");
+
memset(version, 0, sizeof(version));
+ if (pushd(path)) {
+ return NULL;
+ }
+
+ pp = popen("git describe --first-parent --always --tags", "r");
+ if (!pp) {
+ return NULL;
+ }
fgets(version, sizeof(version) - 1, pp);
strip(version);
pclose(pp);
@@ -387,18 +362,25 @@ char *git_describe(const char *path) {
}
char *git_rev_parse(const char *path, char *args) {
- pushd(path);
static char version[NAME_MAX];
char cmd[PATH_MAX];
FILE *pp;
+ memset(version, 0, sizeof(version));
if (isempty(args)) {
- fprintf(stderr, "git_rev_parse args cannot be empty");
+ fprintf(stderr, "git_rev_parse args cannot be empty\n");
+ return NULL;
+ }
+
+ if (pushd(path)) {
return NULL;
}
+
sprintf(cmd, "git rev-parse %s", args);
pp = popen(cmd, "r");
- memset(version, 0, sizeof(version));
+ if (!pp) {
+ return NULL;
+ }
fgets(version, sizeof(version) - 1, pp);
strip(version);
pclose(pp);