git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH v2 0/10] cleaning up check_repository_format_gently
@ 2016-03-11 22:36 Jeff King
  2016-03-11 22:36 ` [PATCH v2 01/10] setup: document check_repository_format() Jeff King
                   ` (9 more replies)
  0 siblings, 10 replies; 12+ messages in thread
From: Jeff King @ 2016-03-11 22:36 UTC (permalink / raw
  To: git; +Cc: David Turner, pclouds

This is a re-roll of:

  http://article.gmane.org/gmane.comp.version-control.git/288017

The changes from v1 are:

  - dropped original 10/10 that got rid of GIT_REPO_VERSION defines
    (David mentioned that he's going to be expanding their use, so the
    argument that they are not used does not make sense)

  - added new 10/10 marking messages for translation (suggested by Duy)

  - added int return value to new read_repository_format(); this is
    redundant with the error value returned in the struct, but allows a
    more idiomatic:

      if (read_repository_format(&format, file) < 0)
         ...

  - drop confusing comment from 06/10, in favor of a better explanation
    in the commit message

  - fixed newline regression from v1 when printing out unknown
    extensions. Note that because we switch from looping over warning()
    or die() to sticking errors into a strbuf (which the caller then
    feeds to warning/die), the format changed a bit.  Naively, it would
    become:

      warning: unknown extension: foo
      unknown:extension: bar

    but I turned it into the more pleasant:

      warning: unknown repository extensions found:
              foo
              bar

    I think it would be better still if warning() was smart enough to
    stick its prefix in front of all lines (like advise() does). But
    that's outside the scope of this series. And it probably doesn't
    matter much either way; this is not a message we'd expect anyone to
    see routinely.

  [01/10]: setup: document check_repository_format()
  [02/10]: wrap shared_repository global in get/set accessors
  [03/10]: lazily load core.sharedrepository
  [04/10]: check_repository_format_gently: stop using git_config_early
  [05/10]: config: drop git_config_early
  [06/10]: setup: refactor repo format reading and verification
  [07/10]: init: use setup.c's repo version verification
  [08/10]: setup: unify repository version callbacks
  [09/10]: setup: drop repository_format_version global
  [10/10]: verify_repository_format: mark messages for translation

-Peff

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v2 01/10] setup: document check_repository_format()
  2016-03-11 22:36 [PATCH v2 0/10] cleaning up check_repository_format_gently Jeff King
@ 2016-03-11 22:36 ` Jeff King
  2016-03-11 22:36 ` [PATCH v2 02/10] wrap shared_repository global in get/set accessors Jeff King
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Jeff King @ 2016-03-11 22:36 UTC (permalink / raw
  To: git; +Cc: David Turner, pclouds

This function's interface is rather enigmatic, so let's
document it further.

While we're here, let's also drop the return value. It will
always either be "0" or the function will die (consequently,
neither of its two callers bothered to check the return).

Signed-off-by: Jeff King <peff@peff.net>
---
 cache.h | 9 ++++++++-
 setup.c | 4 ++--
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/cache.h b/cache.h
index b829410..02e38d1 100644
--- a/cache.h
+++ b/cache.h
@@ -747,7 +747,14 @@ extern int grafts_replace_parents;
 #define GIT_REPO_VERSION_READ 1
 extern int repository_format_version;
 extern int repository_format_precious_objects;
-extern int check_repository_format(void);
+
+/*
+ * 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
diff --git a/setup.c b/setup.c
index de1a2a7..b2f2e69 100644
--- a/setup.c
+++ b/setup.c
@@ -982,9 +982,9 @@ int check_repository_format_version(const char *var, const char *value, void *cb
 	return 0;
 }
 
-int check_repository_format(void)
+void check_repository_format(void)
 {
-	return check_repository_format_gently(get_git_dir(), NULL);
+	check_repository_format_gently(get_git_dir(), NULL);
 }
 
 /*
-- 
2.8.0.rc2.328.g39e2a47

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 02/10] wrap shared_repository global in get/set accessors
  2016-03-11 22:36 [PATCH v2 0/10] cleaning up check_repository_format_gently Jeff King
  2016-03-11 22:36 ` [PATCH v2 01/10] setup: document check_repository_format() Jeff King
@ 2016-03-11 22:36 ` Jeff King
  2016-03-11 22:36 ` [PATCH v2 03/10] lazily load core.sharedrepository Jeff King
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Jeff King @ 2016-03-11 22:36 UTC (permalink / raw
  To: git; +Cc: David Turner, pclouds

It would be useful to control access to the global
shared_repository, so that we can lazily load its config.
The first step to doing so is to make sure all access
goes through a set of functions.

This step is purely mechanical, and should result in no
change of behavior.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/init-db.c | 24 ++++++++++++------------
 cache.h           |  4 +++-
 environment.c     | 13 ++++++++++++-
 path.c            | 10 +++++-----
 setup.c           |  2 +-
 5 files changed, 33 insertions(+), 20 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index 6223b7d..e9b2256 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -199,13 +199,13 @@ static int create_default_files(const char *template_path)
 
 	/* 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"));
@@ -369,7 +369,7 @@ int init_db(const char *template_dir, unsigned int flags)
 
 	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
@@ -377,12 +377,12 @@ int init_db(const char *template_dir, unsigned int flags)
 		 * 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");
@@ -398,7 +398,7 @@ int init_db(const char *template_dir, unsigned int flags)
 		   "", 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] != '/' ? "/" : "");
 	}
 
@@ -493,8 +493,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 				 * 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:
@@ -506,7 +506,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 					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;
@@ -524,7 +524,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 	}
 
 	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 --git a/cache.h b/cache.h
index 02e38d1..fdb9583 100644
--- a/cache.h
+++ b/cache.h
@@ -651,7 +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 @@ 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
diff --git a/environment.c b/environment.c
index 6dec9d0..b42e238 100644
--- a/environment.c
+++ b/environment.c
@@ -29,7 +29,6 @@ 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;
@@ -325,3 +324,15 @@ const char *get_commit_output_encoding(void)
 {
 	return git_commit_encoding ? git_commit_encoding : "UTF-8";
 }
+
+static int the_shared_repository = PERM_UMASK;
+
+void set_shared_repository(int value)
+{
+	the_shared_repository = value;
+}
+
+int get_shared_repository(void)
+{
+	return the_shared_repository;
+}
diff --git a/path.c b/path.c
index 8b7e168..a6f1cd6 100644
--- a/path.c
+++ b/path.c
@@ -699,17 +699,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;
@@ -722,7 +722,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 --git a/setup.c b/setup.c
index b2f2e69..ac777c5 100644
--- a/setup.c
+++ b/setup.c
@@ -377,7 +377,7 @@ static int check_repo_format(const char *var, const char *value, void *cb)
 	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);
+		set_shared_repository(git_config_perm(var, value));
 	else if (skip_prefix(var, "extensions.", &ext)) {
 		/*
 		 * record any known extensions here; otherwise,
-- 
2.8.0.rc2.328.g39e2a47

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 03/10] lazily load core.sharedrepository
  2016-03-11 22:36 [PATCH v2 0/10] cleaning up check_repository_format_gently Jeff King
  2016-03-11 22:36 ` [PATCH v2 01/10] setup: document check_repository_format() Jeff King
  2016-03-11 22:36 ` [PATCH v2 02/10] wrap shared_repository global in get/set accessors Jeff King
@ 2016-03-11 22:36 ` Jeff King
  2016-03-11 22:36 ` [PATCH v2 04/10] check_repository_format_gently: stop using git_config_early Jeff King
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Jeff King @ 2016-03-11 22:36 UTC (permalink / raw
  To: git; +Cc: David Turner, pclouds

The "shared_repository" config is loaded as part of
check_repository_format_version, but it's not quite like the
other values we check there. Something like
core.repositoryformatversion only makes sense in per-repo
config, but core.sharedrepository can be set in a per-user
config (e.g., to make all "git init" invocations shared by
default).

So it would make more sense as part of git_default_config.
Commit 457f06d (Introduce core.sharedrepository, 2005-12-22)
says:

  [...]the config variable is set in the function which
  checks the repository format. If this were done in
  git_default_config instead, a lot of programs would need
  to be modified to call git_config(git_default_config)
  first.

This is still the case today, but we have one extra trick up
our sleeve. Now that we have the git_configset
infrastructure, it's not so expensive for us to ask for a
single value. So we can simply lazy-load it on demand.

This should be OK to do in general. There are some problems
with loading config before setup_git_directory() is called,
but we shouldn't be accessing the value before then (if we
were, then it would already be broken, as the variable would
not have been set by check_repository_format_version!). The
trickiest caller is git-init, but it handles the values
manually itself.

Signed-off-by: Jeff King <peff@peff.net>
---
 environment.c | 9 +++++++++
 setup.c       | 2 --
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/environment.c b/environment.c
index b42e238..8b8c8e8 100644
--- a/environment.c
+++ b/environment.c
@@ -326,13 +326,22 @@ const char *get_commit_output_encoding(void)
 }
 
 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 --git a/setup.c b/setup.c
index ac777c5..a02932b 100644
--- a/setup.c
+++ b/setup.c
@@ -376,8 +376,6 @@ static int check_repo_format(const char *var, const char *value, void *cb)
 
 	if (strcmp(var, "core.repositoryformatversion") == 0)
 		repository_format_version = git_config_int(var, value);
-	else if (strcmp(var, "core.sharedrepository") == 0)
-		set_shared_repository(git_config_perm(var, value));
 	else if (skip_prefix(var, "extensions.", &ext)) {
 		/*
 		 * record any known extensions here; otherwise,
-- 
2.8.0.rc2.328.g39e2a47

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 04/10] check_repository_format_gently: stop using git_config_early
  2016-03-11 22:36 [PATCH v2 0/10] cleaning up check_repository_format_gently Jeff King
                   ` (2 preceding siblings ...)
  2016-03-11 22:36 ` [PATCH v2 03/10] lazily load core.sharedrepository Jeff King
@ 2016-03-11 22:36 ` Jeff King
  2016-03-11 22:37 ` [PATCH v2 05/10] config: drop git_config_early Jeff King
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Jeff King @ 2016-03-11 22:36 UTC (permalink / raw
  To: git; +Cc: David Turner, pclouds

There's a chicken-and-egg problem with using the regular
git_config during the repository setup process. We get
around it here by using a special interface that lets us
specify the per-repo config, and avoid calling
git_pathdup().

But this interface doesn't actually make sense. It will look
in the system and per-user config, too; we definitely would
not want to accept a core.repositoryformatversion from
there.

The git_config_from_file interface is a better match, as it
lets us look at a single file.

Signed-off-by: Jeff King <peff@peff.net>
---
 setup.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/setup.c b/setup.c
index a02932b..a6013e6 100644
--- a/setup.c
+++ b/setup.c
@@ -409,15 +409,10 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 	repo_config = sb.buf;
 
 	/*
-	 * 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.
+	 * Ignore return value; for historical reasons, we must treat a missing
+	 * config file as a noop (git-init relies on this).
 	 */
-	git_config_early(fn, NULL, repo_config);
+	git_config_from_file(fn, repo_config, NULL);
 	if (GIT_REPO_VERSION_READ < repository_format_version) {
 		if (!nongit_ok)
 			die ("Expected git repo version <= %d, found %d",
-- 
2.8.0.rc2.328.g39e2a47

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 05/10] config: drop git_config_early
  2016-03-11 22:36 [PATCH v2 0/10] cleaning up check_repository_format_gently Jeff King
                   ` (3 preceding siblings ...)
  2016-03-11 22:36 ` [PATCH v2 04/10] check_repository_format_gently: stop using git_config_early Jeff King
@ 2016-03-11 22:37 ` Jeff King
  2016-03-11 23:33   ` Junio C Hamano
  2016-03-11 22:37 ` [PATCH v2 06/10] setup: refactor repo format reading and verification Jeff King
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 12+ messages in thread
From: Jeff King @ 2016-03-11 22:37 UTC (permalink / raw
  To: git; +Cc: David Turner, pclouds

There are no more callers, and it's a rather confusing
interface. This could just be folded into
git_config_with_options(), but for the sake of readability,
we'll leave it as a separate (static) helper function.

Signed-off-by: Jeff King <peff@peff.net>
---
 Documentation/technical/api-config.txt |  7 -------
 cache.h                                |  1 -
 config.c                               | 12 ++++--------
 3 files changed, 4 insertions(+), 16 deletions(-)

diff --git a/Documentation/technical/api-config.txt b/Documentation/technical/api-config.txt
index 0d8b99b..20741f3 100644
--- a/Documentation/technical/api-config.txt
+++ b/Documentation/technical/api-config.txt
@@ -63,13 +63,6 @@ parse for configuration, rather than looking in the usual files. Regular
 Specify whether include directives should be followed in parsed files.
 Regular `git_config` defaults to `1`.
 
-There is a special version of `git_config` called `git_config_early`.
-This version takes an additional parameter to specify the repository
-config, instead of having it looked up via `git_path`. This is useful
-early in a Git program before the repository has been found. Unless
-you're working with early setup code, you probably don't want to use
-this.
-
 Reading Specific Files
 ----------------------
 
diff --git a/cache.h b/cache.h
index fdb9583..867e73e 100644
--- a/cache.h
+++ b/cache.h
@@ -1535,7 +1535,6 @@ extern void git_config(config_fn_t fn, void *);
 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 *);
diff --git a/config.c b/config.c
index 9ba40bc..7ddb287 100644
--- a/config.c
+++ b/config.c
@@ -1188,11 +1188,12 @@ int git_config_system(void)
 	return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
 }
 
-int git_config_early(config_fn_t fn, void *data, const char *repo_config)
+static int do_git_config_sequence(config_fn_t fn, void *data)
 {
 	int ret = 0, found = 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)) {
 		ret += git_config_from_file(fn, git_etc_gitconfig(),
@@ -1228,6 +1229,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 
 	free(xdg_config);
 	free(user_config);
+	free(repo_config);
 	return ret == 0 ? found : ret;
 }
 
@@ -1235,8 +1237,6 @@ int git_config_with_options(config_fn_t fn, void *data,
 			    struct git_config_source *config_source,
 			    int respect_includes)
 {
-	char *repo_config = NULL;
-	int ret;
 	struct config_include_data inc = CONFIG_INCLUDE_INIT;
 
 	if (respect_includes) {
@@ -1257,11 +1257,7 @@ int git_config_with_options(config_fn_t fn, void *data,
 	else if (config_source && config_source->blob)
 		return git_config_from_blob_ref(fn, config_source->blob, data);
 
-	repo_config = git_pathdup("config");
-	ret = git_config_early(fn, data, repo_config);
-	if (repo_config)
-		free(repo_config);
-	return ret;
+	return do_git_config_sequence(fn, data);
 }
 
 static void git_config_raw(config_fn_t fn, void *data)
-- 
2.8.0.rc2.328.g39e2a47

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 06/10] setup: refactor repo format reading and verification
  2016-03-11 22:36 [PATCH v2 0/10] cleaning up check_repository_format_gently Jeff King
                   ` (4 preceding siblings ...)
  2016-03-11 22:37 ` [PATCH v2 05/10] config: drop git_config_early Jeff King
@ 2016-03-11 22:37 ` Jeff King
  2016-03-11 22:37 ` [PATCH v2 07/10] init: use setup.c's repo version verification Jeff King
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Jeff King @ 2016-03-11 22:37 UTC (permalink / raw
  To: git; +Cc: David Turner, pclouds

When we want to know if we're in a git repository of
reasonable vintage, we can call check_repository_format_gently(),
which does three things:

  1. Reads the config from the .git/config file.

  2. Verifies that the version info we read is sane.

  3. Writes some global variables based on this.

There are a few things we could improve here.

One is that steps 1 and 3 happen together. So if the
verification in step 2 fails, we still clobber the global
variables. This is especially bad if we go on to try another
repository directory; we may end up with a state of mixed
config variables.

The second is there's no way to ask about the repository
version for anything besides the main repository we're in.
git-init wants to do this, and it's possible that we would
want to start doing so for submodules (e.g., to find out
which ref backend they're using).

We can improve both by splitting the first two steps into
separate functions. Now check_repository_format_gently()
calls out to steps 1 and 2, and does 3 only if step 2
succeeds.

Note that the public interface for read_repository_format()
and what check_repository_format_gently() needs from it are
not quite the same, leading us to have an extra
read_repository_format_1() helper. The extra needs from
check_repository_format_gently() will go away in a future
patch, and we can simplify this then to just the public
interface.

Signed-off-by: Jeff King <peff@peff.net>
---
 cache.h |  24 +++++++++++++
 setup.c | 118 +++++++++++++++++++++++++++++++++++++++++++---------------------
 2 files changed, 103 insertions(+), 39 deletions(-)

diff --git a/cache.h b/cache.h
index 867e73e..4fc42b5 100644
--- a/cache.h
+++ b/cache.h
@@ -750,6 +750,30 @@ extern int grafts_replace_parents;
 extern int repository_format_version;
 extern int repository_format_precious_objects;
 
+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
diff --git a/setup.c b/setup.c
index a6013e6..8aa49a9 100644
--- a/setup.c
+++ b/setup.c
@@ -5,7 +5,6 @@
 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;
 
 /*
  * The input parameter must contain an absolute path, and it must already be
@@ -370,12 +369,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);
+		data->version = git_config_int(var, value);
 	else if (skip_prefix(var, "extensions.", &ext)) {
 		/*
 		 * record any known extensions here; otherwise,
@@ -385,61 +385,104 @@ static int check_repo_format(const char *var, const char *value, void *cb)
 		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);
 	}
 	return 0;
 }
 
+static int read_repository_format_1(struct repository_format *, config_fn_t,
+				    const char *);
+
 static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 {
 	struct strbuf sb = STRBUF_INIT;
-	const char *repo_config;
+	struct strbuf err = STRBUF_INIT;
+	struct repository_format candidate;
 	config_fn_t fn;
-	int ret = 0;
-
-	string_list_clear(&unknown_extensions, 0);
 
 	if (get_common_dir(&sb, gitdir))
 		fn = check_repo_format;
 	else
 		fn = check_repository_format_version;
+
 	strbuf_addstr(&sb, "/config");
-	repo_config = sb.buf;
+	read_repository_format_1(&candidate, fn, sb.buf);
+	strbuf_release(&sb);
 
 	/*
-	 * Ignore return value; for historical reasons, we must treat a missing
-	 * config file as a noop (git-init relies on this).
+	 * 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_from_file(fn, repo_config, NULL);
-	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 (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);
 	}
 
-	if (repository_format_version >= 1 && unknown_extensions.nr) {
+	repository_format_version = candidate.version;
+	repository_format_precious_objects = candidate.precious_objects;
+	string_list_clear(&candidate.unknown_extensions, 0);
+	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;
+	}
+
+	return 0;
+}
+
+static int read_repository_format_1(struct repository_format *format,
+				    config_fn_t fn, 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(fn, path, format);
+	return format->version;
+}
+
+int read_repository_format(struct repository_format *format, const char *path)
+{
+	return read_repository_format_1(format, check_repository_format_version, path);
+}
+
+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;
 }
 
 /*
@@ -958,19 +1001,16 @@ int git_config_perm(const char *var, const char *value)
 
 int check_repository_format_version(const char *var, const char *value, void *cb)
 {
+	struct repository_format *data = 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;
+		data->is_bare = git_config_bool(var, value);
 	} 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;
+		data->work_tree = xstrdup(value);
 	}
 	return 0;
 }
-- 
2.8.0.rc2.328.g39e2a47

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 07/10] init: use setup.c's repo version verification
  2016-03-11 22:36 [PATCH v2 0/10] cleaning up check_repository_format_gently Jeff King
                   ` (5 preceding siblings ...)
  2016-03-11 22:37 ` [PATCH v2 06/10] setup: refactor repo format reading and verification Jeff King
@ 2016-03-11 22:37 ` Jeff King
  2016-03-11 22:37 ` [PATCH v2 08/10] setup: unify repository version callbacks Jeff King
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Jeff King @ 2016-03-11 22:37 UTC (permalink / raw
  To: git; +Cc: David Turner, pclouds

We check our templates to make sure they are from a
version of git we understand (otherwise we would init a
repository we cannot ourselves run in!). But our simple
integer check has fallen behind the times. Let's use the
helpers that setup.c provides to do it right.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/init-db.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/builtin/init-db.c b/builtin/init-db.c
index e9b2256..d9934f3 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -95,6 +95,8 @@ static void copy_templates(const char *template_dir)
 	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;
 
@@ -121,17 +123,18 @@ static void copy_templates(const char *template_dir)
 
 	/* 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;
 	}
 
-- 
2.8.0.rc2.328.g39e2a47

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 08/10] setup: unify repository version callbacks
  2016-03-11 22:36 [PATCH v2 0/10] cleaning up check_repository_format_gently Jeff King
                   ` (6 preceding siblings ...)
  2016-03-11 22:37 ` [PATCH v2 07/10] init: use setup.c's repo version verification Jeff King
@ 2016-03-11 22:37 ` Jeff King
  2016-03-11 22:37 ` [PATCH v2 09/10] setup: drop repository_format_version global Jeff King
  2016-03-11 22:37 ` [PATCH v2 10/10] verify_repository_format: mark messages for translation Jeff King
  9 siblings, 0 replies; 12+ messages in thread
From: Jeff King @ 2016-03-11 22:37 UTC (permalink / raw
  To: git; +Cc: David Turner, pclouds

Once upon a time, check_repository_format_gently would parse
the config with a single callback, and that callback would
set up a bunch of global variables. But now that we have
separate workdirs, we have to be more careful. Commit
31e26eb (setup.c: support multi-checkout repo setup,
2014-11-30) introduced a reduced callback which omits some
values like core.worktree. In the "main" callback we call
the reduced one, and then add back in the missing variables.

Now that we have split the config-parsing from the munging
of the global variables, we can do it all with a single
callback, and keep all of the "are we in a separate workdir"
logic together.

Signed-off-by: Jeff King <peff@peff.net>
---
 cache.h |  1 -
 setup.c | 65 +++++++++++++++++++++++------------------------------------------
 2 files changed, 23 insertions(+), 43 deletions(-)

diff --git a/cache.h b/cache.h
index 4fc42b5..7704bc6 100644
--- a/cache.h
+++ b/cache.h
@@ -1582,7 +1582,6 @@ extern void git_config_set_multivar_in_file(const char *, const char *, const ch
 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);
diff --git a/setup.c b/setup.c
index 8aa49a9..fbe7ec1 100644
--- a/setup.c
+++ b/setup.c
@@ -388,27 +388,26 @@ static int check_repo_format(const char *var, const char *value, void *vdata)
 			data->precious_objects = git_config_bool(var, value);
 		else
 			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 read_repository_format_1(struct repository_format *, config_fn_t,
-				    const char *);
-
 static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 {
 	struct strbuf sb = STRBUF_INIT;
 	struct strbuf err = STRBUF_INIT;
 	struct repository_format candidate;
-	config_fn_t fn;
-
-	if (get_common_dir(&sb, gitdir))
-		fn = check_repo_format;
-	else
-		fn = check_repository_format_version;
+	int has_common;
 
+	has_common = get_common_dir(&sb, gitdir);
 	strbuf_addstr(&sb, "/config");
-	read_repository_format_1(&candidate, fn, sb.buf);
+	read_repository_format(&candidate, sb.buf);
 	strbuf_release(&sb);
 
 	/*
@@ -432,36 +431,34 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 	repository_format_version = candidate.version;
 	repository_format_precious_objects = candidate.precious_objects;
 	string_list_clear(&candidate.unknown_extensions, 0);
-	if (candidate.is_bare != -1) {
-		is_bare_repository_cfg = candidate.is_bare;
-		if (is_bare_repository_cfg == 1)
+	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;
-	}
-	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;
 }
 
-static int read_repository_format_1(struct repository_format *format,
-				    config_fn_t fn, const char *path)
+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(fn, path, format);
+	git_config_from_file(check_repo_format, path, format);
 	return format->version;
 }
 
-int read_repository_format(struct repository_format *format, const char *path)
-{
-	return read_repository_format_1(format, check_repository_format_version, path);
-}
-
 int verify_repository_format(const struct repository_format *format,
 			     struct strbuf *err)
 {
@@ -999,22 +996,6 @@ int git_config_perm(const char *var, const char *value)
 	return -(i & 0666);
 }
 
-int check_repository_format_version(const char *var, const char *value, void *cb)
-{
-	struct repository_format *data = cb;
-	int ret = check_repo_format(var, value, cb);
-	if (ret)
-		return ret;
-	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;
-}
-
 void check_repository_format(void)
 {
 	check_repository_format_gently(get_git_dir(), NULL);
-- 
2.8.0.rc2.328.g39e2a47

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 09/10] setup: drop repository_format_version global
  2016-03-11 22:36 [PATCH v2 0/10] cleaning up check_repository_format_gently Jeff King
                   ` (7 preceding siblings ...)
  2016-03-11 22:37 ` [PATCH v2 08/10] setup: unify repository version callbacks Jeff King
@ 2016-03-11 22:37 ` Jeff King
  2016-03-11 22:37 ` [PATCH v2 10/10] verify_repository_format: mark messages for translation Jeff King
  9 siblings, 0 replies; 12+ messages in thread
From: Jeff King @ 2016-03-11 22:37 UTC (permalink / raw
  To: git; +Cc: David Turner, pclouds

Nobody reads this anymore, and they're not likely to; the
interesting thing is whether or not we passed
check_repository_format(), and possibly the individual
"extension" variables.

Signed-off-by: Jeff King <peff@peff.net>
---
 cache.h       | 1 -
 environment.c | 1 -
 setup.c       | 1 -
 3 files changed, 3 deletions(-)

diff --git a/cache.h b/cache.h
index 7704bc6..bec6db5 100644
--- a/cache.h
+++ b/cache.h
@@ -747,7 +747,6 @@ 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;
 
 struct repository_format {
diff --git a/environment.c b/environment.c
index 8b8c8e8..d9e3861 100644
--- a/environment.c
+++ b/environment.c
@@ -25,7 +25,6 @@ int log_all_ref_updates = -1; /* unspecified */
 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;
diff --git a/setup.c b/setup.c
index fbe7ec1..1314c17 100644
--- a/setup.c
+++ b/setup.c
@@ -428,7 +428,6 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 		die("%s", err.buf);
 	}
 
-	repository_format_version = candidate.version;
 	repository_format_precious_objects = candidate.precious_objects;
 	string_list_clear(&candidate.unknown_extensions, 0);
 	if (!has_common) {
-- 
2.8.0.rc2.328.g39e2a47

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 10/10] verify_repository_format: mark messages for translation
  2016-03-11 22:36 [PATCH v2 0/10] cleaning up check_repository_format_gently Jeff King
                   ` (8 preceding siblings ...)
  2016-03-11 22:37 ` [PATCH v2 09/10] setup: drop repository_format_version global Jeff King
@ 2016-03-11 22:37 ` Jeff King
  9 siblings, 0 replies; 12+ messages in thread
From: Jeff King @ 2016-03-11 22:37 UTC (permalink / raw
  To: git; +Cc: David Turner, pclouds

These messages are human-readable and should be translated.

Signed-off-by: Jeff King <peff@peff.net>
---
 setup.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/setup.c b/setup.c
index 1314c17..09d3720 100644
--- a/setup.c
+++ b/setup.c
@@ -462,7 +462,7 @@ 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",
+		strbuf_addf(err, _("Expected git repo version <= %d, found %d"),
 			    GIT_REPO_VERSION_READ, format->version);
 		return -1;
 	}
@@ -470,7 +470,7 @@ int verify_repository_format(const struct repository_format *format,
 	if (format->version >= 1 && format->unknown_extensions.nr) {
 		int i;
 
-		strbuf_addstr(err, "unknown repository extensions found:");
+		strbuf_addstr(err, _("unknown repository extensions found:"));
 
 		for (i = 0; i < format->unknown_extensions.nr; i++)
 			strbuf_addf(err, "\n\t%s",
-- 
2.8.0.rc2.328.g39e2a47

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 05/10] config: drop git_config_early
  2016-03-11 22:37 ` [PATCH v2 05/10] config: drop git_config_early Jeff King
@ 2016-03-11 23:33   ` Junio C Hamano
  0 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2016-03-11 23:33 UTC (permalink / raw
  To: Jeff King; +Cc: git, David Turner, pclouds

Jeff King <peff@peff.net> writes:

> There are no more callers, and it's a rather confusing
> interface. This could just be folded into
> git_config_with_options(), but for the sake of readability,
> we'll leave it as a separate (static) helper function.

Yay!

;-)

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2016-03-11 23:33 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-03-11 22:36 [PATCH v2 0/10] cleaning up check_repository_format_gently Jeff King
2016-03-11 22:36 ` [PATCH v2 01/10] setup: document check_repository_format() Jeff King
2016-03-11 22:36 ` [PATCH v2 02/10] wrap shared_repository global in get/set accessors Jeff King
2016-03-11 22:36 ` [PATCH v2 03/10] lazily load core.sharedrepository Jeff King
2016-03-11 22:36 ` [PATCH v2 04/10] check_repository_format_gently: stop using git_config_early Jeff King
2016-03-11 22:37 ` [PATCH v2 05/10] config: drop git_config_early Jeff King
2016-03-11 23:33   ` Junio C Hamano
2016-03-11 22:37 ` [PATCH v2 06/10] setup: refactor repo format reading and verification Jeff King
2016-03-11 22:37 ` [PATCH v2 07/10] init: use setup.c's repo version verification Jeff King
2016-03-11 22:37 ` [PATCH v2 08/10] setup: unify repository version callbacks Jeff King
2016-03-11 22:37 ` [PATCH v2 09/10] setup: drop repository_format_version global Jeff King
2016-03-11 22:37 ` [PATCH v2 10/10] verify_repository_format: mark messages for translation Jeff King

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).