summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2023-04-03 12:58:23 +0100
committerEdward Thomson <ethomson@edwardthomson.com>2023-04-04 09:05:16 +0100
commit389f9b10e6e71339fe28145098a37975c49a472d (patch)
tree641c303113e226c50995bc0fe588b11550af5c89
parent24b9c4b63374e850d165ae5f7055db6e47ff3051 (diff)
downloadlibgit2-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.c129
-rw-r--r--tests/libgit2/repo/env.c52
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);
+}