aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/artifactory.h1
-rw-r--r--include/conda.h16
-rw-r--r--include/core.h38
-rw-r--r--include/core_mem.h18
-rw-r--r--include/delivery.h39
-rw-r--r--include/docker.h2
-rw-r--r--include/download.h2
-rw-r--r--include/envctl.h2
-rw-r--r--include/github.h1
-rw-r--r--include/ini.h1
-rw-r--r--include/multiprocessing.h131
-rw-r--r--include/package.h30
-rw-r--r--include/str.h1
-rw-r--r--include/strlist.h5
-rw-r--r--include/template_func_proto.h2
-rw-r--r--include/utils.h31
-rw-r--r--include/wheel.h36
17 files changed, 305 insertions, 51 deletions
diff --git a/include/artifactory.h b/include/artifactory.h
index c6e5c2b..e580886 100644
--- a/include/artifactory.h
+++ b/include/artifactory.h
@@ -5,6 +5,7 @@
#include <stdio.h>
#include <stdlib.h>
#include "core.h"
+#include "download.h"
//! JFrog Artifactory Authentication struct
struct JFRT_Auth {
diff --git a/include/conda.h b/include/conda.h
index c546672..1eb42f4 100644
--- a/include/conda.h
+++ b/include/conda.h
@@ -4,7 +4,9 @@
#include <stdio.h>
#include <string.h>
+#include <sys/utsname.h>
#include "core.h"
+#include "download.h"
#define CONDA_INSTALL_PREFIX "conda"
#define PYPI_INDEX_DEFAULT "https://pypi.org/simple"
@@ -186,10 +188,18 @@ int conda_index(const char *path);
/**
* Determine whether a simple index contains a package
* @param index_url a file system path or url pointing to a simple index
- * @param name package name (required)
- * @param version package version (may be NULL)
+ * @param spec a pip package specification (e.g. `name==1.2.3`)
* @return not found = 0, found = 1, error = -1
*/
-int pip_index_provides(const char *index_url, const char *name, const char *version);
+int pip_index_provides(const char *index_url, const char *spec);
+
+/**
+ * Determine whether conda can find a package in its channel list
+ * @param spec a conda package specification (e.g. `name=1.2.3`)
+ * @return not found = 0, found = 1, error = -1
+ */
+int conda_provides(const char *spec);
+
+char *conda_get_active_environment();
#endif //STASIS_CONDA_H
diff --git a/include/core.h b/include/core.h
index ef90e96..b0a1a11 100644
--- a/include/core.h
+++ b/include/core.h
@@ -1,9 +1,10 @@
-//! @file stasis.h
+//! @file core.h
#ifndef STASIS_CORE_H
#define STASIS_CORE_H
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
@@ -21,36 +22,7 @@
#define HTTP_ERROR(X) X >= 400
#include "config.h"
-#include "envctl.h"
-#include "template.h"
-#include "utils.h"
-#include "copy.h"
-#include "ini.h"
-#include "conda.h"
-#include "environment.h"
-#include "artifactory.h"
-#include "docker.h"
-#include "delivery.h"
-#include "str.h"
-#include "strlist.h"
-#include "system.h"
-#include "download.h"
-#include "recipe.h"
-#include "relocation.h"
-#include "wheel.h"
-#include "junitxml.h"
-#include "github.h"
-#include "template_func_proto.h"
-
-#define guard_runtime_free(X) do { if (X) { runtime_free(X); X = NULL; } } while (0)
-#define guard_strlist_free(X) do { if ((*X)) { strlist_free(X); (*X) = NULL; } } while (0)
-#define guard_free(X) do { if (X) { free(X); X = NULL; } } while (0)
-#define GENERIC_ARRAY_FREE(ARR) do { \
- for (size_t ARR_I = 0; ARR && ARR[ARR_I] != NULL; ARR_I++) { \
- guard_free(ARR[ARR_I]); \
- } \
- guard_free(ARR); \
-} while (0)
+#include "core_mem.h"
#define COE_CHECK_ABORT(COND, MSG) \
do {\
@@ -71,6 +43,10 @@ struct STASIS_GLOBAL {
bool enable_testing; //!< Enable package testing
bool enable_overwrite; //!< Enable release file clobbering
bool enable_rewrite_spec_stage_2; //!< Enable automatic @STR@ replacement in output files
+ bool enable_parallel; //!< Enable testing in parallel
+ long cpu_limit; //!< Limit parallel processing to n cores (default: max - 1)
+ long parallel_fail_fast; //!< Fail immediately on error
+ int pool_status_interval; //!< Report "Task is running" every n seconds
struct StrList *conda_packages; //!< Conda packages to install after initial activation
struct StrList *pip_packages; //!< Pip packages to install after initial activation
char *tmpdir; //!< Path to temporary storage directory
diff --git a/include/core_mem.h b/include/core_mem.h
new file mode 100644
index 0000000..bd50e9d
--- /dev/null
+++ b/include/core_mem.h
@@ -0,0 +1,18 @@
+//! @file core_mem.h
+#ifndef STASIS_CORE_MEM_H
+#define STASIS_CORE_MEM_H
+
+#include "environment.h"
+#include "strlist.h"
+
+#define guard_runtime_free(X) do { if (X) { runtime_free(X); X = NULL; } } while (0)
+#define guard_strlist_free(X) do { if ((*X)) { strlist_free(X); (*X) = NULL; } } while (0)
+#define guard_free(X) do { if (X) { free(X); X = NULL; } } while (0)
+#define GENERIC_ARRAY_FREE(ARR) do { \
+ for (size_t ARR_I = 0; ARR && ARR[ARR_I] != NULL; ARR_I++) { \
+ guard_free(ARR[ARR_I]); \
+ } \
+ guard_free(ARR); \
+} while (0)
+
+#endif //STASIS_CORE_MEM_H
diff --git a/include/delivery.h b/include/delivery.h
index 067cd0b..bd5137c 100644
--- a/include/delivery.h
+++ b/include/delivery.h
@@ -7,7 +7,18 @@
#include <stdbool.h>
#include <unistd.h>
#include <sys/utsname.h>
+#include <fnmatch.h>
+#include <sys/statvfs.h>
#include "core.h"
+#include "copy.h"
+#include "environment.h"
+#include "conda.h"
+#include "ini.h"
+#include "artifactory.h"
+#include "docker.h"
+#include "wheel.h"
+#include "multiprocessing.h"
+#include "recipe.h"
#define DELIVERY_PLATFORM_MAX 4
#define DELIVERY_PLATFORM_MAXLEN 65
@@ -149,7 +160,10 @@ struct Delivery {
char *name; ///< Name of package
char *version; ///< Version of package
char *repository; ///< Git repository of package
+ char *script_setup; ///< Commands to execute before the main script
char *script; ///< Commands to execute
+ bool disable; ///< Toggle a test block
+ bool parallel; ///< Toggle parallel or serial execution
char *build_recipe; ///< Conda recipe to build (optional)
char *repository_info_ref; ///< Git commit hash
char *repository_info_tag; ///< Git tag (first parent)
@@ -286,7 +300,7 @@ int delivery_copy_conda_artifacts(struct Delivery *ctx);
* Retrieve Conda installer
* @param installer_url URL to installation script
*/
-int delivery_get_installer(struct Delivery *ctx, char *installer_url);
+int delivery_get_conda_installer(struct Delivery *ctx, char *installer_url);
/**
* Generate URL based on Delivery context
@@ -294,7 +308,7 @@ int delivery_get_installer(struct Delivery *ctx, char *installer_url);
* @param result pointer to char
* @return in result
*/
-void delivery_get_installer_url(struct Delivery *ctx, char *result);
+void delivery_get_conda_installer_url(struct Delivery *ctx, char *result);
/**
* Install packages based on Delivery context
@@ -376,6 +390,12 @@ void delivery_gather_tool_versions(struct Delivery *ctx);
// helper function
int delivery_init_tmpdir(struct Delivery *ctx);
+void delivery_init_dirs_stage1(struct Delivery *ctx);
+
+void delivery_init_dirs_stage2(struct Delivery *ctx);
+
+int delivery_init_platform(struct Delivery *ctx);
+
int delivery_init_artifactory(struct Delivery *ctx);
int delivery_artifact_upload(struct Delivery *ctx);
@@ -386,10 +406,21 @@ int delivery_docker(struct Delivery *ctx);
int delivery_fixup_test_results(struct Delivery *ctx);
-int *bootstrap_build_info(struct Delivery *ctx);
+int bootstrap_build_info(struct Delivery *ctx);
int delivery_dump_metadata(struct Delivery *ctx);
+int populate_info(struct Delivery *ctx);
+
+int populate_delivery_cfg(struct Delivery *ctx, int render_mode);
+
+int populate_delivery_ini(struct Delivery *ctx, int render_mode);
+
+int populate_mission_ini(struct Delivery **ctx, int render_mode);
+
+void validate_delivery_ini(struct INIFILE *ini);
+
+int filter_repo_tags(char *repo, struct StrList *patterns);
/**
* Determine whether a release on-disk matches the release name in use
* @param ctx Delivery context
@@ -397,4 +428,6 @@ int delivery_dump_metadata(struct Delivery *ctx);
*/
int delivery_exists(struct Delivery *ctx);
+int delivery_overlay_packages_from_env(struct Delivery *ctx, const char *env_name);
+
#endif //STASIS_DELIVERY_H
diff --git a/include/docker.h b/include/docker.h
index ff8a8d5..7585d86 100644
--- a/include/docker.h
+++ b/include/docker.h
@@ -2,6 +2,8 @@
#ifndef STASIS_DOCKER_H
#define STASIS_DOCKER_H
+#include "core.h"
+
//! Flag to squelch output from docker_exec()
#define STASIS_DOCKER_QUIET 1 << 1
diff --git a/include/download.h b/include/download.h
index 058812e..0b6311e 100644
--- a/include/download.h
+++ b/include/download.h
@@ -2,6 +2,8 @@
#ifndef STASIS_DOWNLOAD_H
#define STASIS_DOWNLOAD_H
+#include <stdlib.h>
+#include <string.h>
#include <curl/curl.h>
size_t download_writer(void *fp, size_t size, size_t nmemb, void *stream);
diff --git a/include/envctl.h b/include/envctl.h
index c8ef357..659cae3 100644
--- a/include/envctl.h
+++ b/include/envctl.h
@@ -1,7 +1,9 @@
+//! @file envctl.h
#ifndef STASIS_ENVCTL_H
#define STASIS_ENVCTL_H
#include <stdlib.h>
+#include "core.h"
#define STASIS_ENVCTL_PASSTHRU 0
#define STASIS_ENVCTL_REQUIRED 1 << 1
diff --git a/include/github.h b/include/github.h
index cebeabf..f9b47a3 100644
--- a/include/github.h
+++ b/include/github.h
@@ -1,3 +1,4 @@
+//! @file github.h
#ifndef STASIS_GITHUB_H
#define STASIS_GITHUB_H
diff --git a/include/ini.h b/include/ini.h
index 3d0565b..557f157 100644
--- a/include/ini.h
+++ b/include/ini.h
@@ -5,6 +5,7 @@
#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>
+#include "template.h"
#define INI_WRITE_RAW 0 ///< Dump INI data. Contents are not modified.
#define INI_WRITE_PRESERVE 1 ///< Dump INI data. Template strings are
diff --git a/include/multiprocessing.h b/include/multiprocessing.h
new file mode 100644
index 0000000..5919462
--- /dev/null
+++ b/include/multiprocessing.h
@@ -0,0 +1,131 @@
+/// @file multiprocessing.h
+#ifndef STASIS_MULTIPROCESSING_H
+#define STASIS_MULTIPROCESSING_H
+
+#include "core.h"
+#include <signal.h>
+#include <sys/wait.h>
+#include <semaphore.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+struct MultiProcessingTask {
+ pid_t pid; ///< Program PID
+ pid_t parent_pid; ///< Program PID (parent process)
+ int status; ///< Child process exit status
+ int signaled_by; ///< Last signal received, if any
+ time_t _now; ///< Current time
+ time_t _seconds; ///< Time elapsed (used by MultiprocessingPool.status_interval)
+ char ident[255]; ///< Identity of the pool task
+ char *cmd; ///< Shell command(s) to be executed
+ size_t cmd_len; ///< Length of command string (for mmap/munmap)
+ char working_dir[PATH_MAX]; ///< Path to directory `cmd` should be executed in
+ char log_file[PATH_MAX]; ///< Full path to stdout/stderr log file
+ char parent_script[PATH_MAX]; ///< Path to temporary script executing the task
+ struct {
+ struct timespec t_start;
+ struct timespec t_stop;
+ } time_data; ///< Wall-time counters
+};
+
+struct MultiProcessingPool {
+ struct MultiProcessingTask *task; ///< Array of tasks to execute
+ size_t num_used; ///< Number of tasks populated in the task array
+ size_t num_alloc; ///< Number of tasks allocated by the task array
+ char ident[255]; ///< Identity of task pool
+ char log_root[PATH_MAX]; ///< Base directory to store stderr/stdout log files
+ int status_interval; ///< Report a pooled task is "running" every n seconds
+};
+
+/// Maximum number of multiprocessing tasks STASIS can execute
+#define MP_POOL_TASK_MAX 1000
+
+/// Value signifies a process is unused or finished executing
+#define MP_POOL_PID_UNUSED 0
+
+/// Option flags for mp_pool_join()
+#define MP_POOL_FAIL_FAST 1 << 1
+
+/**
+ * Create a multiprocessing pool
+ *
+ * ```c
+ * #include "multiprocessing.h"
+ * #include "utils.h" // for get_cpu_count()
+ *
+ * int main(int argc, char *argv[]) {
+ * struct MultiProcessingPool *mp;
+ * mp = mp_pool_init("mypool", "/tmp/mypool_logs");
+ * if (mp) {
+ * char *commands[] = {
+ * "/bin/echo hello world",
+ * "/bin/echo world hello",
+ * NULL
+ * }
+ * for (size_t i = 0; commands[i] != NULL); i++) {
+ * struct MultiProcessingTask *task;
+ * char task_name[100];
+ *
+ * sprintf(task_name, "mytask%zu", i);
+ * task = mp_task(mp, task_name, commands[i]);
+ * if (!task) {
+ * // handle task creation error
+ * }
+ * }
+ * if (mp_pool_join(mp, get_cpu_count(), MP_POOL_FAIL_FAST)) {
+ * // handle pool execution error
+ * }
+ * mp_pool_free(&mp);
+ * } else {
+ * // handle pool initialization error
+ * }
+ * }
+ * ```
+ *
+ * @param ident a name to identify the pool
+ * @param log_root the path to store program output
+ * @return pointer to initialized MultiProcessingPool
+ * @return NULL on error
+ */
+struct MultiProcessingPool *mp_pool_init(const char *ident, const char *log_root);
+
+/**
+ * Create a multiprocessing pool task
+ *
+ * @param pool a pointer to MultiProcessingPool
+ * @param ident a name to identify the task
+ * @param cmd a command to execute
+ * @return pointer to MultiProcessingTask structure
+ * @return NULL on error
+ */
+struct MultiProcessingTask *mp_pool_task(struct MultiProcessingPool *pool, const char *ident, char *working_dir, char *cmd);
+
+/**
+ * Execute all tasks in a pool
+ *
+ * @param pool a pointer to MultiProcessingPool
+ * @param jobs the number of processes to spawn at once (for serial execution use `1`)
+ * @param flags option to be OR'd (MP_POOL_FAIL_FAST)
+ * @return 0 on success
+ * @return >0 on failure
+ * @return <0 on error
+ */
+int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags);
+
+/**
+ * Show summary of pool tasks
+ *
+ * @param pool a pointer to MultiProcessingPool
+ */
+void mp_pool_show_summary(struct MultiProcessingPool *pool);
+
+/**
+ * Release resources allocated by mp_pool_init()
+ *
+ * @param a pointer to MultiProcessingPool
+ */
+void mp_pool_free(struct MultiProcessingPool **pool);
+
+
+#endif //STASIS_MULTIPROCESSING_H
diff --git a/include/package.h b/include/package.h
new file mode 100644
index 0000000..eff1874
--- /dev/null
+++ b/include/package.h
@@ -0,0 +1,30 @@
+#ifndef STASIS_PACKAGE_H
+#define STASIS_PACKAGE_H
+
+struct Package {
+ struct {
+ const char *name;
+ const char *version_spec;
+ const char *version;
+ } meta;
+ struct {
+ const char *uri;
+ unsigned handler;
+ } source;
+ struct {
+ struct Test *test;
+ size_t pass;
+ size_t fail;
+ size_t skip;
+ };
+ unsigned state;
+};
+
+struct Package *stasis_package_init(void);
+void stasis_package_set_name(struct Package *pkg, const char *name);
+void stasis_package_set_version(struct Package *pkg, const char *version);
+void stasis_package_set_version_spec(struct Package *pkg, const char *version_spec);
+void stasis_package_set_uri(struct Package *pkg, const char *uri);
+void stasis_package_set_handler(struct Package *pkg, unsigned handler);
+
+#endif //STASIS_PACKAGE_H
diff --git a/include/str.h b/include/str.h
index 4cf221d..7254225 100644
--- a/include/str.h
+++ b/include/str.h
@@ -9,6 +9,7 @@
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
+#include "relocation.h"
#include "core.h"
#define STASIS_SORT_ALPHA 1 << 0
diff --git a/include/strlist.h b/include/strlist.h
index dd22a0a..cdbfc01 100644
--- a/include/strlist.h
+++ b/include/strlist.h
@@ -4,10 +4,15 @@
*/
#ifndef STASIS_STRLIST_H
#define STASIS_STRLIST_H
+
+typedef int (ReaderFn)(size_t line, char **);
+
#include <stdlib.h>
+#include "core.h"
#include "utils.h"
#include "str.h"
+
struct StrList {
size_t num_alloc;
size_t num_inuse;
diff --git a/include/template_func_proto.h b/include/template_func_proto.h
index 7778a11..286ccfb 100644
--- a/include/template_func_proto.h
+++ b/include/template_func_proto.h
@@ -1,3 +1,4 @@
+//! @file template_func_proto.h
#ifndef TEMPLATE_FUNC_PROTO_H
#define TEMPLATE_FUNC_PROTO_H
@@ -7,5 +8,6 @@ int get_github_release_notes_tplfunc_entrypoint(void *frame, void *data_out);
int get_github_release_notes_auto_tplfunc_entrypoint(void *frame, void *data_out);
int get_junitxml_file_entrypoint(void *frame, void *data_out);
int get_basetemp_dir_entrypoint(void *frame, void *data_out);
+int tox_run_entrypoint(void *frame, void *data_out);
#endif //TEMPLATE_FUNC_PROTO_H \ No newline at end of file
diff --git a/include/utils.h b/include/utils.h
index a3d244a..4ade817 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -8,7 +8,12 @@
#include <unistd.h>
#include <limits.h>
#include <errno.h>
+#include "core.h"
+#include "copy.h"
#include "system.h"
+#include "strlist.h"
+#include "utils.h"
+#include "ini.h"
#if defined(STASIS_OS_WINDOWS)
#define PATH_ENV_VAR "path"
@@ -25,8 +30,6 @@
#define STASIS_XML_PRETTY_PRINT_PROG "xmllint"
#define STASIS_XML_PRETTY_PRINT_ARGS "--format"
-typedef int (ReaderFn)(size_t line, char **);
-
/**
* Change directory. Push path on directory stack.
*
@@ -365,4 +368,28 @@ long get_cpu_count();
*/
int mkdirs(const char *_path, mode_t mode);
+/**
+ * Return pointer to a (possible) version specifier
+ *
+ * ```c
+ * char s[] = "abc==1.2.3";
+ * char *spec_begin = find_version_spec(s);
+ * // spec_begin is "==1.2.3"
+ *
+ * char package_name[255];
+ * char s[] = "abc";
+ * char *spec_pos = find_version_spec(s);
+ * if (spec_pos) {
+ * strncpy(package_name, spec_pos - s);
+ * // use spec
+ * } else {
+ * // spec not found
+ * }
+ *
+ * @param str a pointer to a buffer containing a package spec (i.e. abc==1.2.3, abc>=1.2.3, abc)
+ * @return a pointer to the first occurrence of a version spec character
+ * @return NULL if not found
+ */
+char *find_version_spec(char *package_name);
+
#endif //STASIS_UTILS_H
diff --git a/include/wheel.h b/include/wheel.h
index 619e0f7..1a689e9 100644
--- a/include/wheel.h
+++ b/include/wheel.h
@@ -1,3 +1,4 @@
+//! @file wheel.h
#ifndef STASIS_WHEEL_H
#define STASIS_WHEEL_H
@@ -5,20 +6,31 @@
#include <string.h>
#include <stdio.h>
#include "str.h"
-
-#define WHEEL_MATCH_EXACT 0
-#define WHEEL_MATCH_ANY 1
+#define WHEEL_MATCH_EXACT 0 ///< Match when all patterns are present
+#define WHEEL_MATCH_ANY 1 ///< Match when any patterns are present
struct Wheel {
- char *distribution;
- char *version;
- char *build_tag;
- char *python_tag;
- char *abi_tag;
- char *platform_tag;
- char *path_name;
- char *file_name;
+ char *distribution; ///< Package name
+ char *version; ///< Package version
+ char *build_tag; ///< Package build tag (optional)
+ char *python_tag; ///< Package Python tag (pyXY)
+ char *abi_tag; ///< Package ABI tag (cpXY, abiX, none)
+ char *platform_tag; ///< Package platform tag (linux_x86_64, any)
+ char *path_name; ///< Path to package on-disk
+ char *file_name; ///< Name of package on-disk
};
-struct Wheel *get_wheel_file(const char *basepath, const char *name, char *to_match[], unsigned match_mode);
+/**
+ * Extract metadata from a Python Wheel file name
+ *
+ * @param basepath directory containing a wheel file
+ * @param name of wheel file
+ * @param to_match a NULL terminated array of patterns (i.e. platform, arch, version, etc)
+ * @param match_mode WHEEL_MATCH_EXACT
+ * @param match_mode WHEEL_MATCH ANY
+ * @return pointer to populated Wheel on success
+ * @return NULL on error
+ */
+struct Wheel *get_wheel_info(const char *basepath, const char *name, char *to_match[], unsigned match_mode);
+void wheel_free(struct Wheel **wheel);
#endif //STASIS_WHEEL_H