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() { | 
