Skip to content

Commit ed773a1

Browse files
bk2204gitster
authored andcommitted
var: add config file locations
Much like with attributes files, sometimes programs would like to know the location of configuration files at the global or system levels. However, it isn't always clear where these may live, especially for the system file, which may have been hard-coded at compile time or computed dynamically based on the runtime prefix. Since other parties cannot intuitively know how Git was compiled and where it looks for these files, help them by providing variables that can be queried. Because we have multiple paths for global config values, print them in order from highest to lowest priority, and be sure to split on newlines so that "git var -l" produces two entries for the global value. However, be careful not to split all values on newlines, since our editor values could well contain such characters, and we don't want to split them in such a case. Note in the documentation that some values may contain multiple paths and that callers should be prepared for that fact. This helps people write code that will continue to work in the event we allow multiple items elsewhere in the future. Signed-off-by: brian m. carlson <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 576a37f commit ed773a1

File tree

3 files changed

+135
-1
lines changed

3 files changed

+135
-1
lines changed

Documentation/git-var.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,20 @@ GIT_ATTR_SYSTEM::
8080
GIT_ATTR_GLOBAL::
8181
The path to the global (per-user) linkgit:gitattributes[5] file.
8282

83+
GIT_CONFIG_SYSTEM::
84+
The path to the system configuration file, if one is enabled.
85+
86+
GIT_CONFIG_GLOBAL::
87+
The path to the global (per-user) configuration files, if any.
88+
89+
Most path values contain only one value. However, some can contain multiple
90+
values, which are separated by newlines, and are listed in order from highest to
91+
lowest priority. Callers should be prepared for any such path value to contain
92+
multiple items.
93+
94+
Note that paths are printed even if they do not exist, but not if they are
95+
disabled by other environment variables.
96+
8397
SEE ALSO
8498
--------
8599
linkgit:git-commit-tree[1]

builtin/var.c

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,45 @@ static char *git_attr_val_global(int ident_flag UNUSED)
7272
return NULL;
7373
}
7474

75+
static char *git_config_val_system(int ident_flag UNUSED)
76+
{
77+
if (git_config_system()) {
78+
char *file = git_system_config();
79+
normalize_path_copy(file, file);
80+
return file;
81+
}
82+
return NULL;
83+
}
84+
85+
static char *git_config_val_global(int ident_flag UNUSED)
86+
{
87+
struct strbuf buf = STRBUF_INIT;
88+
char *user, *xdg;
89+
size_t unused;
90+
91+
git_global_config(&user, &xdg);
92+
if (xdg && *xdg) {
93+
normalize_path_copy(xdg, xdg);
94+
strbuf_addf(&buf, "%s\n", xdg);
95+
}
96+
if (user && *user) {
97+
normalize_path_copy(user, user);
98+
strbuf_addf(&buf, "%s\n", user);
99+
}
100+
free(xdg);
101+
free(user);
102+
strbuf_trim_trailing_newline(&buf);
103+
if (buf.len == 0) {
104+
strbuf_release(&buf);
105+
return NULL;
106+
}
107+
return strbuf_detach(&buf, &unused);
108+
}
109+
75110
struct git_var {
76111
const char *name;
77112
char *(*read)(int);
113+
int multivalued;
78114
};
79115
static struct git_var git_vars[] = {
80116
{
@@ -113,6 +149,15 @@ static struct git_var git_vars[] = {
113149
.name = "GIT_ATTR_GLOBAL",
114150
.read = git_attr_val_global,
115151
},
152+
{
153+
.name = "GIT_CONFIG_SYSTEM",
154+
.read = git_config_val_system,
155+
},
156+
{
157+
.name = "GIT_CONFIG_GLOBAL",
158+
.read = git_config_val_global,
159+
.multivalued = 1,
160+
},
116161
{
117162
.name = "",
118163
.read = NULL,
@@ -126,7 +171,17 @@ static void list_vars(void)
126171

127172
for (ptr = git_vars; ptr->read; ptr++)
128173
if ((val = ptr->read(0))) {
129-
printf("%s=%s\n", ptr->name, val);
174+
if (ptr->multivalued && *val) {
175+
struct string_list list = STRING_LIST_INIT_DUP;
176+
int i;
177+
178+
string_list_split(&list, val, '\n', -1);
179+
for (i = 0; i < list.nr; i++)
180+
printf("%s=%s\n", ptr->name, list.items[i].string);
181+
string_list_clear(&list, 0);
182+
} else {
183+
printf("%s=%s\n", ptr->name, val);
184+
}
130185
free(val);
131186
}
132187
}

t/t0007-git-var.sh

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,49 @@ test_expect_success 'GIT_ATTR_GLOBAL points to the correct location' '
182182
)
183183
'
184184

185+
test_expect_success 'GIT_CONFIG_SYSTEM points to the correct location' '
186+
TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
187+
test_must_fail env GIT_CONFIG_NOSYSTEM=1 git var GIT_CONFIG_SYSTEM &&
188+
(
189+
sane_unset GIT_CONFIG_NOSYSTEM &&
190+
systempath=$(git var GIT_CONFIG_SYSTEM) &&
191+
test "$systempath" != "" &&
192+
systempath=$(GIT_CONFIG_SYSTEM=/dev/null git var GIT_CONFIG_SYSTEM) &&
193+
if test_have_prereq MINGW
194+
then
195+
test "$systempath" = "nul"
196+
else
197+
test "$systempath" = "/dev/null"
198+
fi &&
199+
systempath=$(GIT_CONFIG_SYSTEM="$TRASHDIR/gitconfig" git var GIT_CONFIG_SYSTEM) &&
200+
test "$systempath" = "$TRASHDIR/gitconfig"
201+
)
202+
'
203+
204+
test_expect_success 'GIT_CONFIG_GLOBAL points to the correct location' '
205+
TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
206+
HOME="$TRASHDIR" XDG_CONFIG_HOME="$TRASHDIR/foo" git var GIT_CONFIG_GLOBAL >actual &&
207+
echo "$TRASHDIR/foo/git/config" >expected &&
208+
echo "$TRASHDIR/.gitconfig" >>expected &&
209+
test_cmp expected actual &&
210+
(
211+
sane_unset XDG_CONFIG_HOME &&
212+
HOME="$TRASHDIR" git var GIT_CONFIG_GLOBAL >actual &&
213+
echo "$TRASHDIR/.config/git/config" >expected &&
214+
echo "$TRASHDIR/.gitconfig" >>expected &&
215+
test_cmp expected actual &&
216+
globalpath=$(GIT_CONFIG_GLOBAL=/dev/null git var GIT_CONFIG_GLOBAL) &&
217+
if test_have_prereq MINGW
218+
then
219+
test "$globalpath" = "nul"
220+
else
221+
test "$globalpath" = "/dev/null"
222+
fi &&
223+
globalpath=$(GIT_CONFIG_GLOBAL="$TRASHDIR/gitconfig" git var GIT_CONFIG_GLOBAL) &&
224+
test "$globalpath" = "$TRASHDIR/gitconfig"
225+
)
226+
'
227+
185228
# For git var -l, we check only a representative variable;
186229
# testing the whole output would make our test too brittle with
187230
# respect to unrelated changes in the test suite's environment.
@@ -199,6 +242,28 @@ test_expect_success 'git var -l lists config' '
199242
test_cmp expect actual.bare
200243
'
201244

245+
test_expect_success 'git var -l lists multiple global configs' '
246+
TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
247+
HOME="$TRASHDIR" XDG_CONFIG_HOME="$TRASHDIR/foo" git var -l >actual &&
248+
grep "^GIT_CONFIG_GLOBAL=" actual >filtered &&
249+
echo "GIT_CONFIG_GLOBAL=$TRASHDIR/foo/git/config" >expected &&
250+
echo "GIT_CONFIG_GLOBAL=$TRASHDIR/.gitconfig" >>expected &&
251+
test_cmp expected filtered
252+
'
253+
254+
test_expect_success 'git var -l does not split multiline editors' '
255+
(
256+
GIT_EDITOR="!f() {
257+
echo Hello!
258+
}; f" &&
259+
export GIT_EDITOR &&
260+
echo "GIT_EDITOR=$GIT_EDITOR" >expected &&
261+
git var -l >var &&
262+
sed -n -e "/^GIT_EDITOR/,\$p" var | head -n 3 >actual &&
263+
test_cmp expected actual
264+
)
265+
'
266+
202267
test_expect_success 'listing and asking for variables are exclusive' '
203268
test_must_fail git var -l GIT_COMMITTER_IDENT
204269
'

0 commit comments

Comments
 (0)