From b2f0eceecf266e60fa95970e0973a8f23f911fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Mar 2018 18:35:54 +0700 Subject: [PATCH 1/6] repository: initialize the_repository in main() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This simplifies initialization of struct repository and anything inside. Easier to read. Easier to add/remove fields. Everything will go through main() common-main.c so this should cover all programs, including t/helper. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- common-main.c | 2 ++ repository.c | 18 +++++++++++++----- repository.h | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/common-main.c b/common-main.c index 6a689007e7..7d716d5a54 100644 --- a/common-main.c +++ b/common-main.c @@ -34,6 +34,8 @@ int main(int argc, const char **argv) git_setup_gettext(); + initialize_the_repository(); + attr_start(); git_extract_argv0_path(argv[0]); diff --git a/repository.c b/repository.c index 4ffbe9bc94..0eddf28fcd 100644 --- a/repository.c +++ b/repository.c @@ -4,10 +4,16 @@ #include "submodule-config.h" /* The main repository */ -static struct repository the_repo = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, &hash_algos[GIT_HASH_SHA1], 0, 0 -}; -struct repository *the_repository = &the_repo; +static struct repository the_repo; +struct repository *the_repository; + +void initialize_the_repository(void) +{ + the_repository = &the_repo; + + the_repo.index = &the_index; + repo_set_hash_algo(&the_repo, GIT_HASH_SHA1); +} static char *git_path_from_env(const char *envvar, const char *git_dir, const char *path, int fromenv) @@ -128,7 +134,9 @@ static int read_and_verify_repository_format(struct repository_format *format, * Initialize 'repo' based on the provided 'gitdir'. * Return 0 upon success and a non-zero value upon failure. */ -int repo_init(struct repository *repo, const char *gitdir, const char *worktree) +static int repo_init(struct repository *repo, + const char *gitdir, + const char *worktree) { struct repository_format format; memset(repo, 0, sizeof(*repo)); diff --git a/repository.h b/repository.h index 0329e40c7f..40c1c81bdc 100644 --- a/repository.h +++ b/repository.h @@ -91,7 +91,7 @@ extern struct repository *the_repository; extern void repo_set_gitdir(struct repository *repo, const char *path); extern void repo_set_worktree(struct repository *repo, const char *path); extern void repo_set_hash_algo(struct repository *repo, int algo); -extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree); +extern void initialize_the_repository(void); extern int repo_submodule_init(struct repository *submodule, struct repository *superproject, const char *path); From 357a03ebe9e04329705a46ff36d526c5ab0c3ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Mar 2018 18:35:55 +0700 Subject: [PATCH 2/6] repository.c: move env-related setup code back to environment.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It does not make sense that generic repository code contains handling of environment variables, which are specific for the main repository only. Refactor repo_set_gitdir() function to take $GIT_DIR and optionally _all_ other customizable paths. These optional paths can be NULL and will be calculated according to the default directory layout. Note that some dead functions are left behind to reduce diff noise. They will be deleted in the next patch. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- cache.h | 2 +- environment.c | 30 +++++++++++++++++++++++--- repository.c | 58 +++++++++++++++++++++++++++++++++++---------------- repository.h | 11 +++++++++- setup.c | 3 +-- 5 files changed, 79 insertions(+), 25 deletions(-) diff --git a/cache.h b/cache.h index 9cac7bb518..41ba67cc16 100644 --- a/cache.h +++ b/cache.h @@ -484,7 +484,7 @@ static inline enum object_type object_type(unsigned int mode) */ extern const char * const local_repo_env[]; -extern void setup_git_env(void); +extern void setup_git_env(const char *git_dir); /* * Returns true iff we have a configured git repository (either via diff --git a/environment.c b/environment.c index de8431e01e..da3f7daa09 100644 --- a/environment.c +++ b/environment.c @@ -13,6 +13,7 @@ #include "refs.h" #include "fmt-merge-msg.h" #include "commit.h" +#include "argv-array.h" int trust_executable_bit = 1; int trust_ctime = 1; @@ -147,10 +148,34 @@ static char *expand_namespace(const char *raw_namespace) return strbuf_detach(&buf, NULL); } -void setup_git_env(void) +/* + * Wrapper of getenv() that returns a strdup value. This value is kept + * in argv to be freed later. + */ +static const char *getenv_safe(struct argv_array *argv, const char *name) +{ + const char *value = getenv(name); + + if (!value) + return NULL; + + argv_array_push(argv, value); + return argv->argv[argv->argc - 1]; +} + +void setup_git_env(const char *git_dir) { const char *shallow_file; const char *replace_ref_base; + struct set_gitdir_args args = { NULL }; + struct argv_array to_free = ARGV_ARRAY_INIT; + + args.commondir = getenv_safe(&to_free, GIT_COMMON_DIR_ENVIRONMENT); + args.object_dir = getenv_safe(&to_free, DB_ENVIRONMENT); + args.graft_file = getenv_safe(&to_free, GRAFT_ENVIRONMENT); + args.index_file = getenv_safe(&to_free, INDEX_ENVIRONMENT); + repo_set_gitdir(the_repository, git_dir, &args); + argv_array_clear(&to_free); if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT)) check_replace_refs = 0; @@ -300,8 +325,7 @@ int set_git_dir(const char *path) { if (setenv(GIT_DIR_ENVIRONMENT, path, 1)) return error("Could not set GIT_DIR to '%s'", path); - repo_set_gitdir(the_repository, path); - setup_git_env(); + setup_git_env(path); return 0; } diff --git a/repository.c b/repository.c index 0eddf28fcd..bb53b54b6d 100644 --- a/repository.c +++ b/repository.c @@ -40,34 +40,55 @@ static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv) return get_common_dir_noenv(sb, gitdir); } -static void repo_setup_env(struct repository *repo) +static void expand_base_dir(char **out, const char *in, + const char *base_dir, const char *def_in) +{ + free(*out); + if (in) + *out = xstrdup(in); + else + *out = xstrfmt("%s/%s", base_dir, def_in); +} + +static void repo_set_commondir(struct repository *repo, + const char *commondir) { struct strbuf sb = STRBUF_INIT; - repo->different_commondir = find_common_dir(&sb, repo->gitdir, - !repo->ignore_env); free(repo->commondir); + + if (commondir) { + repo->different_commondir = 1; + repo->commondir = xstrdup(commondir); + return; + } + + repo->different_commondir = get_common_dir_noenv(&sb, repo->gitdir); repo->commondir = strbuf_detach(&sb, NULL); - free(repo->objectdir); - repo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir, - "objects", !repo->ignore_env); - free(repo->graft_file); - repo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir, - "info/grafts", !repo->ignore_env); - free(repo->index_file); - repo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir, - "index", !repo->ignore_env); } -void repo_set_gitdir(struct repository *repo, const char *path) +void repo_set_gitdir(struct repository *repo, + const char *root, + const struct set_gitdir_args *o) { - const char *gitfile = read_gitfile(path); + const char *gitfile = read_gitfile(root); + /* + * repo->gitdir is saved because the caller could pass "root" + * that also points to repo->gitdir. We want to keep it alive + * until after xstrdup(root). Then we can free it. + */ char *old_gitdir = repo->gitdir; - repo->gitdir = xstrdup(gitfile ? gitfile : path); - repo_setup_env(repo); - + repo->gitdir = xstrdup(gitfile ? gitfile : root); free(old_gitdir); + + repo_set_commondir(repo, o->commondir); + expand_base_dir(&repo->objectdir, o->object_dir, + repo->commondir, "objects"); + expand_base_dir(&repo->graft_file, o->graft_file, + repo->commondir, "info/grafts"); + expand_base_dir(&repo->index_file, o->index_file, + repo->gitdir, "index"); } void repo_set_hash_algo(struct repository *repo, int hash_algo) @@ -85,6 +106,7 @@ static int repo_init_gitdir(struct repository *repo, const char *gitdir) int error = 0; char *abspath = NULL; const char *resolved_gitdir; + struct set_gitdir_args args = { NULL }; abspath = real_pathdup(gitdir, 0); if (!abspath) { @@ -99,7 +121,7 @@ static int repo_init_gitdir(struct repository *repo, const char *gitdir) goto out; } - repo_set_gitdir(repo, resolved_gitdir); + repo_set_gitdir(repo, resolved_gitdir, &args); out: free(abspath); diff --git a/repository.h b/repository.h index 40c1c81bdc..84aeac2825 100644 --- a/repository.h +++ b/repository.h @@ -88,7 +88,16 @@ struct repository { extern struct repository *the_repository; -extern void repo_set_gitdir(struct repository *repo, const char *path); +struct set_gitdir_args { + const char *commondir; + const char *object_dir; + const char *graft_file; + const char *index_file; +}; + +extern void repo_set_gitdir(struct repository *repo, + const char *root, + const struct set_gitdir_args *optional); extern void repo_set_worktree(struct repository *repo, const char *path); extern void repo_set_hash_algo(struct repository *repo, int algo); extern void initialize_the_repository(void); diff --git a/setup.c b/setup.c index c5d55dcee4..6fac1bb58a 100644 --- a/setup.c +++ b/setup.c @@ -1116,8 +1116,7 @@ const char *setup_git_directory_gently(int *nongit_ok) const char *gitdir = getenv(GIT_DIR_ENVIRONMENT); if (!gitdir) gitdir = DEFAULT_GIT_DIR_ENVIRONMENT; - repo_set_gitdir(the_repository, gitdir); - setup_git_env(); + setup_git_env(gitdir); } if (startup_info->have_repository) repo_set_hash_algo(the_repository, repo_fmt.hash_algo); From 0ac5af59957cc46641a6083207c9a04c1a9fa9c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Mar 2018 18:35:56 +0700 Subject: [PATCH 3/6] repository.c: delete dead functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- repository.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/repository.c b/repository.c index bb53b54b6d..e65f4138a7 100644 --- a/repository.c +++ b/repository.c @@ -15,31 +15,6 @@ void initialize_the_repository(void) repo_set_hash_algo(&the_repo, GIT_HASH_SHA1); } -static char *git_path_from_env(const char *envvar, const char *git_dir, - const char *path, int fromenv) -{ - if (fromenv) { - const char *value = getenv(envvar); - if (value) - return xstrdup(value); - } - - return xstrfmt("%s/%s", git_dir, path); -} - -static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv) -{ - if (fromenv) { - const char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT); - if (value) { - strbuf_addstr(sb, value); - return 1; - } - } - - return get_common_dir_noenv(sb, gitdir); -} - static void expand_base_dir(char **out, const char *in, const char *base_dir, const char *def_in) { From 7bc0dcaa6120efec8cf8caef8511c09d35dbcf09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Mar 2018 18:35:57 +0700 Subject: [PATCH 4/6] sha1_file.c: move delayed getenv(altdb) back to setup_git_env() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getenv() is supposed to work on the main repository only. This delayed getenv() code in sha1_file.c makes it more difficult to convert sha1_file.c to a generic object store that could be used by both submodule and main repositories. Move the getenv() back in setup_git_env() where other env vars are also fetched. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- environment.c | 1 + repository.c | 3 +++ repository.h | 4 ++++ sha1_file.c | 6 +----- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/environment.c b/environment.c index da3f7daa09..a5eaa97fb1 100644 --- a/environment.c +++ b/environment.c @@ -174,6 +174,7 @@ void setup_git_env(const char *git_dir) args.object_dir = getenv_safe(&to_free, DB_ENVIRONMENT); args.graft_file = getenv_safe(&to_free, GRAFT_ENVIRONMENT); args.index_file = getenv_safe(&to_free, INDEX_ENVIRONMENT); + args.alternate_db = getenv_safe(&to_free, ALTERNATE_DB_ENVIRONMENT); repo_set_gitdir(the_repository, git_dir, &args); argv_array_clear(&to_free); diff --git a/repository.c b/repository.c index e65f4138a7..04d85a2869 100644 --- a/repository.c +++ b/repository.c @@ -60,6 +60,8 @@ void repo_set_gitdir(struct repository *repo, repo_set_commondir(repo, o->commondir); expand_base_dir(&repo->objectdir, o->object_dir, repo->commondir, "objects"); + free(repo->alternate_db); + repo->alternate_db = xstrdup_or_null(o->alternate_db); expand_base_dir(&repo->graft_file, o->graft_file, repo->commondir, "info/grafts"); expand_base_dir(&repo->index_file, o->index_file, @@ -215,6 +217,7 @@ void repo_clear(struct repository *repo) FREE_AND_NULL(repo->gitdir); FREE_AND_NULL(repo->commondir); FREE_AND_NULL(repo->objectdir); + FREE_AND_NULL(repo->alternate_db); FREE_AND_NULL(repo->graft_file); FREE_AND_NULL(repo->index_file); FREE_AND_NULL(repo->worktree); diff --git a/repository.h b/repository.h index 84aeac2825..2bfbf762f3 100644 --- a/repository.h +++ b/repository.h @@ -26,6 +26,9 @@ struct repository { */ char *objectdir; + /* Path to extra alternate object database if not NULL */ + char *alternate_db; + /* * Path to the repository's graft file. * Cannot be NULL after initialization. @@ -93,6 +96,7 @@ struct set_gitdir_args { const char *object_dir; const char *graft_file; const char *index_file; + const char *alternate_db; }; extern void repo_set_gitdir(struct repository *repo, diff --git a/sha1_file.c b/sha1_file.c index 831d9e7343..4af422e3cf 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -667,15 +667,11 @@ int foreach_alt_odb(alt_odb_fn fn, void *cb) void prepare_alt_odb(void) { - const char *alt; - if (alt_odb_tail) return; - alt = getenv(ALTERNATE_DB_ENVIRONMENT); - alt_odb_tail = &alt_odb_list; - link_alt_odb_entries(alt, PATH_SEP, NULL, 0); + link_alt_odb_entries(the_repository->alternate_db, PATH_SEP, NULL, 0); read_info_alternates(get_object_directory(), 0); } From 2bee50a083fbf549c3f062a2f89c6e636f532762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 3 Mar 2018 18:35:58 +0700 Subject: [PATCH 5/6] repository: delete ignore_env member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This variable was added because the repo_set_gitdir() was created to cover both submodule and main repos, but these two are initialized a bit differently so ignore_env == 0 means main repo, while ignore_env != 0 is submodules. Since the difference part (env variables) has been moved out of repo_set_gitdir(), this function works the same way for both repo types and ignore_env is not needed anymore. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- repository.c | 2 -- repository.h | 9 --------- 2 files changed, 11 deletions(-) diff --git a/repository.c b/repository.c index 04d85a2869..62f52f47fc 100644 --- a/repository.c +++ b/repository.c @@ -140,8 +140,6 @@ static int repo_init(struct repository *repo, struct repository_format format; memset(repo, 0, sizeof(*repo)); - repo->ignore_env = 1; - if (repo_init_gitdir(repo, gitdir)) goto error; diff --git a/repository.h b/repository.h index 2bfbf762f3..e7127baffb 100644 --- a/repository.h +++ b/repository.h @@ -75,15 +75,6 @@ struct repository { const struct git_hash_algo *hash_algo; /* Configurations */ - /* - * Bit used during initialization to indicate if repository state (like - * the location of the 'objectdir') should be read from the - * environment. By default this bit will be set at the begining of - * 'repo_init()' so that all repositories will ignore the environment. - * The exception to this is 'the_repository', which doesn't go through - * the normal 'repo_init()' process. - */ - unsigned ignore_env:1; /* Indicate if a repository has a different 'commondir' from 'gitdir' */ unsigned different_commondir:1; From 00a3da2a131a3e122df7e053d992fbc1735bf4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 23 Mar 2018 16:55:23 +0100 Subject: [PATCH 6/6] repository.h: add comment and clarify repo_set_gitdir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The argument name "optional" may mislead the reader to think this option could be NULL. But it can't be. While at there, document a bit more about struct set_gitdir_args. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- repository.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/repository.h b/repository.h index e7127baffb..f21fd93f72 100644 --- a/repository.h +++ b/repository.h @@ -82,6 +82,10 @@ struct repository { extern struct repository *the_repository; +/* + * Define a custom repository layout. Any field can be NULL, which + * will default back to the path according to the default layout. + */ struct set_gitdir_args { const char *commondir; const char *object_dir; @@ -92,7 +96,7 @@ struct set_gitdir_args { extern void repo_set_gitdir(struct repository *repo, const char *root, - const struct set_gitdir_args *optional); + const struct set_gitdir_args *extra_args); extern void repo_set_worktree(struct repository *repo, const char *path); extern void repo_set_hash_algo(struct repository *repo, int algo); extern void initialize_the_repository(void);