diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2023-04-03 12:58:23 +0100 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2023-04-04 09:05:16 +0100 |
commit | 389f9b10e6e71339fe28145098a37975c49a472d (patch) | |
tree | 641c303113e226c50995bc0fe588b11550af5c89 | |
parent | 24b9c4b63374e850d165ae5f7055db6e47ff3051 (diff) | |
download | libgit2-389f9b10e6e71339fe28145098a37975c49a472d.tar.gz |
repo: honor GIT_CONFIG_* environment variables
When the repository is opened with `GIT_REPOSITORY_OPEN_FROM_ENV`, honor
the `GIT_CONFIG_GLOBAL`, `GIT_CONFIG_SYSTEM` and `GIT_CONFIG_NOSYSTEM`
environment variables.
-rw-r--r-- | src/libgit2/repository.c | 129 | ||||
-rw-r--r-- | tests/libgit2/repo/env.c | 52 |
2 files changed, 146 insertions, 35 deletions
diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index cd0f4ad74..3f57fb23c 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -66,7 +66,7 @@ static const struct { static int check_repositoryformatversion(int *version, git_config *config); static int check_extensions(git_config *config, int version); -static int load_global_config(git_config **config); +static int load_global_config(git_config **config, bool use_env); static int load_objectformat(git_repository *repo, git_config *config); #define GIT_COMMONDIR_FILE "commondir" @@ -586,7 +586,10 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload) return 0; } -static int validate_ownership_config(bool *is_safe, const char *path) +static int validate_ownership_config( + bool *is_safe, + const char *path, + bool use_env) { validate_ownership_data ownership_data = { path, GIT_STR_INIT, is_safe @@ -594,7 +597,7 @@ static int validate_ownership_config(bool *is_safe, const char *path) git_config *config; int error; - if (load_global_config(&config) != 0) + if (load_global_config(&config, use_env) != 0) return 0; error = git_config_get_multivar_foreach(config, @@ -668,7 +671,8 @@ static int validate_ownership(git_repository *repo) } if (is_safe || - (error = validate_ownership_config(&is_safe, validation_paths[0])) < 0) + (error = validate_ownership_config( + &is_safe, validation_paths[0], repo->use_env)) < 0) goto done; if (!is_safe) { @@ -1241,32 +1245,81 @@ static const char *path_unless_empty(git_str *buf) return git_str_len(buf) > 0 ? git_str_cstr(buf) : NULL; } +GIT_INLINE(int) config_path_system(git_str *out, bool use_env) +{ + if (use_env) { + git_str no_system_buf = GIT_STR_INIT; + int no_system = 0; + int error; + + error = git__getenv(&no_system_buf, "GIT_CONFIG_NOSYSTEM"); + + if (error && error != GIT_ENOTFOUND) + return error; + + error = git_config_parse_bool(&no_system, no_system_buf.ptr); + git_str_dispose(&no_system_buf); + + if (no_system) + return 0; + + error = git__getenv(out, "GIT_CONFIG_SYSTEM"); + + if (error == 0 || error != GIT_ENOTFOUND) + return 0; + } + + git_config__find_system(out); + return 0; +} + +GIT_INLINE(int) config_path_global(git_str *out, bool use_env) +{ + if (use_env) { + int error = git__getenv(out, "GIT_CONFIG_GLOBAL"); + + if (error == 0 || error != GIT_ENOTFOUND) + return 0; + } + + git_config__find_global(out); + return 0; +} + int git_repository_config__weakptr(git_config **out, git_repository *repo) { int error = 0; if (repo->_config == NULL) { + git_str system_buf = GIT_STR_INIT; git_str global_buf = GIT_STR_INIT; git_str xdg_buf = GIT_STR_INIT; - git_str system_buf = GIT_STR_INIT; git_str programdata_buf = GIT_STR_INIT; + bool use_env = repo->use_env; git_config *config; - git_config__find_global(&global_buf); - git_config__find_xdg(&xdg_buf); - git_config__find_system(&system_buf); - git_config__find_programdata(&programdata_buf); + if (!(error = config_path_system(&system_buf, use_env)) && + !(error = config_path_global(&global_buf, use_env))) { + git_config__find_xdg(&xdg_buf); + git_config__find_programdata(&programdata_buf); + } - /* If there is no global file, open a backend for it anyway */ - if (git_str_len(&global_buf) == 0) - git_config__global_location(&global_buf); + if (!error) { + /* + * If there is no global file, open a backend + * for it anyway. + */ + if (git_str_len(&global_buf) == 0) + git_config__global_location(&global_buf); + + error = load_config( + &config, repo, + path_unless_empty(&global_buf), + path_unless_empty(&xdg_buf), + path_unless_empty(&system_buf), + path_unless_empty(&programdata_buf)); + } - error = load_config( - &config, repo, - path_unless_empty(&global_buf), - path_unless_empty(&xdg_buf), - path_unless_empty(&system_buf), - path_unless_empty(&programdata_buf)); if (!error) { GIT_REFCOUNT_OWN(config, repo); @@ -1966,7 +2019,7 @@ static bool is_filesystem_case_insensitive(const char *gitdir_path) * Return a configuration object with only the global and system * configurations; no repository-level configuration. */ -static int load_global_config(git_config **config) +static int load_global_config(git_config **config, bool use_env) { git_str global_buf = GIT_STR_INIT; git_str xdg_buf = GIT_STR_INIT; @@ -1974,16 +2027,17 @@ static int load_global_config(git_config **config) git_str programdata_buf = GIT_STR_INIT; int error; - git_config__find_global(&global_buf); - git_config__find_xdg(&xdg_buf); - git_config__find_system(&system_buf); - git_config__find_programdata(&programdata_buf); + if (!(error = config_path_system(&system_buf, use_env)) && + !(error = config_path_global(&global_buf, use_env))) { + git_config__find_xdg(&xdg_buf); + git_config__find_programdata(&programdata_buf); - error = load_config(config, NULL, - path_unless_empty(&global_buf), - path_unless_empty(&xdg_buf), - path_unless_empty(&system_buf), - path_unless_empty(&programdata_buf)); + error = load_config(config, NULL, + path_unless_empty(&global_buf), + path_unless_empty(&xdg_buf), + path_unless_empty(&system_buf), + path_unless_empty(&programdata_buf)); + } git_str_dispose(&global_buf); git_str_dispose(&xdg_buf); @@ -1993,7 +2047,7 @@ static int load_global_config(git_config **config) return error; } -static bool are_symlinks_supported(const char *wd_path) +static bool are_symlinks_supported(const char *wd_path, bool use_env) { git_config *config = NULL; int symlinks = 0; @@ -2006,10 +2060,12 @@ static bool are_symlinks_supported(const char *wd_path) * _not_ set, then we do not test or enable symlink support. */ #ifdef GIT_WIN32 - if (load_global_config(&config) < 0 || + if (load_global_config(&config, use_env) < 0 || git_config_get_bool(&symlinks, config, "core.symlinks") < 0 || !symlinks) goto done; +#else + GIT_UNUSED(use_env); #endif if (!(symlinks = git_fs_path_supports_symlinks(wd_path))) @@ -2082,7 +2138,8 @@ static int repo_init_fs_configs( const char *cfg_path, const char *repo_dir, const char *work_dir, - bool update_ignorecase) + bool update_ignorecase, + bool use_env) { int error = 0; @@ -2093,7 +2150,7 @@ static int repo_init_fs_configs( cfg, "core.filemode", is_chmod_supported(cfg_path))) < 0) return error; - if (!are_symlinks_supported(work_dir)) { + if (!are_symlinks_supported(work_dir, use_env)) { if ((error = git_config_set_bool(cfg, "core.symlinks", false)) < 0) return error; } else if (git_config_delete_entry(cfg, "core.symlinks") < 0) @@ -2130,6 +2187,7 @@ static int repo_init_config( git_config *config = NULL; bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0); bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0); + bool use_env = ((flags & GIT_REPOSITORY_OPEN_FROM_ENV) != 0); int version = GIT_REPO_VERSION_DEFAULT; if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0) @@ -2150,7 +2208,8 @@ static int repo_init_config( SET_REPO_CONFIG(int32, "core.repositoryformatversion", version); if ((error = repo_init_fs_configs( - config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0) + config, cfg_path.ptr, repo_dir, work_dir, + !is_reinit, use_env)) < 0) goto cleanup; if (!is_bare) { @@ -2214,8 +2273,8 @@ int git_repository_reinit_filesystem(git_repository *repo, int recurse) const char *repo_dir = git_repository_path(repo); if (!(error = repo_local_config(&config, &path, repo, repo_dir))) - error = repo_init_fs_configs( - config, path.ptr, repo_dir, git_repository_workdir(repo), true); + error = repo_init_fs_configs(config, path.ptr, repo_dir, + git_repository_workdir(repo), true, repo->use_env); git_config_free(config); git_str_dispose(&path); diff --git a/tests/libgit2/repo/env.c b/tests/libgit2/repo/env.c index 4a61581bd..0e6cc59d5 100644 --- a/tests/libgit2/repo/env.c +++ b/tests/libgit2/repo/env.c @@ -32,6 +32,8 @@ void test_repo_env__cleanup(void) git_futils_rmdir_r("peeled.git", NULL, GIT_RMDIR_REMOVE_FILES); cl_fixture_cleanup("test_workdir"); + cl_fixture_cleanup("test_global_conf"); + cl_fixture_cleanup("test_system_conf"); clear_git_env(); } @@ -315,3 +317,53 @@ void test_repo_env__commondir(void) git_repository_free(repo); cl_setenv("GIT_COMMON_DIR", NULL); } + +void test_repo_env__config(void) +{ + git_repository *repo; + git_config *config; + const char *system_path, *global_path; + int s, g; + + cl_fixture_sandbox("attr"); + cl_git_pass(p_rename("attr/.gitted", "attr/.git")); + + cl_git_rewritefile("test_system_conf", "[tttest]\n\tsys = true\n"); + cl_git_rewritefile("test_global_conf", "[tttest]\n\tglb = true\n"); + + system_path = cl_git_sandbox_path(0, "test_system_conf", NULL); + cl_setenv("GIT_CONFIG_SYSTEM", system_path); + + global_path = cl_git_sandbox_path(0, "test_global_conf", NULL); + cl_setenv("GIT_CONFIG_GLOBAL", global_path); + + /* Ensure we can override the system and global files */ + + cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL)); + cl_git_pass(git_repository_config(&config, repo)); + + cl_git_pass(git_config_get_bool(&s, config, "tttest.sys")); + cl_assert_equal_i(1, s); + cl_git_pass(git_config_get_bool(&g, config, "tttest.glb")); + cl_assert_equal_i(1, g); + + git_config_free(config); + git_repository_free(repo); + + /* Further ensure we can ignore the system file. */ + cl_setenv("GIT_CONFIG_NOSYSTEM", "TrUe"); + + cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL)); + cl_git_pass(git_repository_config(&config, repo)); + + cl_git_fail_with(GIT_ENOTFOUND, git_config_get_bool(&s, config, "tttest.sys")); + cl_git_pass(git_config_get_bool(&g, config, "tttest.glb")); + cl_assert_equal_i(1, g); + + git_config_free(config); + git_repository_free(repo); + + cl_setenv("GIT_CONFIG_NOSYSTEM", NULL); + cl_setenv("GIT_CONFIG_SYSTEM", NULL); + cl_setenv("GIT_CONFIG_GLOBAL", NULL); +} |