diff options
| author | Patrick Steinhardt <ps@pks.im> | 2017-05-24 11:13:36 +0200 |
|---|---|---|
| committer | Patrick Steinhardt <ps@pks.im> | 2017-10-09 12:48:01 +0200 |
| commit | 071b6c0652ff0a0d6ce8c8c35d538d6edd67a52e (patch) | |
| tree | 057196d3563c8cc28d4794e5b3fe19b6cfa167b6 /src | |
| parent | 9d7a75be7c66cd5c7931db620b97cbd6525b626f (diff) | |
| download | libgit2-071b6c0652ff0a0d6ce8c8c35d538d6edd67a52e.tar.gz | |
config_file: implement conditional "gitdir" includes
Upstream git.git has implemented the ability to include other
configuration files based on conditions. Right now, this only includes
the ability to include a file based on the gitdir-location of the
repository the currently parsed configuration file belongs to. This
commit implements handling these conditional includes for the
case-sensitive "gitdir" condition.
Diffstat (limited to 'src')
| -rw-r--r-- | src/config_file.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/src/config_file.c b/src/config_file.c index 800e584d6..ba520fc29 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -1612,6 +1612,86 @@ static int parse_include(struct reader *reader, return result; } +static int conditional_match_gitdir( + int *matches, + const git_repository *repo, + const char *cfg_file, + const char *value) +{ + 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 ((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 const struct { + const char *prefix; + int (*matches)(int *matches, const git_repository *repo, const char *cfg, const char *value); +} conditions[] = { + { "gitdir:", conditional_match_gitdir } +}; + +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, @@ -1656,6 +1736,11 @@ static int read_on_variable( /* Add or append the new config option */ 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); + return result; } |
