summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cache.h1
-rw-r--r--config.c51
-rw-r--r--t/helper/test-config.c20
-rwxr-xr-xt/t1308-config-set.sh24
4 files changed, 87 insertions, 9 deletions
diff --git a/cache.h b/cache.h
index 6049f86711..1bce212e88 100644
--- a/cache.h
+++ b/cache.h
@@ -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)));
diff --git a/config.c b/config.c
index 571151f3e4..d555deeb9a 100644
--- a/config.c
+++ b/config.c
@@ -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;
@@ -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;
}
}
@@ -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;
@@ -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 : "";
}
diff --git a/t/helper/test-config.c b/t/helper/test-config.c
index 6a77552210..3605ef8ee6 100644
--- a/t/helper/test-config.c
+++ b/t/helper/test-config.c
@@ -25,6 +25,9 @@
* 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":
@@ -32,6 +35,20 @@
*
*/
+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)
{
@@ -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]);
diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh
index 005d66dbef..d345a885a3 100755
--- a/t/t1308-config-set.sh
+++ b/t/t1308-config-set.sh
@@ -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