diff options
author | Carlos MartÃn Nieto <carlosmn@github.com> | 2017-11-04 18:30:29 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-04 18:30:29 +0100 |
commit | 0d723f39decff4ff77def8a4acf3b7a656af59b2 (patch) | |
tree | 4e7363374dff5ed9fd55023129c0c1c1c71909e2 | |
parent | 990d2b854ab7eef28dd09209f77ff95d8e6a4ca2 (diff) | |
parent | 42627933327bb8f91ae847bc8c72ab15ec1e2592 (diff) | |
download | libgit2-0d723f39decff4ff77def8a4acf3b7a656af59b2.tar.gz |
Merge pull request #4332 from pks-t/pks/conditional-includes
Conditional includes
-rw-r--r-- | include/git2/config.h | 3 | ||||
-rw-r--r-- | include/git2/repository.h | 12 | ||||
-rw-r--r-- | include/git2/sys/config.h | 5 | ||||
-rw-r--r-- | src/config.c | 18 | ||||
-rw-r--r-- | src/config_file.c | 195 | ||||
-rw-r--r-- | src/config_file.h | 4 | ||||
-rw-r--r-- | src/path.h | 13 | ||||
-rw-r--r-- | src/repository.c | 24 | ||||
-rw-r--r-- | src/submodule.c | 2 | ||||
-rw-r--r-- | src/win32/path_w32.c | 15 | ||||
-rw-r--r-- | tests/config/backend.c | 4 | ||||
-rw-r--r-- | tests/config/conditionals.c | 103 | ||||
-rw-r--r-- | tests/config/configlevel.c | 14 | ||||
-rw-r--r-- | tests/config/multivar.c | 12 | ||||
-rw-r--r-- | tests/config/read.c | 30 | ||||
-rw-r--r-- | tests/config/readonly.c | 10 | ||||
-rw-r--r-- | tests/config/write.c | 8 |
17 files changed, 359 insertions, 113 deletions
diff --git a/include/git2/config.h b/include/git2/config.h index d0f1ba1b3..d812e16bd 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -199,6 +199,8 @@ GIT_EXTERN(int) git_config_new(git_config **out); * @param path path to the configuration file to add * @param level the priority level of the backend * @param force replace config file at the given priority level + * @param repo optional repository to allow parsing of + * conditional includes * @return 0 on success, GIT_EEXISTS when adding more than one file * for a given priority level (and force_replace set to 0), * GIT_ENOTFOUND when the file doesn't exist or error code @@ -207,6 +209,7 @@ GIT_EXTERN(int) git_config_add_file_ondisk( git_config *cfg, const char *path, git_config_level_t level, + const git_repository *repo, int force); /** diff --git a/include/git2/repository.h b/include/git2/repository.h index 8aac0b3f7..6e0c1f71e 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -440,7 +440,7 @@ typedef enum { * @param item The repository item for which to retrieve the path * @return 0, GIT_ENOTFOUND if the path cannot exist or an error code */ -GIT_EXTERN(int) git_repository_item_path(git_buf *out, git_repository *repo, git_repository_item_t item); +GIT_EXTERN(int) git_repository_item_path(git_buf *out, const git_repository *repo, git_repository_item_t item); /** * Get the path of this repository @@ -451,7 +451,7 @@ GIT_EXTERN(int) git_repository_item_path(git_buf *out, git_repository *repo, git * @param repo A repository object * @return the path to the repository */ -GIT_EXTERN(const char *) git_repository_path(git_repository *repo); +GIT_EXTERN(const char *) git_repository_path(const git_repository *repo); /** * Get the path of the working directory for this repository @@ -462,7 +462,7 @@ GIT_EXTERN(const char *) git_repository_path(git_repository *repo); * @param repo A repository object * @return the path to the working dir, if it exists */ -GIT_EXTERN(const char *) git_repository_workdir(git_repository *repo); +GIT_EXTERN(const char *) git_repository_workdir(const git_repository *repo); /** * Get the path of the shared common directory for this repository @@ -473,7 +473,7 @@ GIT_EXTERN(const char *) git_repository_workdir(git_repository *repo); * @param repo A repository object * @return the path to the common dir */ -GIT_EXTERN(const char *) git_repository_commondir(git_repository *repo); +GIT_EXTERN(const char *) git_repository_commondir(const git_repository *repo); /** * Set the path to the working directory for this repository @@ -501,7 +501,7 @@ GIT_EXTERN(int) git_repository_set_workdir( * @param repo Repo to test * @return 1 if the repository is bare, 0 otherwise. */ -GIT_EXTERN(int) git_repository_is_bare(git_repository *repo); +GIT_EXTERN(int) git_repository_is_bare(const git_repository *repo); /** * Check if a repository is a linked work tree @@ -509,7 +509,7 @@ GIT_EXTERN(int) git_repository_is_bare(git_repository *repo); * @param repo Repo to test * @return 1 if the repository is a linked work tree, 0 otherwise. */ -GIT_EXTERN(int) git_repository_is_worktree(git_repository *repo); +GIT_EXTERN(int) git_repository_is_worktree(const git_repository *repo); /** * Get the configuration file for this repository. diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h index 4dad6da42..ed203226f 100644 --- a/include/git2/sys/config.h +++ b/include/git2/sys/config.h @@ -58,7 +58,7 @@ struct git_config_backend { struct git_config *cfg; /* Open means open the file/database and parse if necessary */ - int (*open)(struct git_config_backend *, git_config_level_t level); + int (*open)(struct git_config_backend *, git_config_level_t level, const git_repository *repo); int (*get)(struct git_config_backend *, const char *key, git_config_entry **entry); int (*set)(struct git_config_backend *, const char *key, const char *value); int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value); @@ -111,6 +111,8 @@ GIT_EXTERN(int) git_config_init_backend( * @param cfg the configuration to add the file to * @param file the configuration file (backend) to add * @param level the priority level of the backend + * @param repo optional repository to allow parsing of + * conditional includes * @param force if a config file already exists for the given * priority level, replace it * @return 0 on success, GIT_EEXISTS when adding more than one file @@ -120,6 +122,7 @@ GIT_EXTERN(int) git_config_add_backend( git_config *cfg, git_config_backend *file, git_config_level_t level, + const git_repository *repo, int force); /** @} */ diff --git a/src/config.c b/src/config.c index 602e0e827..1bc11b99f 100644 --- a/src/config.c +++ b/src/config.c @@ -99,6 +99,7 @@ int git_config_add_file_ondisk( git_config *cfg, const char *path, git_config_level_t level, + const git_repository *repo, int force) { git_config_backend *file = NULL; @@ -116,7 +117,7 @@ int git_config_add_file_ondisk( if (git_config_file__ondisk(&file, path) < 0) return -1; - if ((res = git_config_add_backend(cfg, file, level, force)) < 0) { + if ((res = git_config_add_backend(cfg, file, level, repo, force)) < 0) { /* * free manually; the file is not owned by the config * instance yet and will not be freed on cleanup @@ -138,7 +139,7 @@ int git_config_open_ondisk(git_config **out, const char *path) if (git_config_new(&config) < 0) return -1; - if ((error = git_config_add_file_ondisk(config, path, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0) + if ((error = git_config_add_file_ondisk(config, path, GIT_CONFIG_LEVEL_LOCAL, NULL, 0)) < 0) git_config_free(config); else *out = config; @@ -164,7 +165,7 @@ int git_config_snapshot(git_config **out, git_config *in) if ((error = internal->file->snapshot(&b, internal->file)) < 0) break; - if ((error = git_config_add_backend(config, b, internal->level, 0)) < 0) { + if ((error = git_config_add_backend(config, b, internal->level, NULL, 0)) < 0) { b->free(b); break; } @@ -307,6 +308,7 @@ int git_config_add_backend( git_config *cfg, git_config_backend *file, git_config_level_t level, + const git_repository *repo, int force) { file_internal *internal; @@ -316,7 +318,7 @@ int git_config_add_backend( GITERR_CHECK_VERSION(file, GIT_CONFIG_BACKEND_VERSION, "git_config_backend"); - if ((result = file->open(file, level)) < 0) + if ((result = file->open(file, level, repo)) < 0) return result; internal = git__malloc(sizeof(file_internal)); @@ -1147,20 +1149,20 @@ int git_config_open_default(git_config **out) if (!git_config_find_global(&buf) || !git_config__global_location(&buf)) { error = git_config_add_file_ondisk(cfg, buf.ptr, - GIT_CONFIG_LEVEL_GLOBAL, 0); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0); } if (!error && !git_config_find_xdg(&buf)) error = git_config_add_file_ondisk(cfg, buf.ptr, - GIT_CONFIG_LEVEL_XDG, 0); + GIT_CONFIG_LEVEL_XDG, NULL, 0); if (!error && !git_config_find_system(&buf)) error = git_config_add_file_ondisk(cfg, buf.ptr, - GIT_CONFIG_LEVEL_SYSTEM, 0); + GIT_CONFIG_LEVEL_SYSTEM, NULL, 0); if (!error && !git_config_find_programdata(&buf)) error = git_config_add_file_ondisk(cfg, buf.ptr, - GIT_CONFIG_LEVEL_PROGRAMDATA, 0); + GIT_CONFIG_LEVEL_PROGRAMDATA, NULL, 0); git_buf_free(&buf); diff --git a/src/config_file.c b/src/config_file.c index 9a6d81516..cc4e7b3b7 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -105,6 +105,7 @@ typedef struct { diskfile_header header; git_config_level_t level; + const git_repository *repo; bool locked; git_filebuf locked_buf; @@ -119,7 +120,7 @@ typedef struct { diskfile_backend *snapshot_from; } diskfile_readonly_backend; -static int config_read(git_strmap *values, struct config_file *file, git_config_level_t level, int depth); +static int config_read(git_strmap *values, const git_repository *repo, struct config_file *file, git_config_level_t level, int depth); static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const regex_t *preg, const char *value); static char *escape_value(const char *ptr); @@ -281,12 +282,13 @@ static void config_file_clear(struct config_file *file) git__free(file->path); } -static int config_open(git_config_backend *cfg, git_config_level_t level) +static int config_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo) { int res; diskfile_backend *b = (diskfile_backend *)cfg; b->level = level; + b->repo = repo; if ((res = refcounted_strmap_alloc(&b->header.values)) < 0) return res; @@ -295,7 +297,7 @@ static int config_open(git_config_backend *cfg, git_config_level_t level) if (!git_path_exists(b->file.path)) return 0; - if (res < 0 || (res = config_read(b->header.values->values, &b->file, level, 0)) < 0) { + if (res < 0 || (res = config_read(b->header.values->values, repo, &b->file, level, 0)) < 0) { refcounted_strmap_free(b->header.values); b->header.values = NULL; } @@ -359,7 +361,7 @@ static int config_refresh(git_config_backend *cfg) } git_array_clear(b->file.includes); - if ((error = config_read(values->values, &b->file, b->level, 0)) < 0) + if ((error = config_read(values->values, b->repo, &b->file, b->level, 0)) < 0) goto out; if ((error = git_mutex_lock(&b->header.values_mutex)) < 0) { @@ -439,7 +441,7 @@ static int config_iterator_new( if ((error = config_snapshot(&snapshot, backend)) < 0) return error; - if ((error = snapshot->open(snapshot, b->level)) < 0) + if ((error = snapshot->open(snapshot, b->level, b->repo)) < 0) return error; it = git__calloc(1, sizeof(git_config_file_iter)); @@ -831,7 +833,7 @@ static void backend_readonly_free(git_config_backend *_backend) git__free(backend); } -static int config_readonly_open(git_config_backend *cfg, git_config_level_t level) +static int config_readonly_open(git_config_backend *cfg, git_config_level_t level, const git_repository *repo) { diskfile_readonly_backend *b = (diskfile_readonly_backend *) cfg; diskfile_backend *src = b->snapshot_from; @@ -842,8 +844,9 @@ static int config_readonly_open(git_config_backend *cfg, git_config_level_t leve if (!src_header->parent.readonly && (error = config_refresh(&src_header->parent)) < 0) return error; - /* We're just copying data, don't care about the level */ + /* We're just copying data, don't care about the level or repo*/ GIT_UNUSED(level); + GIT_UNUSED(repo); if ((src_map = refcounted_strmap_take(src_header)) == NULL) return -1; @@ -1568,11 +1571,148 @@ static int config_parse( } struct parse_data { + const git_repository *repo; + const char *file_path; git_strmap *values; git_config_level_t level; int depth; }; +static int parse_include(struct reader *reader, + struct parse_data *parse_data, const char *file) +{ + struct config_file *include; + git_buf path = GIT_BUF_INIT; + char *dir; + int result; + + if ((result = git_path_dirname_r(&path, reader->file->path)) < 0) + return result; + + dir = git_buf_detach(&path); + result = included_path(&path, dir, file); + git__free(dir); + + if (result < 0) + return result; + + include = git_array_alloc(reader->file->includes); + memset(include, 0, sizeof(*include)); + git_array_init(include->includes); + include->path = git_buf_detach(&path); + + result = config_read(parse_data->values, parse_data->repo, + include, parse_data->level, parse_data->depth+1); + + if (result == GIT_ENOTFOUND) { + giterr_clear(); + result = 0; + } + + return result; +} + +static int do_match_gitdir( + int *matches, + const git_repository *repo, + const char *cfg_file, + const char *value, + bool case_insensitive) +{ + git_buf path = GIT_BUF_INIT; + int error, fnmatch_flags; + + if (value[0] == '.' && git_path_is_dirsep(value[1])) { + git_path_dirname_r(&path, cfg_file); + git_buf_joinpath(&path, path.ptr, value + 2); + } else if (value[0] == '~' && git_path_is_dirsep(value[1])) + git_sysdir_expand_global_file(&path, value + 1); + else if (!git_path_is_absolute(value)) + git_buf_joinpath(&path, "**", value); + else + git_buf_sets(&path, value); + + if (git_buf_oom(&path)) { + error = -1; + goto out; + } + + if (git_path_is_dirsep(value[strlen(value) - 1])) + git_buf_puts(&path, "**"); + + fnmatch_flags = FNM_PATHNAME|FNM_LEADING_DIR; + if (case_insensitive) + fnmatch_flags |= FNM_IGNORECASE; + + if ((error = p_fnmatch(path.ptr, git_repository_path(repo), fnmatch_flags)) < 0) + goto out; + + *matches = (error == 0); + +out: + git_buf_free(&path); + return error; +} + +static int conditional_match_gitdir( + int *matches, + const git_repository *repo, + const char *cfg_file, + const char *value) +{ + return do_match_gitdir(matches, repo, cfg_file, value, false); +} + +static int conditional_match_gitdir_i( + int *matches, + const git_repository *repo, + const char *cfg_file, + const char *value) +{ + return do_match_gitdir(matches, repo, cfg_file, value, true); +} + +static const struct { + const char *prefix; + int (*matches)(int *matches, const git_repository *repo, const char *cfg, const char *value); +} conditions[] = { + { "gitdir:", conditional_match_gitdir }, + { "gitdir/i:", conditional_match_gitdir_i } +}; + +static int parse_conditional_include(struct reader *reader, + struct parse_data *parse_data, const char *section, const char *file) +{ + char *condition; + size_t i; + int error = 0, matches; + + if (!parse_data->repo) + return 0; + + condition = git__substrdup(section + strlen("includeIf."), + strlen(section) - strlen("includeIf.") - strlen(".path")); + + for (i = 0; i < ARRAY_SIZE(conditions); i++) { + if (git__prefixcmp(condition, conditions[i].prefix)) + continue; + + if ((error = conditions[i].matches(&matches, + parse_data->repo, + parse_data->file_path, + condition + strlen(conditions[i].prefix))) < 0) + break; + + if (matches) + error = parse_include(reader, parse_data, file); + + break; + } + + git__free(condition); + return error; +} + static int read_on_variable( struct reader *reader, const char *current_section, @@ -1615,38 +1755,23 @@ static int read_on_variable( result = 0; /* Add or append the new config option */ - if (!git__strcmp(var->entry->name, "include.path")) { - struct config_file *include; - git_buf path = GIT_BUF_INIT; - char *dir; - - if ((result = git_path_dirname_r(&path, reader->file->path)) < 0) - return result; - - dir = git_buf_detach(&path); - result = included_path(&path, dir, var->entry->value); - git__free(dir); - - if (result < 0) - return result; + if (!git__strcmp(var->entry->name, "include.path")) + result = parse_include(reader, parse_data, var->entry->value); + else if (!git__prefixcmp(var->entry->name, "includeif.") && + !git__suffixcmp(var->entry->name, ".path")) + result = parse_conditional_include(reader, parse_data, + var->entry->name, var->entry->value); - include = git_array_alloc(reader->file->includes); - memset(include, 0, sizeof(*include)); - git_array_init(include->includes); - include->path = git_buf_detach(&path); - - result = config_read(parse_data->values, include, parse_data->level, parse_data->depth+1); - - if (result == GIT_ENOTFOUND) { - giterr_clear(); - result = 0; - } - } return result; } -static int config_read(git_strmap *values, struct config_file *file, git_config_level_t level, int depth) +static int config_read( + git_strmap *values, + const git_repository *repo, + struct config_file *file, + git_config_level_t level, + int depth) { struct parse_data parse_data; struct reader reader; @@ -1675,6 +1800,8 @@ static int config_read(git_strmap *values, struct config_file *file, git_config_ if (*reader.read_ptr == '\0') goto out; + parse_data.repo = repo; + parse_data.file_path = file->path; parse_data.values = values; parse_data.level = level; parse_data.depth = depth; diff --git a/src/config_file.h b/src/config_file.h index 11b8118f5..25ef45e5b 100644 --- a/src/config_file.h +++ b/src/config_file.h @@ -12,9 +12,9 @@ #include "git2/sys/config.h" #include "git2/config.h" -GIT_INLINE(int) git_config_file_open(git_config_backend *cfg, unsigned int level) +GIT_INLINE(int) git_config_file_open(git_config_backend *cfg, unsigned int level, const git_repository *repo) { - return cfg->open(cfg, level); + return cfg->open(cfg, level, repo); } GIT_INLINE(void) git_config_file_free(git_config_backend *cfg) diff --git a/src/path.h b/src/path.h index 360372cfb..aa24bcd2f 100644 --- a/src/path.h +++ b/src/path.h @@ -105,6 +105,12 @@ GIT_INLINE(int) git_path_is_dot_or_dotdotW(const wchar_t *name) (name[1] == L'.' && name[2] == L'\0'))); } +#define git_path_is_absolute(p) \ + (git__isalpha((p)[0]) && (p)[1] == ':' && ((p)[2] == '\\' || (p)[2] == '/')) + +#define git_path_is_dirsep(p) \ + ((p) == '/' || (p) == '\\') + /** * Convert backslashes in path to forward slashes. */ @@ -119,6 +125,13 @@ GIT_INLINE(void) git_path_mkposix(char *path) } #else # define git_path_mkposix(p) /* blank */ + +#define git_path_is_absolute(p) \ + ((p)[0] == '/') + +#define git_path_is_dirsep(p) \ + ((p) == '/') + #endif /** diff --git a/src/repository.c b/src/repository.c index fe549e6e8..fe0696355 100644 --- a/src/repository.c +++ b/src/repository.c @@ -946,7 +946,7 @@ static int load_config( return error; if ((error = git_repository_item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0) - error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0); + error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, repo, 0); if (error && error != GIT_ENOTFOUND) goto on_error; @@ -955,25 +955,25 @@ static int load_config( if (global_config_path != NULL && (error = git_config_add_file_ondisk( - cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, 0)) < 0 && + cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, repo, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; if (xdg_config_path != NULL && (error = git_config_add_file_ondisk( - cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, 0)) < 0 && + cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, repo, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; if (system_config_path != NULL && (error = git_config_add_file_ondisk( - cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, 0)) < 0 && + cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, repo, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; if (programdata_path != NULL && (error = git_config_add_file_ondisk( - cfg, programdata_path, GIT_CONFIG_LEVEL_PROGRAMDATA, 0)) < 0 && + cfg, programdata_path, GIT_CONFIG_LEVEL_PROGRAMDATA, repo, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; @@ -1475,7 +1475,7 @@ static int repo_local_config( giterr_clear(); if (!(error = git_config_add_file_ondisk( - parent, cfg_path, GIT_CONFIG_LEVEL_LOCAL, false))) + parent, cfg_path, GIT_CONFIG_LEVEL_LOCAL, repo, false))) error = git_config_open_level(out, parent, GIT_CONFIG_LEVEL_LOCAL); } @@ -2256,7 +2256,7 @@ int git_repository_is_empty(git_repository *repo) return is_empty; } -int git_repository_item_path(git_buf *out, git_repository *repo, git_repository_item_t item) +int git_repository_item_path(git_buf *out, const git_repository *repo, git_repository_item_t item) { const char *parent; @@ -2296,13 +2296,13 @@ int git_repository_item_path(git_buf *out, git_repository *repo, git_repository_ return 0; } -const char *git_repository_path(git_repository *repo) +const char *git_repository_path(const git_repository *repo) { assert(repo); return repo->gitdir; } -const char *git_repository_workdir(git_repository *repo) +const char *git_repository_workdir(const git_repository *repo) { assert(repo); @@ -2312,7 +2312,7 @@ const char *git_repository_workdir(git_repository *repo) return repo->workdir; } -const char *git_repository_commondir(git_repository *repo) +const char *git_repository_commondir(const git_repository *repo) { assert(repo); return repo->commondir; @@ -2362,13 +2362,13 @@ int git_repository_set_workdir( return error; } -int git_repository_is_bare(git_repository *repo) +int git_repository_is_bare(const git_repository *repo) { assert(repo); return repo->is_bare; } -int git_repository_is_worktree(git_repository *repo) +int git_repository_is_worktree(const git_repository *repo) { assert(repo); return repo->is_worktree; diff --git a/src/submodule.c b/src/submodule.c index 6c3e5f6bd..3ec0307b3 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -1960,7 +1960,7 @@ static git_config_backend *open_gitmodules( if (git_config_file__ondisk(&mods, path.ptr) < 0) mods = NULL; /* open should only fail here if the file is malformed */ - else if (git_config_file_open(mods, GIT_CONFIG_LEVEL_LOCAL) < 0) { + else if (git_config_file_open(mods, GIT_CONFIG_LEVEL_LOCAL, repo) < 0) { git_config_file_free(mods); mods = NULL; } diff --git a/src/win32/path_w32.c b/src/win32/path_w32.c index f8416b848..5e24260f7 100644 --- a/src/win32/path_w32.c +++ b/src/win32/path_w32.c @@ -18,11 +18,6 @@ #define PATH__ABSOLUTE_LEN 3 -#define path__is_dirsep(p) ((p) == '/' || (p) == '\\') - -#define path__is_absolute(p) \ - (git__isalpha((p)[0]) && (p)[1] == ':' && ((p)[2] == '\\' || (p)[2] == '/')) - #define path__is_nt_namespace(p) \ (((p)[0] == '\\' && (p)[1] == '\\' && (p)[2] == '?' && (p)[3] == '\\') || \ ((p)[0] == '/' && (p)[1] == '/' && (p)[2] == '?' && (p)[3] == '/')) @@ -59,7 +54,7 @@ static wchar_t *path__skip_server(wchar_t *path) wchar_t *c; for (c = path; *c; c++) { - if (path__is_dirsep(*c)) + if (git_path_is_dirsep(*c)) return c + 1; } @@ -73,9 +68,9 @@ static wchar_t *path__skip_prefix(wchar_t *path) if (wcsncmp(path, L"UNC\\", 4) == 0) path = path__skip_server(path + 4); - else if (path__is_absolute(path)) + else if (git_path_is_absolute(path)) path += PATH__ABSOLUTE_LEN; - } else if (path__is_absolute(path)) { + } else if (git_path_is_absolute(path)) { path += PATH__ABSOLUTE_LEN; } else if (path__is_unc(path)) { path = path__skip_server(path + 2); @@ -196,7 +191,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) dest += PATH__NT_NAMESPACE_LEN; /* See if this is an absolute path (beginning with a drive letter) */ - if (path__is_absolute(src)) { + if (git_path_is_absolute(src)) { if (git__utf8_to_16(dest, MAX_PATH, src) < 0) goto on_error; } @@ -220,7 +215,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src) if (path__cwd(dest, MAX_PATH) < 0) goto on_error; - if (!path__is_absolute(dest)) { + if (!git_path_is_absolute(dest)) { errno = ENOENT; goto on_error; } diff --git a/tests/config/backend.c b/tests/config/backend.c index 3fd6eb114..18c4ca59e 100644 --- a/tests/config/backend.c +++ b/tests/config/backend.c @@ -10,13 +10,13 @@ void test_config_backend__checks_version(void) backend.version = 1024; cl_git_pass(git_config_new(&cfg)); - cl_git_fail(git_config_add_backend(cfg, &backend, 0, false)); + cl_git_fail(git_config_add_backend(cfg, &backend, 0, NULL, false)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); giterr_clear(); backend.version = 1024; - cl_git_fail(git_config_add_backend(cfg, &backend, 0, false)); + cl_git_fail(git_config_add_backend(cfg, &backend, 0, NULL, false)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); diff --git a/tests/config/conditionals.c b/tests/config/conditionals.c new file mode 100644 index 000000000..3a87de21f --- /dev/null +++ b/tests/config/conditionals.c @@ -0,0 +1,103 @@ +#include "clar_libgit2.h" +#include "buffer.h" +#include "fileops.h" + +#ifdef GIT_WIN32 +# define ROOT_PREFIX "C:" +#else +# define ROOT_PREFIX +#endif + +static git_repository *_repo; + +void test_config_conditionals__initialize(void) +{ + _repo = cl_git_sandbox_init("empty_standard_repo"); +} + +void test_config_conditionals__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +static void assert_condition_includes(const char *keyword, const char *path, bool expected) +{ + git_config *cfg; + git_buf buf = GIT_BUF_INIT; + + git_buf_printf(&buf, "[includeIf \"%s:%s\"]\n", keyword, path); + git_buf_puts(&buf, "path = other\n"); + + cl_git_mkfile("empty_standard_repo/.git/config", buf.ptr); + cl_git_mkfile("empty_standard_repo/.git/other", "[foo]\nbar=baz\n"); + _repo = cl_git_sandbox_reopen(); + + cl_git_pass(git_repository_config(&cfg, _repo)); + + if (expected) { + git_buf_clear(&buf); + cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar")); + cl_assert_equal_s("baz", git_buf_cstr(&buf)); + } else { + cl_git_fail_with(GIT_ENOTFOUND, + git_config_get_string_buf(&buf, cfg, "foo.bar")); + } + + git_buf_free(&buf); + git_config_free(cfg); +} + +void test_config_conditionals__gitdir(void) +{ + git_buf path = GIT_BUF_INIT; + char *sandbox_path; + + assert_condition_includes("gitdir", ROOT_PREFIX "/", true); + assert_condition_includes("gitdir", "empty_standard_repo", true); + assert_condition_includes("gitdir", "empty_standard_repo/", true); + assert_condition_includes("gitdir", "./", true); + + assert_condition_includes("gitdir", ROOT_PREFIX "/nonexistent", false); + assert_condition_includes("gitdir", ROOT_PREFIX "/empty_standard_repo", false); + assert_condition_includes("gitdir", "empty_stand", false); + assert_condition_includes("gitdir", "~/empty_standard_repo", false); + + sandbox_path = p_realpath(clar_sandbox_path(), NULL); + + git_buf_joinpath(&path, sandbox_path, "/"); + assert_condition_includes("gitdir", path.ptr, true); + + git_buf_joinpath(&path, sandbox_path, "/*"); + assert_condition_includes("gitdir", path.ptr, true); + + git_buf_joinpath(&path, sandbox_path, "empty_standard_repo"); + assert_condition_includes("gitdir", path.ptr, true); + + git_buf_joinpath(&path, sandbox_path, "Empty_Standard_Repo"); + assert_condition_includes("gitdir", path.ptr, false); + + git__free(sandbox_path); + git_buf_free(&path); +} + +void test_config_conditionals__gitdir_i(void) +{ + git_buf path = GIT_BUF_INIT; + char *sandbox_path; + + sandbox_path = p_realpath(clar_sandbox_path(), NULL); + + git_buf_joinpath(&path, sandbox_path, "empty_standard_repo"); + assert_condition_includes("gitdir/i", path.ptr, true); + + git_buf_joinpath(&path, sandbox_path, "EMPTY_STANDARD_REPO"); + assert_condition_includes("gitdir/i", path.ptr, true); + + git__free(sandbox_path); + git_buf_free(&path); +} + +void test_config_conditionals__invalid_conditional_fails(void) +{ + assert_condition_includes("foobar", ".git", false); +} diff --git a/tests/config/configlevel.c b/tests/config/configlevel.c index ca478b1a5..b73656cb9 100644 --- a/tests/config/configlevel.c +++ b/tests/config/configlevel.c @@ -7,11 +7,11 @@ void test_config_configlevel__adding_the_same_level_twice_returns_EEXISTS(void) cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), - GIT_CONFIG_LEVEL_LOCAL, 0)); + GIT_CONFIG_LEVEL_LOCAL, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"), - GIT_CONFIG_LEVEL_GLOBAL, 0)); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); error = git_config_add_file_ondisk(cfg, cl_fixture("config/config16"), - GIT_CONFIG_LEVEL_GLOBAL, 0); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0); cl_git_fail(error); cl_assert_equal_i(GIT_EEXISTS, error); @@ -26,9 +26,9 @@ void test_config_configlevel__can_replace_a_config_file_at_an_existing_level(voi cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"), - GIT_CONFIG_LEVEL_LOCAL, 1)); + GIT_CONFIG_LEVEL_LOCAL, NULL, 1)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"), - GIT_CONFIG_LEVEL_LOCAL, 1)); + GIT_CONFIG_LEVEL_LOCAL, NULL, 1)); cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.stringglobal")); cl_assert_equal_s("don't find me!", buf.ptr); @@ -45,9 +45,9 @@ void test_config_configlevel__can_read_from_a_single_level_focused_file_after_pa cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"), - GIT_CONFIG_LEVEL_GLOBAL, 0)); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"), - GIT_CONFIG_LEVEL_LOCAL, 0)); + GIT_CONFIG_LEVEL_LOCAL, NULL, 0)); cl_git_pass(git_config_open_level(&single_level_cfg, cfg, GIT_CONFIG_LEVEL_LOCAL)); diff --git a/tests/config/multivar.c b/tests/config/multivar.c index d1b8c4cda..4f08a4817 100644 --- a/tests/config/multivar.c +++ b/tests/config/multivar.c @@ -94,27 +94,27 @@ void test_config_multivar__get(void) check_get_multivar_foreach(cfg, 2, 1); /* add another that has the _name entry */ - cl_git_pass(git_config_add_file_ondisk(cfg, "config/config9", GIT_CONFIG_LEVEL_SYSTEM, 1)); + cl_git_pass(git_config_add_file_ondisk(cfg, "config/config9", GIT_CONFIG_LEVEL_SYSTEM, NULL, 1)); check_get_multivar_foreach(cfg, 3, 2); /* add another that does not have the _name entry */ - cl_git_pass(git_config_add_file_ondisk(cfg, "config/config0", GIT_CONFIG_LEVEL_GLOBAL, 1)); + cl_git_pass(git_config_add_file_ondisk(cfg, "config/config0", GIT_CONFIG_LEVEL_GLOBAL, NULL, 1)); check_get_multivar_foreach(cfg, 3, 2); /* add another that does not have the _name entry at the end */ - cl_git_pass(git_config_add_file_ondisk(cfg, "config/config1", GIT_CONFIG_LEVEL_APP, 1)); + cl_git_pass(git_config_add_file_ondisk(cfg, "config/config1", GIT_CONFIG_LEVEL_APP, NULL, 1)); check_get_multivar_foreach(cfg, 3, 2); /* drop original file */ - cl_git_pass(git_config_add_file_ondisk(cfg, "config/config2", GIT_CONFIG_LEVEL_LOCAL, 1)); + cl_git_pass(git_config_add_file_ondisk(cfg, "config/config2", GIT_CONFIG_LEVEL_LOCAL, NULL, 1)); check_get_multivar_foreach(cfg, 1, 1); /* drop other file with match */ - cl_git_pass(git_config_add_file_ondisk(cfg, "config/config3", GIT_CONFIG_LEVEL_SYSTEM, 1)); + cl_git_pass(git_config_add_file_ondisk(cfg, "config/config3", GIT_CONFIG_LEVEL_SYSTEM, NULL, 1)); check_get_multivar_foreach(cfg, 0, 0); /* reload original file (add different place in order) */ - cl_git_pass(git_config_add_file_ondisk(cfg, "config/config11", GIT_CONFIG_LEVEL_SYSTEM, 1)); + cl_git_pass(git_config_add_file_ondisk(cfg, "config/config11", GIT_CONFIG_LEVEL_SYSTEM, NULL, 1)); check_get_multivar_foreach(cfg, 2, 1); check_get_multivar(cfg, 2); diff --git a/tests/config/read.c b/tests/config/read.c index f86b2d79e..25a4fcaf4 100644 --- a/tests/config/read.c +++ b/tests/config/read.c @@ -289,9 +289,9 @@ void test_config_read__foreach(void) cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), - GIT_CONFIG_LEVEL_SYSTEM, 0)); + GIT_CONFIG_LEVEL_SYSTEM, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"), - GIT_CONFIG_LEVEL_GLOBAL, 0)); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); count = 0; cl_git_pass(git_config_foreach(cfg, count_cfg_entries_and_compare_levels, &count)); @@ -313,9 +313,9 @@ void test_config_read__iterator(void) cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), - GIT_CONFIG_LEVEL_SYSTEM, 0)); + GIT_CONFIG_LEVEL_SYSTEM, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"), - GIT_CONFIG_LEVEL_GLOBAL, 0)); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); count = 0; cl_git_pass(git_config_iterator_new(&iter, cfg)); @@ -445,7 +445,7 @@ void test_config_read__read_git_config_entry(void) cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), - GIT_CONFIG_LEVEL_SYSTEM, 0)); + GIT_CONFIG_LEVEL_SYSTEM, NULL, 0)); cl_git_pass(git_config_get_entry(&entry, cfg, "core.dummy2")); cl_assert_equal_s("core.dummy2", entry->name); @@ -469,11 +469,11 @@ void test_config_read__local_config_overrides_global_config_overrides_system_con cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), - GIT_CONFIG_LEVEL_SYSTEM, 0)); + GIT_CONFIG_LEVEL_SYSTEM, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"), - GIT_CONFIG_LEVEL_GLOBAL, 0)); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config16"), - GIT_CONFIG_LEVEL_LOCAL, 0)); + GIT_CONFIG_LEVEL_LOCAL, NULL, 0)); cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2")); cl_assert_equal_i(28, i); @@ -482,9 +482,9 @@ void test_config_read__local_config_overrides_global_config_overrides_system_con cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), - GIT_CONFIG_LEVEL_SYSTEM, 0)); + GIT_CONFIG_LEVEL_SYSTEM, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"), - GIT_CONFIG_LEVEL_GLOBAL, 0)); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2")); cl_assert_equal_i(7, i); @@ -510,11 +510,11 @@ void test_config_read__fallback_from_local_to_global_and_from_global_to_system(v cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"), - GIT_CONFIG_LEVEL_SYSTEM, 0)); + GIT_CONFIG_LEVEL_SYSTEM, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"), - GIT_CONFIG_LEVEL_GLOBAL, 0)); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config16"), - GIT_CONFIG_LEVEL_LOCAL, 0)); + GIT_CONFIG_LEVEL_LOCAL, NULL, 0)); cl_git_pass(git_config_get_int32(&i, cfg, "core.global")); cl_assert_equal_i(17, i); @@ -546,9 +546,9 @@ void test_config_read__simple_read_from_specific_level(void) cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"), - GIT_CONFIG_LEVEL_GLOBAL, 0)); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"), - GIT_CONFIG_LEVEL_SYSTEM, 0)); + GIT_CONFIG_LEVEL_SYSTEM, NULL, 0)); cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL)); diff --git a/tests/config/readonly.c b/tests/config/readonly.c index 6d6819eef..a424922c1 100644 --- a/tests/config/readonly.c +++ b/tests/config/readonly.c @@ -22,7 +22,7 @@ void test_config_readonly__writing_to_readonly_fails(void) cl_git_pass(git_config_file__ondisk(&backend, "global")); backend->readonly = 1; - cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0)); + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); cl_git_fail_with(GIT_ENOTFOUND, git_config_set_string(cfg, "foo.bar", "baz")); cl_assert(!git_path_exists("global")); @@ -34,10 +34,10 @@ void test_config_readonly__writing_to_cfg_with_rw_precedence_succeeds(void) cl_git_pass(git_config_file__ondisk(&backend, "global")); backend->readonly = 1; - cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0)); + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); cl_git_pass(git_config_file__ondisk(&backend, "local")); - cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, 0)); + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, NULL, 0)); cl_git_pass(git_config_set_string(cfg, "foo.bar", "baz")); @@ -52,10 +52,10 @@ void test_config_readonly__writing_to_cfg_with_ro_precedence_succeeds(void) cl_git_pass(git_config_file__ondisk(&backend, "local")); backend->readonly = 1; - cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, 0)); + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, NULL, 0)); cl_git_pass(git_config_file__ondisk(&backend, "global")); - cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, 0)); + cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); cl_git_pass(git_config_set_string(cfg, "foo.bar", "baz")); diff --git a/tests/config/write.c b/tests/config/write.c index 01b018b12..6687ba1f7 100644 --- a/tests/config/write.c +++ b/tests/config/write.c @@ -93,9 +93,9 @@ void test_config_write__delete_value_at_specific_level(void) cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, "config9", - GIT_CONFIG_LEVEL_LOCAL, 0)); + GIT_CONFIG_LEVEL_LOCAL, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, "config15", - GIT_CONFIG_LEVEL_GLOBAL, 0)); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL)); @@ -368,9 +368,9 @@ void test_config_write__add_value_at_specific_level(void) // open config15 as global level config file cl_git_pass(git_config_new(&cfg)); cl_git_pass(git_config_add_file_ondisk(cfg, "config9", - GIT_CONFIG_LEVEL_LOCAL, 0)); + GIT_CONFIG_LEVEL_LOCAL, NULL, 0)); cl_git_pass(git_config_add_file_ondisk(cfg, "config15", - GIT_CONFIG_LEVEL_GLOBAL, 0)); + GIT_CONFIG_LEVEL_GLOBAL, NULL, 0)); cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL)); |