]> git.ipfire.org Git - thirdparty/git.git/blobdiff - config.c
Merge branch 'gc/branch-recurse-submodules-fix'
[thirdparty/git.git] / config.c
index 2bffa8d4a01ba1f281d6e6fd95f35bf133cbd9c5..9eb0dbb448bd9f8fe54ba36536ffba5fd7d50bfa 100644 (file)
--- a/config.c
+++ b/config.c
@@ -6,6 +6,7 @@
  *
  */
 #include "cache.h"
+#include "date.h"
 #include "branch.h"
 #include "config.h"
 #include "environment.h"
@@ -21,6 +22,7 @@
 #include "dir.h"
 #include "color.h"
 #include "refs.h"
+#include "worktree.h"
 
 struct config_source {
        struct config_source *prev;
@@ -120,6 +122,22 @@ static long config_buf_ftell(struct config_source *conf)
        return conf->u.buf.pos;
 }
 
+struct config_include_data {
+       int depth;
+       config_fn_t fn;
+       void *data;
+       const struct config_options *opts;
+       struct git_config_source *config_source;
+
+       /*
+        * All remote URLs discovered when reading all config files.
+        */
+       struct string_list *remote_urls;
+};
+#define CONFIG_INCLUDE_INIT { 0 }
+
+static int git_config_include(const char *var, const char *value, void *data);
+
 #define MAX_INCLUDE_DEPTH 10
 static const char include_depth_advice[] = N_(
 "exceeded maximum include depth (%d) while including\n"
@@ -294,9 +312,92 @@ static int include_by_branch(const char *cond, size_t cond_len)
        return ret;
 }
 
-static int include_condition_is_true(const struct config_options *opts,
+static int add_remote_url(const char *var, const char *value, void *data)
+{
+       struct string_list *remote_urls = data;
+       const char *remote_name;
+       size_t remote_name_len;
+       const char *key;
+
+       if (!parse_config_key(var, "remote", &remote_name, &remote_name_len,
+                             &key) &&
+           remote_name &&
+           !strcmp(key, "url"))
+               string_list_append(remote_urls, value);
+       return 0;
+}
+
+static void populate_remote_urls(struct config_include_data *inc)
+{
+       struct config_options opts;
+
+       struct config_source *store_cf = cf;
+       struct key_value_info *store_kvi = current_config_kvi;
+       enum config_scope store_scope = current_parsing_scope;
+
+       opts = *inc->opts;
+       opts.unconditional_remote_url = 1;
+
+       cf = NULL;
+       current_config_kvi = NULL;
+       current_parsing_scope = 0;
+
+       inc->remote_urls = xmalloc(sizeof(*inc->remote_urls));
+       string_list_init_dup(inc->remote_urls);
+       config_with_options(add_remote_url, inc->remote_urls, inc->config_source, &opts);
+
+       cf = store_cf;
+       current_config_kvi = store_kvi;
+       current_parsing_scope = store_scope;
+}
+
+static int forbid_remote_url(const char *var, const char *value, void *data)
+{
+       const char *remote_name;
+       size_t remote_name_len;
+       const char *key;
+
+       if (!parse_config_key(var, "remote", &remote_name, &remote_name_len,
+                             &key) &&
+           remote_name &&
+           !strcmp(key, "url"))
+               die(_("remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url"));
+       return 0;
+}
+
+static int at_least_one_url_matches_glob(const char *glob, int glob_len,
+                                        struct string_list *remote_urls)
+{
+       struct strbuf pattern = STRBUF_INIT;
+       struct string_list_item *url_item;
+       int found = 0;
+
+       strbuf_add(&pattern, glob, glob_len);
+       for_each_string_list_item(url_item, remote_urls) {
+               if (!wildmatch(pattern.buf, url_item->string, WM_PATHNAME)) {
+                       found = 1;
+                       break;
+               }
+       }
+       strbuf_release(&pattern);
+       return found;
+}
+
+static int include_by_remote_url(struct config_include_data *inc,
+               const char *cond, size_t cond_len)
+{
+       if (inc->opts->unconditional_remote_url)
+               return 1;
+       if (!inc->remote_urls)
+               populate_remote_urls(inc);
+       return at_least_one_url_matches_glob(cond, cond_len,
+                                            inc->remote_urls);
+}
+
+static int include_condition_is_true(struct config_include_data *inc,
                                     const char *cond, size_t cond_len)
 {
+       const struct config_options *opts = inc->opts;
 
        if (skip_prefix_mem(cond, cond_len, "gitdir:", &cond, &cond_len))
                return include_by_gitdir(opts, cond, cond_len, 0);
@@ -304,12 +405,15 @@ static int include_condition_is_true(const struct config_options *opts,
                return include_by_gitdir(opts, cond, cond_len, 1);
        else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len))
                return include_by_branch(cond, cond_len);
+       else if (skip_prefix_mem(cond, cond_len, "hasconfig:remote.*.url:", &cond,
+                                  &cond_len))
+               return include_by_remote_url(inc, cond, cond_len);
 
        /* unknown conditionals are always false */
        return 0;
 }
 
-int git_config_include(const char *var, const char *value, void *data)
+static int git_config_include(const char *var, const char *value, void *data)
 {
        struct config_include_data *inc = data;
        const char *cond, *key;
@@ -328,9 +432,15 @@ int git_config_include(const char *var, const char *value, void *data)
                ret = handle_path_include(value, inc);
 
        if (!parse_config_key(var, "includeif", &cond, &cond_len, &key) &&
-           (cond && include_condition_is_true(inc->opts, cond, cond_len)) &&
-           !strcmp(key, "path"))
+           cond && include_condition_is_true(inc, cond, cond_len) &&
+           !strcmp(key, "path")) {
+               config_fn_t old_fn = inc->fn;
+
+               if (inc->opts->unconditional_remote_url)
+                       inc->fn = forbid_remote_url;
                ret = handle_path_include(value, inc);
+               inc->fn = old_fn;
+       }
 
        return ret;
 }
@@ -1213,6 +1323,80 @@ static int git_parse_maybe_bool_text(const char *value)
        return -1;
 }
 
+static const struct fsync_component_name {
+       const char *name;
+       enum fsync_component component_bits;
+} fsync_component_names[] = {
+       { "loose-object", FSYNC_COMPONENT_LOOSE_OBJECT },
+       { "pack", FSYNC_COMPONENT_PACK },
+       { "pack-metadata", FSYNC_COMPONENT_PACK_METADATA },
+       { "commit-graph", FSYNC_COMPONENT_COMMIT_GRAPH },
+       { "index", FSYNC_COMPONENT_INDEX },
+       { "objects", FSYNC_COMPONENTS_OBJECTS },
+       { "reference", FSYNC_COMPONENT_REFERENCE },
+       { "derived-metadata", FSYNC_COMPONENTS_DERIVED_METADATA },
+       { "committed", FSYNC_COMPONENTS_COMMITTED },
+       { "added", FSYNC_COMPONENTS_ADDED },
+       { "all", FSYNC_COMPONENTS_ALL },
+};
+
+static enum fsync_component parse_fsync_components(const char *var, const char *string)
+{
+       enum fsync_component current = FSYNC_COMPONENTS_DEFAULT;
+       enum fsync_component positive = 0, negative = 0;
+
+       while (string) {
+               int i;
+               size_t len;
+               const char *ep;
+               int negated = 0;
+               int found = 0;
+
+               string = string + strspn(string, ", \t\n\r");
+               ep = strchrnul(string, ',');
+               len = ep - string;
+               if (!strcmp(string, "none")) {
+                       current = FSYNC_COMPONENT_NONE;
+                       goto next_name;
+               }
+
+               if (*string == '-') {
+                       negated = 1;
+                       string++;
+                       len--;
+                       if (!len)
+                               warning(_("invalid value for variable %s"), var);
+               }
+
+               if (!len)
+                       break;
+
+               for (i = 0; i < ARRAY_SIZE(fsync_component_names); ++i) {
+                       const struct fsync_component_name *n = &fsync_component_names[i];
+
+                       if (strncmp(n->name, string, len))
+                               continue;
+
+                       found = 1;
+                       if (negated)
+                               negative |= n->component_bits;
+                       else
+                               positive |= n->component_bits;
+               }
+
+               if (!found) {
+                       char *component = xstrndup(string, len);
+                       warning(_("ignoring unknown core.fsync component '%s'"), component);
+                       free(component);
+               }
+
+next_name:
+               string = ep;
+       }
+
+       return (current & ~negative) | positive;
+}
+
 int git_parse_maybe_bool(const char *value)
 {
        int v = git_parse_maybe_bool_text(value);
@@ -1490,7 +1674,28 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
+       if (!strcmp(var, "core.fsync")) {
+               if (!value)
+                       return config_error_nonbool(var);
+               fsync_components = parse_fsync_components(var, value);
+               return 0;
+       }
+
+       if (!strcmp(var, "core.fsyncmethod")) {
+               if (!value)
+                       return config_error_nonbool(var);
+               if (!strcmp(value, "fsync"))
+                       fsync_method = FSYNC_METHOD_FSYNC;
+               else if (!strcmp(value, "writeout-only"))
+                       fsync_method = FSYNC_METHOD_WRITEOUT_ONLY;
+               else
+                       warning(_("ignoring unknown core.fsyncMethod value '%s'"), value);
+
+       }
+
        if (!strcmp(var, "core.fsyncobjectfiles")) {
+               if (fsync_object_files < 0)
+                       warning(_("core.fsyncObjectFiles is deprecated; use core.fsync instead"));
                fsync_object_files = git_config_bool(var, value);
                return 0;
        }
@@ -1544,6 +1749,17 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
        return platform_core_config(var, value, cb);
 }
 
+static int git_default_sparse_config(const char *var, const char *value)
+{
+       if (!strcmp(var, "sparse.expectfilesoutsideofpatterns")) {
+               sparse_expect_files_outside_of_patterns = git_config_bool(var, value);
+               return 0;
+       }
+
+       /* Add other config variables here and to Documentation/config/sparse.txt. */
+       return 0;
+}
+
 static int git_default_i18n_config(const char *var, const char *value)
 {
        if (!strcmp(var, "i18n.commitencoding"))
@@ -1675,6 +1891,9 @@ int git_default_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
+       if (starts_with(var, "sparse."))
+               return git_default_sparse_config(var, value);
+
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
@@ -1929,11 +2148,13 @@ int config_with_options(config_fn_t fn, void *data,
                        const struct config_options *opts)
 {
        struct config_include_data inc = CONFIG_INCLUDE_INIT;
+       int ret;
 
        if (opts->respect_includes) {
                inc.fn = fn;
                inc.data = data;
                inc.opts = opts;
+               inc.config_source = config_source;
                fn = git_config_include;
                data = &inc;
        }
@@ -1946,17 +2167,23 @@ int config_with_options(config_fn_t fn, void *data,
         * regular lookup sequence.
         */
        if (config_source && config_source->use_stdin) {
-               return git_config_from_stdin(fn, data);
+               ret = git_config_from_stdin(fn, data);
        } else if (config_source && config_source->file) {
-               return git_config_from_file(fn, config_source->file, data);
+               ret = git_config_from_file(fn, config_source->file, data);
        } else if (config_source && config_source->blob) {
                struct repository *repo = config_source->repo ?
                        config_source->repo : the_repository;
-               return git_config_from_blob_ref(fn, repo, config_source->blob,
+               ret = git_config_from_blob_ref(fn, repo, config_source->blob,
                                                data);
+       } else {
+               ret = do_git_config_sequence(opts, fn, data);
        }
 
-       return do_git_config_sequence(opts, fn, data);
+       if (inc.remote_urls) {
+               string_list_clear(inc.remote_urls, 0);
+               FREE_AND_NULL(inc.remote_urls);
+       }
+       return ret;
 }
 
 static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
@@ -2178,8 +2405,8 @@ int git_configset_get_string(struct config_set *cs, const char *key, char **dest
                return 1;
 }
 
-int git_configset_get_string_tmp(struct config_set *cs, const char *key,
-                                const char **dest)
+static int git_configset_get_string_tmp(struct config_set *cs, const char *key,
+                                       const char **dest)
 {
        const char *value;
        if (!git_configset_get_value(cs, key, &value)) {
@@ -2884,6 +3111,20 @@ int git_config_set_gently(const char *key, const char *value)
        return git_config_set_multivar_gently(key, value, NULL, 0);
 }
 
+int repo_config_set_worktree_gently(struct repository *r,
+                                   const char *key, const char *value)
+{
+       /* Only use worktree-specific config if it is is already enabled. */
+       if (repository_format_worktree_config) {
+               char *file = repo_git_path(r, "config.worktree");
+               int ret = git_config_set_multivar_in_file_gently(
+                                       file, key, value, NULL, 0);
+               free(file);
+               return ret;
+       }
+       return repo_config_set_multivar_gently(r, key, value, NULL, 0);
+}
+
 void git_config_set(const char *key, const char *value)
 {
        git_config_set_multivar(key, value, NULL, 0);
@@ -3181,14 +3422,28 @@ void git_config_set_multivar_in_file(const char *config_filename,
 int git_config_set_multivar_gently(const char *key, const char *value,
                                   const char *value_pattern, unsigned flags)
 {
-       return git_config_set_multivar_in_file_gently(NULL, key, value, value_pattern,
-                                                     flags);
+       return repo_config_set_multivar_gently(the_repository, key, value,
+                                              value_pattern, flags);
+}
+
+int repo_config_set_multivar_gently(struct repository *r, const char *key,
+                                   const char *value,
+                                   const char *value_pattern, unsigned flags)
+{
+       char *file = repo_git_path(r, "config");
+       int res = git_config_set_multivar_in_file_gently(file,
+                                                        key, value,
+                                                        value_pattern,
+                                                        flags);
+       free(file);
+       return res;
 }
 
 void git_config_set_multivar(const char *key, const char *value,
                             const char *value_pattern, unsigned flags)
 {
-       git_config_set_multivar_in_file(NULL, key, value, value_pattern,
+       git_config_set_multivar_in_file(git_path("config"),
+                                       key, value, value_pattern,
                                        flags);
 }