diff options
Diffstat (limited to 'config.c')
-rw-r--r-- | config.c | 163 |
1 files changed, 109 insertions, 54 deletions
@@ -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--; } @@ -162,7 +190,7 @@ void git_config_push_parameter(const char *text) { struct strbuf env = STRBUF_INIT; const char *old = getenv(CONFIG_DATA_ENVIRONMENT); - if (old) { + if (old && *old) { strbuf_addstr(&env, old); strbuf_addch(&env, ' '); } @@ -205,32 +233,40 @@ int git_config_parse_parameter(const char *text, int git_config_from_parameters(config_fn_t fn, void *data) { const char *env = getenv(CONFIG_DATA_ENVIRONMENT); + int ret = 0; char *envw; 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); if (sq_dequote_to_argv(envw, &argv, &nr, &alloc) < 0) { - free(envw); - return error("bogus format in " CONFIG_DATA_ENVIRONMENT); + ret = error("bogus format in " CONFIG_DATA_ENVIRONMENT); + goto out; } for (i = 0; i < nr; i++) { if (git_config_parse_parameter(argv[i], fn, data) < 0) { - free(argv); - free(envw); - return -1; + ret = -1; + goto out; } } +out: free(argv); free(envw); - return nr > 0; + cf = source.prev; + return ret; } static int get_next_char(void) @@ -717,6 +753,9 @@ static int git_default_core_config(const char *var, const char *value) if (!strcmp(var, "core.attributesfile")) return git_config_pathname(&git_attributes_file, var, value); + if (!strcmp(var, "core.hookspath")) + return git_config_pathname(&git_hooks_path, var, value); + if (!strcmp(var, "core.bare")) { is_bare_repository_cfg = git_config_bool(var, value); return 0; @@ -1194,47 +1233,36 @@ int git_config_system(void) static int do_git_config_sequence(config_fn_t fn, void *data) { - int ret = 0, found = 0; + int ret = 0; char *xdg_config = xdg_config_home("config"); char *user_config = expand_user_path("~/.gitconfig"); char *repo_config = git_pathdup("config"); - if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) { + 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); - found += 1; - } - if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK)) { + 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); - found += 1; - } - if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK)) { + if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK)) ret += git_config_from_file(fn, user_config, data); - found += 1; - } - if (repo_config && !access_or_die(repo_config, R_OK, 0)) { + 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); - found += 1; - } - switch (git_config_from_parameters(fn, data)) { - case -1: /* error */ + current_parsing_scope = CONFIG_SCOPE_CMDLINE; + if (git_config_from_parameters(fn, data) < 0) die(_("unable to parse command-line config")); - break; - case 0: /* found nothing */ - break; - default: /* found at least one item */ - found++; - break; - } + current_parsing_scope = CONFIG_SCOPE_UNKNOWN; free(xdg_config); free(user_config); free(repo_config); - return ret == 0 ? found : ret; + return ret; } int git_config_with_options(config_fn_t fn, void *data, @@ -1269,7 +1297,7 @@ static void git_config_raw(config_fn_t fn, void *data) if (git_config_with_options(fn, data, NULL, 1) < 0) /* * git_config_with_options() normally returns only - * positive values, as most errors are fatal, and + * zero, as most errors are fatal, and * non-fatal potential errors are guarded by "if" * statements that are entered only when no error is * possible. @@ -1278,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) @@ -1287,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; } } @@ -1353,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; @@ -2013,7 +2050,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, lock = xcalloc(1, sizeof(struct lock_file)); fd = hold_lock_file_for_update(lock, config_filename, 0); if (fd < 0) { - error("could not lock config file %s: %s", config_filename, strerror(errno)); + error_errno("could not lock config file %s", config_filename); free(store.key); ret = CONFIG_NO_LOCK; goto out_free; @@ -2027,8 +2064,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, free(store.key); if ( ENOENT != errno ) { - error("opening %s: %s", config_filename, - strerror(errno)); + error_errno("opening %s", config_filename); ret = CONFIG_INVALID_FILE; /* same as "invalid config file" */ goto out_free; } @@ -2112,8 +2148,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, if (contents == MAP_FAILED) { if (errno == ENODEV && S_ISDIR(st.st_mode)) errno = EISDIR; - error("unable to mmap '%s': %s", - config_filename, strerror(errno)); + error_errno("unable to mmap '%s'", config_filename); ret = CONFIG_INVALID_FILE; contents = NULL; goto out_free; @@ -2122,8 +2157,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, in_fd = -1; if (chmod(get_lock_file_path(lock), st.st_mode & 07777) < 0) { - error("chmod on %s failed: %s", - get_lock_file_path(lock), strerror(errno)); + error_errno("chmod on %s failed", get_lock_file_path(lock)); ret = CONFIG_NO_WRITE; goto out_free; } @@ -2179,8 +2213,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, } if (commit_lock_file(lock) < 0) { - error("could not write config file %s: %s", config_filename, - strerror(errno)); + error_errno("could not write config file %s", config_filename); ret = CONFIG_NO_WRITE; lock = NULL; goto out_free; @@ -2331,8 +2364,8 @@ int git_config_rename_section_in_file(const char *config_filename, fstat(fileno(config_file), &st); if (chmod(get_lock_file_path(lock), st.st_mode & 07777) < 0) { - ret = error("chmod on %s failed: %s", - get_lock_file_path(lock), strerror(errno)); + ret = error_errno("chmod on %s failed", + get_lock_file_path(lock)); goto out; } @@ -2386,8 +2419,8 @@ int git_config_rename_section_in_file(const char *config_filename, fclose(config_file); unlock_and_out: if (commit_lock_file(lock) < 0) - ret = error("could not write config file %s: %s", - config_filename, strerror(errno)); + ret = error_errno("could not write config file %s", + config_filename); out: free(filename_buf); return ret; @@ -2443,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; } |