repository: enable initialization of submodules

Introduce 'repo_submodule_init()' which performs initialization of a 'struct repository' as a submodule of another 'struct repository'. The resulting submodule 'struct repository' can be in one of three states: 1. The submodule is initialized and has a worktree. 2. The submodule is initialized but does not have a worktree. This would occur when the submodule's gitdir is present in the superproject's 'gitdir/modules/' directory yet the submodule has not been checked out in superproject's worktree. 3. The submodule remains uninitialized due to an error in the initialization process or there is no matching submodule at the provided path in the superproject. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Brandon Williams committed Jun 22, 2017 at 11:43 UTC 96dc883b3cdae83d0499b26c588fcb762361fd95
2 files changed +64
repository.c
+54
@@ -144,6 +144,58 @@ error:
144 return -1;
145 }
146
147 +/*
148 + * Initialize 'submodule' as the submodule given by 'path' in parent repository
149 + * 'superproject'.
150 + * Return 0 upon success and a non-zero value upon failure.
151 + */
152 +int repo_submodule_init(struct repository *submodule,
153 + struct repository *superproject,
154 + const char *path)
155 +{
156 + const struct submodule *sub;
157 + struct strbuf gitdir = STRBUF_INIT;
158 + struct strbuf worktree = STRBUF_INIT;
159 + int ret = 0;
160 +
161 + sub = submodule_from_cache(superproject, null_sha1, path);
162 + if (!sub) {
163 + ret = -1;
164 + goto out;
165 + }
166 +
167 + strbuf_repo_worktree_path(&gitdir, superproject, "%s/.git", path);
168 + strbuf_repo_worktree_path(&worktree, superproject, "%s", path);
169 +
170 + if (repo_init(submodule, gitdir.buf, worktree.buf)) {
171 + /*
172 + * If initilization fails then it may be due to the submodule
173 + * not being populated in the superproject's worktree. Instead
174 + * we can try to initilize the submodule by finding it's gitdir
175 + * in the superproject's 'modules' directory. In this case the
176 + * submodule would not have a worktree.
177 + */
178 + strbuf_reset(&gitdir);
179 + strbuf_repo_git_path(&gitdir, superproject,
180 + "modules/%s", sub->name);
181 +
182 + if (repo_init(submodule, gitdir.buf, NULL)) {
183 + ret = -1;
184 + goto out;
185 + }
186 + }
187 +
188 + submodule->submodule_prefix = xstrfmt("%s%s/",
189 + superproject->submodule_prefix ?
190 + superproject->submodule_prefix :
191 + "", path);
192 +
193 +out:
194 + strbuf_release(&gitdir);
195 + strbuf_release(&worktree);
196 + return ret;
197 +}
198 +
199 void repo_clear(struct repository *repo)
200 {
201 free(repo->gitdir);
@@ -158,6 +210,8 @@ void repo_clear(struct repository *repo)
210 repo->index_file = NULL;
211 free(repo->worktree);
212 repo->worktree = NULL;
213 + free(repo->submodule_prefix);
214 + repo->submodule_prefix = NULL;
215
216 if (repo->config) {
217 git_configset_clear(repo->config);
repository.h
+10
@@ -43,6 +43,13 @@ struct repository {
43 */
44 char *worktree;
45
46 + /*
47 + * Path from the root of the top-level superproject down to this
48 + * repository. This is only non-NULL if the repository is initialized
49 + * as a submodule of another repository.
50 + */
51 + char *submodule_prefix;
52 +
53 /* Subsystems */
54 /*
55 * Repository's config which contains key-value pairs from the usual
@@ -80,6 +87,9 @@ extern struct repository *the_repository;
87 extern void repo_set_gitdir(struct repository *repo, const char *path);
88 extern void repo_set_worktree(struct repository *repo, const char *path);
89 extern int repo_init(struct repository *repo, const char *gitdir, const char *worktree);
90 +extern int repo_submodule_init(struct repository *submodule,
91 + struct repository *superproject,
92 + const char *path);
93 extern void repo_clear(struct repository *repo);
94
95 extern int repo_read_index(struct repository *repo);