Skip to content

Commit

Permalink
Merge branch 'ab/config-multi-and-nonbool'
Browse files Browse the repository at this point in the history
Assorted config API updates.

* ab/config-multi-and-nonbool:
  for-each-repo: with bad config, don't conflate <path> and <cmd>
  config API: add "string" version of *_value_multi(), fix segfaults
  config API users: test for *_get_value_multi() segfaults
  for-each-repo: error on bad --config
  config API: have *_multi() return an "int" and take a "dest"
  versioncmp.c: refactor config reading next commit
  config API: add and use a "git_config_get()" family of functions
  config tests: add "NULL" tests for *_get_value_multi()
  config tests: cover blind spots in git_die_config() tests
  • Loading branch information
gitster committed Apr 6, 2023
2 parents e9dffbc + 3611f74 commit 87daf40
Show file tree
Hide file tree
Showing 21 changed files with 481 additions and 72 deletions.
14 changes: 6 additions & 8 deletions builtin/for-each-repo.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
static const char *config_key = NULL;
int i, result = 0;
const struct string_list *values;
int err;

const struct option options[] = {
OPT_STRING(0, "config", &config_key, N_("config"),
Expand All @@ -45,14 +46,11 @@ int cmd_for_each_repo(int argc, const char **argv, const char *prefix)
if (!config_key)
die(_("missing --config=<config>"));

values = repo_config_get_value_multi(the_repository,
config_key);

/*
* Do nothing on an empty list, which is equivalent to the case
* where the config variable does not exist at all.
*/
if (!values)
err = repo_config_get_string_multi(the_repository, config_key, &values);
if (err < 0)
usage_msg_optf(_("got bad config --config=%s"),
for_each_repo_usage, options, config_key);
else if (err)
return 0;

for (i = 0; !result && i < values->nr; i++)
Expand Down
15 changes: 5 additions & 10 deletions builtin/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1494,7 +1494,6 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
};
int found = 0;
const char *key = "maintenance.repo";
char *config_value;
char *maintpath = get_maintpath();
struct string_list_item *item;
const struct string_list *list;
Expand All @@ -1509,13 +1508,10 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
git_config_set("maintenance.auto", "false");

/* Set maintenance strategy, if unset */
if (!git_config_get_string("maintenance.strategy", &config_value))
free(config_value);
else
if (git_config_get("maintenance.strategy"))
git_config_set("maintenance.strategy", "incremental");

list = git_config_get_value_multi(key);
if (list) {
if (!git_config_get_string_multi(key, &list)) {
for_each_string_list_item(item, list) {
if (!strcmp(maintpath, item->string)) {
found = 1;
Expand Down Expand Up @@ -1581,11 +1577,10 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
if (config_file) {
git_configset_init(&cs);
git_configset_add_file(&cs, config_file);
list = git_configset_get_value_multi(&cs, key);
} else {
list = git_config_get_value_multi(key);
}
if (list) {
if (!(config_file
? git_configset_get_string_multi(&cs, key, &list)
: git_config_get_string_multi(key, &list))) {
for_each_string_list_item(item, list) {
if (!strcmp(maintpath, item->string)) {
found = 1;
Expand Down
6 changes: 3 additions & 3 deletions builtin/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,10 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f
int i;
char *value = NULL;
struct string_list *include = decoration_filter->include_ref_pattern;
const struct string_list *config_exclude =
git_config_get_value_multi("log.excludeDecoration");
const struct string_list *config_exclude;

if (config_exclude) {
if (!git_config_get_string_multi("log.excludeDecoration",
&config_exclude)) {
struct string_list_item *item;
for_each_string_list_item(item, config_exclude)
string_list_append(decoration_filter->exclude_ref_config_pattern,
Expand Down
7 changes: 3 additions & 4 deletions builtin/submodule--helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
* If there are no path args and submodule.active is set then,
* by default, only initialize 'active' modules.
*/
if (!argc && git_config_get_value_multi("submodule.active"))
if (!argc && !git_config_get("submodule.active"))
module_list_active(&list);

info.prefix = prefix;
Expand Down Expand Up @@ -2745,7 +2745,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
* If there are no path args and submodule.active is set then,
* by default, only initialize 'active' modules.
*/
if (!argc && git_config_get_value_multi("submodule.active"))
if (!argc && !git_config_get("submodule.active"))
module_list_active(&list);

info.prefix = opt.prefix;
Expand Down Expand Up @@ -3142,7 +3142,6 @@ static int config_submodule_in_gitmodules(const char *name, const char *var, con
static void configure_added_submodule(struct add_data *add_data)
{
char *key;
const char *val;
struct child_process add_submod = CHILD_PROCESS_INIT;
struct child_process add_gitmodules = CHILD_PROCESS_INIT;

Expand Down Expand Up @@ -3187,7 +3186,7 @@ static void configure_added_submodule(struct add_data *add_data)
* is_submodule_active(), since that function needs to find
* out the value of "submodule.active" again anyway.
*/
if (!git_config_get_string_tmp("submodule.active", &val)) {
if (!git_config_get("submodule.active")) {
/*
* If the submodule being added isn't already covered by the
* current configured pathspec, set the submodule's active flag
Expand Down
3 changes: 1 addition & 2 deletions builtin/worktree.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,6 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)

if (file_exists(from_file)) {
struct config_set cs = { { 0 } };
const char *core_worktree;
int bare;

if (safe_create_leading_directories(to_file) ||
Expand All @@ -339,7 +338,7 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
to_file, "core.bare", NULL, "true", 0))
error(_("failed to unset '%s' in '%s'"),
"core.bare", to_file);
if (!git_configset_get_value(&cs, "core.worktree", &core_worktree) &&
if (!git_configset_get(&cs, "core.worktree") &&
git_config_set_in_file_gently(to_file,
"core.worktree", NULL))
error(_("failed to unset '%s' in '%s'"),
Expand Down
109 changes: 92 additions & 17 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -2292,23 +2292,29 @@ void read_very_early_config(config_fn_t cb, void *data)
config_with_options(cb, data, NULL, &opts);
}

static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
RESULT_MUST_BE_USED
static int configset_find_element(struct config_set *cs, const char *key,
struct config_set_element **dest)
{
struct config_set_element k;
struct config_set_element *found_entry;
char *normalized_key;
int ret;

/*
* `key` may come from the user, so normalize it before using it
* for querying entries from the hashmap.
*/
if (git_config_parse_key(key, &normalized_key, NULL))
return NULL;
ret = git_config_parse_key(key, &normalized_key, NULL);
if (ret)
return ret;

hashmap_entry_init(&k.ent, strhash(normalized_key));
k.key = normalized_key;
found_entry = hashmap_get_entry(&cs->config_hash, &k, ent, NULL);
free(normalized_key);
return found_entry;
*dest = found_entry;
return 0;
}

static int configset_add_value(struct config_set *cs, const char *key, const char *value)
Expand All @@ -2317,8 +2323,11 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
struct string_list_item *si;
struct configset_list_item *l_item;
struct key_value_info *kv_info = xmalloc(sizeof(*kv_info));
int ret;

e = configset_find_element(cs, key);
ret = configset_find_element(cs, key, &e);
if (ret)
return ret;
/*
* Since the keys are being fed by git_config*() callback mechanism, they
* are already normalized. So simply add them without any further munging.
Expand Down Expand Up @@ -2412,24 +2421,65 @@ int git_configset_add_file(struct config_set *cs, const char *filename)
int git_configset_get_value(struct config_set *cs, const char *key, const char **value)
{
const struct string_list *values = NULL;
int ret;

/*
* Follows "last one wins" semantic, i.e., if there are multiple matches for the
* queried key in the files of the configset, the value returned will be the last
* value in the value list for that key.
*/
values = git_configset_get_value_multi(cs, key);
if ((ret = git_configset_get_value_multi(cs, key, &values)))
return ret;

if (!values)
return 1;
assert(values->nr > 0);
*value = values->items[values->nr - 1].string;
return 0;
}

const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)
int git_configset_get_value_multi(struct config_set *cs, const char *key,
const struct string_list **dest)
{
struct config_set_element *e;
int ret;

if ((ret = configset_find_element(cs, key, &e)))
return ret;
else if (!e)
return 1;
*dest = &e->value_list;

return 0;
}

static int check_multi_string(struct string_list_item *item, void *util)
{
return item->string ? 0 : config_error_nonbool(util);
}

int git_configset_get_string_multi(struct config_set *cs, const char *key,
const struct string_list **dest)
{
int ret;

if ((ret = git_configset_get_value_multi(cs, key, dest)))
return ret;
if ((ret = for_each_string_list((struct string_list *)*dest,
check_multi_string, (void *)key)))
return ret;

return 0;
}

int git_configset_get(struct config_set *cs, const char *key)
{
struct config_set_element *e = configset_find_element(cs, key);
return e ? &e->value_list : NULL;
struct config_set_element *e;
int ret;

if ((ret = configset_find_element(cs, key, &e)))
return ret;
else if (!e)
return 1;
return 0;
}

int git_configset_get_string(struct config_set *cs, const char *key, char **dest)
Expand Down Expand Up @@ -2568,18 +2618,31 @@ void repo_config(struct repository *repo, config_fn_t fn, void *data)
configset_iter(repo->config, fn, data);
}

int repo_config_get(struct repository *repo, const char *key)
{
git_config_check_init(repo);
return git_configset_get(repo->config, key);
}

int repo_config_get_value(struct repository *repo,
const char *key, const char **value)
{
git_config_check_init(repo);
return git_configset_get_value(repo->config, key, value);
}

const struct string_list *repo_config_get_value_multi(struct repository *repo,
const char *key)
int repo_config_get_value_multi(struct repository *repo, const char *key,
const struct string_list **dest)
{
git_config_check_init(repo);
return git_configset_get_value_multi(repo->config, key, dest);
}

int repo_config_get_string_multi(struct repository *repo, const char *key,
const struct string_list **dest)
{
git_config_check_init(repo);
return git_configset_get_value_multi(repo->config, key);
return git_configset_get_string_multi(repo->config, key, dest);
}

int repo_config_get_string(struct repository *repo,
Expand Down Expand Up @@ -2682,14 +2745,25 @@ void git_config_clear(void)
repo_config_clear(the_repository);
}

int git_config_get(const char *key)
{
return repo_config_get(the_repository, key);
}

int git_config_get_value(const char *key, const char **value)
{
return repo_config_get_value(the_repository, key, value);
}

const struct string_list *git_config_get_value_multi(const char *key)
int git_config_get_value_multi(const char *key, const struct string_list **dest)
{
return repo_config_get_value_multi(the_repository, key, dest);
}

int git_config_get_string_multi(const char *key,
const struct string_list **dest)
{
return repo_config_get_value_multi(the_repository, key);
return repo_config_get_string_multi(the_repository, key, dest);
}

int git_config_get_string(const char *key, char **dest)
Expand Down Expand Up @@ -2836,7 +2910,8 @@ void git_die_config(const char *key, const char *err, ...)
error_fn(err, params);
va_end(params);
}
values = git_config_get_value_multi(key);
if (git_config_get_value_multi(key, &values))
BUG("for key '%s' we must have a value to report on", key);
kv_info = values->items[values->nr - 1].util;
git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
}
Expand Down
Loading

0 comments on commit 87daf40

Please sign in to comment.