Skip to content

Commit 2cc7c2c

Browse files
peffgitster
authored andcommitted
setup: refactor repo format reading and verification
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 8018186 commit 2cc7c2c

File tree

2 files changed

+103
-39
lines changed

2 files changed

+103
-39
lines changed

cache.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,30 @@ extern int grafts_replace_parents;
750750
extern int repository_format_version;
751751
extern int repository_format_precious_objects;
752752

753+
struct repository_format {
754+
int version;
755+
int precious_objects;
756+
int is_bare;
757+
char *work_tree;
758+
struct string_list unknown_extensions;
759+
};
760+
761+
/*
762+
* Read the repository format characteristics from the config file "path" into
763+
* "format" struct. Returns the numeric version. On error, -1 is returned,
764+
* format->version is set to -1, and all other fields in the struct are
765+
* undefined.
766+
*/
767+
int read_repository_format(struct repository_format *format, const char *path);
768+
769+
/*
770+
* Verify that the repository described by repository_format is something we
771+
* can read. If it is, return 0. Otherwise, return -1, and "err" will describe
772+
* any errors encountered.
773+
*/
774+
int verify_repository_format(const struct repository_format *format,
775+
struct strbuf *err);
776+
753777
/*
754778
* Check the repository format version in the path found in get_git_dir(),
755779
* and die if it is a version we don't understand. Generally one would

setup.c

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
static int inside_git_dir = -1;
66
static int inside_work_tree = -1;
77
static int work_tree_config_is_bogus;
8-
static struct string_list unknown_extensions = STRING_LIST_INIT_DUP;
98

109
/*
1110
* The input parameter must contain an absolute path, and it must already be
@@ -370,12 +369,13 @@ void setup_work_tree(void)
370369
initialized = 1;
371370
}
372371

373-
static int check_repo_format(const char *var, const char *value, void *cb)
372+
static int check_repo_format(const char *var, const char *value, void *vdata)
374373
{
374+
struct repository_format *data = vdata;
375375
const char *ext;
376376

377377
if (strcmp(var, "core.repositoryformatversion") == 0)
378-
repository_format_version = git_config_int(var, value);
378+
data->version = git_config_int(var, value);
379379
else if (skip_prefix(var, "extensions.", &ext)) {
380380
/*
381381
* record any known extensions here; otherwise,
@@ -385,61 +385,104 @@ static int check_repo_format(const char *var, const char *value, void *cb)
385385
if (!strcmp(ext, "noop"))
386386
;
387387
else if (!strcmp(ext, "preciousobjects"))
388-
repository_format_precious_objects = git_config_bool(var, value);
388+
data->precious_objects = git_config_bool(var, value);
389389
else
390-
string_list_append(&unknown_extensions, ext);
390+
string_list_append(&data->unknown_extensions, ext);
391391
}
392392
return 0;
393393
}
394394

395+
static int read_repository_format_1(struct repository_format *, config_fn_t,
396+
const char *);
397+
395398
static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
396399
{
397400
struct strbuf sb = STRBUF_INIT;
398-
const char *repo_config;
401+
struct strbuf err = STRBUF_INIT;
402+
struct repository_format candidate;
399403
config_fn_t fn;
400-
int ret = 0;
401-
402-
string_list_clear(&unknown_extensions, 0);
403404

404405
if (get_common_dir(&sb, gitdir))
405406
fn = check_repo_format;
406407
else
407408
fn = check_repository_format_version;
409+
408410
strbuf_addstr(&sb, "/config");
409-
repo_config = sb.buf;
411+
read_repository_format_1(&candidate, fn, sb.buf);
412+
strbuf_release(&sb);
410413

411414
/*
412-
* Ignore return value; for historical reasons, we must treat a missing
413-
* config file as a noop (git-init relies on this).
415+
* For historical use of check_repository_format() in git-init,
416+
* we treat a missing config as a silent "ok", even when nongit_ok
417+
* is unset.
414418
*/
415-
git_config_from_file(fn, repo_config, NULL);
416-
if (GIT_REPO_VERSION_READ < repository_format_version) {
417-
if (!nongit_ok)
418-
die ("Expected git repo version <= %d, found %d",
419-
GIT_REPO_VERSION_READ, repository_format_version);
420-
warning("Expected git repo version <= %d, found %d",
421-
GIT_REPO_VERSION_READ, repository_format_version);
422-
warning("Please upgrade Git");
423-
*nongit_ok = -1;
424-
ret = -1;
419+
if (candidate.version < 0)
420+
return 0;
421+
422+
if (verify_repository_format(&candidate, &err) < 0) {
423+
if (nongit_ok) {
424+
warning("%s", err.buf);
425+
strbuf_release(&err);
426+
*nongit_ok = -1;
427+
return -1;
428+
}
429+
die("%s", err.buf);
425430
}
426431

427-
if (repository_format_version >= 1 && unknown_extensions.nr) {
432+
repository_format_version = candidate.version;
433+
repository_format_precious_objects = candidate.precious_objects;
434+
string_list_clear(&candidate.unknown_extensions, 0);
435+
if (candidate.is_bare != -1) {
436+
is_bare_repository_cfg = candidate.is_bare;
437+
if (is_bare_repository_cfg == 1)
438+
inside_work_tree = -1;
439+
}
440+
if (candidate.work_tree) {
441+
free(git_work_tree_cfg);
442+
git_work_tree_cfg = candidate.work_tree;
443+
inside_work_tree = -1;
444+
}
445+
446+
return 0;
447+
}
448+
449+
static int read_repository_format_1(struct repository_format *format,
450+
config_fn_t fn, const char *path)
451+
{
452+
memset(format, 0, sizeof(*format));
453+
format->version = -1;
454+
format->is_bare = -1;
455+
string_list_init(&format->unknown_extensions, 1);
456+
git_config_from_file(fn, path, format);
457+
return format->version;
458+
}
459+
460+
int read_repository_format(struct repository_format *format, const char *path)
461+
{
462+
return read_repository_format_1(format, check_repository_format_version, path);
463+
}
464+
465+
int verify_repository_format(const struct repository_format *format,
466+
struct strbuf *err)
467+
{
468+
if (GIT_REPO_VERSION_READ < format->version) {
469+
strbuf_addf(err, "Expected git repo version <= %d, found %d",
470+
GIT_REPO_VERSION_READ, format->version);
471+
return -1;
472+
}
473+
474+
if (format->version >= 1 && format->unknown_extensions.nr) {
428475
int i;
429476

430-
if (!nongit_ok)
431-
die("unknown repository extension: %s",
432-
unknown_extensions.items[0].string);
477+
strbuf_addstr(err, "unknown repository extensions found:");
433478

434-
for (i = 0; i < unknown_extensions.nr; i++)
435-
warning("unknown repository extension: %s",
436-
unknown_extensions.items[i].string);
437-
*nongit_ok = -1;
438-
ret = -1;
479+
for (i = 0; i < format->unknown_extensions.nr; i++)
480+
strbuf_addf(err, "\n\t%s",
481+
format->unknown_extensions.items[i].string);
482+
return -1;
439483
}
440484

441-
strbuf_release(&sb);
442-
return ret;
485+
return 0;
443486
}
444487

445488
/*
@@ -958,19 +1001,16 @@ int git_config_perm(const char *var, const char *value)
9581001

9591002
int check_repository_format_version(const char *var, const char *value, void *cb)
9601003
{
1004+
struct repository_format *data = cb;
9611005
int ret = check_repo_format(var, value, cb);
9621006
if (ret)
9631007
return ret;
9641008
if (strcmp(var, "core.bare") == 0) {
965-
is_bare_repository_cfg = git_config_bool(var, value);
966-
if (is_bare_repository_cfg == 1)
967-
inside_work_tree = -1;
1009+
data->is_bare = git_config_bool(var, value);
9681010
} else if (strcmp(var, "core.worktree") == 0) {
9691011
if (!value)
9701012
return config_error_nonbool(var);
971-
free(git_work_tree_cfg);
972-
git_work_tree_cfg = xstrdup(value);
973-
inside_work_tree = -1;
1013+
data->work_tree = xstrdup(value);
9741014
}
9751015
return 0;
9761016
}

0 commit comments

Comments
 (0)