aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt28
-rw-r--r--README.md10
-rw-r--r--src/cli/stasis_indexer/include/helpers.h4
-rw-r--r--src/lib/core/copy.c6
-rw-r--r--src/lib/core/download.c6
-rw-r--r--src/lib/core/environment.c2
-rw-r--r--src/lib/core/include/conda.h2
-rw-r--r--src/lib/core/include/core.h8
-rw-r--r--src/lib/core/include/core_mem.h2
-rw-r--r--src/lib/core/include/core_message.h19
-rw-r--r--src/lib/core/include/multiprocessing.h4
-rw-r--r--src/lib/core/ini.c12
-rw-r--r--src/lib/core/junitxml.c4
-rw-r--r--src/lib/core/multiprocessing.c18
-rw-r--r--src/lib/core/str.c2
-rw-r--r--src/lib/core/strlist.c1
-rw-r--r--src/lib/core/template.c44
-rw-r--r--src/lib/core/wheel.c1
-rw-r--r--src/lib/delivery/delivery.c4
-rw-r--r--src/lib/delivery/delivery_artifactory.c37
-rw-r--r--src/lib/delivery/delivery_init.c8
-rw-r--r--src/lib/delivery/delivery_install.c4
-rw-r--r--src/lib/delivery/delivery_populate.c52
-rw-r--r--src/lib/delivery/delivery_postprocess.c26
-rw-r--r--tests/CMakeLists.txt8
-rw-r--r--tests/data/gbo.ini1
-rw-r--r--tests/data/gbo.yml1
-rw-r--r--tests/include/testing.h15
-rw-r--r--tests/test_artifactory.c9
-rw-r--r--tests/test_conda.c6
-rw-r--r--tests/test_copy.c2
-rw-r--r--tests/test_environment.c17
-rw-r--r--tests/test_recipe.c1
-rw-r--r--tests/test_system.c3
-rw-r--r--tests/test_template.c17
-rw-r--r--tests/test_utils.c6
36 files changed, 303 insertions, 87 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d21a553..8f5dfa9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,6 +7,13 @@ set(win_cflags /Wall)
set(CMAKE_C_STANDARD 99)
find_package(LibXml2)
find_package(CURL)
+
+option(ASAN OFF)
+if (ASAN)
+ add_compile_options(-fsanitize=address)
+ add_link_options(-fsanitize=address)
+endif()
+
link_libraries(CURL::libcurl)
link_libraries(LibXml2::LibXml2)
include_directories(${LIBXML2_INCLUDE_DIR})
@@ -16,6 +23,12 @@ if (FORTIFY_SOURCE)
set(nix_cflags ${nix_cflags} -O -D_FORTIFY_SOURCE=1)
endif ()
+# Toggle extremely verbose output
+option(DEBUG_MESSAGES OFF)
+if (DEBUG_MESSAGES)
+ set(nix_cflags ${nix_cflags} -DDEBUG)
+endif()
+
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
add_compile_options(${nix_cflags})
elseif (CMAKE_C_COMPILER_ID MATCHES "Clang")
@@ -23,6 +36,7 @@ elseif (CMAKE_C_COMPILER_ID MATCHES "Clang")
elseif (CMAKE_C_COMPILER_ID STREQUAL "MSVC")
add_compile_options(${win_cflags})
endif()
+message(CHECK_START "Compiler flags: ${nix_cflags}")
set(core_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/core/include)
set(delivery_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/delivery/include)
@@ -31,23 +45,17 @@ configure_file(${PROJECT_SOURCE_DIR}/include/config.h.in ${CMAKE_CURRENT_BINARY_
include_directories(${PROJECT_BINARY_DIR}/include)
add_subdirectory(src)
-# Toggle extremely verbose output
-option(BUILD_TESTING_DEBUG OFF)
-if (BUILD_TESTING_DEBUG)
- add_compile_options(-DDEBUG)
-endif()
-
# Toggle regression testing on/off
-option(BUILD_TESTING_RT ON)
+option(TESTS_RT ON)
# Toggle testing
-option(BUILD_TESTING OFF)
+option(TESTS OFF)
message(CHECK_START "Run unit tests")
-if (BUILD_TESTING)
+if (TESTS)
message(CHECK_PASS "yes")
enable_testing()
message(CHECK_START "Run regression tests")
- if (BUILD_TESTING_RT)
+ if (TESTS_RT)
message(CHECK_PASS "yes")
else()
message(CHECK_PASS "no")
diff --git a/README.md b/README.md
index eb6d885..14f7ddb 100644
--- a/README.md
+++ b/README.md
@@ -170,6 +170,16 @@ stasis mydelivery.ini
| --no-rewrite | n/a | Do not rewrite paths and URLs in output files |
| DELIVERY_FILE | n/a | STASIS delivery file |
+## Indexer Command Line Options
+
+| Long Option | Short Option | Purpose |
+|:-------------|:------------:|:----------------------------------------|
+| --help | -h | Display this usage statement |
+| --destdir | -d | Destination directory |
+| --verbose | -v | Increase output verbosity |
+| --unbuffered | -U | Disable line buffering |
+| --web | -w | Generate HTML indexes (requires pandoc) |
+
## Environment variables
| Name | Purpose |
diff --git a/src/cli/stasis_indexer/include/helpers.h b/src/cli/stasis_indexer/include/helpers.h
index d493f75..46705d2 100644
--- a/src/cli/stasis_indexer/include/helpers.h
+++ b/src/cli/stasis_indexer/include/helpers.h
@@ -5,12 +5,12 @@
#define ARRAY_COUNT_DYNAMIC(X, COUNTER) \
do { \
- for (COUNTER = 0; X && X[COUNTER] != NULL; COUNTER++) {} \
+ for ((COUNTER) = 0; (X) && (X)[COUNTER] != NULL; (COUNTER)++) {} \
} while(0)
#define ARRAY_COUNT_BY_STRUCT_MEMBER(X, MEMBER, COUNTER) \
do { \
- for (COUNTER = 0; X[COUNTER].MEMBER != NULL; COUNTER++) {} \
+ for ((COUNTER) = 0; (X)[COUNTER].MEMBER != NULL; (COUNTER)++) {} \
} while(0)
struct StrList *get_architectures(struct Delivery ctx[], size_t nelem);
diff --git a/src/lib/core/copy.c b/src/lib/core/copy.c
index 928bc40..25eede3 100644
--- a/src/lib/core/copy.c
+++ b/src/lib/core/copy.c
@@ -3,6 +3,7 @@
int copy2(const char *src, const char *dest, unsigned int op) {
struct stat src_stat, dnamest;
+ SYSDEBUG("Stat source file: %s", src);
if (lstat(src, &src_stat) < 0) {
perror(src);
return -1;
@@ -20,7 +21,9 @@ int copy2(const char *src, const char *dest, unsigned int op) {
*dname_endptr = '\0';
}
+ SYSDEBUG("Stat destination file: %s", dname);
stat(dname, &dnamest);
+
if (S_ISLNK(src_stat.st_mode)) {
char lpath[1024] = {0};
if (readlink(src, lpath, sizeof(lpath)) < 0) {
@@ -44,12 +47,14 @@ int copy2(const char *src, const char *dest, unsigned int op) {
} else if (S_ISREG(src_stat.st_mode)) {
char buf[STASIS_BUFSIZ] = {0};
size_t bytes_read;
+ SYSDEBUG("%s", "Opening source file for reading");
FILE *fp1 = fopen(src, "rb");
if (!fp1) {
perror(src);
return -1;
}
+ SYSDEBUG("%s", "Opening destination file for writing");
FILE *fp2 = fopen(dest, "w+b");
if (!fp2) {
perror(dest);
@@ -79,5 +84,6 @@ int copy2(const char *src, const char *dest, unsigned int op) {
errno = EOPNOTSUPP;
return -1;
}
+ SYSDEBUG("%s", "Data copied");
return 0;
}
diff --git a/src/lib/core/download.c b/src/lib/core/download.c
index f07a850..c3f8dca 100644
--- a/src/lib/core/download.c
+++ b/src/lib/core/download.c
@@ -3,6 +3,7 @@
//
#include "download.h"
+#include "core.h"
size_t download_writer(void *fp, size_t size, size_t nmemb, void *stream) {
size_t bytes = fwrite(fp, size, nmemb, (FILE *) stream);
@@ -10,7 +11,6 @@ size_t download_writer(void *fp, size_t size, size_t nmemb, void *stream) {
}
long download(char *url, const char *filename, char **errmsg) {
- extern char *VERSION;
long http_code = -1;
char user_agent[20];
sprintf(user_agent, "stasis/%s", VERSION);
@@ -37,7 +37,9 @@ long download(char *url, const char *filename, char **errmsg) {
}
curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT, timeout);
+ SYSDEBUG("curl_easy_perform(): \n\turl=%s\n\tfilename=%s\n\tuser agent=%s\n\ttimeout=%zu", url, filename, user_agent, timeout);
CURLcode curl_code = curl_easy_perform(c);
+ SYSDEBUG("curl status code: %d", curl_code);
if (curl_code != CURLE_OK) {
if (errmsg) {
strcpy(*errmsg, curl_easy_strerror(curl_code));
@@ -47,8 +49,8 @@ long download(char *url, const char *filename, char **errmsg) {
goto failed;
}
curl_easy_getinfo(c, CURLINFO_RESPONSE_CODE, &http_code);
-
failed:
+ SYSDEBUG("HTTP code: %li", http_code);
fclose(fp);
curl_easy_cleanup(c);
curl_global_cleanup();
diff --git a/src/lib/core/environment.c b/src/lib/core/environment.c
index cc72b8d..45fef2b 100644
--- a/src/lib/core/environment.c
+++ b/src/lib/core/environment.c
@@ -145,7 +145,7 @@ void runtime_export(RuntimeEnv *env, char **keys) {
RuntimeEnv *runtime_copy(char **env) {
RuntimeEnv *rt = NULL;
size_t env_count;
- for (env_count = 0; env[env_count] != NULL; env_count++) {};
+ for (env_count = 0; env[env_count] != NULL; env_count++) {}
rt = strlist_init();
for (size_t i = 0; i < env_count; i++) {
diff --git a/src/lib/core/include/conda.h b/src/lib/core/include/conda.h
index b8d0caa..8b4a0bd 100644
--- a/src/lib/core/include/conda.h
+++ b/src/lib/core/include/conda.h
@@ -24,7 +24,7 @@
#define PKG_INDEX_PROVIDES_E_MANAGER_RUNTIME (PKG_INDEX_PROVIDES_ERROR_MESSAGE_OFFSET + 3)
#define PKG_INDEX_PROVIDES_E_MANAGER_SIGNALED (PKG_INDEX_PROVIDES_ERROR_MESSAGE_OFFSET + 4)
#define PKG_INDEX_PROVIDES_E_MANAGER_EXEC (PKG_INDEX_PROVIDES_ERROR_MESSAGE_OFFSET + 5)
-#define PKG_INDEX_PROVIDES_FAILED(ECODE) (ECODE <= PKG_INDEX_PROVIDES_ERROR_MESSAGE_OFFSET)
+#define PKG_INDEX_PROVIDES_FAILED(ECODE) ((ECODE) <= PKG_INDEX_PROVIDES_ERROR_MESSAGE_OFFSET)
struct MicromambaInfo {
char *micromamba_prefix; //!< Path to write micromamba binary
diff --git a/src/lib/core/include/core.h b/src/lib/core/include/core.h
index 362ac8d..35a9506 100644
--- a/src/lib/core/include/core.h
+++ b/src/lib/core/include/core.h
@@ -11,10 +11,6 @@
#include <time.h>
#include <sys/statvfs.h>
-#define SYSERROR(MSG, ...) do { \
- fprintf(stderr, "%s:%s:%d:%s - ", path_basename(__FILE__), __FUNCTION__, __LINE__, (errno > 0) ? strerror(errno) : "info"); \
- fprintf(stderr, MSG LINE_SEP, __VA_ARGS__); \
-} while (0)
#define STASIS_BUFSIZ 8192
#define STASIS_NAME_MAX 255
#define STASIS_DIRSTACK_MAX 1024
@@ -23,10 +19,11 @@
#include "config.h"
#include "core_mem.h"
+#include "core_message.h"
#define COE_CHECK_ABORT(COND, MSG) \
do {\
- if (!globals.continue_on_error && COND) { \
+ if (!globals.continue_on_error && (COND)) { \
msg(STASIS_MSG_ERROR, MSG ": Aborting execution (--continue-on-error/-C is not enabled)\n"); \
exit(1); \
} \
@@ -76,7 +73,6 @@ extern const char *VERSION;
extern const char *AUTHOR;
extern const char *BANNER;
-
/**
* Free memory allocated in global configuration structure
*/
diff --git a/src/lib/core/include/core_mem.h b/src/lib/core/include/core_mem.h
index bd50e9d..362715f 100644
--- a/src/lib/core/include/core_mem.h
+++ b/src/lib/core/include/core_mem.h
@@ -5,7 +5,7 @@
#include "environment.h"
#include "strlist.h"
-#define guard_runtime_free(X) do { if (X) { runtime_free(X); X = NULL; } } while (0)
+#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 { \
diff --git a/src/lib/core/include/core_message.h b/src/lib/core/include/core_message.h
new file mode 100644
index 0000000..1ffa846
--- /dev/null
+++ b/src/lib/core/include/core_message.h
@@ -0,0 +1,19 @@
+
+#ifndef STASIS_CORE_MESSAGE_H
+#define STASIS_CORE_MESSAGE_H
+
+#define SYSERROR(MSG, ...) do { \
+ fprintf(stderr, "%s:%d:%s():%s - ", path_basename(__FILE__), __LINE__, __FUNCTION__, (errno > 0) ? strerror(errno) : "info"); \
+ fprintf(stderr, MSG LINE_SEP, __VA_ARGS__); \
+} while (0)
+
+#ifdef DEBUG
+#define SYSDEBUG(MSG, ...) do { \
+ fprintf(stderr, "DEBUG: %s:%d:%s(): ", path_basename(__FILE__), __LINE__, __FUNCTION__); \
+ fprintf(stderr, MSG LINE_SEP, __VA_ARGS__); \
+} while (0)
+#else
+#define SYSDEBUG(MSG, ...) do {} while (0)
+#endif
+
+#endif //STASIS_CORE_MESSAGE_H
diff --git a/src/lib/core/include/multiprocessing.h b/src/lib/core/include/multiprocessing.h
index ec7c1ad..ff674e9 100644
--- a/src/lib/core/include/multiprocessing.h
+++ b/src/lib/core/include/multiprocessing.h
@@ -16,7 +16,9 @@ struct MultiProcessingTask {
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)
+ time_t _seconds; ///< Time elapsed since status interval (used by MultiprocessingPool.status_interval)
+ time_t _startup; ///< Time elapsed since task started
+ long elapsed; ///< Total time elapsed in seconds
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)
diff --git a/src/lib/core/ini.c b/src/lib/core/ini.c
index 14f337d..4f449c6 100644
--- a/src/lib/core/ini.c
+++ b/src/lib/core/ini.c
@@ -490,18 +490,12 @@ char *unquote(char *s) {
void ini_free(struct INIFILE **ini) {
for (size_t section = 0; section < (*ini)->section_count; section++) {
-#ifdef DEBUG
- SYSERROR("freeing section: %s", (*ini)->section[section]->key);
-#endif
+ SYSDEBUG("freeing section: %s", (*ini)->section[section]->key);
for (size_t data = 0; data < (*ini)->section[section]->data_count; data++) {
if ((*ini)->section[section]->data[data]) {
-#ifdef DEBUG
- SYSERROR("freeing data key: %s", (*ini)->section[section]->data[data]->key);
-#endif
+ SYSDEBUG("freeing data key: %s", (*ini)->section[section]->data[data]->key);
guard_free((*ini)->section[section]->data[data]->key);
-#ifdef DEBUG
- SYSERROR("freeing data value: %s", (*ini)->section[section]->data[data]->value);
-#endif
+ SYSDEBUG("freeing data value: %s", (*ini)->section[section]->data[data]->value);
guard_free((*ini)->section[section]->data[data]->value);
guard_free((*ini)->section[section]->data[data]);
}
diff --git a/src/lib/core/junitxml.c b/src/lib/core/junitxml.c
index f747224..628f75f 100644
--- a/src/lib/core/junitxml.c
+++ b/src/lib/core/junitxml.c
@@ -8,6 +8,9 @@ static void testcase_result_state_free(struct JUNIT_Testcase **testcase) {
if (tc->tc_result_state_type == JUNIT_RESULT_STATE_FAILURE) {
guard_free(tc->result_state.failure->message);
guard_free(tc->result_state.failure);
+ } else if (tc->tc_result_state_type == JUNIT_RESULT_STATE_ERROR) {
+ guard_free(tc->result_state.error->message);
+ guard_free(tc->result_state.error);
} else if (tc->tc_result_state_type == JUNIT_RESULT_STATE_SKIPPED) {
guard_free(tc->result_state.skipped->message);
guard_free(tc->result_state.skipped);
@@ -31,6 +34,7 @@ void junitxml_testsuite_free(struct JUNIT_Testsuite **testsuite) {
for (size_t i = 0; i < suite->_tc_alloc; i++) {
testcase_free(&suite->testcase[i]);
}
+ guard_free(suite->testcase);
guard_free(suite);
}
diff --git a/src/lib/core/multiprocessing.c b/src/lib/core/multiprocessing.c
index 252bab9..0cf251e 100644
--- a/src/lib/core/multiprocessing.c
+++ b/src/lib/core/multiprocessing.c
@@ -78,6 +78,7 @@ int parent(struct MultiProcessingPool *pool, struct MultiProcessingTask *task, p
}
static int mp_task_fork(struct MultiProcessingPool *pool, struct MultiProcessingTask *task) {
+ SYSDEBUG("Preparing to fork() child task %s:%s", pool->ident, task->ident);
pid_t pid = fork();
int child_status = 0;
if (pid == -1) {
@@ -89,8 +90,10 @@ static int mp_task_fork(struct MultiProcessingPool *pool, struct MultiProcessing
}
struct MultiProcessingTask *mp_pool_task(struct MultiProcessingPool *pool, const char *ident, char *working_dir, char *cmd) {
+ SYSDEBUG("%s", "Finding next available slot");
struct MultiProcessingTask *slot = mp_pool_next_available(pool);
if (pool->num_used != pool->num_alloc) {
+ SYSDEBUG("Using slot %zu of %zu", pool->num_used, pool->num_alloc);
pool->num_used++;
} else {
fprintf(stderr, "Maximum number of tasks reached\n");
@@ -119,6 +122,7 @@ struct MultiProcessingTask *mp_pool_task(struct MultiProcessingPool *pool, const
// Create a temporary file to act as our intermediate command script
FILE *tp = NULL;
char *t_name = NULL;
+
t_name = xmkstemp(&tp, "w");
if (!t_name || !tp) {
return NULL;
@@ -135,11 +139,13 @@ struct MultiProcessingTask *mp_pool_task(struct MultiProcessingPool *pool, const
guard_free(t_name);
// Populate the script
+ SYSDEBUG("Generating runner script: %s", slot->parent_script);
fprintf(tp, "#!/bin/bash\n%s\n", cmd);
fflush(tp);
fclose(tp);
// Record the command(s)
+ SYSDEBUG("%s", "mmap() slot command");
slot->cmd_len = (strlen(cmd) * sizeof(*cmd)) + 1;
slot->cmd = mmap(NULL, slot->cmd_len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
memset(slot->cmd, 0, slot->cmd_len);
@@ -230,14 +236,17 @@ int mp_pool_kill(struct MultiProcessingPool *pool, int signum) {
exit(1);
}
// We are short-circuiting the normal flow, and the process is now dead, so mark it as such
+ SYSDEBUG("Marking slot %zu: UNUSED", i);
slot->pid = MP_POOL_PID_UNUSED;
}
}
}
if (!access(slot->log_file, F_OK)) {
+ SYSDEBUG("Removing log file: %s", slot->log_file);
remove(slot->log_file);
}
if (!access(slot->parent_script, F_OK)) {
+ SYSDEBUG("Removing runner script: %s", slot->parent_script);
remove(slot->parent_script);
}
}
@@ -261,6 +270,7 @@ int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) {
for (size_t i = lower_i; i < upper_i; i++) {
struct MultiProcessingTask *slot = &pool->task[i];
if (slot->status == MP_POOL_TASK_STATUS_INITIAL) {
+ slot->_startup = time(NULL);
if (mp_task_fork(pool, slot)) {
fprintf(stderr, "%s: mp_task_fork failed\n", slot->ident);
kill(0, SIGTERM);
@@ -271,6 +281,7 @@ int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) {
if (slot->pid == MP_POOL_PID_UNUSED) {
// Child is already used up, skip it
hang_check++;
+ SYSDEBUG("slot %zu: hang_check=%zu", i, hang_check);
if (hang_check >= pool->num_used) {
// If you join a pool that's already finished it will spin
// forever. This protects the program from entering an
@@ -331,7 +342,7 @@ int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) {
}
if (status >> 8 != 0 || (status & 0xff) != 0) {
- fprintf(stderr, "%s Task failed\n", progress);
+ fprintf(stderr, "%s Task failed after %lus\n", progress, slot->elapsed);
failures++;
if (flags & MP_POOL_FAIL_FAST && pool->num_used > 1) {
@@ -339,7 +350,7 @@ int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) {
return -2;
}
} else {
- printf("%s Task finished\n", progress);
+ printf("%s Task finished after %lus\n", progress, slot->elapsed);
}
// Clean up logs and scripts left behind by the task
@@ -365,9 +376,10 @@ int mp_pool_join(struct MultiProcessingPool *pool, size_t jobs, size_t flags) {
slot->_seconds = 0;
}
if (slot->_seconds == 0) {
- printf("[%s:%s] Task is running (pid: %d)\n", pool->ident, slot->ident, slot->parent_pid);
+ printf("[%s:%s] Task is running (pid: %d, elapsed: %lus)\n", pool->ident, slot->ident, slot->parent_pid, slot->elapsed);
}
}
+ slot->elapsed = time(NULL) - slot->_startup;
}
if (tasks_complete == pool->num_used) {
diff --git a/src/lib/core/str.c b/src/lib/core/str.c
index d774e72..6457afe 100644
--- a/src/lib/core/str.c
+++ b/src/lib/core/str.c
@@ -526,7 +526,7 @@ char *normalize_space(char *s) {
return NULL;
}
- if ((tmp = calloc(strlen(s) + 1, sizeof(char))) == NULL) {
+ if (!(tmp = strdup(s))) {
perror("could not allocate memory for temporary string");
return NULL;
}
diff --git a/src/lib/core/strlist.c b/src/lib/core/strlist.c
index 704cf9c..08f5893 100644
--- a/src/lib/core/strlist.c
+++ b/src/lib/core/strlist.c
@@ -260,6 +260,7 @@ void strlist_remove(struct StrList *pStrList, size_t index) {
return;
}
if (pStrList->data[index] != NULL) {
+ guard_free(pStrList->data[index]);
for (size_t i = index; i < count; i++) {
pStrList->data[i] = pStrList->data[i + 1];
}
diff --git a/src/lib/core/template.c b/src/lib/core/template.c
index 60ed91e..f3eab62 100644
--- a/src/lib/core/template.c
+++ b/src/lib/core/template.c
@@ -20,6 +20,7 @@ struct tplfunc_frame *tpl_pool_func[1024] = {0};
unsigned tpl_pool_func_used = 0;
extern void tpl_reset() {
+ SYSDEBUG("%s", "Resetting template engine");
tpl_free();
tpl_pool_used = 0;
tpl_pool_func_used = 0;
@@ -31,19 +32,23 @@ void tpl_register_func(char *key, void *tplfunc_ptr, int argc, void *data_in) {
frame->argc = argc;
frame->func = tplfunc_ptr;
frame->data_in = data_in;
+ SYSDEBUG("Registering function:\n\tkey=%s\n\targc=%d\n\tfunc=%p\n\tdata_in=%p", frame->key, frame->argc, frame->func, frame->data_in);
tpl_pool_func[tpl_pool_func_used] = frame;
tpl_pool_func_used++;
}
int tpl_key_exists(char *key) {
+ SYSDEBUG("Key '%s' exists?", key);
for (size_t i = 0; i < tpl_pool_used; i++) {
if (tpl_pool[i]->key) {
if (!strcmp(tpl_pool[i]->key, key)) {
+ SYSDEBUG("%s", "YES");
return true;
}
}
}
+ SYSDEBUG("%s", "NO");
return false;
}
@@ -51,6 +56,7 @@ void tpl_register(char *key, char **ptr) {
struct tpl_item *item = NULL;
int replacing = 0;
+ SYSDEBUG("Registering string:\n\tkey=%s\n\tptr=%s", key, *ptr ? *ptr : "NOT SET");
if (tpl_key_exists(key)) {
for (size_t i = 0; i < tpl_pool_used; i++) {
if (tpl_pool[i]->key) {
@@ -61,7 +67,9 @@ void tpl_register(char *key, char **ptr) {
}
}
replacing = 1;
+ SYSDEBUG("%s", "Item will be replaced");
} else {
+ SYSDEBUG("%s", "Creating new item");
item = calloc(1, sizeof(*item));
item->key = strdup(key);
}
@@ -73,6 +81,7 @@ void tpl_register(char *key, char **ptr) {
item->ptr = ptr;
if (!replacing) {
+ SYSDEBUG("Registered tpl_item at index %u:\n\tkey=%s\n\tptr=%s", tpl_pool_used, item->key, *item->ptr);
tpl_pool[tpl_pool_used] = item;
tpl_pool_used++;
}
@@ -83,27 +92,26 @@ void tpl_free() {
struct tpl_item *item = tpl_pool[i];
if (item) {
if (item->key) {
-#ifdef DEBUG
- SYSERROR("freeing template item key: %s", item->key);
-#endif
+ SYSDEBUG("freeing template item key: %s", item->key);
guard_free(item->key);
}
-#ifdef DEBUG
- SYSERROR("freeing template item: %p", item);
-#endif
+ SYSDEBUG("freeing template item: %p", item);
item->ptr = NULL;
}
guard_free(item);
}
for (unsigned i = 0; i < tpl_pool_func_used; i++) {
struct tplfunc_frame *item = tpl_pool_func[i];
+ SYSDEBUG("freeing template function key: %s", item->key);
guard_free(item->key);
+ SYSDEBUG("freeing template item: %p", item);
guard_free(item);
}
}
char *tpl_getval(char *key) {
char *result = NULL;
+ SYSDEBUG("Getting value of template string: %s", key);
for (size_t i = 0; i < tpl_pool_used; i++) {
if (tpl_pool[i]->key) {
if (!strcmp(tpl_pool[i]->key, key)) {
@@ -116,6 +124,7 @@ char *tpl_getval(char *key) {
}
struct tplfunc_frame *tpl_getfunc(char *key) {
+ SYSDEBUG("Getting function frame: %s", key);
struct tplfunc_frame *result = NULL;
for (size_t i = 0; i < tpl_pool_func_used; i++) {
if (tpl_pool_func[i]->key) {
@@ -131,9 +140,8 @@ struct tplfunc_frame *tpl_getfunc(char *key) {
static int grow(size_t z, size_t *output_bytes, char **output) {
if (z >= *output_bytes) {
size_t new_size = *output_bytes + z + 1;
-#ifdef DEBUG
- fprintf(stderr, "template output buffer new size: %zu\n", new_size);
-#endif
+ SYSDEBUG("template output buffer new size: %zu\n", new_size);
+
char *tmp = realloc(*output, new_size);
if (!tmp) {
perror("realloc failed");
@@ -178,6 +186,7 @@ char *tpl_render(char *str) {
}
// Read key name
+ SYSDEBUG("%s", "Reading key");
size_t key_len = 0;
while (isalnum(pos[off]) || pos[off] != '}') {
if (isspace(pos[off]) || isblank(pos[off])) {
@@ -189,6 +198,7 @@ char *tpl_render(char *str) {
key_len++;
off++;
}
+ SYSDEBUG("Key is %s", key);
char *type_stop = NULL;
type_stop = strchr(key, ':');
@@ -197,8 +207,10 @@ char *tpl_render(char *str) {
int do_func = 0;
if (type_stop) {
if (!strncmp(key, "env", type_stop - key)) {
+ SYSDEBUG("%s", "Will render as value of environment variable");
do_env = 1;
} else if (!strncmp(key, "func", type_stop - key)) {
+ SYSDEBUG("%s", "Will render as output from function");
do_func = 1;
}
}
@@ -207,6 +219,7 @@ char *tpl_render(char *str) {
b_close = strstr(&pos[off], "}}");
if (!b_close) {
fprintf(stderr, "error while templating '%s'\n\nunbalanced brace at position %zu\n", str, z);
+ guard_free(output);
return NULL;
} else {
// Jump past closing brace
@@ -259,12 +272,14 @@ char *tpl_render(char *str) {
fprintf(stderr, "%s returned non-zero status: %d\n", frame->key, func_status);
}
value = strdup(func_result ? func_result : "");
+ SYSDEBUG("Returned from function: %s (status: %d)\nData OUT\n--------\n'%s'", k, func_status, value);
guard_free(func_result);
}
GENERIC_ARRAY_FREE(params);
} else {
// Read replacement value
value = strdup(tpl_getval(key) ? tpl_getval(key) : "");
+ SYSDEBUG("Rendered:\nData\n----\n'%s'", value);
}
}
@@ -279,16 +294,11 @@ char *tpl_render(char *str) {
output[z] = 0;
}
-#ifdef DEBUG
- fprintf(stderr, "z=%zu, output_bytes=%zu\n", z, output_bytes);
-#endif
output[z] = pos[off];
z++;
}
-#ifdef DEBUG
- fprintf(stderr, "template output length: %zu\n", strlen(output));
- fprintf(stderr, "template output bytes: %zu\n", output_bytes);
-#endif
+ SYSDEBUG("template output length: %zu", strlen(output));
+ SYSDEBUG("template output bytes: %zu", output_bytes);
return output;
}
@@ -300,6 +310,7 @@ int tpl_render_to_file(char *str, const char *filename) {
}
// Open the destination file for writing
+ SYSDEBUG("Rendering to %s", filename);
FILE *fp = fopen(filename, "w+");
if (!fp) {
guard_free(result);
@@ -309,6 +320,7 @@ int tpl_render_to_file(char *str, const char *filename) {
// Write rendered string to file
fprintf(fp, "%s", result);
fclose(fp);
+ SYSDEBUG("%s", "Rendered successfully");
guard_free(result);
return 0;
diff --git a/src/lib/core/wheel.c b/src/lib/core/wheel.c
index d5d5ff0..32091cd 100644
--- a/src/lib/core/wheel.c
+++ b/src/lib/core/wheel.c
@@ -121,5 +121,6 @@ void wheel_free(struct Wheel **wheel) {
guard_free(w->python_tag);
guard_free(w->abi_tag);
guard_free(w->python_tag);
+ guard_free(w->platform_tag);
guard_free(w);
}
diff --git a/src/lib/delivery/delivery.c b/src/lib/delivery/delivery.c
index aa3e51a..41be64c 100644
--- a/src/lib/delivery/delivery.c
+++ b/src/lib/delivery/delivery.c
@@ -40,6 +40,7 @@ void delivery_free(struct Delivery *ctx) {
guard_free(ctx->info.build_name);
guard_free(ctx->info.build_number);
guard_free(ctx->info.release_name);
+ guard_free(ctx->info.time_info);
guard_free(ctx->conda.installer_baseurl);
guard_free(ctx->conda.installer_name);
guard_free(ctx->conda.installer_version);
@@ -50,8 +51,10 @@ void delivery_free(struct Delivery *ctx) {
guard_free(ctx->conda.tool_build_version);
guard_strlist_free(&ctx->conda.conda_packages);
guard_strlist_free(&ctx->conda.conda_packages_defer);
+ guard_strlist_free(&ctx->conda.conda_packages_purge);
guard_strlist_free(&ctx->conda.pip_packages);
guard_strlist_free(&ctx->conda.pip_packages_defer);
+ guard_strlist_free(&ctx->conda.pip_packages_purge);
guard_strlist_free(&ctx->conda.wheels_packages);
for (size_t i = 0; i < sizeof(ctx->tests) / sizeof(ctx->tests[0]); i++) {
@@ -62,6 +65,7 @@ void delivery_free(struct Delivery *ctx) {
guard_free(ctx->tests[i].repository_info_tag);
guard_strlist_free(&ctx->tests[i].repository_remove_tags);
guard_free(ctx->tests[i].script);
+ guard_free(ctx->tests[i].script_setup);
guard_free(ctx->tests[i].build_recipe);
// test-specific runtime variables
guard_runtime_free(ctx->tests[i].runtime.environ);
diff --git a/src/lib/delivery/delivery_artifactory.c b/src/lib/delivery/delivery_artifactory.c
index e979b9a..97db752 100644
--- a/src/lib/delivery/delivery_artifactory.c
+++ b/src/lib/delivery/delivery_artifactory.c
@@ -193,11 +193,41 @@ int delivery_series_sync(struct Delivery *ctx) {
return -1; // error
}
+ char *r_fmt = strdup(ctx->rules.release_fmt);
+ if (!r_fmt) {
+ SYSERROR("%s", "Unable to allocate bytes for release format string");
+ return -1;
+ }
+
+ // Replace revision formatters with wildcards
+ const char *to_wild[] = {"%r", "%R"};
+ for (size_t i = 0; i < sizeof(to_wild) / sizeof(*to_wild); i++) {
+ const char *formatter = to_wild[i];
+ if (replace_text(r_fmt, formatter, "*", 0) < 0) {
+ SYSERROR("Failed to replace '%s' in delivery format string", formatter);
+ return -1;
+ }
+ }
+
+ char *release_pattern = NULL;
+ if (delivery_format_str(ctx, &release_pattern, r_fmt) < 0) {
+ SYSERROR("Unable to render delivery format string: %s", r_fmt);
+ guard_free(r_fmt);
+ return -1;
+ }
+ guard_free(r_fmt);
+
char *remote_dir = NULL;
- if (asprintf(&remote_dir, "%s/%s/%s/(*)", globals.jfrog.repo, ctx->meta.mission, ctx->info.build_name) < 0) {
+ if (asprintf(&remote_dir, "%s/%s/%s/(*/*%s*)",
+ globals.jfrog.repo,
+ ctx->meta.mission,
+ ctx->info.build_name,
+ release_pattern) < 0) {
SYSERROR("%s", "Unable to allocate bytes for remote directory path");
+ guard_free(release_pattern);
return -1;
}
+ guard_free(release_pattern);
char *dest_dir = NULL;
if (asprintf(&dest_dir, "%s/{1}", ctx->storage.output_dir) < 0) {
@@ -205,5 +235,8 @@ int delivery_series_sync(struct Delivery *ctx) {
return -1;
}
- return jfrog_cli_rt_download(&ctx->deploy.jfrog_auth, &dl, remote_dir, dest_dir);
+ int status = jfrog_cli_rt_download(&ctx->deploy.jfrog_auth, &dl, remote_dir, dest_dir);
+ guard_free(dest_dir);
+ guard_free(remote_dir);
+ return status;
}
diff --git a/src/lib/delivery/delivery_init.c b/src/lib/delivery/delivery_init.c
index 2fced03..fe60075 100644
--- a/src/lib/delivery/delivery_init.c
+++ b/src/lib/delivery/delivery_init.c
@@ -296,10 +296,12 @@ int bootstrap_build_info(struct Delivery *ctx) {
ctx->info.build_name = strdup(local.info.build_name);
ctx->info.build_number = strdup(local.info.build_number);
ctx->info.release_name = strdup(local.info.release_name);
- ctx->info.time_info = malloc(sizeof(*ctx->info.time_info));
if (!ctx->info.time_info) {
- SYSERROR("Unable to allocate %zu bytes for tm struct: %s", sizeof(*local.info.time_info), strerror(errno));
- return -1;
+ ctx->info.time_info = malloc(sizeof(*ctx->info.time_info));
+ if (!ctx->info.time_info) {
+ SYSERROR("Unable to allocate %zu bytes for tm struct: %s", sizeof(*local.info.time_info), strerror(errno));
+ return -1;
+ }
}
memcpy(ctx->info.time_info, local.info.time_info, sizeof(*local.info.time_info));
ctx->info.time_now = local.info.time_now;
diff --git a/src/lib/delivery/delivery_install.c b/src/lib/delivery/delivery_install.c
index d3aab01..15ad7e0 100644
--- a/src/lib/delivery/delivery_install.c
+++ b/src/lib/delivery/delivery_install.c
@@ -128,7 +128,7 @@ int delivery_purge_packages(struct Delivery *ctx, const char *env_name, int use_
char package_manager[100] = {0};
typedef int (fnptr)(const char *);
- const char *current_env = conda_get_active_environment();
+ char *current_env = conda_get_active_environment();
if (current_env) {
conda_activate(ctx->storage.conda_install_prefix, env_name);
}
@@ -171,10 +171,12 @@ int delivery_purge_packages(struct Delivery *ctx, const char *env_name, int use_
status = 1;
break;
}
+ guard_free(command);
}
if (current_env) {
conda_activate(ctx->storage.conda_install_prefix, current_env);
+ guard_free(current_env);
}
return status;
diff --git a/src/lib/delivery/delivery_populate.c b/src/lib/delivery/delivery_populate.c
index e9aea89..f242328 100644
--- a/src/lib/delivery/delivery_populate.c
+++ b/src/lib/delivery/delivery_populate.c
@@ -30,11 +30,21 @@ int populate_info(struct Delivery *ctx) {
if (!ctx->info.time_str_epoch) {
// Record timestamp used for release
time(&ctx->info.time_now);
- ctx->info.time_info = localtime(&ctx->info.time_now);
+ if (!ctx->info.time_info) {
+ ctx->info.time_info = malloc(sizeof(*ctx->info.time_info));
+ if (!ctx->info.time_info) {
+ msg(STASIS_MSG_ERROR, "%s: Unable to allocate memory for time_info\n", strerror(errno));
+ return -1;
+ }
+ if (!localtime_r(&ctx->info.time_now, ctx->info.time_info)) {
+ msg(STASIS_MSG_ERROR, "%s: localtime_r failed\n", strerror(errno));
+ return -1;
+ }
+ }
ctx->info.time_str_epoch = calloc(STASIS_TIME_STR_MAX, sizeof(*ctx->info.time_str_epoch));
if (!ctx->info.time_str_epoch) {
- msg(STASIS_MSG_ERROR, "Unable to allocate memory for Unix epoch string\n");
+ msg(STASIS_MSG_ERROR, "%s: Unable to allocate memory for Unix epoch string\n", strerror(errno));
return -1;
}
snprintf(ctx->info.time_str_epoch, STASIS_TIME_STR_MAX - 1, "%li", ctx->info.time_now);
@@ -59,16 +69,54 @@ int populate_delivery_cfg(struct Delivery *ctx, int render_mode) {
if (!globals.always_update_base_environment) {
globals.always_update_base_environment = ini_getval_bool(cfg, "default", "always_update_base_environment", render_mode, &err);
}
+ if (globals.conda_install_prefix) {
+ guard_free(globals.conda_install_prefix);
+ }
globals.conda_install_prefix = ini_getval_str(cfg, "default", "conda_install_prefix", render_mode, &err);
+
+ if (globals.conda_packages) {
+ guard_strlist_free(&globals.conda_packages);
+ }
globals.conda_packages = ini_getval_strlist(cfg, "default", "conda_packages", LINE_SEP, render_mode, &err);
+
+ if (globals.pip_packages) {
+ guard_strlist_free(&globals.pip_packages);
+ }
globals.pip_packages = ini_getval_strlist(cfg, "default", "pip_packages", LINE_SEP, render_mode, &err);
+ if (globals.jfrog.jfrog_artifactory_base_url) {
+ guard_free(globals.jfrog.jfrog_artifactory_base_url);
+ }
globals.jfrog.jfrog_artifactory_base_url = ini_getval_str(cfg, "jfrog_cli_download", "url", render_mode, &err);
+
+ if (globals.jfrog.jfrog_artifactory_product) {
+ guard_free(globals.jfrog.jfrog_artifactory_product);
+ }
globals.jfrog.jfrog_artifactory_product = ini_getval_str(cfg, "jfrog_cli_download", "product", render_mode, &err);
+
+ if (globals.jfrog.cli_major_ver) {
+ guard_free(globals.jfrog.cli_major_ver);
+ }
globals.jfrog.cli_major_ver = ini_getval_str(cfg, "jfrog_cli_download", "version_series", render_mode, &err);
+
+ if (globals.jfrog.version) {
+ guard_free(globals.jfrog.version);
+ }
globals.jfrog.version = ini_getval_str(cfg, "jfrog_cli_download", "version", render_mode, &err);
+
+ if (globals.jfrog.remote_filename) {
+ guard_free(globals.jfrog.remote_filename);
+ }
globals.jfrog.remote_filename = ini_getval_str(cfg, "jfrog_cli_download", "filename", render_mode, &err);
+
+ if (globals.jfrog.url) {
+ guard_free(globals.jfrog.url);
+ }
globals.jfrog.url = ini_getval_str(cfg, "deploy:artifactory", "url", render_mode, &err);
+
+ if (globals.jfrog.repo) {
+ guard_free(globals.jfrog.repo);
+ }
globals.jfrog.repo = ini_getval_str(cfg, "deploy:artifactory", "repo", render_mode, &err);
return 0;
diff --git a/src/lib/delivery/delivery_postprocess.c b/src/lib/delivery/delivery_postprocess.c
index 40ac43f..b43e247 100644
--- a/src/lib/delivery/delivery_postprocess.c
+++ b/src/lib/delivery/delivery_postprocess.c
@@ -66,7 +66,9 @@ void delivery_rewrite_spec(struct Delivery *ctx, char *filename, unsigned stage)
FILE *tp = NULL;
if (stage == DELIVERY_REWRITE_SPEC_STAGE_1) {
+ SYSDEBUG("%s", "Entering stage 1");
header = delivery_get_release_header(ctx);
+ SYSDEBUG("Release header:\n%s", header);
if (!header) {
msg(STASIS_MSG_ERROR, "failed to generate release header string\n", filename);
exit(1);
@@ -76,6 +78,7 @@ void delivery_rewrite_spec(struct Delivery *ctx, char *filename, unsigned stage)
msg(STASIS_MSG_ERROR, "%s: unable to create temporary file\n", strerror(errno));
exit(1);
}
+ SYSDEBUG("Writing header to temporary file: %s", tempfile);
fprintf(tp, "%s", header);
// Read the original file
@@ -88,19 +91,22 @@ void delivery_rewrite_spec(struct Delivery *ctx, char *filename, unsigned stage)
// Write temporary data
for (size_t i = 0; contents[i] != NULL; i++) {
if (startswith(contents[i], "channels:")) {
- // Allow for additional conda channel injection
if (ctx->conda.conda_packages_defer && strlist_count(ctx->conda.conda_packages_defer)) {
+ // Allow for additional conda channel injection
+ SYSDEBUG("Appending conda channel template on line %zu", i);
fprintf(tp, "%s - @CONDA_CHANNEL@\n", contents[i]);
continue;
}
} else if (strstr(contents[i], "- pip:")) {
if (ctx->conda.pip_packages_defer && strlist_count(ctx->conda.pip_packages_defer)) {
// Allow for additional pip argument injection
+ SYSDEBUG("Appending pip argument template on line %zu", i);
fprintf(tp, "%s - @PIP_ARGUMENTS@\n", contents[i]);
continue;
}
} else if (startswith(contents[i], "prefix:")) {
// Remove the prefix key
+ SYSDEBUG("Removing prefix key on line %zu", i);
if (strstr(contents[i], "/") || strstr(contents[i], "\\")) {
// path is on the same line as the key
continue;
@@ -118,38 +124,49 @@ void delivery_rewrite_spec(struct Delivery *ctx, char *filename, unsigned stage)
guard_free(header);
fflush(tp);
fclose(tp);
+ SYSDEBUG("Done writing temporary file: %s", tempfile);
// Replace the original file with our temporary data
if (copy2(tempfile, filename, CT_PERM) < 0) {
fprintf(stderr, "%s: could not rename '%s' to '%s'\n", strerror(errno), tempfile, filename);
exit(1);
}
+ SYSDEBUG("Removing file: %s", tempfile);
remove(tempfile);
guard_free(tempfile);
} else if (globals.enable_rewrite_spec_stage_2 && stage == DELIVERY_REWRITE_SPEC_STAGE_2) {
+ SYSDEBUG("%s", "Entering stage 2");
char output[PATH_MAX] = {0};
// Replace "local" channel with the staging URL
if (ctx->storage.conda_staging_url) {
+ SYSDEBUG("%s", "Will replace conda channel with staging area url");
file_replace_text(filename, "@CONDA_CHANNEL@", ctx->storage.conda_staging_url, 0);
} else if (globals.jfrog.repo) {
+ SYSDEBUG("%s", "Will replace conda channel with artifactory repo packages/conda url");
sprintf(output, "%s/%s/%s/%s/packages/conda", globals.jfrog.url, globals.jfrog.repo, ctx->meta.mission, ctx->info.build_name);
file_replace_text(filename, "@CONDA_CHANNEL@", output, 0);
} else {
+ SYSDEBUG("%s", "Will replace conda channel with local conda artifact directory");
msg(STASIS_MSG_WARN, "conda_staging_dir is not configured. Using fallback: '%s'\n", ctx->storage.conda_artifact_dir);
file_replace_text(filename, "@CONDA_CHANNEL@", ctx->storage.conda_artifact_dir, 0);
}
if (ctx->storage.wheel_staging_url) {
+ SYSDEBUG("%s", "Will replace pip arguments with wheel staging url");
+ sprintf(output, "--extra-index-url %s/%s/%s/packages/wheels", ctx->storage.wheel_staging_url, ctx->meta.mission, ctx->info.build_name);
file_replace_text(filename, "@PIP_ARGUMENTS@", ctx->storage.wheel_staging_url, 0);
} else if (globals.enable_artifactory && globals.jfrog.url && globals.jfrog.repo) {
+ SYSDEBUG("%s", "Will replace pip arguments with artifactory repo packages/wheel url");
sprintf(output, "--extra-index-url %s/%s/%s/%s/packages/wheels", globals.jfrog.url, globals.jfrog.repo, ctx->meta.mission, ctx->info.build_name);
file_replace_text(filename, "@PIP_ARGUMENTS@", output, 0);
} else {
+ SYSDEBUG("%s", "Will replace pip arguments with local wheel artifact directory");
msg(STASIS_MSG_WARN, "wheel_staging_dir is not configured. Using fallback: '%s'\n", ctx->storage.wheel_artifact_dir);
sprintf(output, "--extra-index-url file://%s", ctx->storage.wheel_artifact_dir);
file_replace_text(filename, "@PIP_ARGUMENTS@", output, 0);
}
}
+ SYSDEBUG("%s", "Rewriting finished");
}
int delivery_copy_conda_artifacts(struct Delivery *ctx) {
@@ -201,6 +218,7 @@ int delivery_index_wheel_artifacts(struct Delivery *ctx) {
// pip install --extra-index-url
char top_index[PATH_MAX] = {0};
sprintf(top_index, "%s/index.html", ctx->storage.wheel_artifact_dir);
+ SYSDEBUG("Opening top-level index for writing: %s", top_index);
FILE *top_fp = fopen(top_index, "w+");
if (!top_fp) {
closedir(dp);
@@ -215,6 +233,7 @@ int delivery_index_wheel_artifacts(struct Delivery *ctx) {
char bottom_index[PATH_MAX * 2] = {0};
sprintf(bottom_index, "%s/%s/index.html", ctx->storage.wheel_artifact_dir, rec->d_name);
+ SYSDEBUG("Opening bottom-level for writing: %s", bottom_index);
FILE *bottom_fp = fopen(bottom_index, "w+");
if (!bottom_fp) {
closedir(dp);
@@ -225,6 +244,7 @@ int delivery_index_wheel_artifacts(struct Delivery *ctx) {
printf("+ %s\n", rec->d_name);
}
// Add record to top level index
+ SYSDEBUG("Appending top-level link for %s", rec->d_name);
fprintf(top_fp, "<a href=\"%s/\">%s</a><br/>\n", rec->d_name, rec->d_name);
char dpath[PATH_MAX * 2] = {0};
@@ -238,7 +258,7 @@ int delivery_index_wheel_artifacts(struct Delivery *ctx) {
}
for (size_t i = 0; i < strlist_count(packages); i++) {
- char *package = strlist_item(packages, i);
+ char *package = path_basename(strlist_item(packages, i));
if (!endswith(package, ".whl")) {
continue;
}
@@ -246,6 +266,7 @@ int delivery_index_wheel_artifacts(struct Delivery *ctx) {
printf("`- %s\n", package);
}
// Write record to bottom level index
+ SYSDEBUG("Appending bottom-level link for %s", package);
fprintf(bottom_fp, "<a href=\"%s\">%s</a><br/>\n", package, package);
}
fclose(bottom_fp);
@@ -254,5 +275,6 @@ int delivery_index_wheel_artifacts(struct Delivery *ctx) {
}
closedir(dp);
fclose(top_fp);
+ SYSDEBUG("%s", "Wheel indexing complete");
return 0;
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index bcc05ce..2b09e9e 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,9 +1,9 @@
find_program(BASH_PROGRAM bash)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/tests)
set(CTEST_BINARY_DIRECTORY ${PROJECT_BINARY_DIR}/tests)
-set(nix_gnu_cflags -Wno-format-truncation -Wno-error -Wno-unused-parameter -Wno-unused-result -Wno-discarded-qualifiers)
-set(nix_clang_cflags -Wno-format-truncation -Wno-unused-parameter -Wno-unused-result -Wno-incompatible-pointer-types-discards-qualifiers)
-set(win_msvc_cflags /Wall)
+set(nix_gnu_cflags ${CMAKE_C_FLAGS} -Wno-format-truncation -Wno-error -Wno-unused-parameter -Wno-unused-result -Wno-discarded-qualifiers)
+set(nix_clang_cflags ${CMAKE_C_FLAGS} -Wno-format-truncation -Wno-unused-parameter -Wno-unused-result -Wno-incompatible-pointer-types-discards-qualifiers)
+set(win_msvc_cflags ${CMAKE_C_FLAGS} /Wall)
file(GLOB source_files "test_*.c")
file(GLOB rt_files "rt_*.sh")
@@ -12,7 +12,7 @@ set(ext_pattern "(^.*/|\\.[^.]*$)")
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
-if (BASH_PROGRAM AND BUILD_TESTING_RT)
+if (BASH_PROGRAM AND TESTS_RT)
foreach(rt_file ${rt_files})
file(REAL_PATH ${rt_file} rt_name)
string(REGEX REPLACE ${ext_pattern} "" rt_name ${rt_file})
diff --git a/tests/data/gbo.ini b/tests/data/gbo.ini
index 609b8f3..3ee6481 100644
--- a/tests/data/gbo.ini
+++ b/tests/data/gbo.ini
@@ -17,6 +17,7 @@ installer_baseurl = https://github.com/conda-forge/miniforge/releases/download/{
;conda_packages =
pip_packages =
firewatch==0.0.4
+ gwcs==0.22.1
tweakwcs==0.8.8
diff --git a/tests/data/gbo.yml b/tests/data/gbo.yml
index 3ab97a7..929f351 100644
--- a/tests/data/gbo.yml
+++ b/tests/data/gbo.yml
@@ -6,4 +6,5 @@ dependencies:
- setuptools
- pip:
- firewatch==0.0.3
+ - gwcs==0.22.1
- tweakwcs==0.8.7 \ No newline at end of file
diff --git a/tests/include/testing.h b/tests/include/testing.h
index 4c97bf2..ab24115 100644
--- a/tests/include/testing.h
+++ b/tests/include/testing.h
@@ -92,9 +92,10 @@ inline char *stasis_testing_read_ascii(const char *filename) {
return NULL;
}
- char *result;
+ char *result = NULL;
result = calloc(st.st_size + 1, sizeof(*result));
if (fread(result, sizeof(*result), st.st_size, fp) < 1) {
+ guard_free(result);
perror(filename);
fclose(fp);
return NULL;
@@ -211,7 +212,7 @@ inline void stasis_testing_teardown_workspace() {
.lineno = __LINE__, \
.status = (COND), \
.msg_assertion = "ASSERT(" #COND ")", \
- .msg_reason = REASON } ); \
+ .msg_reason = (REASON) } ); \
} while (0)
#define STASIS_ASSERT_FATAL(COND, REASON) do { \
@@ -221,7 +222,7 @@ inline void stasis_testing_teardown_workspace() {
.lineno = __LINE__, \
.status = (COND), \
.msg_assertion = "ASSERT FATAL (" #COND ")", \
- .msg_reason = REASON } \
+ .msg_reason = (REASON) } \
); \
if (stasis_test_results[stasis_test_results_i ? stasis_test_results_i - 1 : stasis_test_results_i].status == false) {\
exit(STASIS_TEST_SUITE_FATAL); \
@@ -236,7 +237,7 @@ inline void stasis_testing_teardown_workspace() {
.status = true, \
.skip = (COND), \
.msg_assertion = "SKIP (" #COND ")", \
- .msg_reason = REASON } \
+ .msg_reason = (REASON) } \
); \
if (stasis_test_results[stasis_test_results_i ? stasis_test_results_i - 1 : stasis_test_results_i].skip == true) {\
return; \
@@ -244,9 +245,9 @@ inline void stasis_testing_teardown_workspace() {
} while (0)
#define STASIS_TEST_RUN(X) do { \
- for (size_t i = 0; i < sizeof(X) / sizeof(*X); i++) { \
- if (X[i]) { \
- X[i](); \
+ for (size_t i = 0; i < sizeof(X) / sizeof(*(X)); i++) { \
+ if ((X)[i]) { \
+ (X)[i](); \
} \
} \
} while (0)
diff --git a/tests/test_artifactory.c b/tests/test_artifactory.c
index 2c732fa..4af7eec 100644
--- a/tests/test_artifactory.c
+++ b/tests/test_artifactory.c
@@ -2,9 +2,7 @@
#include "artifactory.h"
#include "delivery.h"
-// Import private functions from core
-extern int delivery_init_platform(struct Delivery *ctx);
-extern int populate_delivery_cfg(struct Delivery *ctx, int render_mode);
+
struct JFRT_Auth gauth;
struct JFRT_Auth gnoauth;
@@ -73,11 +71,12 @@ int main(int argc, char *argv[]) {
memset(&gnoauth, 0, sizeof(gnoauth));
memset(&ctx, 0, sizeof(ctx));
- const char *basedir = realpath(".", NULL);
+ char *basedir = realpath(".", NULL);
const char *ws = "workspace";
mkdir(ws, 0755);
if (pushd(ws)) {
SYSERROR("failed to change directory to %s", ws);
+ guard_free(basedir);
STASIS_ASSERT_FATAL(true, "workspace creation failed");
}
@@ -107,6 +106,7 @@ int main(int argc, char *argv[]) {
ctx._stasis_ini_fp.cfg = ini_open(cfg_path);
if (!ctx._stasis_ini_fp.cfg) {
SYSERROR("%s: configuration is invalid", cfg_path);
+ guard_free(basedir);
return STASIS_TEST_SUITE_SKIP;
}
delivery_init_platform(&ctx);
@@ -118,6 +118,7 @@ int main(int argc, char *argv[]) {
SYSERROR("%s", "Not configured to test Artifactory. Skipping.");
return STASIS_TEST_SUITE_SKIP;
}
+ guard_free(basedir);
STASIS_TEST_FUNC *tests[] = {
test_jfrog_cli_rt_ping,
diff --git a/tests/test_conda.c b/tests/test_conda.c
index 63a2781..81f593f 100644
--- a/tests/test_conda.c
+++ b/tests/test_conda.c
@@ -43,6 +43,8 @@ void test_conda_installation() {
delivery_get_conda_installer_url(&ctx, install_url);
delivery_get_conda_installer(&ctx, install_url);
delivery_install_conda(ctx.conda.installer_path, ctx.storage.conda_install_prefix);
+
+ guard_free(install_url);
STASIS_ASSERT_FATAL(access(ctx.storage.conda_install_prefix, F_OK) == 0, "conda was not installed correctly");
STASIS_ASSERT_FATAL(conda_activate(ctx.storage.conda_install_prefix, "base") == 0, "unable to activate base environment");
STASIS_ASSERT_FATAL(conda_exec("info") == 0, "conda was not installed correctly");
@@ -155,7 +157,9 @@ void test_pip_index_provides() {
void test_conda_get_active_environment() {
conda_activate(ctx.storage.conda_install_prefix, "base");
- STASIS_ASSERT(strcmp(conda_get_active_environment(), "base") == 0, "base environment not active");
+ char *active_env = conda_get_active_environment();
+ STASIS_ASSERT(strcmp(active_env, "base") == 0, "base environment not active");
+ guard_free(active_env);
}
void test_conda_provides() {
diff --git a/tests/test_copy.c b/tests/test_copy.c
index 14310e4..b37b1d3 100644
--- a/tests/test_copy.c
+++ b/tests/test_copy.c
@@ -18,7 +18,7 @@ void test_copy() {
for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) {
struct stat st_a, st_b;
struct testcase *test = &tc[i];
- char *mock_data = malloc(test->expect_size * sizeof(*mock_data));
+ char *mock_data = malloc(test->expect_size + 1 * sizeof(*mock_data));
memset(mock_data, 'A', test->expect_size);
mock_data[test->expect_size] = '\0';
stasis_testing_write_ascii(test->in_file, mock_data);
diff --git a/tests/test_environment.c b/tests/test_environment.c
index 3418800..43c3672 100644
--- a/tests/test_environment.c
+++ b/tests/test_environment.c
@@ -1,6 +1,6 @@
#include "testing.h"
-extern char **environ;
+
void test_runtime_copy() {
RuntimeEnv *env = runtime_copy(environ);
@@ -27,11 +27,11 @@ void test_runtime_copy_empty() {
void test_runtime() {
RuntimeEnv *env = runtime_copy(environ);
runtime_set(env, "CUSTOM_KEY", "Very custom");
- ssize_t idx = -1;
+ ssize_t idx;
STASIS_ASSERT((idx = runtime_contains(env, "CUSTOM_KEY")) >= 0, "CUSTOM_KEY should exist in object");
STASIS_ASSERT(strcmp(strlist_item(env, idx), "CUSTOM_KEY=Very custom") == 0, "Incorrect index returned by runtime_contains");
- const char *custom_value = runtime_get(env, "CUSTOM_KEY");
+ char *custom_value = runtime_get(env, "CUSTOM_KEY");
STASIS_ASSERT_FATAL(custom_value != NULL, "CUSTOM_KEY should not be NULL");
STASIS_ASSERT(strcmp(custom_value, "Very custom") == 0, "CUSTOM_KEY has incorrect data");
STASIS_ASSERT(strstr_array(environ, "CUSTOM_KEY") == NULL, "CUSTOM_KEY should not exist in the global environment");
@@ -44,6 +44,7 @@ void test_runtime() {
STASIS_ASSERT(setenv("CUSTOM_KEY", "modified", 1) == 0, "modifying global CUSTOM_KEY failed");
global_custom_value = getenv("CUSTOM_KEY");
STASIS_ASSERT(strcmp(global_custom_value, custom_value) != 0, "local and global CUSTOM_KEY variable are supposed to be different");
+ guard_free(custom_value);
runtime_replace(&env, environ);
runtime_apply(env);
@@ -53,13 +54,19 @@ void test_runtime() {
STASIS_ASSERT_FATAL(custom_value != NULL, "CUSTOM_KEY must exist in local environment after calling runtime_replace()");
STASIS_ASSERT_FATAL(global_custom_value != NULL, "CUSTOM_KEY must exist in global environment after calling runtime_replace()");
STASIS_ASSERT(strcmp(global_custom_value, custom_value) == 0, "local and global CUSTOM_KEY variable are supposed to be identical");
+ guard_free(custom_value);
char output_truth[BUFSIZ] = {0};
- sprintf(output_truth, "Your PATH is '%s'.", runtime_get(env, "PATH"));
- const char *output_expanded = runtime_expand_var(env, "Your PATH is '${PATH}'.");
+ char *your_path = runtime_get(env, "PATH");
+ sprintf(output_truth, "Your PATH is '%s'.", your_path);
+ guard_free(your_path);
+
+ char *output_expanded = runtime_expand_var(env, "Your PATH is '${PATH}'.");
STASIS_ASSERT(output_expanded != NULL, "expansion of PATH should not fail");
STASIS_ASSERT(strcmp(output_expanded, output_truth) == 0, "the expansion, and the expected result should be identical");
+ guard_free(output_expanded);
+ guard_runtime_free(env);
// TODO: runtime_export()
// requires dumping stdout to a file and comparing it with the current environment array
}
diff --git a/tests/test_recipe.c b/tests/test_recipe.c
index 531b3b4..fc7cc78 100644
--- a/tests/test_recipe.c
+++ b/tests/test_recipe.c
@@ -85,6 +85,7 @@ void test_recipe_clone() {
// Verify the result path does not exist
STASIS_ASSERT(result_path && access(result_path, F_OK) != 0, "result path should not exist");
}
+ guard_free(result_path);
}
}
diff --git a/tests/test_system.c b/tests/test_system.c
index 0f6bfb7..2271e13 100644
--- a/tests/test_system.c
+++ b/tests/test_system.c
@@ -18,6 +18,7 @@ void test_shell_output_null_args() {
result = shell_output(NULL, &status);
STASIS_ASSERT(strcmp(result, "") == 0, "no output expected");
STASIS_ASSERT(status != 0, "expected a non-zero exit code due to null argument string");
+ guard_free(result);
}
void test_shell_output_non_zero_exit() {
@@ -26,6 +27,7 @@ void test_shell_output_non_zero_exit() {
result = shell_output("HELLO1234 WORLD", &status);
STASIS_ASSERT(strcmp(result, "") == 0, "no output expected");
STASIS_ASSERT(status != 0, "expected a non-zero exit code due to intentional error");
+ guard_free(result);
}
void test_shell_output() {
@@ -34,6 +36,7 @@ void test_shell_output() {
result = shell_output("echo HELLO WORLD", &status);
STASIS_ASSERT(strcmp(result, "HELLO WORLD\n") == 0, "output message was incorrect");
STASIS_ASSERT(status == 0, "expected zero exit code");
+ guard_free(result);
}
void test_shell_safe() {
diff --git a/tests/test_template.c b/tests/test_template.c
index 79fce5e..596c2b7 100644
--- a/tests/test_template.c
+++ b/tests/test_template.c
@@ -47,9 +47,15 @@ void test_tpl_workflow() {
tpl_reset();
tpl_register("hello_message", &data);
- STASIS_ASSERT(strcmp(tpl_render("I said, \"{{ hello_message }}\""), "I said, \"Hello world!\"") == 0, "stored value in key is incorrect");
+ char *result = NULL;
+ result = tpl_render("I said, \"{{ hello_message }}\"");
+ STASIS_ASSERT(strcmp(result, "I said, \"Hello world!\"") == 0, "stored value in key is incorrect");
+ guard_free(result);
+
setenv("HELLO", "Hello environment!", 1);
- STASIS_ASSERT(strcmp(tpl_render("{{ env:HELLO }}"), "Hello environment!") == 0, "environment variable content mismatch");
+ result = tpl_render("{{ env:HELLO }}");
+ STASIS_ASSERT(strcmp(result, "Hello environment!") == 0, "environment variable content mismatch");
+ guard_free(result);
unsetenv("HELLO");
guard_free(data);
}
@@ -87,18 +93,25 @@ void test_tpl_register_func() {
char *result = NULL;
result = tpl_render("{{ func:add(0,3) }}");
STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ guard_free(result);
result = tpl_render("{{ func:add(1,2) }}");
STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ guard_free(result);
result = tpl_render("{{ func:sub(6,3) }}");
STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ guard_free(result);
result = tpl_render("{{ func:sub(4,1) }}");
STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ guard_free(result);
result = tpl_render("{{ func:mul(1, 3) }}");
STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ guard_free(result);
result = tpl_render("{{ func:div(6,2) }}");
STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ guard_free(result);
result = tpl_render("{{ func:div(3,1) }}");
STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3");
+ guard_free(result);
}
int main(int argc, char *argv[]) {
diff --git a/tests/test_utils.c b/tests/test_utils.c
index 9090b05..8f0a667 100644
--- a/tests/test_utils.c
+++ b/tests/test_utils.c
@@ -46,6 +46,7 @@ void test_redact_sensitive() {
char output[100] = {0};
redact_sensitive(to_redact, sizeof(to_redact) / sizeof(*to_redact), input, output, sizeof(output) - 1);
STASIS_ASSERT(strcmp(output, expected[i]) == 0, "incorrect redaction");
+ guard_free(input);
}
}
@@ -118,6 +119,7 @@ void test_path_store() {
STASIS_ASSERT(dest != NULL, "dest should not be NULL");
STASIS_ASSERT(dest && (access(dest, F_OK) == 0), "destination path was not created");
rmtree(dest);
+ guard_free(dest);
}
void test_isempty_dir() {
@@ -226,6 +228,7 @@ void test_git_clone_and_describe() {
char *taginfo_bad = git_describe("abc1234_not_here_or_there");
STASIS_ASSERT(taginfo_bad == NULL, "a repository that shouldn't exist... exists and has a tag.");
chdir(cwd);
+ guard_free(cwd);
}
void test_touch() {
@@ -414,9 +417,11 @@ void test_pushd_popd() {
// we should be inside the test directory, not the starting directory
STASIS_ASSERT(strcmp(cwd_workspace, cwd) != 0, "");
STASIS_ASSERT(popd() == 0, "return from directory failed");
+ guard_free(cwd);
char *cwd_after_popd = getcwd(NULL, PATH_MAX);
STASIS_ASSERT(strcmp(cwd_workspace, cwd_after_popd) == 0, "should be the path where we started");
+ guard_free(cwd_after_popd);
}
void test_pushd_popd_suggested_workflow() {
@@ -436,6 +441,7 @@ void test_pushd_popd_suggested_workflow() {
// cwd should be our starting directory
char *cwd = getcwd(NULL, PATH_MAX);
STASIS_ASSERT(strcmp(cwd_workspace, cwd) == 0, NULL);
+ guard_free(cwd);
} else {
STASIS_ASSERT(false, "mkdir function failed");
}