1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-17 17:46:10 +02:00

config: report cached filenames in die_bad_number()

If, when parsing numbers from config, die_bad_number() is called, it
reports the filename and config source type if we were parsing a config
file, but not if we were iterating a config_set (it defaults to a less
specific error message). Most call sites don't parse config files
because config is typically read once and cached, so we only report
filename and config source type in "git config --type" (since "git
config" always parses config files).

This could have been fixed when we taught the current_config_*
functions to respect config_set values (0d44a2dacc (config: return
configset value for current_config_ functions, 2016-05-26), but it was
hard to spot then and we might have just missed it (I didn't find
mention of die_bad_number() in the original ML discussion [1].)

Fix this by refactoring the current_config_* functions into variants
that don't BUG() when we aren't reading config, and using the resulting
functions in die_bad_number(). "git config --get[-regexp] --type=int"
cannot use the non-refactored version because it parses the int value
_after_ parsing the config file, which would run into the BUG().

Since the refactored functions aren't public, they use "struct
config_reader".

1. https://lore.kernel.org/git/20160518223712.GA18317@sigill.intra.peff.net/

Signed-off-by: Glen Choo <chooglen@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Glen Choo 2023-03-28 17:51:53 +00:00 committed by Junio C Hamano
parent 5cdf18e7cd
commit e2016508e7
4 changed files with 75 additions and 23 deletions

View File

@ -1311,39 +1311,48 @@ int git_parse_ssize_t(const char *value, ssize_t *ret)
return 1;
}
static int reader_config_name(struct config_reader *reader, const char **out);
static int reader_origin_type(struct config_reader *reader,
enum config_origin_type *type);
NORETURN
static void die_bad_number(struct config_source *cf, const char *name,
static void die_bad_number(struct config_reader *reader, const char *name,
const char *value)
{
const char *error_type = (errno == ERANGE) ?
N_("out of range") : N_("invalid unit");
const char *bad_numeric = N_("bad numeric config value '%s' for '%s': %s");
const char *config_name = NULL;
enum config_origin_type config_origin = CONFIG_ORIGIN_UNKNOWN;
if (!value)
value = "";
if (!(cf && cf->name))
/* Ignoring the return value is okay since we handle missing values. */
reader_config_name(reader, &config_name);
reader_origin_type(reader, &config_origin);
if (!config_name)
die(_(bad_numeric), value, name, _(error_type));
switch (cf->origin_type) {
switch (config_origin) {
case CONFIG_ORIGIN_BLOB:
die(_("bad numeric config value '%s' for '%s' in blob %s: %s"),
value, name, cf->name, _(error_type));
value, name, config_name, _(error_type));
case CONFIG_ORIGIN_FILE:
die(_("bad numeric config value '%s' for '%s' in file %s: %s"),
value, name, cf->name, _(error_type));
value, name, config_name, _(error_type));
case CONFIG_ORIGIN_STDIN:
die(_("bad numeric config value '%s' for '%s' in standard input: %s"),
value, name, _(error_type));
case CONFIG_ORIGIN_SUBMODULE_BLOB:
die(_("bad numeric config value '%s' for '%s' in submodule-blob %s: %s"),
value, name, cf->name, _(error_type));
value, name, config_name, _(error_type));
case CONFIG_ORIGIN_CMDLINE:
die(_("bad numeric config value '%s' for '%s' in command line %s: %s"),
value, name, cf->name, _(error_type));
value, name, config_name, _(error_type));
default:
die(_("bad numeric config value '%s' for '%s' in %s: %s"),
value, name, cf->name, _(error_type));
value, name, config_name, _(error_type));
}
}
@ -1351,7 +1360,7 @@ int git_config_int(const char *name, const char *value)
{
int ret;
if (!git_parse_int(value, &ret))
die_bad_number(the_reader.source, name, value);
die_bad_number(&the_reader, name, value);
return ret;
}
@ -1359,7 +1368,7 @@ int64_t git_config_int64(const char *name, const char *value)
{
int64_t ret;
if (!git_parse_int64(value, &ret))
die_bad_number(the_reader.source, name, value);
die_bad_number(&the_reader, name, value);
return ret;
}
@ -1367,7 +1376,7 @@ unsigned long git_config_ulong(const char *name, const char *value)
{
unsigned long ret;
if (!git_parse_ulong(value, &ret))
die_bad_number(the_reader.source, name, value);
die_bad_number(&the_reader, name, value);
return ret;
}
@ -1375,7 +1384,7 @@ ssize_t git_config_ssize_t(const char *name, const char *value)
{
ssize_t ret;
if (!git_parse_ssize_t(value, &ret))
die_bad_number(the_reader.source, name, value);
die_bad_number(&the_reader, name, value);
return ret;
}
@ -3839,14 +3848,23 @@ int parse_config_key(const char *var,
return 0;
}
static int reader_origin_type(struct config_reader *reader,
enum config_origin_type *type)
{
if (the_reader.config_kvi)
*type = reader->config_kvi->origin_type;
else if(the_reader.source)
*type = reader->source->origin_type;
else
return 1;
return 0;
}
const char *current_config_origin_type(void)
{
int type;
if (the_reader.config_kvi)
type = the_reader.config_kvi->origin_type;
else if(the_reader.source)
type = the_reader.source->origin_type;
else
enum config_origin_type type = CONFIG_ORIGIN_UNKNOWN;
if (reader_origin_type(&the_reader, &type))
BUG("current_config_origin_type called outside config callback");
switch (type) {
@ -3885,14 +3903,21 @@ const char *config_scope_name(enum config_scope scope)
}
}
static int reader_config_name(struct config_reader *reader, const char **out)
{
if (the_reader.config_kvi)
*out = reader->config_kvi->filename;
else if (the_reader.source)
*out = reader->source->name;
else
return 1;
return 0;
}
const char *current_config_name(void)
{
const char *name;
if (the_reader.config_kvi)
name = the_reader.config_kvi->filename;
else if (the_reader.source)
name = the_reader.source->name;
else
if (reader_config_name(&the_reader, &name))
BUG("current_config_name called outside config callback");
return name ? name : "";
}

View File

@ -56,6 +56,7 @@ struct git_config_source {
};
enum config_origin_type {
CONFIG_ORIGIN_UNKNOWN = 0,
CONFIG_ORIGIN_BLOB,
CONFIG_ORIGIN_FILE,
CONFIG_ORIGIN_STDIN,

View File

@ -30,6 +30,9 @@
* iterate -> iterate over all values using git_config(), and print some
* data for each
*
* git_config_int -> iterate over all values using git_config() and print the
* integer value for the entered key or die
*
* Examples:
*
* To print the value with highest priority for key "foo.bAr Baz.rock":
@ -54,6 +57,17 @@ static int iterate_cb(const char *var, const char *value, void *data UNUSED)
return 0;
}
static int parse_int_cb(const char *var, const char *value, void *data)
{
const char *key_to_match = data;
if (!strcmp(key_to_match, var)) {
int parsed = git_config_int(value, value);
printf("%d\n", parsed);
}
return 0;
}
static int early_config_cb(const char *var, const char *value, void *vdata)
{
const char *key = vdata;
@ -176,6 +190,9 @@ int cmd__config(int argc, const char **argv)
} else if (!strcmp(argv[1], "iterate")) {
git_config(iterate_cb, NULL);
goto exit0;
} else if (argc == 3 && !strcmp(argv[1], "git_config_int")) {
git_config(parse_int_cb, (void *) argv[2]);
goto exit0;
}
die("%s: Please check the syntax and the function name", argv[0]);

View File

@ -120,6 +120,10 @@ test_expect_success 'find integer value for a key' '
check_config get_int lamb.chop 65
'
test_expect_success 'parse integer value during iteration' '
check_config git_config_int lamb.chop 65
'
test_expect_success 'find string value for a key' '
check_config get_string case.baz hask &&
check_config expect_code 1 get_string case.ba "Value not found for \"case.ba\""
@ -134,6 +138,11 @@ test_expect_success 'find integer if value is non parse-able' '
check_config expect_code 128 get_int lamb.head
'
test_expect_success 'non parse-able integer value during iteration' '
check_config expect_code 128 git_config_int lamb.head 2>result &&
grep "fatal: bad numeric config value .* in file \.git/config" result
'
test_expect_success 'find bool value for the entered key' '
check_config get_bool goat.head 1 &&
check_config get_bool goat.skin 0 &&