aboutsummaryrefslogtreecommitdiff
path: root/include
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 /include
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
Diffstat (limited to 'include')
-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
8 files changed, 397 insertions, 37 deletions
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
*/