Merge branch 'jc/optional-path' into jch
"git config get --path" segfaulted on an ":(optional)path" that does not exist, which has been corrected. * jc/optional-path: config: really treat missing optional path as not configured config: really pretend missing :(optional) value is not there config: mark otherwise unused function as file-scope static
commit
40b9df660d
|
|
@ -739,7 +739,8 @@ static int git_blame_config(const char *var, const char *value,
|
|||
ret = git_config_pathname(&str, var, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
string_list_insert(&ignore_revs_file_list, str);
|
||||
if (str)
|
||||
string_list_insert(&ignore_revs_file_list, str);
|
||||
free(str);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -261,6 +261,12 @@ struct strbuf_list {
|
|||
int alloc;
|
||||
};
|
||||
|
||||
/*
|
||||
* Format the configuration key-value pair (`key_`, `value_`) and
|
||||
* append it into strbuf `buf`. Returns a negative value on failure,
|
||||
* 0 on success, 1 on a missing optional value (i.e., telling the
|
||||
* caller to pretend that <key_,value_> did not exist).
|
||||
*/
|
||||
static int format_config(const struct config_display_options *opts,
|
||||
struct strbuf *buf, const char *key_,
|
||||
const char *value_, const struct key_value_info *kvi)
|
||||
|
|
@ -299,7 +305,10 @@ static int format_config(const struct config_display_options *opts,
|
|||
char *v;
|
||||
if (git_config_pathname(&v, key_, value_) < 0)
|
||||
return -1;
|
||||
strbuf_addstr(buf, v);
|
||||
if (v)
|
||||
strbuf_addstr(buf, v);
|
||||
else
|
||||
return 1; /* :(optional)no-such-file */
|
||||
free((char *)v);
|
||||
} else if (opts->type == TYPE_EXPIRY_DATE) {
|
||||
timestamp_t t;
|
||||
|
|
@ -344,6 +353,7 @@ static int collect_config(const char *key_, const char *value_,
|
|||
struct collect_config_data *data = cb;
|
||||
struct strbuf_list *values = data->values;
|
||||
const struct key_value_info *kvi = ctx->kvi;
|
||||
int status;
|
||||
|
||||
if (!(data->get_value_flags & GET_VALUE_KEY_REGEXP) &&
|
||||
strcmp(key_, data->key))
|
||||
|
|
@ -361,8 +371,15 @@ static int collect_config(const char *key_, const char *value_,
|
|||
ALLOC_GROW(values->items, values->nr + 1, values->alloc);
|
||||
strbuf_init(&values->items[values->nr], 0);
|
||||
|
||||
return format_config(data->display_opts, &values->items[values->nr++],
|
||||
key_, value_, kvi);
|
||||
status = format_config(data->display_opts, &values->items[values->nr++],
|
||||
key_, value_, kvi);
|
||||
if (status < 0)
|
||||
return status;
|
||||
if (status) {
|
||||
strbuf_release(&values->items[--values->nr]);
|
||||
status = 0;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int get_value(const struct config_location_options *opts,
|
||||
|
|
@ -438,15 +455,23 @@ static int get_value(const struct config_location_options *opts,
|
|||
if (!values.nr && display_opts->default_value) {
|
||||
struct key_value_info kvi = KVI_INIT;
|
||||
struct strbuf *item;
|
||||
int status;
|
||||
|
||||
kvi_from_param(&kvi);
|
||||
ALLOC_GROW(values.items, values.nr + 1, values.alloc);
|
||||
item = &values.items[values.nr++];
|
||||
strbuf_init(item, 0);
|
||||
if (format_config(display_opts, item, key_,
|
||||
display_opts->default_value, &kvi) < 0)
|
||||
|
||||
status = format_config(display_opts, item, key_,
|
||||
display_opts->default_value, &kvi);
|
||||
if (status < 0)
|
||||
die(_("failed to format default config value: %s"),
|
||||
display_opts->default_value);
|
||||
if (status) {
|
||||
/* default was a missing optional value */
|
||||
values.nr--;
|
||||
strbuf_release(item);
|
||||
}
|
||||
}
|
||||
|
||||
ret = !values.nr;
|
||||
|
|
@ -714,11 +739,13 @@ static int get_urlmatch(const struct config_location_options *opts,
|
|||
for_each_string_list_item(item, &values) {
|
||||
struct urlmatch_current_candidate_value *matched = item->util;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int status;
|
||||
|
||||
format_config(&display_opts, &buf, item->string,
|
||||
matched->value_is_null ? NULL : matched->value.buf,
|
||||
&matched->kvi);
|
||||
fwrite(buf.buf, 1, buf.len, stdout);
|
||||
status = format_config(&display_opts, &buf, item->string,
|
||||
matched->value_is_null ? NULL : matched->value.buf,
|
||||
&matched->kvi);
|
||||
if (!status)
|
||||
fwrite(buf.buf, 1, buf.len, stdout);
|
||||
strbuf_release(&buf);
|
||||
|
||||
strbuf_release(&matched->value);
|
||||
|
|
|
|||
|
|
@ -177,8 +177,9 @@ static int receive_pack_config(const char *var, const char *value,
|
|||
|
||||
if (git_config_pathname(&path, var, value))
|
||||
return -1;
|
||||
strbuf_addf(&fsck_msg_types, "%cskiplist=%s",
|
||||
fsck_msg_types.len ? ',' : '=', path);
|
||||
if (path)
|
||||
strbuf_addf(&fsck_msg_types, "%cskiplist=%s",
|
||||
fsck_msg_types.len ? ',' : '=', path);
|
||||
free(path);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
3
config.c
3
config.c
|
|
@ -1291,6 +1291,7 @@ int git_config_pathname(char **dest, const char *var, const char *value)
|
|||
|
||||
if (is_optional && is_missing_file(path)) {
|
||||
free(path);
|
||||
*dest = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1953,7 +1954,7 @@ int git_configset_get_maybe_bool(struct config_set *set, const char *key, int *d
|
|||
return 1;
|
||||
}
|
||||
|
||||
int git_configset_get_pathname(struct config_set *set, const char *key, char **dest)
|
||||
static int git_configset_get_pathname(struct config_set *set, const char *key, char **dest)
|
||||
{
|
||||
const char *value;
|
||||
if (!git_configset_get_value(set, key, &value, NULL))
|
||||
|
|
|
|||
1
config.h
1
config.h
|
|
@ -564,7 +564,6 @@ int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned lon
|
|||
int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
|
||||
int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);
|
||||
int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
|
||||
int git_configset_get_pathname(struct config_set *cs, const char *key, char **dest);
|
||||
|
||||
/**
|
||||
* Run only the discover part of the repo_config_get_*() functions
|
||||
|
|
|
|||
|
|
@ -1865,8 +1865,9 @@ int fetch_pack_fsck_config(const char *var, const char *value,
|
|||
|
||||
if (git_config_pathname(&path, var, value))
|
||||
return -1;
|
||||
strbuf_addf(msg_types, "%cskiplist=%s",
|
||||
msg_types->len ? ',' : '=', path);
|
||||
if (path)
|
||||
strbuf_addf(msg_types, "%cskiplist=%s",
|
||||
msg_types->len ? ',' : '=', path);
|
||||
free(path);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
12
fsck.c
12
fsck.c
|
|
@ -1398,14 +1398,16 @@ int git_fsck_config(const char *var, const char *value,
|
|||
|
||||
if (strcmp(var, "fsck.skiplist") == 0) {
|
||||
char *path;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
if (git_config_pathname(&path, var, value))
|
||||
return -1;
|
||||
strbuf_addf(&sb, "skiplist=%s", path);
|
||||
free(path);
|
||||
fsck_set_msg_types(options, sb.buf);
|
||||
strbuf_release(&sb);
|
||||
if (path) {
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
strbuf_addf(&sb, "skiplist=%s", path);
|
||||
free(path);
|
||||
fsck_set_msg_types(options, sb.buf);
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -794,8 +794,16 @@ static int git_gpg_config(const char *var, const char *value,
|
|||
fmtname = "ssh";
|
||||
|
||||
if (fmtname) {
|
||||
char *program;
|
||||
int status;
|
||||
|
||||
fmt = get_format_by_name(fmtname);
|
||||
return git_config_pathname((char **) &fmt->program, var, value);
|
||||
status = git_config_pathname(&program, var, value);
|
||||
if (status)
|
||||
return status;
|
||||
if (program)
|
||||
fmt->program = program;
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
2
setup.c
2
setup.c
|
|
@ -1248,7 +1248,7 @@ static int safe_directory_cb(const char *key, const char *value,
|
|||
} else {
|
||||
char *allowed = NULL;
|
||||
|
||||
if (!git_config_pathname(&allowed, key, value)) {
|
||||
if (!git_config_pathname(&allowed, key, value) && allowed) {
|
||||
char *normalized = NULL;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ integration_tests = [
|
|||
't1308-config-set.sh',
|
||||
't1309-early-config.sh',
|
||||
't1310-config-default.sh',
|
||||
't1311-config-optional.sh',
|
||||
't1350-config-hooks-path.sh',
|
||||
't1400-update-ref.sh',
|
||||
't1401-symbolic-ref.sh',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2025 Google LLC
|
||||
#
|
||||
|
||||
test_description=':(optional) paths'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'var=:(optional)path-exists' '
|
||||
test_config a.path ":(optional)path-exists" &&
|
||||
>path-exists &&
|
||||
echo path-exists >expect &&
|
||||
|
||||
git config get --path a.path >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'missing optional value is ignored' '
|
||||
test_config a.path ":(optional)no-such-path" &&
|
||||
# Using --show-scope ensures we skip writing not only the value
|
||||
# but also any meta-information about the ignored key.
|
||||
test_must_fail git config get --show-scope --path a.path >actual &&
|
||||
test_line_count = 0 actual
|
||||
'
|
||||
|
||||
test_expect_success 'missing optional value is ignored in multi-value config' '
|
||||
test_when_finished "git config unset --all a.path" &&
|
||||
git config set --append a.path ":(optional)path-exists" &&
|
||||
git config set --append a.path ":(optional)no-such-path" &&
|
||||
>path-exists &&
|
||||
echo path-exists >expect &&
|
||||
|
||||
git config --get --path a.path >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
Loading…
Reference in New Issue