merge-recursive: flush output buffer even when erroring out
[gitweb.git] / config.c
index c5d0b0c7aa8d06a29b0dd50ef4870f537b048ac4..bea937e4ecf8417a910882c1aafb263e792f2e1c 100644 (file)
--- a/config.c
+++ b/config.c
@@ -38,7 +38,33 @@ 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;
+
+/*
+ * Similar to the variables above, this gives access to the "scope" of the
+ * current value (repo, global, etc). For cached values, it can be found via
+ * the current_config_kvi as above. During parsing, the current value can be
+ * found in this variable. It's not part of "cf" because it transcends a single
+ * file (i.e., a file included from .git/config is still in "repo" scope).
+ */
+static enum config_scope current_parsing_scope;
 
 static int zlib_compression_seen;
 
@@ -131,7 +157,9 @@ static int handle_path_include(const char *path, struct config_include_data *inc
        if (!access_or_die(path, R_OK, 0)) {
                if (++inc->depth > MAX_INCLUDE_DEPTH)
                        die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
-                           cf && cf->name ? cf->name : "the command line");
+                           !cf ? "<unknown>" :
+                           cf->name ? cf->name :
+                           "the command line");
                ret = git_config_from_file(git_config_include, path, inc);
                inc->depth--;
        }
@@ -210,9 +238,15 @@ int git_config_from_parameters(config_fn_t fn, void *data)
        const char **argv = NULL;
        int nr = 0, alloc = 0;
        int i;
+       struct config_source source;
 
        if (!env)
                return 0;
+
+       memset(&source, 0, sizeof(source));
+       source.prev = cf;
+       cf = &source;
+
        /* sq_dequote will write over it */
        envw = xstrdup(env);
 
@@ -231,6 +265,7 @@ int git_config_from_parameters(config_fn_t fn, void *data)
 out:
        free(argv);
        free(envw);
+       cf = source.prev;
        return ret;
 }
 
@@ -1203,22 +1238,27 @@ static int do_git_config_sequence(config_fn_t fn, void *data)
        char *user_config = expand_user_path("~/.gitconfig");
        char *repo_config = git_pathdup("config");
 
+       current_parsing_scope = CONFIG_SCOPE_SYSTEM;
        if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0))
                ret += git_config_from_file(fn, git_etc_gitconfig(),
                                            data);
 
+       current_parsing_scope = CONFIG_SCOPE_GLOBAL;
        if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
                ret += git_config_from_file(fn, xdg_config, data);
 
        if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
                ret += git_config_from_file(fn, user_config, data);
 
+       current_parsing_scope = CONFIG_SCOPE_REPO;
        if (repo_config && !access_or_die(repo_config, R_OK, 0))
                ret += git_config_from_file(fn, repo_config, data);
 
+       current_parsing_scope = CONFIG_SCOPE_CMDLINE;
        if (git_config_from_parameters(fn, data) < 0)
                die(_("unable to parse command-line config"));
 
+       current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
        free(xdg_config);
        free(user_config);
        free(repo_config);
@@ -1266,7 +1306,7 @@ static void git_config_raw(config_fn_t fn, void *data)
                 * something went really wrong and we should stop
                 * immediately.
                 */
-               die(_("unknown error occured while reading the configuration files"));
+               die(_("unknown error occurred while reading the configuration files"));
 }
 
 static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
@@ -1275,16 +1315,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;
        }
 }
 
@@ -1341,14 +1385,19 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
        l_item->e = e;
        l_item->value_index = e->value_list.nr - 1;
 
-       if (cf) {
+       if (!cf)
+               die("BUG: configset_add_value has no source");
+       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;
        }
+       kv_info->scope = current_parsing_scope;
        si->util = kv_info;
 
        return 0;
@@ -2427,10 +2476,32 @@ int parse_config_key(const char *var,
 
 const char *current_config_origin_type(void)
 {
-       return cf && cf->origin_type ? cf->origin_type : "command line";
+       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 type ? type : "command line";
 }
 
 const char *current_config_name(void)
 {
-       return cf && cf->name ? cf->name : "";
+       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 name ? name : "";
+}
+
+enum config_scope current_config_scope(void)
+{
+       if (current_config_kvi)
+               return current_config_kvi->scope;
+       else
+               return current_parsing_scope;
 }