Commit af795759 by Vicent Martí

Merge pull request #1552 from carlosmn/config-helpers

Config helpers for global/xdg config files
parents d6465e1a 5d831887
...@@ -195,6 +195,21 @@ GIT_EXTERN(int) git_config_open_level( ...@@ -195,6 +195,21 @@ GIT_EXTERN(int) git_config_open_level(
unsigned int level); unsigned int level);
/** /**
* Open the global/XDG configuration file according to git's rules
*
* Git allows you to store your global configuration at
* `$HOME/.config` or `$XDG_CONFIG_HOME/git/config`. For backwards
* compatability, the XDG file shouldn't be used unless the use has
* created it explicitly. With this function you'll open the correct
* one to write to.
*
* @param out pointer in which to store the config object
* @param config the config object in which to look
*/
GIT_EXTERN(int) git_config_open_global(git_config **out, git_config *config);
/**
* Reload changed config files * Reload changed config files
* *
* A config file may be changed on disk out from under the in-memory * A config file may be changed on disk out from under the in-memory
......
...@@ -91,13 +91,15 @@ int git_config_add_file_ondisk( ...@@ -91,13 +91,15 @@ int git_config_add_file_ondisk(
int force) int force)
{ {
git_config_backend *file = NULL; git_config_backend *file = NULL;
struct stat st;
int res; int res;
assert(cfg && path); assert(cfg && path);
if (!git_path_isfile(path)) { res = p_stat(path, &st);
giterr_set(GITERR_CONFIG, "Cannot find config file '%s'", path); if (res < 0 && errno != ENOENT) {
return GIT_ENOTFOUND; giterr_set(GITERR_CONFIG, "Error stat'ing config file '%s'", path);
return -1;
} }
if (git_config_file__ondisk(&file, path) < 0) if (git_config_file__ondisk(&file, path) < 0)
...@@ -225,6 +227,14 @@ static int git_config__add_internal( ...@@ -225,6 +227,14 @@ static int git_config__add_internal(
return 0; return 0;
} }
int git_config_open_global(git_config **cfg_out, git_config *cfg)
{
if (!git_config_open_level(cfg_out, cfg, GIT_CONFIG_LEVEL_XDG))
return 0;
return git_config_open_level(cfg_out, cfg, GIT_CONFIG_LEVEL_GLOBAL);
}
int git_config_open_level( int git_config_open_level(
git_config **cfg_out, git_config **cfg_out,
const git_config *cfg_parent, const git_config *cfg_parent,
...@@ -381,7 +391,6 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) ...@@ -381,7 +391,6 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value)
internal = git_vector_get(&cfg->files, 0); internal = git_vector_get(&cfg->files, 0);
if (!internal) if (!internal)
/* Should we auto-vivify .git/config? Tricky from this location */
return config_error_nofiles(name); return config_error_nofiles(name);
file = internal->file; file = internal->file;
...@@ -598,6 +607,33 @@ int git_config_find_system(char *system_config_path, size_t length) ...@@ -598,6 +607,33 @@ int git_config_find_system(char *system_config_path, size_t length)
system_config_path, length, git_config_find_system_r); system_config_path, length, git_config_find_system_r);
} }
int git_config__global_location(git_buf *buf)
{
const git_buf *paths;
const char *sep, *start;
size_t len;
if (git_futils_dirs_get(&paths, GIT_FUTILS_DIR_GLOBAL) < 0)
return -1;
/* no paths, so give up */
if (git_buf_len(paths) == 0)
return -1;
start = git_buf_cstr(paths);
sep = strchr(start, GIT_PATH_LIST_SEPARATOR);
if (sep)
len = sep - start;
else
len = paths->size;
if (git_buf_set(buf, start, len) < 0)
return -1;
return git_buf_joinpath(buf, buf->ptr, GIT_CONFIG_FILENAME_GLOBAL);
}
int git_config_open_default(git_config **out) int git_config_open_default(git_config **out)
{ {
int error; int error;
...@@ -606,9 +642,12 @@ int git_config_open_default(git_config **out) ...@@ -606,9 +642,12 @@ int git_config_open_default(git_config **out)
error = git_config_new(&cfg); error = git_config_new(&cfg);
if (!error && !git_config_find_global_r(&buf)) if (!error && (!git_config_find_global_r(&buf) ||
!git_config__global_location(&buf))) {
error = git_config_add_file_ondisk(cfg, buf.ptr, error = git_config_add_file_ondisk(cfg, buf.ptr,
GIT_CONFIG_LEVEL_GLOBAL, 0); GIT_CONFIG_LEVEL_GLOBAL, 0);
} else {
}
if (!error && !git_config_find_xdg_r(&buf)) if (!error && !git_config_find_xdg_r(&buf))
error = git_config_add_file_ondisk(cfg, buf.ptr, error = git_config_add_file_ondisk(cfg, buf.ptr,
......
...@@ -28,6 +28,9 @@ extern int git_config_find_global_r(git_buf *global_config_path); ...@@ -28,6 +28,9 @@ extern int git_config_find_global_r(git_buf *global_config_path);
extern int git_config_find_xdg_r(git_buf *system_config_path); extern int git_config_find_xdg_r(git_buf *system_config_path);
extern int git_config_find_system_r(git_buf *system_config_path); extern int git_config_find_system_r(git_buf *system_config_path);
extern int git_config__global_location(git_buf *buf);
extern int git_config_rename_section( extern int git_config_rename_section(
git_repository *repo, git_repository *repo,
const char *old_section_name, /* eg "branch.dummy" */ const char *old_section_name, /* eg "branch.dummy" */
......
...@@ -594,6 +594,10 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo) ...@@ -594,6 +594,10 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo)
git_config_find_xdg_r(&xdg_buf); git_config_find_xdg_r(&xdg_buf);
git_config_find_system_r(&system_buf); git_config_find_system_r(&system_buf);
/* If there is no global file, open a backend for it anyway */
if (git_buf_len(&global_buf) == 0)
git_config__global_location(&global_buf);
error = load_config( error = load_config(
&config, repo, &config, repo,
path_unless_empty(&global_buf), path_unless_empty(&global_buf),
......
#include "clar_libgit2.h"
#include "buffer.h"
#include "fileops.h"
void test_config_global__initialize(void)
{
git_buf path = GIT_BUF_INIT;
cl_must_pass(p_mkdir("home", 0777));
cl_git_pass(git_path_prettify(&path, "home", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_must_pass(p_mkdir("xdg", 0777));
cl_git_pass(git_path_prettify(&path, "xdg", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, NULL));
git_buf_free(&path);
}
void test_config_global__cleanup(void)
{
cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(git_futils_rmdir_r("xdg", NULL, GIT_RMDIR_REMOVE_FILES));
}
void test_config_global__open_global(void)
{
git_config *cfg, *global, *selected, *dummy;
cl_git_pass(git_config_open_default(&cfg));
cl_git_pass(git_config_open_level(&global, cfg, GIT_CONFIG_LEVEL_GLOBAL));
cl_git_fail(git_config_open_level(&dummy, cfg, GIT_CONFIG_LEVEL_XDG));
cl_git_pass(git_config_open_global(&selected, cfg));
git_config_free(selected);
git_config_free(global);
git_config_free(cfg);
}
void test_config_global__open_xdg(void)
{
git_config *cfg, *xdg, *selected;
const char *val, *str = "teststring";
const char *key = "this.variable";
p_setenv("XDG_CONFIG_HOME", "xdg", 1);
cl_must_pass(p_mkdir("xdg/git/", 0777));
cl_git_mkfile("xdg/git/config", "");
cl_git_pass(git_config_open_default(&cfg));
cl_git_pass(git_config_open_level(&xdg, cfg, GIT_CONFIG_LEVEL_XDG));
cl_git_pass(git_config_open_global(&selected, cfg));
cl_git_pass(git_config_set_string(xdg, key, str));
cl_git_pass(git_config_get_string(&val, selected, key));
cl_assert_equal_s(str, val);
git_config_free(selected);
git_config_free(xdg);
git_config_free(cfg);
}
...@@ -449,10 +449,3 @@ void test_config_read__can_load_and_parse_an_empty_config_file(void) ...@@ -449,10 +449,3 @@ void test_config_read__can_load_and_parse_an_empty_config_file(void)
git_config_free(cfg); git_config_free(cfg);
} }
void test_config_read__cannot_load_a_non_existing_config_file(void)
{
git_config *cfg;
cl_assert_equal_i(GIT_ENOTFOUND, git_config_open_ondisk(&cfg, "./no.config"));
}
#include "clar_libgit2.h"
#include "fileops.h"
#include <ctype.h>
git_buf path = GIT_BUF_INIT;
void test_repo_config__initialize(void)
{
cl_fixture_sandbox("empty_standard_repo");
cl_git_pass(cl_rename("empty_standard_repo/.gitted", "empty_standard_repo/.git"));
git_buf_clear(&path);
cl_must_pass(p_mkdir("alternate", 0777));
cl_git_pass(git_path_prettify(&path, "alternate", NULL));
}
void test_repo_config__cleanup(void)
{
cl_git_pass(git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES));
git_buf_free(&path);
cl_fixture_cleanup("empty_standard_repo");
}
void test_repo_config__open_missing_global(void)
{
git_repository *repo;
git_config *config, *global;
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr));
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
cl_git_pass(git_repository_config(&config, repo));
cl_git_pass(git_config_open_level(&global, config, GIT_CONFIG_LEVEL_GLOBAL));
cl_git_pass(git_config_set_string(global, "test.set", "42"));
git_config_free(global);
git_config_free(config);
git_repository_free(repo);
}
void test_repo_config__open_missing_global_with_separators(void)
{
git_repository *repo;
git_config *config, *global;
cl_git_pass(git_buf_printf(&path, "%c%s", GIT_PATH_LIST_SEPARATOR, "dummy"));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr));
git_buf_free(&path);
cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
cl_git_pass(git_repository_config(&config, repo));
cl_git_pass(git_config_open_level(&global, config, GIT_CONFIG_LEVEL_GLOBAL));
cl_git_pass(git_config_set_string(global, "test.set", "42"));
git_config_free(global);
git_config_free(config);
git_repository_free(repo);
}
...@@ -309,7 +309,7 @@ void test_repo_open__no_config(void) ...@@ -309,7 +309,7 @@ void test_repo_open__no_config(void)
cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); cl_git_pass(git_repository_open(&repo, "empty_standard_repo"));
cl_git_pass(git_repository_config(&config, repo)); cl_git_pass(git_repository_config(&config, repo));
cl_git_fail(git_config_set_string(config, "test.set", "42")); cl_git_pass(git_config_set_string(config, "test.set", "42"));
git_config_free(config); git_config_free(config);
git_repository_free(repo); git_repository_free(repo);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment