builtin-config.c 8.6 KB
Newer Older
1
#include "builtin.h"
2
#include "cache.h"
3
#include "color.h"
4 5

static const char git_config_set_usage[] =
6
"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default]";
7

8 9 10 11 12 13 14 15
static char *key;
static regex_t *key_regexp;
static regex_t *regexp;
static int show_keys;
static int use_key_regexp;
static int do_all;
static int do_not_match;
static int seen;
16 17 18
static char delim = '=';
static char key_delim = ' ';
static char term = '\n';
19
static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
20

P
Petr Baudis 已提交
21 22 23
static int show_all_config(const char *key_, const char *value_)
{
	if (value_)
24
		printf("%s%c%s%c", key_, delim, value_, term);
P
Petr Baudis 已提交
25
	else
26
		printf("%s%c", key_, term);
P
Petr Baudis 已提交
27 28 29
	return 0;
}

30 31
static int show_config(const char* key_, const char* value_)
{
32 33
	char value[256];
	const char *vptr = value;
34
	int dup_error = 0;
35

36 37 38 39 40
	if (!use_key_regexp && strcmp(key_, key))
		return 0;
	if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
		return 0;
	if (regexp != NULL &&
41
			 (do_not_match ^
42
			  regexec(regexp, (value_?value_:""), 0, NULL, 0)))
43 44
		return 0;

45 46
	if (show_keys) {
		if (value_)
47
			printf("%s%c", key_, key_delim);
48 49 50
		else
			printf("%s", key_);
	}
51 52 53
	if (seen && !do_all)
		dup_error = 1;
	if (type == T_INT)
54
		sprintf(value, "%d", git_config_int(key_, value_?value_:""));
55 56 57
	else if (type == T_BOOL)
		vptr = git_config_bool(key_, value_) ? "true" : "false";
	else
58
		vptr = value_?value_:"";
59 60 61 62
	seen++;
	if (dup_error) {
		error("More than one value for the key %s: %s",
				key_, vptr);
63
	}
64
	else
65
		printf("%s%c", vptr, term);
66

67 68 69 70 71
	return 0;
}

static int get_value(const char* key_, const char* regex_)
{
72
	int ret = -1;
L
Linus Torvalds 已提交
73
	char *tl;
74
	char *global = NULL, *repo_config = NULL;
75
	const char *system_wide = NULL, *local;
76

77
	local = getenv(CONFIG_ENVIRONMENT);
78 79
	if (!local) {
		const char *home = getenv("HOME");
80
		local = getenv(CONFIG_LOCAL_ENVIRONMENT);
81
		if (!local)
82
			local = repo_config = xstrdup(git_path("config"));
83
		if (home)
84
			global = xstrdup(mkpath("%s/.gitconfig", home));
85
		system_wide = git_etc_gitconfig();
86
	}
87

88
	key = xstrdup(key_);
L
Linus Torvalds 已提交
89 90 91 92
	for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
		*tl = tolower(*tl);
	for (tl=key; *tl && *tl != '.'; ++tl)
		*tl = tolower(*tl);
93

94
	if (use_key_regexp) {
J
Jonas Fonseca 已提交
95
		key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
96
		if (regcomp(key_regexp, key, REG_EXTENDED)) {
97
			fprintf(stderr, "Invalid key pattern: %s\n", key_);
98
			goto free_strings;
99 100 101
		}
	}

102
	if (regex_) {
103 104 105 106 107
		if (regex_[0] == '!') {
			do_not_match = 1;
			regex_++;
		}

J
Jonas Fonseca 已提交
108
		regexp = (regex_t*)xmalloc(sizeof(regex_t));
109
		if (regcomp(regexp, regex_, REG_EXTENDED)) {
110
			fprintf(stderr, "Invalid pattern: %s\n", regex_);
111
			goto free_strings;
112 113 114
		}
	}

115 116
	if (do_all && system_wide)
		git_config_from_file(show_config, system_wide);
117 118 119 120 121
	if (do_all && global)
		git_config_from_file(show_config, global);
	git_config_from_file(show_config, local);
	if (!do_all && !seen && global)
		git_config_from_file(show_config, global);
122 123
	if (!do_all && !seen && system_wide)
		git_config_from_file(show_config, system_wide);
124

125
	free(key);
126 127 128
	if (regexp) {
		regfree(regexp);
		free(regexp);
129 130 131
	}

	if (do_all)
132 133
		ret = !seen;
	else
P
Petr Baudis 已提交
134
		ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
135 136

free_strings:
J
Junio C Hamano 已提交
137 138
	free(repo_config);
	free(global);
139
	return ret;
140
}
141

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
char *normalize_value(const char *key, const char *value)
{
	char *normalized;

	if (!value)
		return NULL;

	if (type == T_RAW)
		normalized = xstrdup(value);
	else {
		normalized = xmalloc(64);
		if (type == T_INT) {
			int v = git_config_int(key, value);
			sprintf(normalized, "%d", v);
		}
		else if (type == T_BOOL)
			sprintf(normalized, "%s",
				git_config_bool(key, value) ? "true" : "false");
	}

	return normalized;
}

165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
static int get_color_found;
static const char *get_color_slot;
static char parsed_color[COLOR_MAXLEN];

static int git_get_color_config(const char *var, const char *value)
{
	if (!strcmp(var, get_color_slot)) {
		color_parse(value, var, parsed_color);
		get_color_found = 1;
	}
	return 0;
}

static int get_color(int argc, const char **argv)
{
	/*
	 * grab the color setting for the given slot from the configuration,
	 * or parse the default value if missing, and return ANSI color
	 * escape sequence.
	 *
	 * e.g.
	 * git config --get-color color.diff.whitespace "blue reverse"
	 */
	const char *def_color = NULL;

	switch (argc) {
	default:
		usage(git_config_set_usage);
	case 2:
		def_color = argv[1];
		/* fallthru */
	case 1:
		get_color_slot = argv[0];
		break;
	}

	get_color_found = 0;
	parsed_color[0] = '\0';
	git_config(git_get_color_config);

	if (!get_color_found && def_color)
		color_parse(def_color, "command line", parsed_color);

	fputs(parsed_color, stdout);
	return 0;
}

212
int cmd_config(int argc, const char **argv, const char *prefix)
213
{
214
	int nongit = 0;
215
	char* value;
216
	const char *file = setup_git_directory_gently(&nongit);
217 218 219 220 221 222

	while (1 < argc) {
		if (!strcmp(argv[1], "--int"))
			type = T_INT;
		else if (!strcmp(argv[1], "--bool"))
			type = T_BOOL;
223 224 225
		else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
			if (argc != 2)
				usage(git_config_set_usage);
226 227 228 229
			if (git_config(show_all_config) < 0 && file && errno)
				die("unable to read config file %s: %s", file,
				    strerror(errno));
			return 0;
230
		}
S
Sean 已提交
231 232 233 234
		else if (!strcmp(argv[1], "--global")) {
			char *home = getenv("HOME");
			if (home) {
				char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
235
				setenv(CONFIG_ENVIRONMENT, user_config, 1);
S
Sean 已提交
236 237 238 239
				free(user_config);
			} else {
				die("$HOME not set");
			}
240 241
		}
		else if (!strcmp(argv[1], "--system"))
242
			setenv(CONFIG_ENVIRONMENT, git_etc_gitconfig(), 1);
243 244 245
		else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) {
			if (argc < 3)
				usage(git_config_set_usage);
246 247 248 249 250 251
			if (!is_absolute_path(argv[2]) && file)
				file = prefix_filename(file, strlen(file),
						       argv[2]);
			else
				file = argv[2];
			setenv(CONFIG_ENVIRONMENT, file, 1);
252 253 254
			argc--;
			argv++;
		}
255 256 257 258 259
		else if (!strcmp(argv[1], "--null") || !strcmp(argv[1], "-z")) {
			term = '\0';
			delim = '\n';
			key_delim = '\n';
		}
260
		else if (!strcmp(argv[1], "--rename-section")) {
261 262 263 264 265 266 267 268 269 270 271
			int ret;
			if (argc != 4)
				usage(git_config_set_usage);
			ret = git_config_rename_section(argv[2], argv[3]);
			if (ret < 0)
				return ret;
			if (ret == 0) {
				fprintf(stderr, "No such section!\n");
				return 1;
			}
			return 0;
272
		}
273 274 275 276 277 278 279 280 281 282 283 284
		else if (!strcmp(argv[1], "--remove-section")) {
			int ret;
			if (argc != 3)
				usage(git_config_set_usage);
			ret = git_config_rename_section(argv[2], NULL);
			if (ret < 0)
				return ret;
			if (ret == 0) {
				fprintf(stderr, "No such section!\n");
				return 1;
			}
			return 0;
285 286 287
		} else if (!strcmp(argv[1], "--get-color")) {
			return get_color(argc-2, argv+2);
		} else
288 289 290 291 292
			break;
		argc--;
		argv++;
	}

293 294
	switch (argc) {
	case 2:
295
		return get_value(argv[1], NULL);
296 297 298
	case 3:
		if (!strcmp(argv[1], "--unset"))
			return git_config_set(argv[2], NULL);
299 300 301 302 303 304 305
		else if (!strcmp(argv[1], "--unset-all"))
			return git_config_set_multivar(argv[2], NULL, NULL, 1);
		else if (!strcmp(argv[1], "--get"))
			return get_value(argv[2], NULL);
		else if (!strcmp(argv[1], "--get-all")) {
			do_all = 1;
			return get_value(argv[2], NULL);
306 307 308 309 310
		} else if (!strcmp(argv[1], "--get-regexp")) {
			show_keys = 1;
			use_key_regexp = 1;
			do_all = 1;
			return get_value(argv[2], NULL);
311 312 313 314
		} else {
			value = normalize_value(argv[1], argv[2]);
			return git_config_set(argv[1], value);
		}
315 316
	case 4:
		if (!strcmp(argv[1], "--unset"))
317 318 319 320 321 322 323 324
			return git_config_set_multivar(argv[2], NULL, argv[3], 0);
		else if (!strcmp(argv[1], "--unset-all"))
			return git_config_set_multivar(argv[2], NULL, argv[3], 1);
		else if (!strcmp(argv[1], "--get"))
			return get_value(argv[2], argv[3]);
		else if (!strcmp(argv[1], "--get-all")) {
			do_all = 1;
			return get_value(argv[2], argv[3]);
325 326 327 328 329
		} else if (!strcmp(argv[1], "--get-regexp")) {
			show_keys = 1;
			use_key_regexp = 1;
			do_all = 1;
			return get_value(argv[2], argv[3]);
330 331 332 333 334 335 336 337 338 339
		} else if (!strcmp(argv[1], "--add")) {
			value = normalize_value(argv[2], argv[3]);
			return git_config_set_multivar(argv[2], value, "^$", 0);
		} else if (!strcmp(argv[1], "--replace-all")) {
			value = normalize_value(argv[2], argv[3]);
			return git_config_set_multivar(argv[2], value, NULL, 1);
		} else {
			value = normalize_value(argv[1], argv[2]);
			return git_config_set_multivar(argv[1], value, argv[3], 0);
		}
340
	case 5:
341 342 343 344
		if (!strcmp(argv[1], "--replace-all")) {
			value = normalize_value(argv[2], argv[3]);
			return git_config_set_multivar(argv[2], value, argv[4], 1);
		}
345
	case 1:
346 347 348 349 350
	default:
		usage(git_config_set_usage);
	}
	return 0;
}