Merge branch 'jk/check-repository-format' into maint
authorJunio C Hamano <gitster@pobox.com>
Mon, 2 May 2016 21:24:04 +0000 (14:24 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 2 May 2016 21:24:04 +0000 (14:24 -0700)
The repository set-up sequence has been streamlined (the biggest
change is that there is no longer git_config_early()), so that we
do not attempt to look into refs/* when we know we do not have a
Git repository.

* jk/check-repository-format:
verify_repository_format: mark messages for translation
setup: drop repository_format_version global
setup: unify repository version callbacks
init: use setup.c's repo version verification
setup: refactor repo format reading and verification
config: drop git_config_early
check_repository_format_gently: stop using git_config_early
lazily load core.sharedrepository
wrap shared_repository global in get/set accessors
setup: document check_repository_format()

1  2 
builtin/init-db.c
cache.h
environment.c
path.c
setup.c
diff --combined builtin/init-db.c
index da531f6b766fb300d8c1fff0d94a0756bbbf1f6f,d9934f3592a4364066ff070c219556883f29959e..b2d8d40a6750e5794dd9bfbfbcb31924a7eec4ba
@@@ -95,6 -95,8 +95,8 @@@ static void copy_templates(const char *
        struct strbuf path = STRBUF_INIT;
        struct strbuf template_path = STRBUF_INIT;
        size_t template_len;
+       struct repository_format template_format;
+       struct strbuf err = STRBUF_INIT;
        DIR *dir;
        char *to_free = NULL;
  
  
        /* Make sure that template is from the correct vintage */
        strbuf_addstr(&template_path, "config");
-       repository_format_version = 0;
-       git_config_from_file(check_repository_format_version,
-                            template_path.buf, NULL);
+       read_repository_format(&template_format, template_path.buf);
        strbuf_setlen(&template_path, template_len);
  
-       if (repository_format_version &&
-           repository_format_version != GIT_REPO_VERSION) {
-               warning(_("not copying templates of "
-                       "a wrong format version %d from '%s'"),
-                       repository_format_version,
-                       template_dir);
+       /*
+        * No mention of version at all is OK, but anything else should be
+        * verified.
+        */
+       if (template_format.version >= 0 &&
+           verify_repository_format(&template_format, &err) < 0) {
+               warning(_("not copying templates from '%s': %s"),
+                         template_dir, err.buf);
+               strbuf_release(&err);
                goto close_free_return;
        }
  
@@@ -199,13 -202,13 +202,13 @@@ static int create_default_files(const c
  
        /* reading existing config may have overwrote it */
        if (init_shared_repository != -1)
-               shared_repository = init_shared_repository;
+               set_shared_repository(init_shared_repository);
  
        /*
         * We would have created the above under user's umask -- under
         * shared-repository settings, we would need to fix them up.
         */
-       if (shared_repository) {
+       if (get_shared_repository()) {
                adjust_shared_perm(get_git_dir());
                adjust_shared_perm(git_path_buf(&buf, "refs"));
                adjust_shared_perm(git_path_buf(&buf, "refs/heads"));
@@@ -322,7 -325,6 +325,7 @@@ int set_git_dir_init(const char *git_di
                set_git_dir(real_path(git_dir));
                git_link = NULL;
        }
 +      startup_info->have_repository = 1;
        return 0;
  }
  
@@@ -370,7 -372,7 +373,7 @@@ int init_db(const char *template_dir, u
  
        create_object_directory();
  
-       if (shared_repository) {
+       if (get_shared_repository()) {
                char buf[10];
                /* We do not spell "group" and such, so that
                 * the configuration can be read by older version
                 * and compatibility values for PERM_GROUP and
                 * PERM_EVERYBODY.
                 */
-               if (shared_repository < 0)
+               if (get_shared_repository() < 0)
                        /* force to the mode value */
-                       xsnprintf(buf, sizeof(buf), "0%o", -shared_repository);
-               else if (shared_repository == PERM_GROUP)
+                       xsnprintf(buf, sizeof(buf), "0%o", -get_shared_repository());
+               else if (get_shared_repository() == PERM_GROUP)
                        xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_GROUP);
-               else if (shared_repository == PERM_EVERYBODY)
+               else if (get_shared_repository() == PERM_EVERYBODY)
                        xsnprintf(buf, sizeof(buf), "%d", OLD_PERM_EVERYBODY);
                else
                        die("BUG: invalid value for shared_repository");
                   "", and the last '%s%s' is the verbatim directory name. */
                printf(_("%s%s Git repository in %s%s\n"),
                       reinit ? _("Reinitialized existing") : _("Initialized empty"),
-                      shared_repository ? _(" shared") : "",
+                      get_shared_repository() ? _(" shared") : "",
                       git_dir, len && git_dir[len-1] != '/' ? "/" : "");
        }
  
@@@ -494,8 -496,8 +497,8 @@@ int cmd_init_db(int argc, const char **
                                 * and we know shared_repository should always be 0;
                                 * but just in case we play safe.
                                 */
-                               saved = shared_repository;
-                               shared_repository = 0;
+                               saved = get_shared_repository();
+                               set_shared_repository(0);
                                switch (safe_create_leading_directories_const(argv[0])) {
                                case SCLD_OK:
                                case SCLD_PERMS:
                                        die_errno(_("cannot mkdir %s"), argv[0]);
                                        break;
                                }
-                               shared_repository = saved;
+                               set_shared_repository(saved);
                                if (mkdir(argv[0], 0777) < 0)
                                        die_errno(_("cannot mkdir %s"), argv[0]);
                                mkdir_tried = 1;
        }
  
        if (init_shared_repository != -1)
-               shared_repository = init_shared_repository;
+               set_shared_repository(init_shared_repository);
  
        /*
         * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
diff --combined cache.h
index 9f09540bbca587cb2ba0135a69d65aa966b09622,bec6db5e2ea72a88d564f0474520cce34797704f..2711048cad7d5c7bba04c5737aa6142caf49d023
+++ b/cache.h
@@@ -651,7 -651,6 +651,6 @@@ extern int prefer_symlink_refs
  extern int log_all_ref_updates;
  extern int warn_ambiguous_refs;
  extern int warn_on_object_refname_ambiguity;
- extern int shared_repository;
  extern const char *apply_default_whitespace;
  extern const char *apply_default_ignorewhitespace;
  extern const char *git_attributes_file;
@@@ -664,6 -663,9 +663,9 @@@ extern size_t delta_base_cache_limit
  extern unsigned long big_file_threshold;
  extern unsigned long pack_size_limit_cfg;
  
+ void set_shared_repository(int value);
+ int get_shared_repository(void);
  /*
   * Do replace refs need to be checked this run?  This variable is
   * initialized to true unless --no-replace-object is used or
@@@ -745,9 -747,39 +747,39 @@@ extern int grafts_replace_parents
   */
  #define GIT_REPO_VERSION 0
  #define GIT_REPO_VERSION_READ 1
- extern int repository_format_version;
  extern int repository_format_precious_objects;
- extern int check_repository_format(void);
+ struct repository_format {
+       int version;
+       int precious_objects;
+       int is_bare;
+       char *work_tree;
+       struct string_list unknown_extensions;
+ };
+ /*
+  * Read the repository format characteristics from the config file "path" into
+  * "format" struct. Returns the numeric version. On error, -1 is returned,
+  * format->version is set to -1, and all other fields in the struct are
+  * undefined.
+  */
+ int read_repository_format(struct repository_format *format, const char *path);
+ /*
+  * Verify that the repository described by repository_format is something we
+  * can read. If it is, return 0. Otherwise, return -1, and "err" will describe
+  * any errors encountered.
+  */
+ int verify_repository_format(const struct repository_format *format,
+                            struct strbuf *err);
+ /*
+  * Check the repository format version in the path found in get_git_dir(),
+  * and die if it is a version we don't understand. Generally one would
+  * set_git_dir() before calling this, and use it only for "are we in a valid
+  * repo?".
+  */
+ extern void check_repository_format(void);
  
  #define MTIME_CHANGED 0x0001
  #define CTIME_CHANGED 0x0002
@@@ -1526,7 -1558,6 +1558,6 @@@ extern void git_config(config_fn_t fn, 
  extern int git_config_with_options(config_fn_t fn, void *,
                                   struct git_config_source *config_source,
                                   int respect_includes);
- extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
  extern int git_parse_ulong(const char *, unsigned long *);
  extern int git_parse_maybe_bool(const char *);
  extern int git_config_int(const char *, const char *);
@@@ -1550,7 -1581,6 +1581,6 @@@ extern void git_config_set_multivar_in_
  extern int git_config_rename_section(const char *, const char *);
  extern int git_config_rename_section_in_file(const char *, const char *, const char *);
  extern const char *git_etc_gitconfig(void);
- extern int check_repository_format_version(const char *var, const char *value, void *cb);
  extern int git_env_bool(const char *, int);
  extern unsigned long git_env_ulong(const char *, unsigned long);
  extern int git_config_system(void);
@@@ -1771,7 -1801,7 +1801,7 @@@ int split_cmdline(char *cmdline, const 
  /* Takes a negative value returned by split_cmdline */
  const char *split_cmdline_strerror(int cmdline_errno);
  
 -/* git.c */
 +/* setup.c */
  struct startup_info {
        int have_repository;
        const char *prefix;
diff --combined environment.c
index 6cc0a7780f790d6cea3774acd989a57e52934f91,d9e3861fe8f1f93cf2b34235dd9eaf9d8bd8847a..57acb2fe2aee79a30c4c956dcececd6a7122aeb6
@@@ -25,11 -25,9 +25,9 @@@ int log_all_ref_updates = -1; /* unspec
  int warn_ambiguous_refs = 1;
  int warn_on_object_refname_ambiguity = 1;
  int ref_paranoia = -1;
- int repository_format_version;
  int repository_format_precious_objects;
  const char *git_commit_encoding;
  const char *git_log_output_encoding;
- int shared_repository = PERM_UMASK;
  const char *apply_default_whitespace;
  const char *apply_default_ignorewhitespace;
  const char *git_attributes_file;
@@@ -64,6 -62,7 +62,6 @@@ int grafts_replace_parents = 1
  int core_apply_sparse_checkout;
  int merge_log_config = -1;
  int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
 -struct startup_info *startup_info;
  unsigned long pack_size_limit_cfg;
  
  #ifndef PROTECT_HFS_DEFAULT
@@@ -324,3 -323,24 +322,24 @@@ const char *get_commit_output_encoding(
  {
        return git_commit_encoding ? git_commit_encoding : "UTF-8";
  }
+ static int the_shared_repository = PERM_UMASK;
+ static int need_shared_repository_from_config = 1;
+ void set_shared_repository(int value)
+ {
+       the_shared_repository = value;
+       need_shared_repository_from_config = 0;
+ }
+ int get_shared_repository(void)
+ {
+       if (need_shared_repository_from_config) {
+               const char *var = "core.sharedrepository";
+               const char *value;
+               if (!git_config_get_value(var, &value))
+                       the_shared_repository = git_config_perm(var, value);
+               need_shared_repository_from_config = 0;
+       }
+       return the_shared_repository;
+ }
diff --combined path.c
index 969b494d72dff1439150e7bb945339be07c4d475,a6f1cd69a06e02fb2a3881d87a32d34c1f8af854..bbaea5ab0bf73056dfa74063474f62685fda1d5e
--- 1/path.c
--- 2/path.c
+++ b/path.c
@@@ -584,9 -584,6 +584,9 @@@ char *expand_user_path(const char *path
                        if (!home)
                                goto return_null;
                        strbuf_addstr(&user_path, home);
 +#ifdef GIT_WINDOWS_NATIVE
 +                      convert_slashes(user_path.buf);
 +#endif
                } else {
                        struct passwd *pw = getpw_str(username, username_len);
                        if (!pw)
@@@ -702,17 -699,17 +702,17 @@@ static int calc_shared_perm(int mode
  {
        int tweak;
  
-       if (shared_repository < 0)
-               tweak = -shared_repository;
+       if (get_shared_repository() < 0)
+               tweak = -get_shared_repository();
        else
-               tweak = shared_repository;
+               tweak = get_shared_repository();
  
        if (!(mode & S_IWUSR))
                tweak &= ~0222;
        if (mode & S_IXUSR)
                /* Copy read bits to execute bits */
                tweak |= (tweak & 0444) >> 2;
-       if (shared_repository < 0)
+       if (get_shared_repository() < 0)
                mode = (mode & ~0777) | tweak;
        else
                mode |= tweak;
@@@ -725,7 -722,7 +725,7 @@@ int adjust_shared_perm(const char *path
  {
        int old_mode, new_mode;
  
-       if (!shared_repository)
+       if (!get_shared_repository())
                return 0;
        if (get_st_mode_bits(path, &old_mode) < 0)
                return -1;
diff --combined setup.c
index 3439ec6d815f823ed853251c9afa94d14d78556a,09d37204f9cf0de78945bb5983ccfff21bc22e60..1563cd42df2865d9f4390c9e68cdc666b45fcf96
+++ b/setup.c
@@@ -5,11 -5,7 +5,10 @@@
  static int inside_git_dir = -1;
  static int inside_work_tree = -1;
  static int work_tree_config_is_bogus;
- static struct string_list unknown_extensions = STRING_LIST_INIT_DUP;
  
 +static struct startup_info the_startup_info;
 +struct startup_info *startup_info = &the_startup_info;
 +
  /*
   * The input parameter must contain an absolute path, and it must already be
   * normalized.
@@@ -373,14 -369,13 +372,13 @@@ void setup_work_tree(void
        initialized = 1;
  }
  
- static int check_repo_format(const char *var, const char *value, void *cb)
+ static int check_repo_format(const char *var, const char *value, void *vdata)
  {
+       struct repository_format *data = vdata;
        const char *ext;
  
        if (strcmp(var, "core.repositoryformatversion") == 0)
-               repository_format_version = git_config_int(var, value);
-       else if (strcmp(var, "core.sharedrepository") == 0)
-               shared_repository = git_config_perm(var, value);
+               data->version = git_config_int(var, value);
        else if (skip_prefix(var, "extensions.", &ext)) {
                /*
                 * record any known extensions here; otherwise,
                if (!strcmp(ext, "noop"))
                        ;
                else if (!strcmp(ext, "preciousobjects"))
-                       repository_format_precious_objects = git_config_bool(var, value);
+                       data->precious_objects = git_config_bool(var, value);
                else
-                       string_list_append(&unknown_extensions, ext);
+                       string_list_append(&data->unknown_extensions, ext);
+       } else if (strcmp(var, "core.bare") == 0) {
+               data->is_bare = git_config_bool(var, value);
+       } else if (strcmp(var, "core.worktree") == 0) {
+               if (!value)
+                       return config_error_nonbool(var);
+               data->work_tree = xstrdup(value);
        }
        return 0;
  }
  static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
  {
        struct strbuf sb = STRBUF_INIT;
-       const char *repo_config;
-       config_fn_t fn;
-       int ret = 0;
-       string_list_clear(&unknown_extensions, 0);
+       struct strbuf err = STRBUF_INIT;
+       struct repository_format candidate;
+       int has_common;
  
-       if (get_common_dir(&sb, gitdir))
-               fn = check_repo_format;
-       else
-               fn = check_repository_format_version;
+       has_common = get_common_dir(&sb, gitdir);
        strbuf_addstr(&sb, "/config");
-       repo_config = sb.buf;
+       read_repository_format(&candidate, sb.buf);
+       strbuf_release(&sb);
  
        /*
-        * git_config() can't be used here because it calls git_pathdup()
-        * to get $GIT_CONFIG/config. That call will make setup_git_env()
-        * set git_dir to ".git".
-        *
-        * We are in gitdir setup, no git dir has been found useable yet.
-        * Use a gentler version of git_config() to check if this repo
-        * is a good one.
+        * For historical use of check_repository_format() in git-init,
+        * we treat a missing config as a silent "ok", even when nongit_ok
+        * is unset.
         */
-       git_config_early(fn, NULL, repo_config);
-       if (GIT_REPO_VERSION_READ < repository_format_version) {
-               if (!nongit_ok)
-                       die ("Expected git repo version <= %d, found %d",
-                            GIT_REPO_VERSION_READ, repository_format_version);
-               warning("Expected git repo version <= %d, found %d",
-                       GIT_REPO_VERSION_READ, repository_format_version);
-               warning("Please upgrade Git");
-               *nongit_ok = -1;
-               ret = -1;
-       }
-       if (repository_format_version >= 1 && unknown_extensions.nr) {
+       if (candidate.version < 0)
+               return 0;
+       if (verify_repository_format(&candidate, &err) < 0) {
+               if (nongit_ok) {
+                       warning("%s", err.buf);
+                       strbuf_release(&err);
+                       *nongit_ok = -1;
+                       return -1;
+               }
+               die("%s", err.buf);
+       }
+       repository_format_precious_objects = candidate.precious_objects;
+       string_list_clear(&candidate.unknown_extensions, 0);
+       if (!has_common) {
+               if (candidate.is_bare != -1) {
+                       is_bare_repository_cfg = candidate.is_bare;
+                       if (is_bare_repository_cfg == 1)
+                               inside_work_tree = -1;
+               }
+               if (candidate.work_tree) {
+                       free(git_work_tree_cfg);
+                       git_work_tree_cfg = candidate.work_tree;
+                       inside_work_tree = -1;
+               }
+       } else {
+               free(candidate.work_tree);
+       }
+       return 0;
+ }
+ int read_repository_format(struct repository_format *format, const char *path)
+ {
+       memset(format, 0, sizeof(*format));
+       format->version = -1;
+       format->is_bare = -1;
+       string_list_init(&format->unknown_extensions, 1);
+       git_config_from_file(check_repo_format, path, format);
+       return format->version;
+ }
+ int verify_repository_format(const struct repository_format *format,
+                            struct strbuf *err)
+ {
+       if (GIT_REPO_VERSION_READ < format->version) {
+               strbuf_addf(err, _("Expected git repo version <= %d, found %d"),
+                           GIT_REPO_VERSION_READ, format->version);
+               return -1;
+       }
+       if (format->version >= 1 && format->unknown_extensions.nr) {
                int i;
  
-               if (!nongit_ok)
-                       die("unknown repository extension: %s",
-                           unknown_extensions.items[0].string);
+               strbuf_addstr(err, _("unknown repository extensions found:"));
  
-               for (i = 0; i < unknown_extensions.nr; i++)
-                       warning("unknown repository extension: %s",
-                               unknown_extensions.items[i].string);
-               *nongit_ok = -1;
-               ret = -1;
+               for (i = 0; i < format->unknown_extensions.nr; i++)
+                       strbuf_addf(err, "\n\t%s",
+                                   format->unknown_extensions.items[i].string);
+               return -1;
        }
  
-       strbuf_release(&sb);
-       return ret;
+       return 0;
  }
  
  /*
@@@ -908,9 -937,10 +940,9 @@@ const char *setup_git_directory_gently(
        else
                setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
  
 -      if (startup_info) {
 -              startup_info->have_repository = !nongit_ok || !*nongit_ok;
 -              startup_info->prefix = prefix;
 -      }
 +      startup_info->have_repository = !nongit_ok || !*nongit_ok;
 +      startup_info->prefix = prefix;
 +
        return prefix;
  }
  
@@@ -965,30 -995,9 +997,10 @@@ int git_config_perm(const char *var, co
        return -(i & 0666);
  }
  
- int check_repository_format_version(const char *var, const char *value, void *cb)
- {
-       int ret = check_repo_format(var, value, cb);
-       if (ret)
-               return ret;
-       if (strcmp(var, "core.bare") == 0) {
-               is_bare_repository_cfg = git_config_bool(var, value);
-               if (is_bare_repository_cfg == 1)
-                       inside_work_tree = -1;
-       } else if (strcmp(var, "core.worktree") == 0) {
-               if (!value)
-                       return config_error_nonbool(var);
-               free(git_work_tree_cfg);
-               git_work_tree_cfg = xstrdup(value);
-               inside_work_tree = -1;
-       }
-       return 0;
- }
- int check_repository_format(void)
+ void check_repository_format(void)
  {
        check_repository_format_gently(get_git_dir(), NULL);
-       return 0;
 +      startup_info->have_repository = 1;
  }
  
  /*