зеркало из https://github.com/microsoft/git.git
Merge branch 'bc/more-git-var'
Add more "git var" for toolsmiths to learn various locations Git is configured with either via the configuration or hardcoded defaults. * bc/more-git-var: var: add config file locations var: add attributes files locations attr: expose and rename accessor functions var: adjust memory allocation for strings var: format variable structure with C99 initializers var: add support for listing the shell t: add a function to check executable bit var: mark unused parameters in git_var callbacks
This commit is contained in:
Коммит
89d62d5e8e
|
@ -71,6 +71,29 @@ endif::git-default-pager[]
|
|||
GIT_DEFAULT_BRANCH::
|
||||
The name of the first branch created in newly initialized repositories.
|
||||
|
||||
GIT_SHELL_PATH::
|
||||
The path of the binary providing the POSIX shell for commands which use the shell.
|
||||
|
||||
GIT_ATTR_SYSTEM::
|
||||
The path to the system linkgit:gitattributes[5] file, if one is enabled.
|
||||
|
||||
GIT_ATTR_GLOBAL::
|
||||
The path to the global (per-user) linkgit:gitattributes[5] file.
|
||||
|
||||
GIT_CONFIG_SYSTEM::
|
||||
The path to the system configuration file, if one is enabled.
|
||||
|
||||
GIT_CONFIG_GLOBAL::
|
||||
The path to the global (per-user) configuration files, if any.
|
||||
|
||||
Most path values contain only one value. However, some can contain multiple
|
||||
values, which are separated by newlines, and are listed in order from highest to
|
||||
lowest priority. Callers should be prepared for any such path value to contain
|
||||
multiple items.
|
||||
|
||||
Note that paths are printed even if they do not exist, but not if they are
|
||||
disabled by other environment variables.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-commit-tree[1]
|
||||
|
|
14
attr.c
14
attr.c
|
@ -872,7 +872,7 @@ static struct attr_stack *read_attr(struct index_state *istate,
|
|||
return res;
|
||||
}
|
||||
|
||||
static const char *git_etc_gitattributes(void)
|
||||
const char *git_attr_system_file(void)
|
||||
{
|
||||
static const char *system_wide;
|
||||
if (!system_wide)
|
||||
|
@ -880,7 +880,7 @@ static const char *git_etc_gitattributes(void)
|
|||
return system_wide;
|
||||
}
|
||||
|
||||
static const char *get_home_gitattributes(void)
|
||||
const char *git_attr_global_file(void)
|
||||
{
|
||||
if (!git_attributes_file)
|
||||
git_attributes_file = xdg_config_home("attributes");
|
||||
|
@ -888,7 +888,7 @@ static const char *get_home_gitattributes(void)
|
|||
return git_attributes_file;
|
||||
}
|
||||
|
||||
static int git_attr_system(void)
|
||||
int git_attr_system_is_enabled(void)
|
||||
{
|
||||
return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
|
||||
}
|
||||
|
@ -922,14 +922,14 @@ static void bootstrap_attr_stack(struct index_state *istate,
|
|||
push_stack(stack, e, NULL, 0);
|
||||
|
||||
/* system-wide frame */
|
||||
if (git_attr_system()) {
|
||||
e = read_attr_from_file(git_etc_gitattributes(), flags);
|
||||
if (git_attr_system_is_enabled()) {
|
||||
e = read_attr_from_file(git_attr_system_file(), flags);
|
||||
push_stack(stack, e, NULL, 0);
|
||||
}
|
||||
|
||||
/* home directory */
|
||||
if (get_home_gitattributes()) {
|
||||
e = read_attr_from_file(get_home_gitattributes(), flags);
|
||||
if (git_attr_global_file()) {
|
||||
e = read_attr_from_file(git_attr_global_file(), flags);
|
||||
push_stack(stack, e, NULL, 0);
|
||||
}
|
||||
|
||||
|
|
9
attr.h
9
attr.h
|
@ -227,4 +227,13 @@ void git_attr_set_direction(enum git_attr_direction new_direction);
|
|||
|
||||
void attr_start(void);
|
||||
|
||||
/* Return the system gitattributes file. */
|
||||
const char *git_attr_system_file(void);
|
||||
|
||||
/* Return the global gitattributes file, if any. */
|
||||
const char *git_attr_global_file(void);
|
||||
|
||||
/* Return whether the system gitattributes file is enabled and should be used. */
|
||||
int git_attr_system_is_enabled(void);
|
||||
|
||||
#endif /* ATTR_H */
|
||||
|
|
169
builtin/var.c
169
builtin/var.c
|
@ -4,60 +4,188 @@
|
|||
* Copyright (C) Eric Biederman, 2005
|
||||
*/
|
||||
#include "builtin.h"
|
||||
#include "attr.h"
|
||||
#include "config.h"
|
||||
#include "editor.h"
|
||||
#include "ident.h"
|
||||
#include "pager.h"
|
||||
#include "refs.h"
|
||||
#include "path.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
static const char var_usage[] = "git var (-l | <variable>)";
|
||||
|
||||
static const char *editor(int flag)
|
||||
static char *committer(int ident_flag)
|
||||
{
|
||||
return git_editor();
|
||||
return xstrdup_or_null(git_committer_info(ident_flag));
|
||||
}
|
||||
|
||||
static const char *sequence_editor(int flag)
|
||||
static char *author(int ident_flag)
|
||||
{
|
||||
return git_sequence_editor();
|
||||
return xstrdup_or_null(git_author_info(ident_flag));
|
||||
}
|
||||
|
||||
static const char *pager(int flag)
|
||||
static char *editor(int ident_flag UNUSED)
|
||||
{
|
||||
return xstrdup_or_null(git_editor());
|
||||
}
|
||||
|
||||
static char *sequence_editor(int ident_flag UNUSED)
|
||||
{
|
||||
return xstrdup_or_null(git_sequence_editor());
|
||||
}
|
||||
|
||||
static char *pager(int ident_flag UNUSED)
|
||||
{
|
||||
const char *pgm = git_pager(1);
|
||||
|
||||
if (!pgm)
|
||||
pgm = "cat";
|
||||
return pgm;
|
||||
return xstrdup(pgm);
|
||||
}
|
||||
|
||||
static const char *default_branch(int flag)
|
||||
static char *default_branch(int ident_flag UNUSED)
|
||||
{
|
||||
return git_default_branch_name(1);
|
||||
return xstrdup_or_null(git_default_branch_name(1));
|
||||
}
|
||||
|
||||
static char *shell_path(int ident_flag UNUSED)
|
||||
{
|
||||
return xstrdup(SHELL_PATH);
|
||||
}
|
||||
|
||||
static char *git_attr_val_system(int ident_flag UNUSED)
|
||||
{
|
||||
if (git_attr_system_is_enabled()) {
|
||||
char *file = xstrdup(git_attr_system_file());
|
||||
normalize_path_copy(file, file);
|
||||
return file;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *git_attr_val_global(int ident_flag UNUSED)
|
||||
{
|
||||
char *file = xstrdup(git_attr_global_file());
|
||||
if (file) {
|
||||
normalize_path_copy(file, file);
|
||||
return file;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *git_config_val_system(int ident_flag UNUSED)
|
||||
{
|
||||
if (git_config_system()) {
|
||||
char *file = git_system_config();
|
||||
normalize_path_copy(file, file);
|
||||
return file;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *git_config_val_global(int ident_flag UNUSED)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
char *user, *xdg;
|
||||
size_t unused;
|
||||
|
||||
git_global_config(&user, &xdg);
|
||||
if (xdg && *xdg) {
|
||||
normalize_path_copy(xdg, xdg);
|
||||
strbuf_addf(&buf, "%s\n", xdg);
|
||||
}
|
||||
if (user && *user) {
|
||||
normalize_path_copy(user, user);
|
||||
strbuf_addf(&buf, "%s\n", user);
|
||||
}
|
||||
free(xdg);
|
||||
free(user);
|
||||
strbuf_trim_trailing_newline(&buf);
|
||||
if (buf.len == 0) {
|
||||
strbuf_release(&buf);
|
||||
return NULL;
|
||||
}
|
||||
return strbuf_detach(&buf, &unused);
|
||||
}
|
||||
|
||||
struct git_var {
|
||||
const char *name;
|
||||
const char *(*read)(int);
|
||||
char *(*read)(int);
|
||||
int multivalued;
|
||||
};
|
||||
static struct git_var git_vars[] = {
|
||||
{ "GIT_COMMITTER_IDENT", git_committer_info },
|
||||
{ "GIT_AUTHOR_IDENT", git_author_info },
|
||||
{ "GIT_EDITOR", editor },
|
||||
{ "GIT_SEQUENCE_EDITOR", sequence_editor },
|
||||
{ "GIT_PAGER", pager },
|
||||
{ "GIT_DEFAULT_BRANCH", default_branch },
|
||||
{ "", NULL },
|
||||
{
|
||||
.name = "GIT_COMMITTER_IDENT",
|
||||
.read = committer,
|
||||
},
|
||||
{
|
||||
.name = "GIT_AUTHOR_IDENT",
|
||||
.read = author,
|
||||
},
|
||||
{
|
||||
.name = "GIT_EDITOR",
|
||||
.read = editor,
|
||||
},
|
||||
{
|
||||
.name = "GIT_SEQUENCE_EDITOR",
|
||||
.read = sequence_editor,
|
||||
},
|
||||
{
|
||||
.name = "GIT_PAGER",
|
||||
.read = pager,
|
||||
},
|
||||
{
|
||||
.name = "GIT_DEFAULT_BRANCH",
|
||||
.read = default_branch,
|
||||
},
|
||||
{
|
||||
.name = "GIT_SHELL_PATH",
|
||||
.read = shell_path,
|
||||
},
|
||||
{
|
||||
.name = "GIT_ATTR_SYSTEM",
|
||||
.read = git_attr_val_system,
|
||||
},
|
||||
{
|
||||
.name = "GIT_ATTR_GLOBAL",
|
||||
.read = git_attr_val_global,
|
||||
},
|
||||
{
|
||||
.name = "GIT_CONFIG_SYSTEM",
|
||||
.read = git_config_val_system,
|
||||
},
|
||||
{
|
||||
.name = "GIT_CONFIG_GLOBAL",
|
||||
.read = git_config_val_global,
|
||||
.multivalued = 1,
|
||||
},
|
||||
{
|
||||
.name = "",
|
||||
.read = NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static void list_vars(void)
|
||||
{
|
||||
struct git_var *ptr;
|
||||
const char *val;
|
||||
char *val;
|
||||
|
||||
for (ptr = git_vars; ptr->read; ptr++)
|
||||
if ((val = ptr->read(0)))
|
||||
printf("%s=%s\n", ptr->name, val);
|
||||
if ((val = ptr->read(0))) {
|
||||
if (ptr->multivalued && *val) {
|
||||
struct string_list list = STRING_LIST_INIT_DUP;
|
||||
int i;
|
||||
|
||||
string_list_split(&list, val, '\n', -1);
|
||||
for (i = 0; i < list.nr; i++)
|
||||
printf("%s=%s\n", ptr->name, list.items[i].string);
|
||||
string_list_clear(&list, 0);
|
||||
} else {
|
||||
printf("%s=%s\n", ptr->name, val);
|
||||
}
|
||||
free(val);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct git_var *get_git_var(const char *var)
|
||||
|
@ -83,7 +211,7 @@ static int show_config(const char *var, const char *value, void *cb)
|
|||
int cmd_var(int argc, const char **argv, const char *prefix UNUSED)
|
||||
{
|
||||
const struct git_var *git_var;
|
||||
const char *val;
|
||||
char *val;
|
||||
|
||||
if (argc != 2)
|
||||
usage(var_usage);
|
||||
|
@ -104,6 +232,7 @@ int cmd_var(int argc, const char **argv, const char *prefix UNUSED)
|
|||
return 1;
|
||||
|
||||
printf("%s\n", val);
|
||||
free(val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
6
t/README
6
t/README
|
@ -1102,6 +1102,12 @@ see test-lib-functions.sh for the full list and their options.
|
|||
the symbolic link in the file system and a part that does; then only
|
||||
the latter part need be protected by a SYMLINKS prerequisite (see below).
|
||||
|
||||
- test_path_is_executable
|
||||
|
||||
This tests whether a file is executable and prints an error message
|
||||
if not. This must be used only under the POSIXPERM prerequisite
|
||||
(see below).
|
||||
|
||||
- test_oid_init
|
||||
|
||||
This function loads facts and useful object IDs related to the hash
|
||||
|
|
|
@ -147,6 +147,84 @@ test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration and environment
|
|||
)
|
||||
'
|
||||
|
||||
test_expect_success POSIXPERM 'GIT_SHELL_PATH points to a valid executable' '
|
||||
shellpath=$(git var GIT_SHELL_PATH) &&
|
||||
test_path_is_executable "$shellpath"
|
||||
'
|
||||
|
||||
# We know in this environment that our shell will be one of a few fixed values
|
||||
# that all end in "sh".
|
||||
test_expect_success MINGW 'GIT_SHELL_PATH points to a suitable shell' '
|
||||
shellpath=$(git var GIT_SHELL_PATH) &&
|
||||
case "$shellpath" in
|
||||
*sh) ;;
|
||||
*) return 1;;
|
||||
esac
|
||||
'
|
||||
|
||||
test_expect_success 'GIT_ATTR_SYSTEM produces expected output' '
|
||||
test_must_fail env GIT_ATTR_NOSYSTEM=1 git var GIT_ATTR_SYSTEM &&
|
||||
(
|
||||
sane_unset GIT_ATTR_NOSYSTEM &&
|
||||
systempath=$(git var GIT_ATTR_SYSTEM) &&
|
||||
test "$systempath" != ""
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'GIT_ATTR_GLOBAL points to the correct location' '
|
||||
TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
|
||||
globalpath=$(XDG_CONFIG_HOME="$TRASHDIR/.config" git var GIT_ATTR_GLOBAL) &&
|
||||
test "$globalpath" = "$TRASHDIR/.config/git/attributes" &&
|
||||
(
|
||||
sane_unset XDG_CONFIG_HOME &&
|
||||
globalpath=$(HOME="$TRASHDIR" git var GIT_ATTR_GLOBAL) &&
|
||||
test "$globalpath" = "$TRASHDIR/.config/git/attributes"
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'GIT_CONFIG_SYSTEM points to the correct location' '
|
||||
TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
|
||||
test_must_fail env GIT_CONFIG_NOSYSTEM=1 git var GIT_CONFIG_SYSTEM &&
|
||||
(
|
||||
sane_unset GIT_CONFIG_NOSYSTEM &&
|
||||
systempath=$(git var GIT_CONFIG_SYSTEM) &&
|
||||
test "$systempath" != "" &&
|
||||
systempath=$(GIT_CONFIG_SYSTEM=/dev/null git var GIT_CONFIG_SYSTEM) &&
|
||||
if test_have_prereq MINGW
|
||||
then
|
||||
test "$systempath" = "nul"
|
||||
else
|
||||
test "$systempath" = "/dev/null"
|
||||
fi &&
|
||||
systempath=$(GIT_CONFIG_SYSTEM="$TRASHDIR/gitconfig" git var GIT_CONFIG_SYSTEM) &&
|
||||
test "$systempath" = "$TRASHDIR/gitconfig"
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'GIT_CONFIG_GLOBAL points to the correct location' '
|
||||
TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
|
||||
HOME="$TRASHDIR" XDG_CONFIG_HOME="$TRASHDIR/foo" git var GIT_CONFIG_GLOBAL >actual &&
|
||||
echo "$TRASHDIR/foo/git/config" >expected &&
|
||||
echo "$TRASHDIR/.gitconfig" >>expected &&
|
||||
test_cmp expected actual &&
|
||||
(
|
||||
sane_unset XDG_CONFIG_HOME &&
|
||||
HOME="$TRASHDIR" git var GIT_CONFIG_GLOBAL >actual &&
|
||||
echo "$TRASHDIR/.config/git/config" >expected &&
|
||||
echo "$TRASHDIR/.gitconfig" >>expected &&
|
||||
test_cmp expected actual &&
|
||||
globalpath=$(GIT_CONFIG_GLOBAL=/dev/null git var GIT_CONFIG_GLOBAL) &&
|
||||
if test_have_prereq MINGW
|
||||
then
|
||||
test "$globalpath" = "nul"
|
||||
else
|
||||
test "$globalpath" = "/dev/null"
|
||||
fi &&
|
||||
globalpath=$(GIT_CONFIG_GLOBAL="$TRASHDIR/gitconfig" git var GIT_CONFIG_GLOBAL) &&
|
||||
test "$globalpath" = "$TRASHDIR/gitconfig"
|
||||
)
|
||||
'
|
||||
|
||||
# For git var -l, we check only a representative variable;
|
||||
# testing the whole output would make our test too brittle with
|
||||
# respect to unrelated changes in the test suite's environment.
|
||||
|
@ -164,6 +242,28 @@ test_expect_success 'git var -l lists config' '
|
|||
test_cmp expect actual.bare
|
||||
'
|
||||
|
||||
test_expect_success 'git var -l lists multiple global configs' '
|
||||
TRASHDIR="$(test-tool path-utils normalize_path_copy "$(pwd)")" &&
|
||||
HOME="$TRASHDIR" XDG_CONFIG_HOME="$TRASHDIR/foo" git var -l >actual &&
|
||||
grep "^GIT_CONFIG_GLOBAL=" actual >filtered &&
|
||||
echo "GIT_CONFIG_GLOBAL=$TRASHDIR/foo/git/config" >expected &&
|
||||
echo "GIT_CONFIG_GLOBAL=$TRASHDIR/.gitconfig" >>expected &&
|
||||
test_cmp expected filtered
|
||||
'
|
||||
|
||||
test_expect_success 'git var -l does not split multiline editors' '
|
||||
(
|
||||
GIT_EDITOR="!f() {
|
||||
echo Hello!
|
||||
}; f" &&
|
||||
export GIT_EDITOR &&
|
||||
echo "GIT_EDITOR=$GIT_EDITOR" >expected &&
|
||||
git var -l >var &&
|
||||
sed -n -e "/^GIT_EDITOR/,\$p" var | head -n 3 >actual &&
|
||||
test_cmp expected actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'listing and asking for variables are exclusive' '
|
||||
test_must_fail git var -l GIT_COMMITTER_IDENT
|
||||
'
|
||||
|
|
|
@ -910,6 +910,15 @@ test_path_is_symlink () {
|
|||
fi
|
||||
}
|
||||
|
||||
test_path_is_executable () {
|
||||
test "$#" -ne 1 && BUG "1 param"
|
||||
if ! test -x "$1"
|
||||
then
|
||||
echo "$1 is not executable"
|
||||
false
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if the directory exists and is empty as expected, barf otherwise.
|
||||
test_dir_is_empty () {
|
||||
test "$#" -ne 1 && BUG "1 param"
|
||||
|
|
Загрузка…
Ссылка в новой задаче