Skip to content

Commit

Permalink
config: return configset value for current_config_ functions
Browse files Browse the repository at this point in the history
When 473166b (config: add 'origin_type' to config_source
struct, 2016-02-19) added accessor functions for the origin
type and name, it taught them only to look at the "cf"
struct that is filled in while we are parsing the config.
This is sufficient to make it work with git-config, which
uses git_config_with_options() under the hood. That function
freshly parses the config files and triggers the callback
when it parses each key.

Most git programs, however, use git_config(). This interface
will populate a cache during the actual parse, and then
serve values from the cache. Calling current_config_filename()
in a callback here will find a NULL cf and produce an error.
There are no such callers right now, but let's prepare for
adding some by making this work.

We already record source information in a struct attached to
each value. We just need to make it globally available and
then consult it from the accessor functions.

Signed-off-by: Jeff King <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
peff authored and gitster committed May 27, 2016
1 parent 3258258 commit 0d44a2d
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 9 deletions.
1 change: 1 addition & 0 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -1696,6 +1696,7 @@ extern int ignore_untracked_cache_config;
struct key_value_info {
const char *filename;
int linenr;
const char *origin_type;
};

extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
Expand Down
51 changes: 42 additions & 9 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,24 @@ struct config_source {
long (*do_ftell)(struct config_source *c);
};

/*
* These variables record the "current" config source, which
* can be accessed by parsing callbacks.
*
* The "cf" variable will be non-NULL only when we are actually parsing a real
* config source (file, blob, cmdline, etc).
*
* The "current_config_kvi" variable will be non-NULL only when we are feeding
* cached config from a configset into a callback.
*
* They should generally never be non-NULL at the same time. If they are both
* NULL, then we aren't parsing anything (and depending on the function looking
* at the variables, it's either a bug for it to be called in the first place,
* or it's a function which can be reused for non-config purposes, and should
* fall back to some sane behavior).
*/
static struct config_source *cf;
static struct key_value_info *current_config_kvi;

static int zlib_compression_seen;

Expand Down Expand Up @@ -1284,16 +1301,20 @@ static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
struct string_list *values;
struct config_set_element *entry;
struct configset_list *list = &cs->list;
struct key_value_info *kv_info;

for (i = 0; i < list->nr; i++) {
entry = list->items[i].e;
value_index = list->items[i].value_index;
values = &entry->value_list;
if (fn(entry->key, values->items[value_index].string, data) < 0) {
kv_info = values->items[value_index].util;
git_die_config_linenr(entry->key, kv_info->filename, kv_info->linenr);
}

current_config_kvi = values->items[value_index].util;

if (fn(entry->key, values->items[value_index].string, data) < 0)
git_die_config_linenr(entry->key,
current_config_kvi->filename,
current_config_kvi->linenr);

current_config_kvi = NULL;
}
}

Expand Down Expand Up @@ -1355,10 +1376,12 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
if (cf->name) {
kv_info->filename = strintern(cf->name);
kv_info->linenr = cf->linenr;
kv_info->origin_type = strintern(cf->origin_type);
} else {
/* for values read from `git_config_from_parameters()` */
kv_info->filename = NULL;
kv_info->linenr = -1;
kv_info->origin_type = NULL;
}
si->util = kv_info;

Expand Down Expand Up @@ -2438,14 +2461,24 @@ int parse_config_key(const char *var,

const char *current_config_origin_type(void)
{
if (!cf)
const char *type;
if (current_config_kvi)
type = current_config_kvi->origin_type;
else if(cf)
type = cf->origin_type;
else
die("BUG: current_config_origin_type called outside config callback");
return cf->origin_type ? cf->origin_type : "command line";
return type ? type : "command line";
}

const char *current_config_name(void)
{
if (!cf)
const char *name;
if (current_config_kvi)
name = current_config_kvi->filename;
else if (cf)
name = cf->name;
else
die("BUG: current_config_name called outside config callback");
return cf->name ? cf->name : "";
return name ? name : "";
}
20 changes: 20 additions & 0 deletions t/helper/test-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,30 @@
* ascending order of priority from a config_set
* constructed from files entered as arguments.
*
* iterate -> iterate over all values using git_config(), and print some
* data for each
*
* Examples:
*
* To print the value with highest priority for key "foo.bAr Baz.rock":
* test-config get_value "foo.bAr Baz.rock"
*
*/

static int iterate_cb(const char *var, const char *value, void *data)
{
static int nr;

if (nr++)
putchar('\n');

printf("key=%s\n", var);
printf("value=%s\n", value ? value : "(null)");
printf("origin=%s\n", current_config_origin_type());
printf("name=%s\n", current_config_name());

return 0;
}

int main(int argc, char **argv)
{
Expand Down Expand Up @@ -134,6 +151,9 @@ int main(int argc, char **argv)
printf("Value not found for \"%s\"\n", argv[2]);
goto exit1;
}
} else if (!strcmp(argv[1], "iterate")) {
git_config(iterate_cb, NULL);
goto exit0;
}

die("%s: Please check the syntax and the function name", argv[0]);
Expand Down
24 changes: 24 additions & 0 deletions t/t1308-config-set.sh
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,28 @@ test_expect_success 'error on modifying repo config without repo' '
)
'

cmdline_config="'foo.bar=from-cmdline'"
test_expect_success 'iteration shows correct origins' '
echo "[foo]bar = from-repo" >.git/config &&
echo "[foo]bar = from-home" >.gitconfig &&
cat >expect <<-EOF &&
key=foo.bar
value=from-home
origin=file
name=$(pwd)/.gitconfig
key=foo.bar
value=from-repo
origin=file
name=.git/config
key=foo.bar
value=from-cmdline
origin=command line
name=
EOF
GIT_CONFIG_PARAMETERS=$cmdline_config test-config iterate >actual &&
test_cmp expect actual
'

test_done

0 comments on commit 0d44a2d

Please sign in to comment.