391 lines
7.6 KiB
C
391 lines
7.6 KiB
C
/*
|
|
* GIT - The information manager from hell
|
|
*
|
|
* Copyright (C) Eric Biederman, 2005
|
|
*/
|
|
|
|
#define USE_THE_REPOSITORY_VARIABLE
|
|
|
|
#include "builtin.h"
|
|
|
|
#include "attr.h"
|
|
#include "config.h"
|
|
#include "editor.h"
|
|
#include "environment.h"
|
|
#include "ident.h"
|
|
#include "pager.h"
|
|
#include "parse-options.h"
|
|
#include "path.h"
|
|
#include "refs.h"
|
|
#include "run-command.h"
|
|
#include "strbuf.h"
|
|
#include "string-list.h"
|
|
|
|
static const char * const var_usage[] = {
|
|
N_("git var [-z] -l"),
|
|
N_("git var [-z] <variable>..."),
|
|
NULL
|
|
};
|
|
|
|
enum ident_part {
|
|
IDENT_NAME,
|
|
IDENT_MAIL,
|
|
IDENT_DATE,
|
|
};
|
|
|
|
static char *ident_part(const char *ident, enum ident_part part)
|
|
{
|
|
struct ident_split split;
|
|
|
|
if (!ident)
|
|
return NULL;
|
|
if (split_ident_line(&split, ident, strlen(ident)))
|
|
return NULL;
|
|
|
|
switch (part) {
|
|
case IDENT_NAME:
|
|
if (!split.name_begin || !split.name_end)
|
|
BUG("split_ident_line() gave NULL names???");
|
|
return xmemdupz(split.name_begin,
|
|
split.name_end - split.name_begin);
|
|
case IDENT_MAIL:
|
|
if (!split.mail_begin || !split.mail_end)
|
|
BUG("split_ident_line() gave NULL mail???");
|
|
return xmemdupz(split.mail_begin,
|
|
split.mail_end - split.mail_begin);
|
|
case IDENT_DATE:
|
|
if (!split.date_begin || !split.tz_end)
|
|
BUG("split_ident_line() gave NULL date/tz???");
|
|
return xmemdupz(split.date_begin,
|
|
split.tz_end - split.date_begin);
|
|
default:
|
|
BUG("unknown ident_part %d", part);
|
|
}
|
|
}
|
|
|
|
static char *committer(int ident_flag)
|
|
{
|
|
return xstrdup_or_null(git_committer_info(ident_flag));
|
|
}
|
|
|
|
static char *committer_name(int ident_flag)
|
|
{
|
|
return ident_part(git_committer_info(ident_flag), IDENT_NAME);
|
|
}
|
|
|
|
static char *committer_email(int ident_flag)
|
|
{
|
|
return ident_part(git_committer_info(ident_flag), IDENT_MAIL);
|
|
}
|
|
|
|
static char *committer_date(int ident_flag)
|
|
{
|
|
return ident_part(git_committer_info(ident_flag), IDENT_DATE);
|
|
}
|
|
|
|
static char *author(int ident_flag)
|
|
{
|
|
return xstrdup_or_null(git_author_info(ident_flag));
|
|
}
|
|
|
|
static char *author_name(int ident_flag)
|
|
{
|
|
return ident_part(git_author_info(ident_flag), IDENT_NAME);
|
|
}
|
|
|
|
static char *author_email(int ident_flag)
|
|
{
|
|
return ident_part(git_author_info(ident_flag), IDENT_MAIL);
|
|
}
|
|
|
|
static char *author_date(int ident_flag)
|
|
{
|
|
return ident_part(git_author_info(ident_flag), IDENT_DATE);
|
|
}
|
|
|
|
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(the_repository, 1);
|
|
|
|
if (!pgm)
|
|
pgm = "cat";
|
|
return xstrdup(pgm);
|
|
}
|
|
|
|
static char *default_branch(int ident_flag UNUSED)
|
|
{
|
|
return repo_default_branch_name(the_repository, 1);
|
|
}
|
|
|
|
static char *shell_path(int ident_flag UNUSED)
|
|
{
|
|
return git_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_or_null(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 void git_config_val_global(struct string_list *list)
|
|
{
|
|
char *user, *xdg;
|
|
|
|
git_global_config_paths(&user, &xdg);
|
|
if (xdg && *xdg) {
|
|
normalize_path_copy(xdg, xdg);
|
|
string_list_append(list, xdg);
|
|
}
|
|
if (user && *user) {
|
|
normalize_path_copy(user, user);
|
|
string_list_append(list, user);
|
|
}
|
|
free(xdg);
|
|
free(user);
|
|
}
|
|
|
|
struct git_var {
|
|
const char *name;
|
|
char *(*read)(int);
|
|
void (*multiread)(struct string_list *);
|
|
};
|
|
static struct git_var git_vars[] = {
|
|
{
|
|
.name = "GIT_COMMITTER_IDENT",
|
|
.read = committer,
|
|
},
|
|
{
|
|
.name = "GIT_COMMITTER_NAME",
|
|
.read = committer_name,
|
|
},
|
|
{
|
|
.name = "GIT_COMMITTER_EMAIL",
|
|
.read = committer_email,
|
|
},
|
|
{
|
|
.name = "GIT_COMMITTER_DATE",
|
|
.read = committer_date,
|
|
},
|
|
{
|
|
.name = "GIT_AUTHOR_IDENT",
|
|
.read = author,
|
|
},
|
|
{
|
|
.name = "GIT_AUTHOR_NAME",
|
|
.read = author_name,
|
|
},
|
|
{
|
|
.name = "GIT_AUTHOR_EMAIL",
|
|
.read = author_email,
|
|
},
|
|
{
|
|
.name = "GIT_AUTHOR_DATE",
|
|
.read = author_date,
|
|
},
|
|
{
|
|
.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",
|
|
.multiread = git_config_val_global,
|
|
},
|
|
{
|
|
.name = "",
|
|
.read = NULL,
|
|
},
|
|
};
|
|
|
|
static void list_vars(int nul_term)
|
|
{
|
|
struct git_var *ptr;
|
|
char delim = nul_term ? '\n' : '=';
|
|
char term = nul_term ? '\0' : '\n';
|
|
|
|
for (ptr = git_vars; ptr->read || ptr->multiread; ptr++) {
|
|
if (ptr->read) {
|
|
char *val = ptr->read(0);
|
|
|
|
if (val) {
|
|
printf("%s%c%s%c", ptr->name, delim, val, term);
|
|
free(val);
|
|
}
|
|
} else {
|
|
struct string_list list = STRING_LIST_INIT_DUP;
|
|
|
|
ptr->multiread(&list);
|
|
for (size_t i = 0; i < list.nr; i++)
|
|
printf("%s%c%s%c", ptr->name, delim,
|
|
list.items[i].string, term);
|
|
string_list_clear(&list, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static const struct git_var *get_git_var(const char *var)
|
|
{
|
|
struct git_var *ptr;
|
|
for (ptr = git_vars; ptr->read || ptr->multiread; ptr++) {
|
|
if (strcmp(var, ptr->name) == 0) {
|
|
return ptr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int show_config(const char *var, const char *value,
|
|
const struct config_context *ctx, void *cb)
|
|
{
|
|
int *nul_term = cb;
|
|
char delim = *nul_term ? '\n' : '=';
|
|
char term = *nul_term ? '\0' : '\n';
|
|
|
|
if (value)
|
|
printf("%s%c%s%c", var, delim, value, term);
|
|
else
|
|
printf("%s%c", var, term);
|
|
return git_default_config(var, value, ctx, cb);
|
|
}
|
|
|
|
int cmd_var(int argc,
|
|
const char **argv,
|
|
const char *prefix,
|
|
struct repository *repo UNUSED)
|
|
{
|
|
int list = 0;
|
|
int nul_term = 0;
|
|
char delim;
|
|
char term;
|
|
struct option options[] = {
|
|
OPT_BOOL('l', NULL, &list,
|
|
N_("list all variables")),
|
|
OPT_BOOL('z', NULL, &nul_term,
|
|
N_("terminate entries with NUL")),
|
|
OPT_END(),
|
|
};
|
|
|
|
argc = parse_options(argc, argv, prefix, options,
|
|
var_usage, PARSE_OPT_STOP_AT_NON_OPTION);
|
|
|
|
if (list) {
|
|
if (argc)
|
|
usage_with_options(var_usage, options);
|
|
repo_config(the_repository, show_config, &nul_term);
|
|
list_vars(nul_term);
|
|
return 0;
|
|
}
|
|
|
|
if (!argc)
|
|
usage_with_options(var_usage, options);
|
|
|
|
repo_config(the_repository, git_default_config, NULL);
|
|
|
|
delim = nul_term ? '\n' : '=';
|
|
term = nul_term ? '\0' : '\n';
|
|
|
|
for (int i = 0; i < argc; i++) {
|
|
const struct git_var *git_var = get_git_var(argv[i]);
|
|
|
|
if (!git_var)
|
|
usage_with_options(var_usage, options);
|
|
|
|
if (git_var->read) {
|
|
char *val = git_var->read(IDENT_STRICT);
|
|
|
|
if (!val) {
|
|
if (argc == 1)
|
|
return 1;
|
|
continue;
|
|
}
|
|
if (argc == 1)
|
|
printf("%s%c", val, term);
|
|
else
|
|
printf("%s%c%s%c", git_var->name, delim,
|
|
val, term);
|
|
free(val);
|
|
} else {
|
|
struct string_list list = STRING_LIST_INIT_DUP;
|
|
|
|
git_var->multiread(&list);
|
|
if (argc == 1 && !list.nr) {
|
|
string_list_clear(&list, 0);
|
|
return 1;
|
|
}
|
|
for (size_t j = 0; j < list.nr; j++) {
|
|
if (argc == 1)
|
|
printf("%s%c", list.items[j].string,
|
|
term);
|
|
else
|
|
printf("%s%c%s%c", git_var->name, delim,
|
|
list.items[j].string, term);
|
|
}
|
|
string_list_clear(&list, 0);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|