diff options
author | Joseph Hunkeler <jhunkeler@users.noreply.github.com> | 2024-08-07 13:52:10 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-07 13:52:10 -0400 |
commit | 1d5e5f26014ceefd824382acec732f326d8d6ce2 (patch) | |
tree | 2d329c1a76e1bb5a13a84659465a60d2c6e99cd2 | |
parent | 202e69c8951a38187489c66e994dd593755d62cb (diff) | |
download | stasis-1d5e5f26014ceefd824382acec732f326d8d6ce2.tar.gz |
Refactor ini getter and setter usage (#19)
* Add handler for space-delimited lists
* This needs attention, however. The INI writer has no way to know a list with spaces is a list; this happens in the value conversion functions.
* Add type_hint member to INIData structure. At some point support with be added for all INIVAL_TYPE_* defines. Right now it's only used with arrays.
* Zero out line buffer in ini_open after each iteration
* Do not strip raw INI data. Let the conversion functions handle it
* Add spaces to key value pairs in rendered INI output.
* Add ini_getvar_TYPE() functions
* These replace the functionality of static conv_TYPE() functions in delivery.c
* Add support for missing types: U/CHAR, U/SHORT, STRLIST
* ini_getval: expand template variables immediately before processing the output
* Strip leading space to avoid issues with string comparisons against the result
* ini_getval: Return copies, not the original.
* This forces one to use ini_setval to replace/append values to the data array(s). It's safer this way.
* fix_tox_conf(): Use ini_getval and ini_setval instead of modifying the original pointers directly
* Tests: Free resources
* Replace ini_getval(), ini_getval_required() and conv_*() usage
* Now using ini_getval_TYPE() functions and ini_setval()
* Remove unused helper functions and variables
* download() returns long, not int
* actions: update apt cache
-rw-r--r-- | .github/workflows/cmake-multi-platform.yml | 5 | ||||
-rw-r--r-- | include/ini.h | 52 | ||||
-rw-r--r-- | src/delivery.c | 315 | ||||
-rw-r--r-- | src/ini.c | 164 | ||||
-rw-r--r-- | src/utils.c | 30 | ||||
-rw-r--r-- | tests/test_utils.c | 2 |
6 files changed, 324 insertions, 244 deletions
diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index e7d4b33..0a30f4c 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -37,6 +37,11 @@ jobs: run: | echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + - name: Update apt + if: matrix.os == 'ubuntu-latest' + run: > + sudo apt update + - name: Install Linux dependencies if: matrix.os == 'ubuntu-latest' run: > diff --git a/include/ini.h b/include/ini.h index 7167cad..5c840f5 100644 --- a/include/ini.h +++ b/include/ini.h @@ -14,24 +14,32 @@ #define INI_SEARCH_SUBSTR 2 ///< expanded to preserve runtime state. -#define INIVAL_TYPE_INT 1 ///< Integer -#define INIVAL_TYPE_UINT 2 ///< Unsigned integer -#define INIVAL_TYPE_LONG 3 ///< Long integer -#define INIVAL_TYPE_ULONG 4 ///< Unsigned long integer -#define INIVAL_TYPE_LLONG 5 ///< Long long integer -#define INIVAL_TYPE_ULLONG 6 ///< Unsigned long long integer -#define INIVAL_TYPE_DOUBLE 7 ///< Double precision float -#define INIVAL_TYPE_FLOAT 8 ///< Single precision float -#define INIVAL_TYPE_STR 9 ///< String -#define INIVAL_TYPE_STR_ARRAY 10 ///< String Array -#define INIVAL_TYPE_BOOL 11 ///< Boolean +#define INIVAL_TYPE_CHAR 1 ///< Byte +#define INIVAL_TYPE_UCHAR 2 ///< Unsigned byte +#define INIVAL_TYPE_SHORT 3 ///< Short integer +#define INIVAL_TYPE_USHORT 4 ///< Unsigned short integer +#define INIVAL_TYPE_INT 5 ///< Integer +#define INIVAL_TYPE_UINT 6 ///< Unsigned integer +#define INIVAL_TYPE_LONG 7 ///< Long integer +#define INIVAL_TYPE_ULONG 8 ///< Unsigned long integer +#define INIVAL_TYPE_LLONG 9 ///< Long long integer +#define INIVAL_TYPE_ULLONG 10 ///< Unsigned long long integer +#define INIVAL_TYPE_DOUBLE 11 ///< Double precision float +#define INIVAL_TYPE_FLOAT 12 ///< Single precision float +#define INIVAL_TYPE_STR 13 ///< String +#define INIVAL_TYPE_STR_ARRAY 14 ///< String Array +#define INIVAL_TYPE_BOOL 15 ///< Boolean #define INIVAL_TO_LIST 1 << 1 /*! \union INIVal - * \brief Consolidation possible value types + * \brief Consolidate possible value types */ union INIVal { + char as_char; ///< Byte + unsigned char as_uchar; ///< Unsigned byte + short as_short; ///< Short integer + unsigned short as_ushort; ///< Unsigned short integer int as_int; ///< Integer unsigned as_uint; ///< Unsigned integer long as_long; ///< Long integer @@ -52,6 +60,7 @@ union INIVal { struct INIData { char *key; ///< INI variable name char *value; ///< INI variable value + unsigned type_hint; }; /*! \struct INISection @@ -225,4 +234,23 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode); * @param ini */ void ini_free(struct INIFILE **ini); + +int ini_getval_int(struct INIFILE *ini, char *section_name, char *key, int *state); +unsigned int ini_getval_uint(struct INIFILE *ini, char *section_name, char *key, int *state); +long ini_getval_long(struct INIFILE *ini, char *section_name, char *key, int *state); +unsigned long ini_getval_ulong(struct INIFILE *ini, char *section_name, char *key, int *state); +long long ini_getval_llong(struct INIFILE *ini, char *section_name, char *key, int *state); +unsigned long long ini_getval_ullong(struct INIFILE *ini, char *section_name, char *key, int *state); +float ini_getval_float(struct INIFILE *ini, char *section_name, char *key, int *state); +double ini_getval_double(struct INIFILE *ini, char *section_name, char *key, int *state); +bool ini_getval_bool(struct INIFILE *ini, char *section_name, char *key, int *state); +short ini_getval_short(struct INIFILE *ini, char *section_name, char *key, int *state); +unsigned short ini_getval_ushort(struct INIFILE *ini, char *section_name, char *key, int *state); +char ini_getval_char(struct INIFILE *ini, char *section_name, char *key, int *state); +unsigned char ini_getval_uchar(struct INIFILE *ini, char *section_name, char *key, int *state); +char *ini_getval_char_p(struct INIFILE *ini, char *section_name, char *key, int *state); +char *ini_getval_str(struct INIFILE *ini, char *section_name, char *key, int *state); +char **ini_getval_char_array_p(struct INIFILE *ini, char *section_name, char *key, int *state); +char **ini_getval_str_array(struct INIFILE *ini, char *section_name, char *key, int *state); +struct StrList *ini_getval_strlist(struct INIFILE *ini, char *section_name, char *key, char *tok, int *state); #endif //STASIS_INI_H diff --git a/src/delivery.c b/src/delivery.c index b1997f6..1b16f39 100644 --- a/src/delivery.c +++ b/src/delivery.c @@ -13,18 +13,6 @@ static void ini_has_key_required(struct INIFILE *ini, const char *section_name, } } -static void ini_getval_required(struct INIFILE *ini, char *section_name, char *key, unsigned type, union INIVal *val) { - int status = ini_getval(ini, section_name, key, type, val); - if (status || isempty(val->as_char_p)) { - SYSERROR("%s:%s value is required but not defined", section_name, key); - exit(1); - } -} - -static void conv_int(int *x, union INIVal val) { - *x = val.as_int; -} - static void conv_str(char **x, union INIVal val) { if (*x) { guard_free(*x); @@ -41,30 +29,6 @@ static void conv_str(char **x, union INIVal val) { } } -static void conv_str_noexpand(char **x, union INIVal val) { - if (*x) { - guard_free(*x); - } - *x = strdup(val.as_char_p); -} - -static void conv_strlist(struct StrList **x, char *tok, union INIVal val) { - if (!(*x)) - (*x) = strlist_init(); - if (val.as_char_p) { - char *tplop = tpl_render(val.as_char_p); - if (tplop) { - strip(tplop); - strlist_append_tokenize((*x), tplop, tok); - guard_free(tplop); - } - } -} - -static void conv_bool(bool *x, union INIVal val) { - *x = val.as_bool; -} - int delivery_init_tmpdir(struct Delivery *ctx) { char *tmpdir = NULL; char *x = NULL; @@ -380,7 +344,7 @@ int delivery_init_platform(struct Delivery *ctx) { } static int populate_mission_ini(struct Delivery **ctx) { - union INIVal val; + int err = 0; struct INIFILE *ini; if ((*ctx)->_stasis_ini_fp.mission) { @@ -406,16 +370,13 @@ static int populate_mission_ini(struct Delivery **ctx) { } (*ctx)->_stasis_ini_fp.mission_path = strdup(missionfile); - ini_getval_required(ini, "meta", "release_fmt", INIVAL_TYPE_STR, &val); - conv_str(&(*ctx)->rules.release_fmt, val); + (*ctx)->rules.release_fmt = ini_getval_str(ini, "meta", "release_fmt", &err); // Used for setting artifactory build info - ini_getval_required(ini, "meta", "build_name_fmt", INIVAL_TYPE_STR, &val); - conv_str(&(*ctx)->rules.build_name_fmt, val); + (*ctx)->rules.build_name_fmt = ini_getval_str(ini, "meta", "build_name_fmt", &err); // Used for setting artifactory build info - ini_getval_required(ini, "meta", "build_number_fmt", INIVAL_TYPE_STR, &val); - conv_str(&(*ctx)->rules.build_number_fmt, val); + (*ctx)->rules.build_number_fmt = ini_getval_str(ini, "meta", "build_number_fmt", &err); return 0; } @@ -489,80 +450,67 @@ static int populate_delivery_ini(struct Delivery *ctx) { runtime_apply(rt); ctx->runtime.environ = rt; - ini_getval_required(ini, "meta", "mission", INIVAL_TYPE_STR, &val); - conv_str(&ctx->meta.mission, val); + int err = 0; + ctx->meta.mission = ini_getval_str(ini, "meta", "mission", &err); if (!strcasecmp(ctx->meta.mission, "hst")) { - ini_getval(ini, "meta", "codename", INIVAL_TYPE_STR, &val); - conv_str(&ctx->meta.codename, val); + ctx->meta.codename = ini_getval_str(ini, "meta", "codename", &err); } else { ctx->meta.codename = NULL; } - /* - if (!strcasecmp(ctx->meta.mission, "jwst")) { - ini_getval(ini, "meta", "version", INIVAL_TYPE_STR, &val); - conv_str(&ctx->meta.version, val); - - } else { - ctx->meta.version = NULL; - } - */ - ini_getval(ini, "meta", "version", INIVAL_TYPE_STR, &val); - conv_str(&ctx->meta.version, val); - - ini_getval_required(ini, "meta", "name", INIVAL_TYPE_STR, &val); - conv_str(&ctx->meta.name, val); - - ini_getval(ini, "meta", "rc", INIVAL_TYPE_INT, &val); - conv_int(&ctx->meta.rc, val); - - ini_getval(ini, "meta", "final", INIVAL_TYPE_BOOL, &val); - conv_bool(&ctx->meta.final, val); - - ini_getval(ini, "meta", "based_on", INIVAL_TYPE_STR, &val); - conv_str(&ctx->meta.based_on, val); + ctx->meta.version = ini_getval_str(ini, "meta", "version", &err); + ctx->meta.name = ini_getval_str(ini, "meta", "name", &err); + ctx->meta.rc = ini_getval_int(ini, "meta", "rc", &err); + ctx->meta.final = ini_getval_bool(ini, "meta", "final", &err); + ctx->meta.based_on = ini_getval_str(ini, "meta", "based_on", &err); if (!ctx->meta.python) { - ini_getval(ini, "meta", "python", INIVAL_TYPE_STR, &val); - conv_str(&ctx->meta.python, val); + ctx->meta.python = ini_getval_str(ini, "meta", "python", &err); guard_free(ctx->meta.python_compact); ctx->meta.python_compact = to_short_version(ctx->meta.python); } else { ini_setval(&ini, INI_SETVAL_REPLACE, "meta", "python", ctx->meta.python); } - ini_getval_required(ini, "conda", "installer_name", INIVAL_TYPE_STR, &val); - conv_str(&ctx->conda.installer_name, val); - - ini_getval_required(ini, "conda", "installer_version", INIVAL_TYPE_STR, &val); - conv_str(&ctx->conda.installer_version, val); - - ini_getval_required(ini, "conda", "installer_platform", INIVAL_TYPE_STR, &val); - conv_str(&ctx->conda.installer_platform, val); + ctx->conda.installer_name = ini_getval_str(ini, "conda", "installer_name", &err); + ctx->conda.installer_version = ini_getval_str(ini, "conda", "installer_version", &err); + ctx->conda.installer_platform = ini_getval_str(ini, "conda", "installer_platform", &err); + ctx->conda.installer_arch = ini_getval_str(ini, "conda", "installer_arch", &err); + ctx->conda.installer_baseurl = ini_getval_str(ini, "conda", "installer_baseurl", &err); + ctx->conda.conda_packages = ini_getval_strlist(ini, "conda", "conda_packages", " "LINE_SEP, &err); - ini_getval_required(ini, "conda", "installer_arch", INIVAL_TYPE_STR, &val); - conv_str(&ctx->conda.installer_arch, val); - - ini_getval_required(ini, "conda", "installer_baseurl", INIVAL_TYPE_STR, &val); - conv_str(&ctx->conda.installer_baseurl, val); - - ini_getval(ini, "conda", "conda_packages", INIVAL_TYPE_STR_ARRAY, &val); - conv_strlist(&ctx->conda.conda_packages, LINE_SEP, val); + if (ctx->conda.conda_packages->data && ctx->conda.conda_packages->data[0] && strpbrk(ctx->conda.conda_packages->data[0], " \t")) { + normalize_space(ctx->conda.conda_packages->data[0]); + replace_text(ctx->conda.conda_packages->data[0], " ", LINE_SEP, 0); + char *pip_packages_replacement = join(ctx->conda.conda_packages->data, LINE_SEP); + ini_setval(&ini, INI_SETVAL_REPLACE, "conda", "conda_packages", pip_packages_replacement); + guard_free(pip_packages_replacement); + guard_strlist_free(&ctx->conda.conda_packages); + ctx->conda.conda_packages = ini_getval_strlist(ini, "conda", "conda_packages", LINE_SEP, &err); + } for (size_t i = 0; i < strlist_count(ctx->conda.conda_packages); i++) { char *pkg = strlist_item(ctx->conda.conda_packages, i); - if (strpbrk(pkg, ";#")) { + if (strpbrk(pkg, ";#") || isempty(pkg)) { strlist_remove(ctx->conda.conda_packages, i); } } - ini_getval(ini, "conda", "pip_packages", INIVAL_TYPE_STR_ARRAY, &val); - conv_strlist(&ctx->conda.pip_packages, LINE_SEP, val); + ctx->conda.pip_packages = ini_getval_strlist(ini, "conda", "pip_packages", LINE_SEP, &err); + if (ctx->conda.pip_packages->data && ctx->conda.pip_packages->data[0] && strpbrk(ctx->conda.pip_packages->data[0], " \t")) { + normalize_space(ctx->conda.pip_packages->data[0]); + replace_text(ctx->conda.pip_packages->data[0], " ", LINE_SEP, 0); + char *pip_packages_replacement = join(ctx->conda.pip_packages->data, LINE_SEP); + ini_setval(&ini, INI_SETVAL_REPLACE, "conda", "pip_packages", pip_packages_replacement); + guard_free(pip_packages_replacement); + guard_strlist_free(&ctx->conda.pip_packages); + ctx->conda.pip_packages = ini_getval_strlist(ini, "conda", "pip_packages", LINE_SEP, &err); + } for (size_t i = 0; i < strlist_count(ctx->conda.pip_packages); i++) { char *pkg = strlist_item(ctx->conda.pip_packages, i); - if (strpbrk(pkg, ";#")) { + if (strpbrk(pkg, ";#") || isempty(pkg)) { strlist_remove(ctx->conda.pip_packages, i); } } @@ -599,150 +547,95 @@ static int populate_delivery_ini(struct Delivery *ctx) { } for (size_t z = 0, i = 0; i < ini->section_count; i++) { - if (startswith(ini->section[i]->key, "test:")) { + char *section_name = ini->section[i]->key; + if (startswith(section_name, "test:")) { + struct Test *test = &ctx->tests[z]; val.as_char_p = strchr(ini->section[i]->key, ':') + 1; if (val.as_char_p && isempty(val.as_char_p)) { return 1; } - conv_str(&ctx->tests[z].name, val); - - ini_getval(ini, ini->section[i]->key, "version", INIVAL_TYPE_STR, &val); - conv_str(&ctx->tests[z].version, val); - - ini_getval_required(ini, ini->section[i]->key, "repository", INIVAL_TYPE_STR, &val); - conv_str(&ctx->tests[z].repository, val); - - ini_getval_required(ini, ini->section[i]->key, "script", INIVAL_TYPE_STR, &val); - conv_str_noexpand(&ctx->tests[z].script, val); - - ini_getval(ini, ini->section[i]->key, "repository_remove_tags", INIVAL_TYPE_STR_ARRAY, &val); - conv_strlist(&ctx->tests[z].repository_remove_tags, LINE_SEP, val); - - ini_getval(ini, ini->section[i]->key, "build_recipe", INIVAL_TYPE_STR, &val); - conv_str(&ctx->tests[z].build_recipe, val); - - ini_getval(ini, ini->section[i]->key, "runtime", INIVAL_TO_LIST, &val); - conv_strlist(&ctx->tests[z].runtime.environ, LINE_SEP, val); + conv_str(&test->name, val); + + test->version = ini_getval_str(ini, section_name, "version", &err); + test->repository = ini_getval_str(ini, section_name, "repository", &err); + test->script = ini_getval_str(ini, section_name, "script", &err); + test->repository_remove_tags = ini_getval_strlist(ini, section_name, "repository_remove_tags", LINE_SEP, &err); + test->build_recipe = ini_getval_str(ini, section_name, "build_recipe", &err); + test->runtime.environ = ini_getval_strlist(ini, section_name, "runtime", LINE_SEP, &err); z++; } } for (size_t z = 0, i = 0; i < ini->section_count; i++) { - if (startswith(ini->section[i]->key, "deploy:artifactory")) { + char *section_name = ini->section[i]->key; + struct Deploy *deploy = &ctx->deploy; + if (startswith(section_name, "deploy:artifactory")) { + struct JFrog *jfrog = &deploy->jfrog[z]; // Artifactory base configuration - ini_getval(ini, ini->section[i]->key, "workaround_parent_only", INIVAL_TYPE_BOOL, &val); - conv_bool(&ctx->deploy.jfrog[z].upload_ctx.workaround_parent_only, val); - - ini_getval(ini, ini->section[i]->key, "exclusions", INIVAL_TYPE_STR, &val); - conv_str(&ctx->deploy.jfrog[z].upload_ctx.exclusions, val); - - ini_getval(ini, ini->section[i]->key, "explode", INIVAL_TYPE_BOOL, &val); - conv_bool(&ctx->deploy.jfrog[z].upload_ctx.explode, val); - - ini_getval(ini, ini->section[i]->key, "recursive", INIVAL_TYPE_BOOL, &val); - conv_bool(&ctx->deploy.jfrog[z].upload_ctx.recursive, val); - - ini_getval(ini, ini->section[i]->key, "retries", INIVAL_TYPE_INT, &val); - conv_int(&ctx->deploy.jfrog[z].upload_ctx.retries, val); - - ini_getval(ini, ini->section[i]->key, "retry_wait_time", INIVAL_TYPE_INT, &val); - conv_int(&ctx->deploy.jfrog[z].upload_ctx.retry_wait_time, val); - ini_getval(ini, ini->section[i]->key, "detailed_summary", INIVAL_TYPE_BOOL, &val); - conv_bool(&ctx->deploy.jfrog[z].upload_ctx.detailed_summary, val); - - ini_getval(ini, ini->section[i]->key, "quiet", INIVAL_TYPE_BOOL, &val); - conv_bool(&ctx->deploy.jfrog[z].upload_ctx.quiet, val); - - ini_getval(ini, ini->section[i]->key, "regexp", INIVAL_TYPE_BOOL, &val); - conv_bool(&ctx->deploy.jfrog[z].upload_ctx.regexp, val); - - ini_getval(ini, ini->section[i]->key, "spec", INIVAL_TYPE_STR, &val); - conv_str(&ctx->deploy.jfrog[z].upload_ctx.spec, val); - - ini_getval(ini, ini->section[i]->key, "flat", INIVAL_TYPE_BOOL, &val); - conv_bool(&ctx->deploy.jfrog[z].upload_ctx.flat, val); - - ini_getval(ini, ini->section[i]->key, "repo", INIVAL_TYPE_STR, &val); - conv_str(&ctx->deploy.jfrog[z].repo, val); - - ini_getval(ini, ini->section[i]->key, "dest", INIVAL_TYPE_STR, &val); - conv_str(&ctx->deploy.jfrog[z].dest, val); - - ini_getval(ini, ini->section[i]->key, "files", INIVAL_TYPE_STR_ARRAY, &val); - conv_strlist(&ctx->deploy.jfrog[z].files, LINE_SEP, val); + jfrog->upload_ctx.workaround_parent_only = ini_getval_bool(ini, section_name, "workaround_parent_only", &err); + jfrog->upload_ctx.exclusions = ini_getval_str(ini, section_name, "exclusions", &err); + jfrog->upload_ctx.explode = ini_getval_bool(ini, section_name, "explode", &err); + jfrog->upload_ctx.recursive = ini_getval_bool(ini, section_name, "recursive", &err); + jfrog->upload_ctx.retries = ini_getval_int(ini, section_name, "retries", &err); + jfrog->upload_ctx.retry_wait_time = ini_getval_int(ini, section_name, "retry_wait_time", &err); + jfrog->upload_ctx.detailed_summary = ini_getval_bool(ini, section_name, "detailed_summary", &err); + jfrog->upload_ctx.quiet = ini_getval_bool(ini, section_name, "quiet", &err); + jfrog->upload_ctx.regexp = ini_getval_bool(ini, section_name, "regexp", &err); + jfrog->upload_ctx.spec = ini_getval_str(ini, section_name, "spec", &err); + jfrog->upload_ctx.flat = ini_getval_bool(ini, section_name, "flat", &err); + jfrog->repo = ini_getval_str(ini, section_name, "repo", &err); + jfrog->dest = ini_getval_str(ini, section_name, "dest", &err); + jfrog->files = ini_getval_strlist(ini, section_name, "dest", LINE_SEP, &err); z++; } } for (size_t i = 0; i < ini->section_count; i++) { + char *section_name = ini->section[i]->key; + struct Deploy *deploy = &ctx->deploy; if (startswith(ini->section[i]->key, "deploy:docker")) { - ini_getval(ini, ini->section[i]->key, "registry", INIVAL_TYPE_STR, &val); - conv_str(&ctx->deploy.docker.registry, val); - - ini_getval(ini, ini->section[i]->key, "image_compression", INIVAL_TYPE_STR, &val); - conv_str(&ctx->deploy.docker.image_compression, val); + struct Docker *docker = &deploy->docker; - ini_getval(ini, ini->section[i]->key, "test_script", INIVAL_TYPE_STR, &val); - conv_str(&ctx->deploy.docker.test_script, val); - - ini_getval(ini, ini->section[i]->key, "build_args", INIVAL_TYPE_STR_ARRAY, &val); - conv_strlist(&ctx->deploy.docker.build_args, LINE_SEP, val); - - ini_getval(ini, ini->section[i]->key, "tags", INIVAL_TYPE_STR_ARRAY, &val); - conv_strlist(&ctx->deploy.docker.tags, LINE_SEP, val); + docker->registry = ini_getval_str(ini, section_name, "registry", &err); + docker->image_compression = ini_getval_str(ini, section_name, "image_compression", &err); + docker->test_script = ini_getval_str(ini, section_name, "test_script", &err); + docker->build_args = ini_getval_strlist(ini, section_name, "build_args", LINE_SEP, &err); + docker->tags = ini_getval_strlist(ini, section_name, "tags", LINE_SEP, &err); } } return 0; } static int populate_delivery_cfg(struct Delivery *ctx) { - union INIVal val; struct INIFILE *cfg = ctx->_stasis_ini_fp.cfg; if (!cfg) { return -1; } - ini_getval(cfg, "default", "conda_staging_dir", INIVAL_TYPE_STR, &val); - conv_str(&ctx->storage.conda_staging_dir, val); - ini_getval(cfg, "default", "conda_staging_url", INIVAL_TYPE_STR, &val); - conv_str(&ctx->storage.conda_staging_url, val); - ini_getval(cfg, "default", "wheel_staging_dir", INIVAL_TYPE_STR, &val); - conv_str(&ctx->storage.wheel_staging_dir, val); - ini_getval(cfg, "default", "wheel_staging_url", INIVAL_TYPE_STR, &val); - conv_str(&ctx->storage.wheel_staging_url, val); - ini_getval(cfg, "default", "conda_fresh_start", INIVAL_TYPE_BOOL, &val); - conv_bool(&globals.conda_fresh_start, val); - // Below can also be toggled by command-line arguments + int err = 0; + ctx->storage.conda_staging_dir = ini_getval_str(cfg, "default", "conda_staging_dir", &err); + ctx->storage.conda_staging_url = ini_getval_str(cfg, "default", "conda_staging_url", &err); + ctx->storage.wheel_staging_dir = ini_getval_str(cfg, "default", "wheel_staging_dir", &err); + ctx->storage.wheel_staging_url = ini_getval_str(cfg, "default", "wheel_staging_url", &err); + globals.conda_fresh_start = ini_getval_bool(cfg, "default", "conda_fresh_start", &err); if (!globals.continue_on_error) { - ini_getval(cfg, "default", "continue_on_error", INIVAL_TYPE_BOOL, &val); - conv_bool(&globals.continue_on_error, val); - } - // Below can also be toggled by command-line arguments - if (!globals.always_update_base_environment) { - ini_getval(cfg, "default", "always_update_base_environment", INIVAL_TYPE_BOOL, &val); - conv_bool(&globals.always_update_base_environment, val); - } - ini_getval(cfg, "default", "conda_install_prefix", INIVAL_TYPE_STR, &val); - conv_str(&globals.conda_install_prefix, val); - ini_getval(cfg, "default", "conda_packages", INIVAL_TYPE_STR_ARRAY, &val); - conv_strlist(&globals.conda_packages, LINE_SEP, val); - ini_getval(cfg, "default", "pip_packages", INIVAL_TYPE_STR_ARRAY, &val); - conv_strlist(&globals.pip_packages, LINE_SEP, val); - // Configure jfrog cli downloader - ini_getval(cfg, "jfrog_cli_download", "url", INIVAL_TYPE_STR, &val); - conv_str(&globals.jfrog.jfrog_artifactory_base_url, val); - ini_getval(cfg, "jfrog_cli_download", "product", INIVAL_TYPE_STR, &val); - conv_str(&globals.jfrog.jfrog_artifactory_product, val); - ini_getval(cfg, "jfrog_cli_download", "version_series", INIVAL_TYPE_STR, &val); - conv_str(&globals.jfrog.cli_major_ver, val); - ini_getval(cfg, "jfrog_cli_download", "version", INIVAL_TYPE_STR, &val); - conv_str(&globals.jfrog.version, val); - ini_getval(cfg, "jfrog_cli_download", "filename", INIVAL_TYPE_STR, &val); - conv_str(&globals.jfrog.remote_filename, val); - ini_getval(cfg, "deploy:artifactory", "url", INIVAL_TYPE_STR, &val); - conv_str(&globals.jfrog.url, val); - ini_getval(cfg, "deploy:artifactory", "repo", INIVAL_TYPE_STR, &val); - conv_str(&globals.jfrog.repo, val); + globals.continue_on_error = ini_getval_bool(cfg, "default", "continue_on_error", &err); + } + if (globals.always_update_base_environment) { + globals.always_update_base_environment = ini_getval_bool(cfg, "default", "always_update_base_environment", &err); + } + globals.conda_install_prefix = ini_getval_str(cfg, "default", "conda_install_prefix", &err); + globals.conda_packages = ini_getval_strlist(cfg, "default", "conda_packages", LINE_SEP, &err); + globals.pip_packages = ini_getval_strlist(cfg, "default", "pip_packages", LINE_SEP, &err); + + globals.jfrog.jfrog_artifactory_base_url = ini_getval_str(cfg, "jfrog_cli_download", "url", &err); + globals.jfrog.jfrog_artifactory_product = ini_getval_str(cfg, "jfrog_cli_download", "product", &err); + globals.jfrog.cli_major_ver = ini_getval_str(cfg, "jfrog_cli_download", "version_series", &err); + globals.jfrog.version = ini_getval_str(cfg, "jfrog_cli_download", "version", &err); + globals.jfrog.remote_filename = ini_getval_str(cfg, "jfrog_cli_download", "filename", &err); + globals.jfrog.url = ini_getval_str(cfg, "deploy:artifactory", "url", &err); + globals.jfrog.repo = ini_getval_str(cfg, "deploy:artifactory", "repo", &err); + return 0; } @@ -1201,7 +1094,7 @@ static const struct Test *requirement_from_test(struct Delivery *ctx, const char result = NULL; for (size_t i = 0; i < sizeof(ctx->tests) / sizeof(ctx->tests[0]); i++) { - if (strstr(name, ctx->tests[i].name)) { + if (ctx->tests[i].name && strstr(name, ctx->tests[i].name)) { result = &ctx->tests[i]; break; } @@ -1336,7 +1229,7 @@ int delivery_get_installer(struct Delivery *ctx, char *installer_url) { sprintf(script_path, "%s/%s", ctx->storage.tmpdir, installer); if (access(script_path, F_OK)) { // Script doesn't exist - int fetch_status = download(installer_url, script_path, NULL); + long fetch_status = download(installer_url, script_path, NULL); if (HTTP_ERROR(fetch_status) || fetch_status < 0) { // download failed return -1; @@ -2046,8 +1939,8 @@ int delivery_mission_render_files(struct Delivery *ctx) { sprintf(data.src, "%s/%s/%s", ctx->storage.mission_dir, ctx->meta.mission, val.as_char_p); msg(STASIS_MSG_L2, "%s\n", data.src); - ini_getval_required(cfg, section_name, "destination", INIVAL_TYPE_STR, &val); - conv_str(&data.dest, val); + int err = 0; + data.dest = ini_getval_str(cfg, section_name, "destination", &err); char *contents; struct stat st; @@ -122,7 +122,27 @@ int ini_getval(struct INIFILE *ini, char *section_name, char *key, int type, uni result->as_char_p = NULL; return -1; } + + char *render = tpl_render(data->value); + if (render) { + guard_free(data->value); + data->value = render; + } + lstrip(data->value); + switch (type) { + case INIVAL_TYPE_CHAR: + result->as_char = (char) strtol(data->value, NULL, 10); + break; + case INIVAL_TYPE_UCHAR: + result->as_uchar = (unsigned char) strtoul(data->value, NULL, 10); + break; + case INIVAL_TYPE_SHORT: + result->as_short = (short) strtol(data->value, NULL, 10); + break; + case INIVAL_TYPE_USHORT: + result->as_ushort = (unsigned short) strtoul(data->value, NULL, 10); + break; case INIVAL_TYPE_INT: result->as_int = (int) strtol(data->value, NULL, 10); break; @@ -148,17 +168,26 @@ int ini_getval(struct INIFILE *ini, char *section_name, char *key, int type, uni result->as_float = (float) strtod(data->value, NULL); break; case INIVAL_TYPE_STR: - result->as_char_p = lstrip(data->value); + result->as_char_p = strdup(data->value); + if (!result->as_char_p) { + return -1; + } + lstrip(result->as_char_p); break; case INIVAL_TYPE_STR_ARRAY: strcpy(tbufp, data->value); - *data->value = '\0'; + char *value = NULL; + size_t lines = num_chars(tbufp, '\n'); + value = calloc(strlen(tbufp) + lines + 1, sizeof(*value)); + if (!value) { + return -1; + } while ((token = strsep(&tbufp, "\n")) != NULL) { lstrip(token); - strcat(data->value, token); - strcat(data->value, "\n"); + strcat(value, token); + strcat(value, "\n"); } - result->as_char_p = data->value; + result->as_char_p = value; break; case INIVAL_TYPE_BOOL: result->as_bool = false; @@ -175,6 +204,107 @@ int ini_getval(struct INIFILE *ini, char *section_name, char *key, int type, uni return 0; } +#define getval_returns(t) return result.t +#define getval_setup(t) \ + union INIVal result; \ + int state_local = 0; \ + state_local = ini_getval(ini, section_name, key, t, &result); \ + if (state != NULL) { \ + *state = state_local; \ + } + +int ini_getval_int(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_INT) + getval_returns(as_int); +} + +unsigned int ini_getval_uint(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_UINT) + getval_returns(as_uint); +} + +long ini_getval_long(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_LONG) + getval_returns(as_long); +} + +unsigned long ini_getval_ulong(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_ULONG) + getval_returns(as_ulong); +} + +long long ini_getval_llong(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_LLONG) + getval_returns(as_llong); +} + +unsigned long long ini_getval_ullong(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_ULLONG) + getval_returns(as_ullong); +} + +float ini_getval_float(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_FLOAT) + getval_returns(as_float); +} + +double ini_getval_double(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_DOUBLE) + getval_returns(as_double); +} + +bool ini_getval_bool(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_BOOL) + getval_returns(as_bool); +} + +short ini_getval_short(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_SHORT) + getval_returns(as_short); +} + +unsigned short ini_getval_ushort(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_USHORT) + getval_returns(as_ushort); +} + +char ini_getval_char(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_CHAR) + getval_returns(as_char); +} + +unsigned char ini_getval_uchar(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_UCHAR) + getval_returns(as_uchar); +} + +char *ini_getval_char_p(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_STR) + getval_returns(as_char_p); +} + +char *ini_getval_str(struct INIFILE *ini, char *section_name, char *key, int *state) { + return ini_getval_char_p(ini, section_name, key, state); +} + +char **ini_getval_char_array_p(struct INIFILE *ini, char *section_name, char *key, int *state) { + getval_setup(INIVAL_TYPE_STR_ARRAY) + getval_returns(as_char_array_p); +} + +char **ini_getval_str_array(struct INIFILE *ini, char *section_name, char *key, int *state) { + return ini_getval_char_array_p(ini, section_name, key, state); +} + +struct StrList *ini_getval_strlist(struct INIFILE *ini, char *section_name, char *key, char *tok, int *state) { + getval_setup(INIVAL_TYPE_STR_ARRAY) + struct StrList *list; + list = strlist_init(); + strlist_append_tokenize(list, result.as_char_p, tok); + guard_free(result.as_char_p); + return list; +} + int ini_data_append(struct INIFILE **ini, char *section_name, char *key, char *value) { struct INISection *section = ini_section_search(ini, INI_SEARCH_EXACT, section_name); if (section == NULL) { @@ -292,13 +422,18 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { char *render = NULL; if (mode == INI_WRITE_PRESERVE) { render = tpl_render(parts[p]); + replace_text(render, "\n", "\n ", 0); } else { render = parts[p]; } if (p == 0) { sprintf(outvalue, "%s" LINE_SEP, render); } else { - sprintf(outvalue + strlen(outvalue), " %s" LINE_SEP, render); + if (!isspace(render[0])) { + sprintf(outvalue + strlen(outvalue), " %s" LINE_SEP, render); + } else { + sprintf(outvalue + strlen(outvalue), "%s" LINE_SEP, render); + } } if (mode == INI_WRITE_PRESERVE) { guard_free(render); @@ -307,9 +442,9 @@ int ini_write(struct INIFILE *ini, FILE **stream, unsigned mode) { GENERIC_ARRAY_FREE(parts); strip(outvalue); strcat(outvalue, LINE_SEP); - fprintf(*stream, "%s=%s%s", ini->section[x]->data[y]->key, parts_total > 1 ? LINE_SEP " " : "", outvalue); + fprintf(*stream, "%s = %s%s", ini->section[x]->data[y]->key, ini->section[x]->data[y]->type_hint || parts_total > 1 ? LINE_SEP " " : "", outvalue); } else { - fprintf(*stream, "%s=%s", ini->section[x]->data[y]->key, ini->section[x]->data[y]->value); + fprintf(*stream, "%s = %s", ini->section[x]->data[y]->key, ini->section[x]->data[y]->value); } } fprintf(*stream, LINE_SEP); @@ -352,6 +487,13 @@ void ini_free(struct INIFILE **ini) { guard_free((*ini)); } +static void ini_data_set_hint(struct INIFILE **ini, char *section_name, char *key, int hint) { + struct INIData *data = ini_data_get(*ini, section_name, key); + if (data) { + data->type_hint = hint; + } +} + struct INIFILE *ini_open(const char *filename) { FILE *fp; char line[STASIS_BUFSIZ] = {0}; @@ -440,8 +582,10 @@ struct INIFILE *ini_open(const char *filename) { ini_section_create(&ini, section_name); // Record the name of the section. This is used until another section is found. + memset(current_section, 0, sizeof(current_section)); strcpy(current_section, section_name); guard_free(section_name); + memset(line, 0, sizeof(line)); continue; } @@ -473,6 +617,7 @@ struct INIFILE *ini_open(const char *filename) { } if (isempty(value)) { //printf("%s is probably long raw data\n", key); + ini_data_set_hint(&ini, current_section, key, INIVAL_TYPE_STR_ARRAY); multiline_data = 1; no_data = 1; } else { @@ -484,15 +629,14 @@ struct INIFILE *ini_open(const char *filename) { strcpy(key, key_last); strcpy(value, line); } + memset(line, 0, sizeof(line)); // Store key value pair in section's data array if (strlen(key)) { lstrip(key); strip(key); unquote(value); - lstrip(value); if (!multiline_data) { - strip(value); reading_value = 0; ini_data_append(&ini, current_section, key, value); continue; diff --git a/src/utils.c b/src/utils.c index 2143c52..f721581 100644 --- a/src/utils.c +++ b/src/utils.c @@ -579,6 +579,7 @@ int xml_pretty_print_in_place(const char *filename, const char *pretty_print_pro goto pretty_print_failed; } + fclose(fp); guard_free(tempfile); guard_free(result); return 0; @@ -638,24 +639,31 @@ int fix_tox_conf(const char *filename, char **result) { for (size_t i = 0; i < toxini->section_count; i++) { struct INISection *section = toxini->section[i]; if (section) { - if (startswith(section->key, "testenv")) { - for (size_t k = 0; k < section->data_count; k++) { - struct INIData *data = section->data[k]; - if (data) { - if (!strcmp(data->key, "commands") && (startswith(data->value, "pytest") && !strstr(data->value, "{posargs}"))) { - strip(data->value); + char *section_name = section->key; + for (size_t k = 0; k < section->data_count; k++) { + struct INIData *data = section->data[k]; + if (data) { + int err = 0; + char *key = data->key; + char *value = ini_getval_str(toxini, section->key, data->key, &err); + if (key && value) { + if (startswith(value, "pytest") && !strstr(value, "{posargs}")) { + strip(value); char *tmp; - tmp = realloc(data->value, strlen(data->value) + strlen(with_posargs) + 1); + tmp = realloc(value, strlen(value) + strlen(with_posargs) + 1); if (!tmp) { - SYSERROR("failed to increase data->value size to +%zu bytes", strlen(data->value) + strlen(with_posargs) + 1); + SYSERROR("failed to increase size to +%zu bytes", + strlen(value) + strlen(with_posargs) + 1); guard_free(*result); return -1; - } else if (tmp != data->value) { - data->value = tmp; + } else if (tmp != value) { + value = tmp; } - strcat(data->value, with_posargs); + strcat(value, with_posargs); + ini_setval(&toxini, INI_SETVAL_REPLACE, section_name, key, value); } } + guard_free(value); } } } diff --git a/tests/test_utils.c b/tests/test_utils.c index 4b19604..9090b05 100644 --- a/tests/test_utils.c +++ b/tests/test_utils.c @@ -71,6 +71,7 @@ void test_fix_tox_conf() { char **lines = file_readlines(result, 0, 0, NULL); STASIS_ASSERT(strstr_array(lines, expected) != NULL, "{posargs} not found in result"); + GENERIC_ARRAY_FREE(lines); remove(result); guard_free(result); @@ -106,6 +107,7 @@ void test_xml_pretty_print_in_place() { STASIS_ASSERT(false, "failed to consume formatted xml file contents"); } STASIS_ASSERT(strcmp(expected, buf) == 0, "xml file was not reformatted"); + fclose(fp); } void test_path_store() { |