Skip to content

Commit 923ffa2

Browse files
committed
Merge branch 'ds/config-list-with-type' into seen
"git config list" is taught to show the values interpreted for specific type with "--type=<X>" option. Comments? * ds/config-list-with-type: config: make 'git config list --type=<X>' work config: create special init for list mode config: allow format_config() to filter parse: add git_parse_maybe_pathname() config: move show_all_config()
2 parents 318670b + 59112c8 commit 923ffa2

File tree

6 files changed

+147
-52
lines changed

6 files changed

+147
-52
lines changed

Documentation/git-config.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,9 @@ Valid `<type>`'s include:
240240
that the given value is canonicalize-able as an ANSI color, but it is written
241241
as-is.
242242
+
243+
If the command is in `list` mode, then the `--type <type>` argument will apply
244+
to each listed config value. If the value does not successfully parse in that
245+
format, then it will be omitted from the list.
243246

244247
--bool::
245248
--int::

builtin/config.c

Lines changed: 92 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "abspath.h"
44
#include "config.h"
55
#include "color.h"
6+
#include "date.h"
67
#include "editor.h"
78
#include "environment.h"
89
#include "gettext.h"
@@ -231,30 +232,6 @@ static void show_config_scope(const struct config_display_options *opts,
231232
strbuf_addch(buf, term);
232233
}
233234

234-
static int show_all_config(const char *key_, const char *value_,
235-
const struct config_context *ctx,
236-
void *cb)
237-
{
238-
const struct config_display_options *opts = cb;
239-
const struct key_value_info *kvi = ctx->kvi;
240-
241-
if (opts->show_origin || opts->show_scope) {
242-
struct strbuf buf = STRBUF_INIT;
243-
if (opts->show_scope)
244-
show_config_scope(opts, kvi, &buf);
245-
if (opts->show_origin)
246-
show_config_origin(opts, kvi, &buf);
247-
/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
248-
fwrite(buf.buf, 1, buf.len, stdout);
249-
strbuf_release(&buf);
250-
}
251-
if (!opts->omit_values && value_)
252-
printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
253-
else
254-
printf("%s%c", key_, opts->term);
255-
return 0;
256-
}
257-
258235
struct strbuf_list {
259236
struct strbuf *items;
260237
int nr;
@@ -269,7 +246,8 @@ struct strbuf_list {
269246
*/
270247
static int format_config(const struct config_display_options *opts,
271248
struct strbuf *buf, const char *key_,
272-
const char *value_, const struct key_value_info *kvi)
249+
const char *value_, const struct key_value_info *kvi,
250+
int die_on_parse)
273251
{
274252
if (opts->show_scope)
275253
show_config_scope(opts, kvi, buf);
@@ -281,27 +259,55 @@ static int format_config(const struct config_display_options *opts,
281259
if (opts->show_keys)
282260
strbuf_addch(buf, opts->key_delim);
283261

284-
if (opts->type == TYPE_INT)
262+
if (opts->type == TYPE_INT && die_on_parse) {
285263
strbuf_addf(buf, "%"PRId64,
286264
git_config_int64(key_, value_ ? value_ : "", kvi));
287-
else if (opts->type == TYPE_BOOL)
265+
} else if (opts->type == TYPE_INT) {
266+
int64_t v;
267+
int ret = git_parse_int64(value_, &v);
268+
269+
if (ret)
270+
return -1;
271+
272+
strbuf_addf(buf, "%"PRId64, v);
273+
}
274+
else if (opts->type == TYPE_BOOL && die_on_parse) {
288275
strbuf_addstr(buf, git_config_bool(key_, value_) ?
289276
"true" : "false");
290-
else if (opts->type == TYPE_BOOL_OR_INT) {
291-
int is_bool, v;
292-
v = git_config_bool_or_int(key_, value_, kvi,
293-
&is_bool);
277+
} else if (opts->type == TYPE_BOOL) {
278+
int value = git_parse_maybe_bool(value_);
279+
280+
if (value < 0)
281+
return -1;
282+
283+
strbuf_addstr(buf, value ? "true" : "false");
284+
} else if (opts->type == TYPE_BOOL_OR_INT && die_on_parse) {
285+
int is_bool = 0;
286+
int v = git_config_bool_or_int(key_, value_, kvi,
287+
&is_bool);
288+
if (is_bool)
289+
strbuf_addstr(buf, v ? "true" : "false");
290+
else
291+
strbuf_addf(buf, "%d", v);
292+
} else if (opts->type == TYPE_BOOL_OR_INT) {
293+
int is_bool = 0;
294+
int v = git_parse_maybe_bool_text(value_);
295+
296+
if (v < 0)
297+
return -1;
298+
294299
if (is_bool)
295300
strbuf_addstr(buf, v ? "true" : "false");
296301
else
297302
strbuf_addf(buf, "%d", v);
298303
} else if (opts->type == TYPE_BOOL_OR_STR) {
304+
/* Note: this can't fail to parse! */
299305
int v = git_parse_maybe_bool(value_);
300306
if (v < 0)
301307
strbuf_addstr(buf, value_);
302308
else
303309
strbuf_addstr(buf, v ? "true" : "false");
304-
} else if (opts->type == TYPE_PATH) {
310+
} else if (opts->type == TYPE_PATH && die_on_parse) {
305311
char *v;
306312
if (git_config_pathname(&v, key_, value_) < 0)
307313
return -1;
@@ -310,16 +316,35 @@ static int format_config(const struct config_display_options *opts,
310316
else
311317
return 1; /* :(optional)no-such-file */
312318
free((char *)v);
313-
} else if (opts->type == TYPE_EXPIRY_DATE) {
319+
} else if (opts->type == TYPE_PATH) {
320+
char *v;
321+
if (git_parse_maybe_pathname(value_, &v) < 0)
322+
return -1;
323+
if (v)
324+
strbuf_addstr(buf, v);
325+
else
326+
return 1; /* :(optional)no-such-file */
327+
free((char *)v);
328+
} else if (opts->type == TYPE_EXPIRY_DATE && die_on_parse) {
314329
timestamp_t t;
315330
if (git_config_expiry_date(&t, key_, value_) < 0)
316331
return -1;
317332
strbuf_addf(buf, "%"PRItime, t);
318-
} else if (opts->type == TYPE_COLOR) {
333+
} else if (opts->type == TYPE_EXPIRY_DATE) {
334+
timestamp_t t;
335+
if (parse_expiry_date(value_, &t) < 0)
336+
return -1;
337+
strbuf_addf(buf, "%"PRItime, t);
338+
} else if (opts->type == TYPE_COLOR && die_on_parse) {
319339
char v[COLOR_MAXLEN];
320340
if (git_config_color(v, key_, value_) < 0)
321341
return -1;
322342
strbuf_addstr(buf, v);
343+
} else if (opts->type == TYPE_COLOR) {
344+
char v[COLOR_MAXLEN];
345+
if (color_parse(value_, v) < 0)
346+
return -1;
347+
strbuf_addstr(buf, v);
323348
} else if (value_) {
324349
strbuf_addstr(buf, value_);
325350
} else {
@@ -332,6 +357,21 @@ static int format_config(const struct config_display_options *opts,
332357
return 0;
333358
}
334359

360+
static int show_all_config(const char *key_, const char *value_,
361+
const struct config_context *ctx,
362+
void *cb)
363+
{
364+
const struct config_display_options *opts = cb;
365+
const struct key_value_info *kvi = ctx->kvi;
366+
struct strbuf formatted = STRBUF_INIT;
367+
368+
if (format_config(opts, &formatted, key_, value_, kvi, 0) >= 0)
369+
fwrite(formatted.buf, 1, formatted.len, stdout);
370+
371+
strbuf_release(&formatted);
372+
return 0;
373+
}
374+
335375
#define GET_VALUE_ALL (1 << 0)
336376
#define GET_VALUE_KEY_REGEXP (1 << 1)
337377

@@ -372,7 +412,7 @@ static int collect_config(const char *key_, const char *value_,
372412
strbuf_init(&values->items[values->nr], 0);
373413

374414
status = format_config(data->display_opts, &values->items[values->nr++],
375-
key_, value_, kvi);
415+
key_, value_, kvi, 1);
376416
if (status < 0)
377417
return status;
378418
if (status) {
@@ -463,7 +503,7 @@ static int get_value(const struct config_location_options *opts,
463503
strbuf_init(item, 0);
464504

465505
status = format_config(display_opts, item, key_,
466-
display_opts->default_value, &kvi);
506+
display_opts->default_value, &kvi, 1);
467507
if (status < 0)
468508
die(_("failed to format default config value: %s"),
469509
display_opts->default_value);
@@ -743,7 +783,7 @@ static int get_urlmatch(const struct config_location_options *opts,
743783

744784
status = format_config(&display_opts, &buf, item->string,
745785
matched->value_is_null ? NULL : matched->value.buf,
746-
&matched->kvi);
786+
&matched->kvi, 1);
747787
if (!status)
748788
fwrite(buf.buf, 1, buf.len, stdout);
749789
strbuf_release(&buf);
@@ -868,6 +908,19 @@ static void display_options_init(struct config_display_options *opts)
868908
}
869909
}
870910

911+
static void display_options_init_list(struct config_display_options *opts)
912+
{
913+
opts->show_keys = 1;
914+
915+
if (opts->end_nul) {
916+
display_options_init(opts);
917+
} else {
918+
opts->term = '\n';
919+
opts->delim = ' ';
920+
opts->key_delim = '=';
921+
}
922+
}
923+
871924
static int cmd_config_list(int argc, const char **argv, const char *prefix,
872925
struct repository *repo UNUSED)
873926
{
@@ -886,7 +939,7 @@ static int cmd_config_list(int argc, const char **argv, const char *prefix,
886939
check_argc(argc, 0, 0);
887940

888941
location_options_init(&location_opts, prefix);
889-
display_options_init(&display_opts);
942+
display_options_init_list(&display_opts);
890943

891944
setup_auto_pager("config", 1);
892945

@@ -1317,6 +1370,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
13171370

13181371
if (actions == ACTION_LIST) {
13191372
check_argc(argc, 0, 0);
1373+
display_options_init_list(&display_opts);
13201374
if (config_with_options(show_all_config, &display_opts,
13211375
&location_opts.source, the_repository,
13221376
&location_opts.options) < 0) {

config.c

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,24 +1287,12 @@ int git_config_string(char **dest, const char *var, const char *value)
12871287

12881288
int git_config_pathname(char **dest, const char *var, const char *value)
12891289
{
1290-
bool is_optional;
1291-
char *path;
1292-
12931290
if (!value)
12941291
return config_error_nonbool(var);
12951292

1296-
is_optional = skip_prefix(value, ":(optional)", &value);
1297-
path = interpolate_path(value, 0);
1298-
if (!path)
1293+
if (git_parse_maybe_pathname(value, dest) < 0)
12991294
die(_("failed to expand user dir in: '%s'"), value);
13001295

1301-
if (is_optional && is_missing_file(path)) {
1302-
free(path);
1303-
*dest = NULL;
1304-
return 0;
1305-
}
1306-
1307-
*dest = path;
13081296
return 0;
13091297
}
13101298

parse.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "git-compat-util.h"
22
#include "gettext.h"
33
#include "parse.h"
4+
#include "path.h"
45

56
static uintmax_t get_unit_factor(const char *end)
67
{
@@ -218,3 +219,26 @@ unsigned long git_env_ulong(const char *k, unsigned long val)
218219
die(_("failed to parse %s"), k);
219220
return val;
220221
}
222+
223+
int git_parse_maybe_pathname(const char *value, char **dest)
224+
{
225+
bool is_optional;
226+
char *path;
227+
228+
if (!value)
229+
return -1;
230+
231+
is_optional = skip_prefix(value, ":(optional)", &value);
232+
path = interpolate_path(value, 0);
233+
if (!path)
234+
return -1;
235+
236+
if (is_optional && is_missing_file(path)) {
237+
free(path);
238+
*dest = NULL;
239+
return 0;
240+
}
241+
242+
*dest = path;
243+
return 0;
244+
}

parse.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ int git_parse_maybe_bool_text(const char *value);
2020
int git_env_bool(const char *, int);
2121
unsigned long git_env_ulong(const char *, unsigned long);
2222

23+
int git_parse_maybe_pathname(const char *value, char **dest);
24+
2325
#endif /* PARSE_H */

t/t1300-config.sh

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2459,9 +2459,10 @@ done
24592459

24602460
cat >.git/config <<-\EOF &&
24612461
[section]
2462-
foo = true
2462+
foo = True
24632463
number = 10
24642464
big = 1M
2465+
path = ~/dir
24652466
EOF
24662467

24672468
test_expect_success 'identical modern --type specifiers are allowed' '
@@ -2503,6 +2504,29 @@ test_expect_success 'unset type specifiers may be reset to conflicting ones' '
25032504
test_cmp_config 1048576 --type=bool --no-type --type=int section.big
25042505
'
25052506

2507+
test_expect_success 'list --type=bool shows only canonicalizable bool values' '
2508+
cat >expect <<-EOF &&
2509+
section.foo=true
2510+
section.number=true
2511+
section.big=true
2512+
EOF
2513+
2514+
git config ${mode_prefix}list --type=bool >actual &&
2515+
test_cmp expect actual
2516+
'
2517+
2518+
test_expect_success 'list --type=path shows only canonicalizable path values' '
2519+
cat >expect <<-EOF &&
2520+
section.foo=True
2521+
section.number=10
2522+
section.big=1M
2523+
section.path=$HOME/dir
2524+
EOF
2525+
2526+
git config ${mode_prefix}list --type=path >actual &&
2527+
test_cmp expect actual
2528+
'
2529+
25062530
test_expect_success '--type rejects unknown specifiers' '
25072531
test_must_fail git config --type=nonsense section.foo 2>error &&
25082532
test_grep "unrecognized --type argument" error

0 commit comments

Comments
 (0)