From eac773d92bccc7d3fc7ce1b18578d374873e0d7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 14 Jan 2015 15:05:43 +0100 Subject: config: add parsing and getter for paths --- CHANGELOG.md | 4 ++++ include/git2/config.h | 32 ++++++++++++++++++++++++++++++++ src/config.c | 41 +++++++++++++++++++++++++++++++++++++++++ tests/config/read.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96bd9a16e..892a489a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ v0.22 + 1 ### API additions +* Parsing and retrieving a configuration value as a path is exposed + via `git_config_parse_path()` and `git_config_get_path()` + respectively. + ### API removals ### Breaking API changes diff --git a/include/git2/config.h b/include/git2/config.h index e32c614ea..1ed8d2441 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -319,6 +319,24 @@ GIT_EXTERN(int) git_config_get_int64(int64_t *out, const git_config *cfg, const */ GIT_EXTERN(int) git_config_get_bool(int *out, const git_config *cfg, const char *name); +/** + * Get the value of a path config variable. + * + * A leading '~' will be expanded to the global search path (which + * defaults to the user's home directory but can be overridden via + * `git_libgit2_opts()`. + * + * All config files will be looked into, in the order of their + * defined level. A higher level means a higher priority. The + * first occurrence of the variable will be returned here. + * + * @param out the buffer in which to store the result + * @param cfg where to look for the variable + * @param name the variable's name + * @param 0 or an error code + */ +GIT_EXTERN(int) git_config_get_path(git_buf *out, const git_config *cfg, const char *name); + /** * Get the value of a string config variable. * @@ -615,6 +633,20 @@ GIT_EXTERN(int) git_config_parse_int32(int32_t *out, const char *value); */ GIT_EXTERN(int) git_config_parse_int64(int64_t *out, const char *value); +/** + * Parse a string value as a path. + * + * A leading '~' will be expanded to the global search path (which + * defaults to the user's home directory but can be overridden via + * `git_libgit2_opts()`. + * + * If the value does not begin with a tilde, the input will be + * returned. + * + * @param out placae to store the result of parsing + * @param value the path to evaluate + */ +GIT_EXTERN(int) git_config_parse_path(git_buf *out, const char *value); /** * Perform an operation on each config variable in given config backend diff --git a/src/config.c b/src/config.c index 0f8c24465..f80770138 100644 --- a/src/config.c +++ b/src/config.c @@ -785,6 +785,17 @@ int git_config_get_bool(int *out, const git_config *cfg, const char *name) return git_config_parse_bool(out, entry->value); } +int git_config_get_path(git_buf *out, const git_config *cfg, const char *name) +{ + const git_config_entry *entry; + int error; + + if ((error = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) + return error; + + return git_config_parse_path(out, entry->value); +} + int git_config_get_string( const char **out, const git_config *cfg, const char *name) { @@ -1184,6 +1195,36 @@ fail_parse: return -1; } +int git_config_parse_path(git_buf *out, const char *value) +{ + int error = 0; + const git_buf *home; + + assert(out && value); + + git_buf_sanitize(out); + + if (value[0] == '~') { + if (value[1] != '\0' && value[1] != '/') { + giterr_set(GITERR_CONFIG, "retrieving a homedir by name is not supported"); + return -1; + } + + if ((error = git_sysdir_get(&home, GIT_SYSDIR_GLOBAL)) < 0) + return error; + + git_buf_sets(out, home->ptr); + git_buf_puts(out, value + 1); + + if (git_buf_oom(out)) + return -1; + + return 0; + } + + return git_buf_sets(out, value); +} + /* Take something the user gave us and make it nice for our hash function */ int git_config__normalize_name(const char *in, char **out) { diff --git a/tests/config/read.c b/tests/config/read.c index 25672729f..1799970fb 100644 --- a/tests/config/read.c +++ b/tests/config/read.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "buffer.h" +#include "path.h" void test_config_read__simple_read(void) { @@ -567,3 +569,47 @@ void test_config_read__override_variable(void) git_config_free(cfg); } + +void test_config_read__path(void) +{ + git_config *cfg; + git_buf path = GIT_BUF_INIT; + git_buf old_path = GIT_BUF_INIT; + git_buf home_path = GIT_BUF_INIT; + git_buf expected_path = GIT_BUF_INIT; + + cl_git_pass(p_mkdir("fakehome", 0777)); + cl_git_pass(git_path_prettify(&home_path, "fakehome", NULL)); + cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &old_path)); + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, home_path.ptr)); + cl_git_mkfile("./testconfig", "[some]\n path = ~/somefile"); + cl_git_pass(git_path_join_unrooted(&expected_path, "somefile", home_path.ptr, NULL)); + + cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig")); + cl_git_pass(git_config_get_path(&path, cfg, "some.path")); + cl_assert_equal_s(expected_path.ptr, path.ptr); + git_buf_free(&path); + + cl_git_mkfile("./testconfig", "[some]\n path = ~/"); + cl_git_pass(git_path_join_unrooted(&expected_path, "", home_path.ptr, NULL)); + + cl_git_pass(git_config_get_path(&path, cfg, "some.path")); + cl_assert_equal_s(expected_path.ptr, path.ptr); + git_buf_free(&path); + + cl_git_mkfile("./testconfig", "[some]\n path = ~"); + cl_git_pass(git_buf_sets(&expected_path, home_path.ptr)); + + cl_git_pass(git_config_get_path(&path, cfg, "some.path")); + cl_assert_equal_s(expected_path.ptr, path.ptr); + git_buf_free(&path); + + cl_git_mkfile("./testconfig", "[some]\n path = ~user/foo"); + cl_git_fail(git_config_get_path(&path, cfg, "some.path")); + + cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, old_path.ptr)); + git_buf_free(&old_path); + git_buf_free(&home_path); + git_buf_free(&expected_path); + git_config_free(cfg); +} -- cgit v1.2.1