Skip to content

Commit 389f9b1

Browse files
committed
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.
1 parent 24b9c4b commit 389f9b1

File tree

2 files changed

+146
-35
lines changed

2 files changed

+146
-35
lines changed

src/libgit2/repository.c

Lines changed: 94 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ static const struct {
6666

6767
static int check_repositoryformatversion(int *version, git_config *config);
6868
static int check_extensions(git_config *config, int version);
69-
static int load_global_config(git_config **config);
69+
static int load_global_config(git_config **config, bool use_env);
7070
static int load_objectformat(git_repository *repo, git_config *config);
7171

7272
#define GIT_COMMONDIR_FILE "commondir"
@@ -586,15 +586,18 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload)
586586
return 0;
587587
}
588588

589-
static int validate_ownership_config(bool *is_safe, const char *path)
589+
static int validate_ownership_config(
590+
bool *is_safe,
591+
const char *path,
592+
bool use_env)
590593
{
591594
validate_ownership_data ownership_data = {
592595
path, GIT_STR_INIT, is_safe
593596
};
594597
git_config *config;
595598
int error;
596599

597-
if (load_global_config(&config) != 0)
600+
if (load_global_config(&config, use_env) != 0)
598601
return 0;
599602

600603
error = git_config_get_multivar_foreach(config,
@@ -668,7 +671,8 @@ static int validate_ownership(git_repository *repo)
668671
}
669672

670673
if (is_safe ||
671-
(error = validate_ownership_config(&is_safe, validation_paths[0])) < 0)
674+
(error = validate_ownership_config(
675+
&is_safe, validation_paths[0], repo->use_env)) < 0)
672676
goto done;
673677

674678
if (!is_safe) {
@@ -1241,32 +1245,81 @@ static const char *path_unless_empty(git_str *buf)
12411245
return git_str_len(buf) > 0 ? git_str_cstr(buf) : NULL;
12421246
}
12431247

1248+
GIT_INLINE(int) config_path_system(git_str *out, bool use_env)
1249+
{
1250+
if (use_env) {
1251+
git_str no_system_buf = GIT_STR_INIT;
1252+
int no_system = 0;
1253+
int error;
1254+
1255+
error = git__getenv(&no_system_buf, "GIT_CONFIG_NOSYSTEM");
1256+
1257+
if (error && error != GIT_ENOTFOUND)
1258+
return error;
1259+
1260+
error = git_config_parse_bool(&no_system, no_system_buf.ptr);
1261+
git_str_dispose(&no_system_buf);
1262+
1263+
if (no_system)
1264+
return 0;
1265+
1266+
error = git__getenv(out, "GIT_CONFIG_SYSTEM");
1267+
1268+
if (error == 0 || error != GIT_ENOTFOUND)
1269+
return 0;
1270+
}
1271+
1272+
git_config__find_system(out);
1273+
return 0;
1274+
}
1275+
1276+
GIT_INLINE(int) config_path_global(git_str *out, bool use_env)
1277+
{
1278+
if (use_env) {
1279+
int error = git__getenv(out, "GIT_CONFIG_GLOBAL");
1280+
1281+
if (error == 0 || error != GIT_ENOTFOUND)
1282+
return 0;
1283+
}
1284+
1285+
git_config__find_global(out);
1286+
return 0;
1287+
}
1288+
12441289
int git_repository_config__weakptr(git_config **out, git_repository *repo)
12451290
{
12461291
int error = 0;
12471292

12481293
if (repo->_config == NULL) {
1294+
git_str system_buf = GIT_STR_INIT;
12491295
git_str global_buf = GIT_STR_INIT;
12501296
git_str xdg_buf = GIT_STR_INIT;
1251-
git_str system_buf = GIT_STR_INIT;
12521297
git_str programdata_buf = GIT_STR_INIT;
1298+
bool use_env = repo->use_env;
12531299
git_config *config;
12541300

1255-
git_config__find_global(&global_buf);
1256-
git_config__find_xdg(&xdg_buf);
1257-
git_config__find_system(&system_buf);
1258-
git_config__find_programdata(&programdata_buf);
1301+
if (!(error = config_path_system(&system_buf, use_env)) &&
1302+
!(error = config_path_global(&global_buf, use_env))) {
1303+
git_config__find_xdg(&xdg_buf);
1304+
git_config__find_programdata(&programdata_buf);
1305+
}
12591306

1260-
/* If there is no global file, open a backend for it anyway */
1261-
if (git_str_len(&global_buf) == 0)
1262-
git_config__global_location(&global_buf);
1307+
if (!error) {
1308+
/*
1309+
* If there is no global file, open a backend
1310+
* for it anyway.
1311+
*/
1312+
if (git_str_len(&global_buf) == 0)
1313+
git_config__global_location(&global_buf);
1314+
1315+
error = load_config(
1316+
&config, repo,
1317+
path_unless_empty(&global_buf),
1318+
path_unless_empty(&xdg_buf),
1319+
path_unless_empty(&system_buf),
1320+
path_unless_empty(&programdata_buf));
1321+
}
12631322

1264-
error = load_config(
1265-
&config, repo,
1266-
path_unless_empty(&global_buf),
1267-
path_unless_empty(&xdg_buf),
1268-
path_unless_empty(&system_buf),
1269-
path_unless_empty(&programdata_buf));
12701323
if (!error) {
12711324
GIT_REFCOUNT_OWN(config, repo);
12721325

@@ -1966,24 +2019,25 @@ static bool is_filesystem_case_insensitive(const char *gitdir_path)
19662019
* Return a configuration object with only the global and system
19672020
* configurations; no repository-level configuration.
19682021
*/
1969-
static int load_global_config(git_config **config)
2022+
static int load_global_config(git_config **config, bool use_env)
19702023
{
19712024
git_str global_buf = GIT_STR_INIT;
19722025
git_str xdg_buf = GIT_STR_INIT;
19732026
git_str system_buf = GIT_STR_INIT;
19742027
git_str programdata_buf = GIT_STR_INIT;
19752028
int error;
19762029

1977-
git_config__find_global(&global_buf);
1978-
git_config__find_xdg(&xdg_buf);
1979-
git_config__find_system(&system_buf);
1980-
git_config__find_programdata(&programdata_buf);
2030+
if (!(error = config_path_system(&system_buf, use_env)) &&
2031+
!(error = config_path_global(&global_buf, use_env))) {
2032+
git_config__find_xdg(&xdg_buf);
2033+
git_config__find_programdata(&programdata_buf);
19812034

1982-
error = load_config(config, NULL,
1983-
path_unless_empty(&global_buf),
1984-
path_unless_empty(&xdg_buf),
1985-
path_unless_empty(&system_buf),
1986-
path_unless_empty(&programdata_buf));
2035+
error = load_config(config, NULL,
2036+
path_unless_empty(&global_buf),
2037+
path_unless_empty(&xdg_buf),
2038+
path_unless_empty(&system_buf),
2039+
path_unless_empty(&programdata_buf));
2040+
}
19872041

19882042
git_str_dispose(&global_buf);
19892043
git_str_dispose(&xdg_buf);
@@ -1993,7 +2047,7 @@ static int load_global_config(git_config **config)
19932047
return error;
19942048
}
19952049

1996-
static bool are_symlinks_supported(const char *wd_path)
2050+
static bool are_symlinks_supported(const char *wd_path, bool use_env)
19972051
{
19982052
git_config *config = NULL;
19992053
int symlinks = 0;
@@ -2006,10 +2060,12 @@ static bool are_symlinks_supported(const char *wd_path)
20062060
* _not_ set, then we do not test or enable symlink support.
20072061
*/
20082062
#ifdef GIT_WIN32
2009-
if (load_global_config(&config) < 0 ||
2063+
if (load_global_config(&config, use_env) < 0 ||
20102064
git_config_get_bool(&symlinks, config, "core.symlinks") < 0 ||
20112065
!symlinks)
20122066
goto done;
2067+
#else
2068+
GIT_UNUSED(use_env);
20132069
#endif
20142070

20152071
if (!(symlinks = git_fs_path_supports_symlinks(wd_path)))
@@ -2082,7 +2138,8 @@ static int repo_init_fs_configs(
20822138
const char *cfg_path,
20832139
const char *repo_dir,
20842140
const char *work_dir,
2085-
bool update_ignorecase)
2141+
bool update_ignorecase,
2142+
bool use_env)
20862143
{
20872144
int error = 0;
20882145

@@ -2093,7 +2150,7 @@ static int repo_init_fs_configs(
20932150
cfg, "core.filemode", is_chmod_supported(cfg_path))) < 0)
20942151
return error;
20952152

2096-
if (!are_symlinks_supported(work_dir)) {
2153+
if (!are_symlinks_supported(work_dir, use_env)) {
20972154
if ((error = git_config_set_bool(cfg, "core.symlinks", false)) < 0)
20982155
return error;
20992156
} else if (git_config_delete_entry(cfg, "core.symlinks") < 0)
@@ -2130,6 +2187,7 @@ static int repo_init_config(
21302187
git_config *config = NULL;
21312188
bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
21322189
bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
2190+
bool use_env = ((flags & GIT_REPOSITORY_OPEN_FROM_ENV) != 0);
21332191
int version = GIT_REPO_VERSION_DEFAULT;
21342192

21352193
if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0)
@@ -2150,7 +2208,8 @@ static int repo_init_config(
21502208
SET_REPO_CONFIG(int32, "core.repositoryformatversion", version);
21512209

21522210
if ((error = repo_init_fs_configs(
2153-
config, cfg_path.ptr, repo_dir, work_dir, !is_reinit)) < 0)
2211+
config, cfg_path.ptr, repo_dir, work_dir,
2212+
!is_reinit, use_env)) < 0)
21542213
goto cleanup;
21552214

21562215
if (!is_bare) {
@@ -2214,8 +2273,8 @@ int git_repository_reinit_filesystem(git_repository *repo, int recurse)
22142273
const char *repo_dir = git_repository_path(repo);
22152274

22162275
if (!(error = repo_local_config(&config, &path, repo, repo_dir)))
2217-
error = repo_init_fs_configs(
2218-
config, path.ptr, repo_dir, git_repository_workdir(repo), true);
2276+
error = repo_init_fs_configs(config, path.ptr, repo_dir,
2277+
git_repository_workdir(repo), true, repo->use_env);
22192278

22202279
git_config_free(config);
22212280
git_str_dispose(&path);

tests/libgit2/repo/env.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ void test_repo_env__cleanup(void)
3232
git_futils_rmdir_r("peeled.git", NULL, GIT_RMDIR_REMOVE_FILES);
3333

3434
cl_fixture_cleanup("test_workdir");
35+
cl_fixture_cleanup("test_global_conf");
36+
cl_fixture_cleanup("test_system_conf");
3537

3638
clear_git_env();
3739
}
@@ -315,3 +317,53 @@ void test_repo_env__commondir(void)
315317
git_repository_free(repo);
316318
cl_setenv("GIT_COMMON_DIR", NULL);
317319
}
320+
321+
void test_repo_env__config(void)
322+
{
323+
git_repository *repo;
324+
git_config *config;
325+
const char *system_path, *global_path;
326+
int s, g;
327+
328+
cl_fixture_sandbox("attr");
329+
cl_git_pass(p_rename("attr/.gitted", "attr/.git"));
330+
331+
cl_git_rewritefile("test_system_conf", "[tttest]\n\tsys = true\n");
332+
cl_git_rewritefile("test_global_conf", "[tttest]\n\tglb = true\n");
333+
334+
system_path = cl_git_sandbox_path(0, "test_system_conf", NULL);
335+
cl_setenv("GIT_CONFIG_SYSTEM", system_path);
336+
337+
global_path = cl_git_sandbox_path(0, "test_global_conf", NULL);
338+
cl_setenv("GIT_CONFIG_GLOBAL", global_path);
339+
340+
/* Ensure we can override the system and global files */
341+
342+
cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL));
343+
cl_git_pass(git_repository_config(&config, repo));
344+
345+
cl_git_pass(git_config_get_bool(&s, config, "tttest.sys"));
346+
cl_assert_equal_i(1, s);
347+
cl_git_pass(git_config_get_bool(&g, config, "tttest.glb"));
348+
cl_assert_equal_i(1, g);
349+
350+
git_config_free(config);
351+
git_repository_free(repo);
352+
353+
/* Further ensure we can ignore the system file. */
354+
cl_setenv("GIT_CONFIG_NOSYSTEM", "TrUe");
355+
356+
cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL));
357+
cl_git_pass(git_repository_config(&config, repo));
358+
359+
cl_git_fail_with(GIT_ENOTFOUND, git_config_get_bool(&s, config, "tttest.sys"));
360+
cl_git_pass(git_config_get_bool(&g, config, "tttest.glb"));
361+
cl_assert_equal_i(1, g);
362+
363+
git_config_free(config);
364+
git_repository_free(repo);
365+
366+
cl_setenv("GIT_CONFIG_NOSYSTEM", NULL);
367+
cl_setenv("GIT_CONFIG_SYSTEM", NULL);
368+
cl_setenv("GIT_CONFIG_GLOBAL", NULL);
369+
}

0 commit comments

Comments
 (0)