diff options
Diffstat (limited to 'config.c')
-rw-r--r-- | config.c | 219 |
1 files changed, 133 insertions, 86 deletions
@@ -6,6 +6,7 @@ * */ #include "cache.h" +#include "branch.h" #include "config.h" #include "repository.h" #include "lockfile.h" @@ -14,6 +15,7 @@ #include "quote.h" #include "hashmap.h" #include "string-list.h" +#include "object-store.h" #include "utf8.h" #include "dir.h" #include "color.h" @@ -31,11 +33,12 @@ struct config_source { enum config_origin_type origin_type; const char *name; const char *path; - int die_on_error; + enum config_error_action default_error_action; int linenr; int eof; struct strbuf value; struct strbuf var; + unsigned subsection_case_sensitive : 1; int (*do_fgetc)(struct config_source *c); int (*do_ungetc)(int c, struct config_source *conf); @@ -116,12 +119,12 @@ static long config_buf_ftell(struct config_source *conf) } #define MAX_INCLUDE_DEPTH 10 -static const char include_depth_advice[] = +static const char include_depth_advice[] = N_( "exceeded maximum include depth (%d) while including\n" " %s\n" "from\n" " %s\n" -"Do you have circular includes?"; +"This might be due to circular includes."); static int handle_path_include(const char *path, struct config_include_data *inc) { int ret = 0; @@ -133,7 +136,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc expanded = expand_user_path(path, 0); if (!expanded) - return error("could not expand include path '%s'", path); + return error(_("could not expand include path '%s'"), path); path = expanded; /* @@ -144,7 +147,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc char *slash; if (!cf || !cf->path) - return error("relative config includes must come from files"); + return error(_("relative config includes must come from files")); slash = find_last_dir_sep(cf->path); if (slash) @@ -155,7 +158,7 @@ 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, + die(_(include_depth_advice), MAX_INCLUDE_DEPTH, path, !cf ? "<unknown>" : cf->name ? cf->name : "the command line"); @@ -342,13 +345,13 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele if (last_dot == NULL || last_dot == key) { if (!quiet) - error("key does not contain a section: %s", key); + error(_("key does not contain a section: %s"), key); return -CONFIG_NO_SECTION_OR_NAME; } if (!last_dot[1]) { if (!quiet) - error("key does not contain variable name: %s", key); + error(_("key does not contain variable name: %s"), key); return -CONFIG_NO_SECTION_OR_NAME; } @@ -372,13 +375,13 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele if (!iskeychar(c) || (i == baselen + 1 && !isalpha(c))) { if (!quiet) - error("invalid key: %s", key); + error(_("invalid key: %s"), key); goto out_free_ret_1; } c = tolower(c); } else if (c == '\n') { if (!quiet) - error("invalid key (newline): %s", key); + error(_("invalid key (newline): %s"), key); goto out_free_ret_1; } if (store_key) @@ -414,7 +417,7 @@ int git_config_parse_parameter(const char *text, pair = strbuf_split_str(text, '=', 2); if (!pair[0]) - return error("bogus config parameter: %s", text); + return error(_("bogus config parameter: %s"), text); if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') { strbuf_setlen(pair[0], pair[0]->len - 1); @@ -426,7 +429,7 @@ int git_config_parse_parameter(const char *text, strbuf_trim(pair[0]); if (!pair[0]->len) { strbuf_list_free(pair); - return error("bogus config parameter: %s", text); + return error(_("bogus config parameter: %s"), text); } if (git_config_parse_key(pair[0]->buf, &canonical_name, NULL)) { @@ -461,7 +464,7 @@ int git_config_from_parameters(config_fn_t fn, void *data) envw = xstrdup(env); if (sq_dequote_to_argv(envw, &argv, &nr, &alloc) < 0) { - ret = error("bogus format in " CONFIG_DATA_ENVIRONMENT); + ret = error(_("bogus format in %s"), CONFIG_DATA_ENVIRONMENT); goto out; } @@ -604,6 +607,7 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name) static int get_extended_base_var(struct strbuf *name, int c) { + cf->subsection_case_sensitive = 0; do { if (c == '\n') goto error_incomplete_line; @@ -640,6 +644,7 @@ error_incomplete_line: static int get_base_var(struct strbuf *name) { + cf->subsection_case_sensitive = 1; for (;;) { int c = get_next_char(); if (cf->eof) @@ -809,10 +814,21 @@ static int git_parse_source(config_fn_t fn, void *data, cf->linenr, cf->name); } - if (cf->die_on_error) + switch (opts && opts->error_action ? + opts->error_action : + cf->default_error_action) { + case CONFIG_ERROR_DIE: die("%s", error_msg); - else + break; + case CONFIG_ERROR_ERROR: error_return = error("%s", error_msg); + break; + case CONFIG_ERROR_SILENT: + error_return = -1; + break; + case CONFIG_ERROR_UNSET: + BUG("config error action unset"); + } free(error_msg); return error_return; @@ -921,7 +937,7 @@ int git_parse_ulong(const char *value, unsigned long *ret) return 1; } -static int git_parse_ssize_t(const char *value, ssize_t *ret) +int git_parse_ssize_t(const char *value, ssize_t *ret) { intmax_t tmp; if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(ssize_t))) @@ -1077,7 +1093,7 @@ int git_config_color(char *dest, const char *var, const char *value) return 0; } -static int git_default_core_config(const char *var, const char *value) +static int git_default_core_config(const char *var, const char *value, void *cb) { /* This needs a better name */ if (!strcmp(var, "core.filemode")) { @@ -1154,7 +1170,7 @@ static int git_default_core_config(const char *var, const char *value) else { int abbrev = git_config_int(var, value); if (abbrev < minimum_abbrev || abbrev > 40) - return error("abbrev length out of range: %d", abbrev); + return error(_("abbrev length out of range: %d"), abbrev); default_abbrev = abbrev; } return 0; @@ -1233,7 +1249,7 @@ static int git_default_core_config(const char *var, const char *value) } eol_rndtrp_die = git_config_bool(var, value); global_conv_flags_eol = eol_rndtrp_die ? - CONV_EOL_RNDTRP_DIE : CONV_EOL_RNDTRP_WARN; + CONV_EOL_RNDTRP_DIE : 0; return 0; } @@ -1271,7 +1287,7 @@ static int git_default_core_config(const char *var, const char *value) comment_line_char = value[0]; auto_comment_line_char = 0; } else - return error("core.commentChar should only be one character"); + return error(_("core.commentChar should only be one character")); return 0; } @@ -1308,11 +1324,6 @@ static int git_default_core_config(const char *var, const char *value) return 0; } - if (!strcmp(var, "core.commitgraph")) { - core_commit_graph = git_config_bool(var, value); - return 0; - } - if (!strcmp(var, "core.sparsecheckout")) { core_apply_sparse_checkout = git_config_bool(var, value); return 0; @@ -1333,21 +1344,18 @@ static int git_default_core_config(const char *var, const char *value) return 0; } - if (!strcmp(var, "core.hidedotfiles")) { - if (value && !strcasecmp(value, "dotgitonly")) - hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; - else - hide_dotfiles = git_config_bool(var, value); - return 0; - } - if (!strcmp(var, "core.partialclonefilter")) { return git_config_string(&core_partial_clone_filter_default, var, value); } + if (!strcmp(var, "core.usereplacerefs")) { + read_replace_refs = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ - return 0; + return platform_core_config(var, value, cb); } static int git_default_i18n_config(const char *var, const char *value) @@ -1384,7 +1392,7 @@ static int git_default_branch_config(const char *var, const char *value) else if (!strcmp(value, "always")) autorebase = AUTOREBASE_ALWAYS; else - return error("malformed value for %s", var); + return error(_("malformed value for %s"), var); return 0; } @@ -1410,9 +1418,9 @@ static int git_default_push_config(const char *var, const char *value) else if (!strcmp(value, "current")) push_default = PUSH_DEFAULT_CURRENT; else { - error("malformed value for %s: %s", var, value); - return error("Must be one of nothing, matching, simple, " - "upstream or current."); + error(_("malformed value for %s: %s"), var, value); + return error(_("must be one of nothing, matching, simple, " + "upstream or current")); } return 0; } @@ -1432,13 +1440,13 @@ static int git_default_mailmap_config(const char *var, const char *value) return 0; } -int git_default_config(const char *var, const char *value, void *dummy) +int git_default_config(const char *var, const char *value, void *cb) { if (starts_with(var, "core.")) - return git_default_core_config(var, value); + return git_default_core_config(var, value, cb); if (starts_with(var, "user.")) - return git_ident_config(var, value, dummy); + return git_ident_config(var, value, cb); if (starts_with(var, "i18n.")) return git_default_i18n_config(var, value); @@ -1520,7 +1528,7 @@ static int do_config_from_file(config_fn_t fn, top.origin_type = origin_type; top.name = name; top.path = path; - top.die_on_error = 1; + top.default_error_action = CONFIG_ERROR_DIE; top.do_fgetc = config_file_fgetc; top.do_ungetc = config_file_ungetc; top.do_ftell = config_file_ftell; @@ -1558,8 +1566,10 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data) return git_config_from_file_with_options(fn, filename, data, NULL); } -int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_type, - const char *name, const char *buf, size_t len, void *data) +int git_config_from_mem(config_fn_t fn, + const enum config_origin_type origin_type, + const char *name, const char *buf, size_t len, + void *data, const struct config_options *opts) { struct config_source top; @@ -1569,12 +1579,12 @@ int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_typ top.origin_type = origin_type; top.name = name; top.path = NULL; - top.die_on_error = 0; + top.default_error_action = CONFIG_ERROR_ERROR; top.do_fgetc = config_buf_fgetc; top.do_ungetc = config_buf_ungetc; top.do_ftell = config_buf_ftell; - return do_config_from(&top, fn, data, NULL); + return do_config_from(&top, fn, data, opts); } int git_config_from_blob_oid(config_fn_t fn, @@ -1589,13 +1599,14 @@ int git_config_from_blob_oid(config_fn_t fn, buf = read_object_file(oid, &type, &size); if (!buf) - return error("unable to load config blob object '%s'", name); + return error(_("unable to load config blob object '%s'"), name); if (type != OBJ_BLOB) { free(buf); - return error("reference '%s' does not point to a blob", name); + return error(_("reference '%s' does not point to a blob"), name); } - ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size, data); + ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size, + data, NULL); free(buf); return ret; @@ -1608,7 +1619,7 @@ static int git_config_from_blob_ref(config_fn_t fn, struct object_id oid; if (get_oid(name, &oid) < 0) - return error("unable to resolve config blob '%s'", name); + return error(_("unable to resolve config blob '%s'"), name); return git_config_from_blob_oid(fn, name, &oid, data); } @@ -1638,7 +1649,7 @@ unsigned long git_env_ulong(const char *k, unsigned long val) { const char *v = getenv(k); if (v && !git_parse_ulong(v, &val)) - die("failed to parse %s", k); + die(_("failed to parse %s"), k); return val; } @@ -1657,6 +1668,8 @@ static int do_git_config_sequence(const struct config_options *opts, if (opts->commondir) repo_config = mkpathdup("%s/config", opts->commondir); + else if (opts->git_dir) + BUG("git_dir without commondir"); else repo_config = NULL; @@ -1676,6 +1689,17 @@ static int do_git_config_sequence(const struct config_options *opts, if (repo_config && !access_or_die(repo_config, R_OK, 0)) ret += git_config_from_file(fn, repo_config, data); + /* + * Note: this should have a new scope, CONFIG_SCOPE_WORKTREE. + * But let's not complicate things before it's actually needed. + */ + if (repository_format_worktree_config) { + char *path = git_pathdup("config.worktree"); + if (!access_or_die(path, R_OK, 0)) + ret += git_config_from_file(fn, path, data); + free(path); + } + current_parsing_scope = CONFIG_SCOPE_CMDLINE; if (git_config_from_parameters(fn, data) < 0) die(_("unable to parse command-line config")); @@ -2172,23 +2196,6 @@ int git_config_get_pathname(const char *key, const char **dest) return repo_config_get_pathname(the_repository, key, dest); } -/* - * Note: This function exists solely to maintain backward compatibility with - * 'fetch' and 'update_clone' storing configuration in '.gitmodules' and should - * NOT be used anywhere else. - * - * Runs the provided config function on the '.gitmodules' file found in the - * working directory. - */ -void config_from_gitmodules(config_fn_t fn, void *data) -{ - if (the_repository->worktree) { - char *file = repo_worktree_path(the_repository, GITMODULES_FILE); - git_config_from_file(fn, file, data); - free(file); - } -} - int git_config_get_expiry(const char *key, const char **output) { int ret = git_config_get_string_const(key, output); @@ -2276,7 +2283,7 @@ int git_config_get_max_percent_split_change(void) int git_config_get_fsmonitor(void) { if (git_config_get_pathname("core.fsmonitor", &core_fsmonitor)) - core_fsmonitor = getenv("GIT_FSMONITOR_TEST"); + core_fsmonitor = getenv("GIT_TEST_FSMONITOR"); if (core_fsmonitor && !*core_fsmonitor) core_fsmonitor = NULL; @@ -2287,6 +2294,27 @@ int git_config_get_fsmonitor(void) return 0; } +int git_config_get_index_threads(int *dest) +{ + int is_bool, val; + + val = git_env_ulong("GIT_TEST_INDEX_THREADS", 0); + if (val) { + *dest = val; + return 0; + } + + if (!git_config_get_bool_or_int("index.threads", &is_bool, &val)) { + if (is_bool) + *dest = val ? 0 : 1; + else + *dest = val; + return 0; + } + + return 1; +} + NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr) { @@ -2371,14 +2399,21 @@ static int store_aux_event(enum config_event_t type, store->parsed[store->parsed_nr].type = type; if (type == CONFIG_EVENT_SECTION) { + int (*cmpfn)(const char *, const char *, size_t); + if (cf->var.len < 2 || cf->var.buf[cf->var.len - 1] != '.') - return error("invalid section name '%s'", cf->var.buf); + return error(_("invalid section name '%s'"), cf->var.buf); + + if (cf->subsection_case_sensitive) + cmpfn = strncasecmp; + else + cmpfn = strncmp; /* Is this the section we were looking for? */ store->is_keys_section = store->parsed[store->parsed_nr].is_keys_section = cf->var.len - 1 == store->baselen && - !strncasecmp(cf->var.buf, store->key, store->baselen); + !cmpfn(cf->var.buf, store->key, store->baselen); if (store->is_keys_section) { store->section_seen = 1; ALLOC_GROW(store->seen, store->seen_nr + 1, @@ -2428,7 +2463,7 @@ static int store_aux(const char *key, const char *value, void *cb) static int write_error(const char *filename) { - error("failed to write new configuration file %s", filename); + error(_("failed to write new configuration file %s"), filename); /* Same error code as "failed to rename". */ return 4; @@ -2530,7 +2565,6 @@ static ssize_t write_pair(int fd, const char *key, const char *value, * entry (which all are to be removed). */ static void maybe_remove_section(struct config_store_data *store, - const char *contents, size_t *begin_offset, size_t *end_offset, int *seen_ptr) { @@ -2679,7 +2713,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, */ fd = hold_lock_file_for_update(&lock, config_filename, 0); if (fd < 0) { - error_errno("could not lock config file %s", config_filename); + error_errno(_("could not lock config file %s"), config_filename); ret = CONFIG_NO_LOCK; goto out_free; } @@ -2690,7 +2724,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, in_fd = open(config_filename, O_RDONLY); if ( in_fd < 0 ) { if ( ENOENT != errno ) { - error_errno("opening %s", config_filename); + error_errno(_("opening %s"), config_filename); ret = CONFIG_INVALID_FILE; /* same as "invalid config file" */ goto out_free; } @@ -2725,7 +2759,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, store.value_regex = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(store.value_regex, value_regex, REG_EXTENDED)) { - error("invalid pattern: %s", value_regex); + error(_("invalid pattern: %s"), value_regex); FREE_AND_NULL(store.value_regex); ret = CONFIG_INVALID_PATTERN; goto out_free; @@ -2750,7 +2784,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, if (git_config_from_file_with_options(store_aux, config_filename, &store, &opts)) { - error("invalid config file %s", config_filename); + error(_("invalid config file %s"), config_filename); ret = CONFIG_INVALID_FILE; goto out_free; } @@ -2774,7 +2808,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_errno("unable to mmap '%s'", config_filename); + error_errno(_("unable to mmap '%s'"), config_filename); ret = CONFIG_INVALID_FILE; contents = NULL; goto out_free; @@ -2783,7 +2817,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_errno("chmod on %s failed", get_lock_file_path(&lock)); + error_errno(_("chmod on %s failed"), get_lock_file_path(&lock)); ret = CONFIG_NO_WRITE; goto out_free; } @@ -2815,7 +2849,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, replace_end = store.parsed[j].end; copy_end = store.parsed[j].begin; if (!value) - maybe_remove_section(&store, contents, + maybe_remove_section(&store, ©_end, &replace_end, &i); /* @@ -2868,7 +2902,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, } if (commit_lock_file(&lock) < 0) { - error_errno("could not write config file %s", config_filename); + error_errno(_("could not write config file %s"), config_filename); ret = CONFIG_NO_WRITE; goto out_free; } @@ -2994,7 +3028,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename memset(&store, 0, sizeof(store)); if (new_name && !section_name_is_ok(new_name)) { - ret = error("invalid section name: %s", new_name); + ret = error(_("invalid section name: %s"), new_name); goto out_no_rollback; } @@ -3003,7 +3037,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename out_fd = hold_lock_file_for_update(&lock, config_filename, 0); if (out_fd < 0) { - ret = error("could not lock config file %s", config_filename); + ret = error(_("could not lock config file %s"), config_filename); goto out; } @@ -3021,7 +3055,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename } if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) { - ret = error_errno("chmod on %s failed", + ret = error_errno(_("chmod on %s failed"), get_lock_file_path(&lock)); goto out; } @@ -3118,7 +3152,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename config_file = NULL; commit_and_out: if (commit_lock_file(&lock) < 0) - ret = error_errno("could not write config file %s", + ret = error_errno(_("could not write config file %s"), config_filename); out: if (config_file) @@ -3161,7 +3195,7 @@ int git_config_copy_section(const char *old_name, const char *new_name) #undef config_error_nonbool int config_error_nonbool(const char *var) { - return error("missing value for '%s'", var); + return error(_("missing value for '%s'"), var); } int parse_config_key(const char *var, @@ -3245,3 +3279,16 @@ enum config_scope current_config_scope(void) else return current_parsing_scope; } + +int lookup_config(const char **mapping, int nr_mapping, const char *var) +{ + int i; + + for (i = 0; i < nr_mapping; i++) { + const char *name = mapping[i]; + + if (name && !strcasecmp(var, name)) + return i; + } + return -1; +} |