]> git.proxmox.com Git - libgit2.git/blame - src/submodule.c
New upstream version 0.27.4+dfsg.1
[libgit2.git] / src / submodule.c
CommitLineData
bfc9ca59 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
bfc9ca59
RB
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
eae0bfdc
PP
8#include "submodule.h"
9
bfc9ca59 10#include "git2/config.h"
83041c71 11#include "git2/sys/config.h"
bfc9ca59 12#include "git2/types.h"
bfc9ca59 13#include "git2/index.h"
bfc9ca59 14#include "buffer.h"
7bf87ab6 15#include "buf_text.h"
bfc9ca59
RB
16#include "vector.h"
17#include "posix.h"
18#include "config_file.h"
19#include "config.h"
20#include "repository.h"
aa13bf05
RB
21#include "tree.h"
22#include "iterator.h"
114f5a6c
RB
23#include "path.h"
24#include "index.h"
b0c9bc92 25#include "worktree.h"
aa13bf05
RB
26
27#define GIT_MODULES_FILE ".gitmodules"
bfc9ca59 28
95dfb031
RB
29static git_cvar_map _sm_update_map[] = {
30 {GIT_CVAR_STRING, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT},
31 {GIT_CVAR_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE},
aa13bf05
RB
32 {GIT_CVAR_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE},
33 {GIT_CVAR_STRING, "none", GIT_SUBMODULE_UPDATE_NONE},
f9775a37
RB
34 {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_UPDATE_NONE},
35 {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_UPDATE_CHECKOUT},
bfc9ca59
RB
36};
37
95dfb031 38static git_cvar_map _sm_ignore_map[] = {
aa13bf05 39 {GIT_CVAR_STRING, "none", GIT_SUBMODULE_IGNORE_NONE},
95dfb031 40 {GIT_CVAR_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED},
aa13bf05
RB
41 {GIT_CVAR_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
42 {GIT_CVAR_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
f9775a37
RB
43 {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_IGNORE_NONE},
44 {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_IGNORE_ALL},
bfc9ca59
RB
45};
46
fccadba2
L
47static git_cvar_map _sm_recurse_map[] = {
48 {GIT_CVAR_STRING, "on-demand", GIT_SUBMODULE_RECURSE_ONDEMAND},
49 {GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_RECURSE_NO},
50 {GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_RECURSE_YES},
51};
52
a4ccd2b0
RB
53enum {
54 CACHE_OK = 0,
55 CACHE_REFRESH = 1,
56 CACHE_FLUSH = 2
57};
58enum {
59 GITMODULES_EXISTING = 0,
60 GITMODULES_CREATE = 1,
61};
62
72ee0787 63static kh_inline khint_t str_hash_no_trailing_slash(const char *s)
bfc9ca59 64{
01fed0a8 65 khint_t h;
bfc9ca59 66
01fed0a8 67 for (h = 0; *s; ++s)
5f4a61ae 68 if (s[1] != '\0' || *s != '/')
01fed0a8 69 h = (h << 5) - h + *s;
bfc9ca59 70
01fed0a8 71 return h;
bfc9ca59
RB
72}
73
72ee0787 74static kh_inline int str_equal_no_trailing_slash(const char *a, const char *b)
bfc9ca59 75{
01fed0a8
RB
76 size_t alen = a ? strlen(a) : 0;
77 size_t blen = b ? strlen(b) : 0;
bfc9ca59 78
5f4a61ae 79 if (alen > 0 && a[alen - 1] == '/')
bfc9ca59 80 alen--;
5f4a61ae 81 if (blen > 0 && b[blen - 1] == '/')
bfc9ca59
RB
82 blen--;
83
486302d6
PS
84 return (alen == 0 && blen == 0) ||
85 (alen == blen && strncmp(a, b, alen) == 0);
bfc9ca59
RB
86}
87
aa13bf05
RB
88__KHASH_IMPL(
89 str, static kh_inline, const char *, void *, 1,
c8e02b87 90 str_hash_no_trailing_slash, str_equal_no_trailing_slash)
aa13bf05 91
dfda2f68
CMN
92static int submodule_alloc(git_submodule **out, git_repository *repo, const char *name);
93static git_config_backend *open_gitmodules(git_repository *repo, int gitmod);
4b3ec53c 94static int gitmodules_snapshot(git_config **snap, git_repository *repo);
f2fb4bac 95static int get_url_base(git_buf *url, git_repository *repo);
f2fb4bac 96static int lookup_head_remote_key(git_buf *remote_key, git_repository *repo);
de43efcf 97static int lookup_default_remote(git_remote **remote, git_repository *repo);
f17525b0
CMN
98static int submodule_load_each(const git_config_entry *entry, void *payload);
99static int submodule_read_config(git_submodule *sm, git_config *cfg);
591e8295 100static int submodule_load_from_wd_lite(git_submodule *);
1aad6137
RB
101static void submodule_get_index_status(unsigned int *, git_submodule *);
102static void submodule_get_wd_status(unsigned int *, git_submodule *, git_repository *, git_submodule_ignore_t);
dfda2f68
CMN
103static void submodule_update_from_index_entry(git_submodule *sm, const git_index_entry *ie);
104static void submodule_update_from_head_data(git_submodule *sm, mode_t mode, const git_oid *id);
aa13bf05
RB
105
106static int submodule_cmp(const void *a, const void *b)
107{
108 return strcmp(((git_submodule *)a)->name, ((git_submodule *)b)->name);
109}
110
111static int submodule_config_key_trunc_puts(git_buf *key, const char *suffix)
112{
113 ssize_t idx = git_buf_rfind(key, '.');
114 git_buf_truncate(key, (size_t)(idx + 1));
115 return git_buf_puts(key, suffix);
116}
117
118/*
119 * PUBLIC APIS
120 */
121
69b6ffc4
RB
122static void submodule_set_lookup_error(int error, const char *name)
123{
124 if (!error)
125 return;
126
127 giterr_set(GITERR_SUBMODULE, (error == GIT_ENOTFOUND) ?
909d5494
ET
128 "no submodule named '%s'" :
129 "submodule '%s' has not been added yet", name);
69b6ffc4
RB
130}
131
d769a3fd
CMN
132typedef struct {
133 const char *path;
134 char *name;
135} fbp_data;
136
137static int find_by_path(const git_config_entry *entry, void *payload)
138{
139 fbp_data *data = payload;
140
141 if (!strcmp(entry->value, data->path)) {
142 const char *fdot, *ldot;
143 fdot = strchr(entry->name, '.');
144 ldot = strrchr(entry->name, '.');
145 data->name = git__strndup(fdot + 1, ldot - fdot - 1);
146 GITERR_CHECK_ALLOC(data->name);
147 }
148
149 return 0;
150}
151
f17525b0 152/**
4d99c4cf 153 * Release the name map returned by 'load_submodule_names'.
f17525b0 154 */
4d99c4cf
BP
155static void free_submodule_names(git_strmap *names)
156{
157 git_buf *name = 0;
158 if (names == NULL)
159 return;
160 git_strmap_foreach_value(names, name, {
161 git__free(name);
162 });
163 git_strmap_free(names);
164 return;
165}
166
167/**
168 * Map submodule paths to names.
169 * TODO: for some use-cases, this might need case-folding on a
170 * case-insensitive filesystem
171 */
4b3ec53c 172static int load_submodule_names(git_strmap *out, git_repository *repo, git_config *cfg)
f17525b0
CMN
173{
174 const char *key = "submodule\\..*\\.path";
175 git_config_iterator *iter;
176 git_config_entry *entry;
4d99c4cf 177 git_buf buf = GIT_BUF_INIT;
4b3ec53c 178 int rval, isvalid;
4d99c4cf 179 int error = 0;
f17525b0
CMN
180
181 if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0)
182 return error;
183
4d99c4cf 184 while (git_config_next(&entry, iter) == 0) {
f17525b0 185 const char *fdot, *ldot;
f17525b0
CMN
186 fdot = strchr(entry->name, '.');
187 ldot = strrchr(entry->name, '.');
188
4b3ec53c
XL
189 if (git_strmap_exists(out, entry->value)) {
190 giterr_set(GITERR_SUBMODULE,
191 "duplicated submodule path '%s'", entry->value);
192 error = -1;
193 goto out;
194 }
195
196 git_buf_clear(&buf);
4d99c4cf 197 git_buf_put(&buf, fdot + 1, ldot - fdot - 1);
4b3ec53c
XL
198 isvalid = git_submodule_name_is_valid(repo, buf.ptr, 0);
199 if (isvalid < 0) {
200 error = isvalid;
201 goto out;
202 }
203 if (!isvalid)
204 continue;
205
73028af8 206 git_strmap_insert(out, entry->value, git_buf_detach(&buf), &rval);
4d99c4cf 207 if (rval < 0) {
0fbff82b 208 giterr_set(GITERR_NOMEMORY, "error inserting submodule into hash table");
4d99c4cf
BP
209 return -1;
210 }
f17525b0 211 }
4b3ec53c
XL
212 if (error == GIT_ITEROVER)
213 error = 0;
f17525b0 214
4b3ec53c
XL
215out:
216 git_buf_free(&buf);
ab8f2c66 217 git_config_iterator_free(iter);
4b3ec53c 218 return error;
f17525b0
CMN
219}
220
dfda2f68 221int git_submodule_lookup(
69b6ffc4
RB
222 git_submodule **out, /* NULL if user only wants to test existence */
223 git_repository *repo,
224 const char *name) /* trailing slash is allowed */
225{
226 int error;
2278637c 227 unsigned int location;
dfda2f68 228 git_submodule *sm;
69b6ffc4
RB
229
230 assert(repo && name);
231
eae0bfdc
PP
232 if (repo->is_bare) {
233 giterr_set(GITERR_SUBMODULE, "cannot get submodules without a working tree");
234 return -1;
235 }
236
4d99c4cf
BP
237 if (repo->submodule_cache != NULL) {
238 khiter_t pos = git_strmap_lookup_index(repo->submodule_cache, name);
239 if (git_strmap_valid_index(repo->submodule_cache, pos)) {
240 if (out) {
241 *out = git_strmap_value_at(repo->submodule_cache, pos);
242 GIT_REFCOUNT_INC(*out);
243 }
244 return 0;
245 }
246 }
247
dfda2f68
CMN
248 if ((error = submodule_alloc(&sm, repo, name)) < 0)
249 return error;
aa13bf05 250
dfda2f68
CMN
251 if ((error = git_submodule_reload(sm, false)) < 0) {
252 git_submodule_free(sm);
aa13bf05 253 return error;
dfda2f68 254 }
aa13bf05 255
2278637c
CMN
256 if ((error = git_submodule_location(&location, sm)) < 0) {
257 git_submodule_free(sm);
258 return error;
259 }
260
c28a5c97 261 /* If it's not configured or we're looking by path */
2278637c
CMN
262 if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
263 git_config_backend *mods;
d769a3fd 264 const char *pattern = "submodule\\..*\\.path";
c28a5c97
CMN
265 git_buf path = GIT_BUF_INIT;
266 fbp_data data = { NULL, NULL };
267
268 git_buf_puts(&path, name);
269 while (path.ptr[path.size-1] == '/') {
270 path.ptr[--path.size] = '\0';
271 }
272 data.path = path.ptr;
d769a3fd 273
2278637c
CMN
274 mods = open_gitmodules(repo, GITMODULES_EXISTING);
275
276 if (mods)
277 error = git_config_file_foreach_match(mods, pattern, find_by_path, &data);
278
279 git_config_file_free(mods);
280
281 if (error < 0) {
282 git_submodule_free(sm);
5c5df666 283 git_buf_free(&path);
d769a3fd 284 return error;
2278637c 285 }
d769a3fd
CMN
286
287 if (data.name) {
288 git__free(sm->name);
289 sm->name = data.name;
c28a5c97 290 sm->path = git_buf_detach(&path);
d769a3fd
CMN
291
292 /* Try to load again with the right name */
293 if ((error = git_submodule_reload(sm, false)) < 0) {
294 git_submodule_free(sm);
295 return error;
296 }
297 }
c28a5c97
CMN
298
299 git_buf_free(&path);
d769a3fd
CMN
300 }
301
2278637c
CMN
302 if ((error = git_submodule_location(&location, sm)) < 0) {
303 git_submodule_free(sm);
304 return error;
305 }
306
307 /* If we still haven't found it, do the WD check */
308 if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
dfda2f68
CMN
309 git_submodule_free(sm);
310 error = GIT_ENOTFOUND;
aa13bf05 311
dfda2f68 312 /* If it's not configured, we still check if there's a repo at the path */
aa13bf05
RB
313 if (git_repository_workdir(repo)) {
314 git_buf path = GIT_BUF_INIT;
18234b14 315 if (git_buf_join3(&path,
dfda2f68 316 '/', git_repository_workdir(repo), name, DOT_GIT) < 0)
aa13bf05
RB
317 return -1;
318
18234b14 319 if (git_path_exists(path.ptr))
aa13bf05
RB
320 error = GIT_EEXISTS;
321
322 git_buf_free(&path);
323 }
324
69b6ffc4 325 submodule_set_lookup_error(error, name);
dfda2f68 326 return error;
aa13bf05
RB
327 }
328
dfda2f68
CMN
329 if (out)
330 *out = sm;
331 else
332 git_submodule_free(sm);
333
334 return 0;
aa13bf05 335}
01fed0a8 336
4b3ec53c
XL
337int git_submodule_name_is_valid(git_repository *repo, const char *name, int flags)
338{
339 git_buf buf = GIT_BUF_INIT;
340 int error, isvalid;
341
342 if (flags == 0)
343 flags = GIT_PATH_REJECT_FILESYSTEM_DEFAULTS;
344
345 /* Avoid allocating a new string if we can avoid it */
346 if (strchr(name, '\\') != NULL) {
347 if ((error = git_path_normalize_slashes(&buf, name)) < 0)
348 return error;
349 } else {
350 git_buf_attach_notowned(&buf, name, strlen(name));
351 }
352
353 isvalid = git_path_isvalid(repo, buf.ptr, 0, flags);
354 git_buf_free(&buf);
355
356 return isvalid;
357}
358
aa78c9ba
RB
359static void submodule_free_dup(void *sm)
360{
361 git_submodule_free(sm);
362}
363
dfda2f68
CMN
364static int submodule_get_or_create(git_submodule **out, git_repository *repo, git_strmap *map, const char *name)
365{
366 int error = 0;
367 khiter_t pos;
368 git_submodule *sm = NULL;
369
370 pos = git_strmap_lookup_index(map, name);
371 if (git_strmap_valid_index(map, pos)) {
372 sm = git_strmap_value_at(map, pos);
373 goto done;
374 }
375
376 /* if the submodule doesn't exist yet in the map, create it */
377 if ((error = submodule_alloc(&sm, repo, name)) < 0)
378 return error;
379
f31cb45a 380 pos = git_strmap_put(map, sm->name, &error);
dfda2f68
CMN
381 /* nobody can beat us to adding it */
382 assert(error != 0);
383 if (error < 0) {
384 git_submodule_free(sm);
385 return error;
386 }
387
388 git_strmap_set_value_at(map, pos, sm);
389
390done:
391 GIT_REFCOUNT_INC(sm);
392 *out = sm;
393 return 0;
394}
395
f17525b0 396static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cfg)
dfda2f68 397{
ca05857e 398 int error;
e2b3dc16 399 git_iterator *i = NULL;
ca05857e 400 const git_index_entry *entry;
4d99c4cf 401 git_strmap *names = 0;
e2b3dc16 402
4d99c4cf 403 git_strmap_alloc(&names);
4b3ec53c 404 if ((error = load_submodule_names(names, git_index_owner(idx), cfg)))
4d99c4cf 405 goto done;
dfda2f68 406
ca05857e 407 if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
4d99c4cf 408 goto done;
f17525b0 409
ca05857e
DT
410 while (!(error = git_iterator_advance(&entry, i))) {
411 khiter_t pos = git_strmap_lookup_index(map, entry->path);
412 git_submodule *sm;
413
ca05857e
DT
414 if (git_strmap_valid_index(map, pos)) {
415 sm = git_strmap_value_at(map, pos);
416
417 if (S_ISGITLINK(entry->mode))
418 submodule_update_from_index_entry(sm, entry);
419 else
420 sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
421 } else if (S_ISGITLINK(entry->mode)) {
4d99c4cf
BP
422 khiter_t name_pos;
423 const char *name;
424
425 name_pos = git_strmap_lookup_index(names, entry->path);
426 if (git_strmap_valid_index(names, name_pos)) {
427 name = git_strmap_value_at(names, name_pos);
428 } else {
429 name = entry->path;
430 }
dfda2f68 431
4d99c4cf 432 if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name)) {
ca05857e
DT
433 submodule_update_from_index_entry(sm, entry);
434 git_submodule_free(sm);
435 }
436 }
437 }
dfda2f68 438
ca05857e
DT
439 if (error == GIT_ITEROVER)
440 error = 0;
dfda2f68 441
4d99c4cf 442done:
ca05857e 443 git_iterator_free(i);
4d99c4cf 444 free_submodule_names(names);
dfda2f68 445
ca05857e 446 return error;
dfda2f68
CMN
447}
448
f17525b0 449static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg)
dfda2f68 450{
ca05857e 451 int error;
d0c418c0 452 git_iterator *i = NULL;
ca05857e 453 const git_index_entry *entry;
4d99c4cf
BP
454 git_strmap *names = 0;
455 git_strmap_alloc(&names);
4b3ec53c 456 if ((error = load_submodule_names(names, git_tree_owner(head), cfg)))
4d99c4cf 457 goto done;
dfda2f68 458
ca05857e 459 if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
4d99c4cf 460 goto done;
f17525b0 461
ca05857e
DT
462 while (!(error = git_iterator_advance(&entry, i))) {
463 khiter_t pos = git_strmap_lookup_index(map, entry->path);
464 git_submodule *sm;
465
ca05857e
DT
466 if (git_strmap_valid_index(map, pos)) {
467 sm = git_strmap_value_at(map, pos);
468
469 if (S_ISGITLINK(entry->mode))
470 submodule_update_from_head_data(sm, entry->mode, &entry->id);
471 else
472 sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
473 } else if (S_ISGITLINK(entry->mode)) {
4d99c4cf
BP
474 khiter_t name_pos;
475 const char *name;
476
477 name_pos = git_strmap_lookup_index(names, entry->path);
478 if (git_strmap_valid_index(names, name_pos)) {
479 name = git_strmap_value_at(names, name_pos);
480 } else {
481 name = entry->path;
482 }
dfda2f68 483
4d99c4cf 484 if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name)) {
ca05857e
DT
485 submodule_update_from_head_data(
486 sm, entry->mode, &entry->id);
487 git_submodule_free(sm);
488 }
489 }
490 }
dfda2f68 491
ca05857e
DT
492 if (error == GIT_ITEROVER)
493 error = 0;
dfda2f68 494
4d99c4cf 495done:
ca05857e 496 git_iterator_free(i);
4d99c4cf 497 free_submodule_names(names);
dfda2f68 498
ca05857e 499 return error;
dfda2f68
CMN
500}
501
502/* If have_sm is true, sm is populated, otherwise map an repo are. */
503typedef struct {
f17525b0 504 git_config *mods;
dfda2f68
CMN
505 git_strmap *map;
506 git_repository *repo;
507} lfc_data;
508
4d99c4cf 509int git_submodule__map(git_repository *repo, git_strmap *map)
dfda2f68
CMN
510{
511 int error = 0;
512 git_index *idx = NULL;
513 git_tree *head = NULL;
514 const char *wd = NULL;
515 git_buf path = GIT_BUF_INIT;
516 git_submodule *sm;
f17525b0 517 git_config *mods = NULL;
dfda2f68
CMN
518 uint32_t mask;
519
520 assert(repo && map);
521
522 /* get sources that we will need to check */
523 if (git_repository_index(&idx, repo) < 0)
524 giterr_clear();
525 if (git_repository_head_tree(&head, repo) < 0)
526 giterr_clear();
527
528 wd = git_repository_workdir(repo);
529 if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
530 goto cleanup;
531
532 /* clear submodule flags that are to be refreshed */
533 mask = 0;
534 mask |= GIT_SUBMODULE_STATUS_IN_INDEX |
535 GIT_SUBMODULE_STATUS__INDEX_FLAGS |
536 GIT_SUBMODULE_STATUS__INDEX_OID_VALID |
537 GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
538
539 mask |= GIT_SUBMODULE_STATUS_IN_HEAD |
540 GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
541 mask |= GIT_SUBMODULE_STATUS_IN_CONFIG;
542 if (mask != 0)
543 mask |= GIT_SUBMODULE_STATUS_IN_WD |
544 GIT_SUBMODULE_STATUS__WD_SCANNED |
545 GIT_SUBMODULE_STATUS__WD_FLAGS |
546 GIT_SUBMODULE_STATUS__WD_OID_VALID;
547
f17525b0
CMN
548 /* add submodule information from .gitmodules */
549 if (wd) {
550 lfc_data data = { 0 };
551 data.map = map;
552 data.repo = repo;
553
4b3ec53c
XL
554 if ((error = gitmodules_snapshot(&mods, repo)) < 0) {
555 if (error == GIT_ENOTFOUND)
556 error = 0;
f17525b0 557 goto cleanup;
4b3ec53c 558 }
f17525b0
CMN
559
560 data.mods = mods;
561 if ((error = git_config_foreach(
562 mods, submodule_load_each, &data)) < 0)
563 goto cleanup;
564 }
dfda2f68 565 /* add back submodule information from index */
60c2bf47 566 if (mods && idx) {
f17525b0 567 if ((error = submodules_from_index(map, idx, mods)) < 0)
dfda2f68
CMN
568 goto cleanup;
569 }
570 /* add submodule information from HEAD */
60c2bf47 571 if (mods && head) {
f17525b0 572 if ((error = submodules_from_head(map, head, mods)) < 0)
dfda2f68
CMN
573 goto cleanup;
574 }
575 /* shallow scan submodules in work tree as needed */
576 if (wd && mask != 0) {
577 git_strmap_foreach_value(map, sm, {
578 submodule_load_from_wd_lite(sm);
579 });
580 }
581
582cleanup:
f17525b0 583 git_config_free(mods);
dfda2f68
CMN
584 /* TODO: if we got an error, mark submodule config as invalid? */
585 git_index_free(idx);
586 git_tree_free(head);
587 git_buf_free(&path);
588 return error;
589}
590
aa13bf05
RB
591int git_submodule_foreach(
592 git_repository *repo,
eda726cf 593 git_submodule_cb callback,
aa13bf05
RB
594 void *payload)
595{
dfda2f68
CMN
596 git_vector snapshot = GIT_VECTOR_INIT;
597 git_strmap *submodules;
598 git_submodule *sm;
aa13bf05 599 int error;
aa78c9ba 600 size_t i;
aa13bf05 601
eae0bfdc
PP
602 if (repo->is_bare) {
603 giterr_set(GITERR_SUBMODULE, "cannot get submodules without a working tree");
604 return -1;
605 }
606
dfda2f68 607 if ((error = git_strmap_alloc(&submodules)) < 0)
aa13bf05
RB
608 return error;
609
4d99c4cf 610 if ((error = git_submodule__map(repo, submodules)) < 0)
dfda2f68 611 goto done;
aa78c9ba
RB
612
613 if (!(error = git_vector_init(
63e914cb 614 &snapshot, git_strmap_num_entries(submodules), submodule_cmp))) {
aa78c9ba 615
dfda2f68 616 git_strmap_foreach_value(submodules, sm, {
aa78c9ba 617 if ((error = git_vector_insert(&snapshot, sm)) < 0)
aa13bf05 618 break;
aa78c9ba
RB
619 GIT_REFCOUNT_INC(sm);
620 });
621 }
622
aa78c9ba
RB
623 if (error < 0)
624 goto done;
625
626 git_vector_uniq(&snapshot, submodule_free_dup);
627
628 git_vector_foreach(&snapshot, i, sm) {
c7b3e1b3 629 if ((error = callback(sm, sm->name, payload)) != 0) {
26c1cb91 630 giterr_set_after_callback(error);
aa13bf05 631 break;
c7b3e1b3 632 }
aa78c9ba 633 }
aa13bf05 634
aa78c9ba
RB
635done:
636 git_vector_foreach(&snapshot, i, sm)
637 git_submodule_free(sm);
638 git_vector_free(&snapshot);
aa13bf05 639
dfda2f68
CMN
640 git_strmap_foreach_value(submodules, sm, {
641 git_submodule_free(sm);
642 });
643 git_strmap_free(submodules);
aa13bf05 644
dfda2f68 645 return error;
aa13bf05
RB
646}
647
bc737620
JM
648static int submodule_repo_init(
649 git_repository **out,
650 git_repository *parent_repo,
651 const char *path,
652 const char *url,
653 bool use_gitlink)
654{
655 int error = 0;
656 git_buf workdir = GIT_BUF_INIT, repodir = GIT_BUF_INIT;
657 git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
658 git_repository *subrepo = NULL;
659
660 error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
661 if (error < 0)
662 goto cleanup;
663
664 initopt.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_NO_REINIT;
665 initopt.origin_url = url;
666
667 /* init submodule repository and add origin remote as needed */
668
669 /* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
670 * gitlink in the sub-repo workdir directory to that repository
671 *
672 * Old style: sub-repo goes directly into repo/<name>/.git/
673 */
674 if (use_gitlink) {
c5f3da96
PS
675 error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
676 if (error < 0)
677 goto cleanup;
678 error = git_buf_joinpath(&repodir, repodir.ptr, path);
bc737620
JM
679 if (error < 0)
680 goto cleanup;
681
682 initopt.workdir_path = workdir.ptr;
683 initopt.flags |=
684 GIT_REPOSITORY_INIT_NO_DOTGIT_DIR |
685 GIT_REPOSITORY_INIT_RELATIVE_GITLINK;
686
687 error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
688 } else
689 error = git_repository_init_ext(&subrepo, workdir.ptr, &initopt);
690
691cleanup:
692 git_buf_free(&workdir);
693 git_buf_free(&repodir);
694
695 *out = subrepo;
696
697 return error;
698}
699
aa13bf05 700int git_submodule_add_setup(
a15c7802 701 git_submodule **out,
aa13bf05
RB
702 git_repository *repo,
703 const char *url,
704 const char *path,
705 int use_gitlink)
706{
707 int error = 0;
54b2a37a 708 git_config_backend *mods = NULL;
a15c7802 709 git_submodule *sm = NULL;
aa13bf05 710 git_buf name = GIT_BUF_INIT, real_url = GIT_BUF_INIT;
aa13bf05
RB
711 git_repository *subrepo = NULL;
712
713 assert(repo && url && path);
714
715 /* see if there is already an entry for this submodule */
716
69b6ffc4 717 if (git_submodule_lookup(NULL, repo, path) < 0)
aa13bf05
RB
718 giterr_clear();
719 else {
720 giterr_set(GITERR_SUBMODULE,
909d5494 721 "attempt to add submodule '%s' that already exists", path);
aa13bf05
RB
722 return GIT_EEXISTS;
723 }
724
aa13bf05
RB
725 /* validate and normalize path */
726
727 if (git__prefixcmp(path, git_repository_workdir(repo)) == 0)
728 path += strlen(git_repository_workdir(repo));
729
730 if (git_path_root(path) >= 0) {
909d5494 731 giterr_set(GITERR_SUBMODULE, "submodule path must be a relative path");
aa13bf05
RB
732 error = -1;
733 goto cleanup;
734 }
735
736 /* update .gitmodules */
737
dfda2f68 738 if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) {
aa13bf05 739 giterr_set(GITERR_SUBMODULE,
909d5494 740 "adding submodules to a bare repository is not supported");
aa13bf05
RB
741 return -1;
742 }
743
744 if ((error = git_buf_printf(&name, "submodule.%s.path", path)) < 0 ||
745 (error = git_config_file_set_string(mods, name.ptr, path)) < 0)
746 goto cleanup;
747
748 if ((error = submodule_config_key_trunc_puts(&name, "url")) < 0 ||
b2ab887e 749 (error = git_config_file_set_string(mods, name.ptr, url)) < 0)
aa13bf05
RB
750 goto cleanup;
751
752 git_buf_clear(&name);
753
754 /* init submodule repository and add origin remote as needed */
755
756 error = git_buf_joinpath(&name, git_repository_workdir(repo), path);
757 if (error < 0)
758 goto cleanup;
759
bc737620
JM
760 /* if the repo does not already exist, then init a new repo and add it.
761 * Otherwise, just add the existing repo.
aa13bf05 762 */
bc737620
JM
763 if (!(git_path_exists(name.ptr) &&
764 git_path_contains(&name, DOT_GIT))) {
b2ab887e
JM
765
766 /* resolve the actual URL to use */
767 if ((error = git_submodule_resolve_url(&real_url, repo, url)) < 0)
768 goto cleanup;
769
770 if ((error = submodule_repo_init(&subrepo, repo, path, real_url.ptr, use_gitlink)) < 0)
aa13bf05 771 goto cleanup;
aa13bf05 772 }
aa13bf05 773
dfda2f68 774 if ((error = git_submodule_lookup(&sm, repo, path)) < 0)
aa78c9ba 775 goto cleanup;
aa13bf05 776
dfda2f68 777 error = git_submodule_init(sm, false);
aa78c9ba 778
aa13bf05 779cleanup:
a15c7802
RB
780 if (error && sm) {
781 git_submodule_free(sm);
782 sm = NULL;
783 }
784 if (out != NULL)
785 *out = sm;
aa13bf05 786
db0e7878 787 git_config_file_free(mods);
aa13bf05
RB
788 git_repository_free(subrepo);
789 git_buf_free(&real_url);
790 git_buf_free(&name);
791
792 return error;
793}
794
bc737620
JM
795int git_submodule_repo_init(
796 git_repository **out,
797 const git_submodule *sm,
798 int use_gitlink)
799{
800 int error;
801 git_repository *sub_repo = NULL;
b2ab887e
JM
802 const char *configured_url;
803 git_config *cfg = NULL;
804 git_buf buf = GIT_BUF_INIT;
bc737620
JM
805
806 assert(out && sm);
807
b2ab887e
JM
808 /* get the configured remote url of the submodule */
809 if ((error = git_buf_printf(&buf, "submodule.%s.url", sm->name)) < 0 ||
9d1f97df 810 (error = git_repository_config_snapshot(&cfg, sm->repo)) < 0 ||
b2ab887e
JM
811 (error = git_config_get_string(&configured_url, cfg, buf.ptr)) < 0 ||
812 (error = submodule_repo_init(&sub_repo, sm->repo, sm->path, configured_url, use_gitlink)) < 0)
813 goto done;
bc737620
JM
814
815 *out = sub_repo;
816
b2ab887e
JM
817done:
818 git_config_free(cfg);
819 git_buf_free(&buf);
bc737620
JM
820 return error;
821}
822
aa13bf05
RB
823int git_submodule_add_finalize(git_submodule *sm)
824{
825 int error;
826 git_index *index;
827
828 assert(sm);
829
1aad6137 830 if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
25743bd7 831 (error = git_index_add_bypath(index, GIT_MODULES_FILE)) < 0)
aa13bf05
RB
832 return error;
833
5f4a61ae 834 return git_submodule_add_to_index(sm, true);
aa13bf05
RB
835}
836
5f4a61ae 837int git_submodule_add_to_index(git_submodule *sm, int write_index)
aa13bf05
RB
838{
839 int error;
1aad6137 840 git_repository *sm_repo = NULL;
aa13bf05
RB
841 git_index *index;
842 git_buf path = GIT_BUF_INIT;
843 git_commit *head;
844 git_index_entry entry;
845 struct stat st;
846
847 assert(sm);
848
5f4a61ae
RB
849 /* force reload of wd OID by git_submodule_open */
850 sm->flags = sm->flags & ~GIT_SUBMODULE_STATUS__WD_OID_VALID;
851
1aad6137 852 if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
aa13bf05 853 (error = git_buf_joinpath(
1aad6137 854 &path, git_repository_workdir(sm->repo), sm->path)) < 0 ||
aa13bf05
RB
855 (error = git_submodule_open(&sm_repo, sm)) < 0)
856 goto cleanup;
857
858 /* read stat information for submodule working directory */
859 if (p_stat(path.ptr, &st) < 0) {
860 giterr_set(GITERR_SUBMODULE,
909d5494 861 "cannot add submodule without working directory");
aa13bf05
RB
862 error = -1;
863 goto cleanup;
864 }
97a17e4e
RB
865
866 memset(&entry, 0, sizeof(entry));
5f4a61ae 867 entry.path = sm->path;
14997dc5
RB
868 git_index_entry__init_from_stat(
869 &entry, &st, !(git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE));
aa13bf05
RB
870
871 /* calling git_submodule_open will have set sm->wd_oid if possible */
872 if ((sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) == 0) {
873 giterr_set(GITERR_SUBMODULE,
909d5494 874 "cannot add submodule without HEAD to index");
aa13bf05
RB
875 error = -1;
876 goto cleanup;
877 }
d541170c 878 git_oid_cpy(&entry.id, &sm->wd_oid);
aa13bf05
RB
879
880 if ((error = git_commit_lookup(&head, sm_repo, &sm->wd_oid)) < 0)
881 goto cleanup;
882
3b2fa0fb 883 entry.ctime.seconds = (int32_t)git_commit_time(head);
aa13bf05 884 entry.ctime.nanoseconds = 0;
3b2fa0fb 885 entry.mtime.seconds = (int32_t)git_commit_time(head);
aa13bf05
RB
886 entry.mtime.nanoseconds = 0;
887
888 git_commit_free(head);
889
5f4a61ae 890 /* add it */
f45ec1a0 891 error = git_index_add(index, &entry);
aa13bf05 892
5f4a61ae
RB
893 /* write it, if requested */
894 if (!error && write_index) {
895 error = git_index_write(index);
896
897 if (!error)
898 git_oid_cpy(&sm->index_oid, &sm->wd_oid);
899 }
900
aa13bf05
RB
901cleanup:
902 git_repository_free(sm_repo);
903 git_buf_free(&path);
904 return error;
905}
906
f9775a37
RB
907const char *git_submodule_update_to_str(git_submodule_update_t update)
908{
909 int i;
910 for (i = 0; i < (int)ARRAY_SIZE(_sm_update_map); ++i)
60655056 911 if (_sm_update_map[i].map_value == (int)update)
f9775a37
RB
912 return _sm_update_map[i].str_match;
913 return NULL;
914}
915
aa13bf05
RB
916git_repository *git_submodule_owner(git_submodule *submodule)
917{
918 assert(submodule);
1aad6137 919 return submodule->repo;
aa13bf05
RB
920}
921
922const char *git_submodule_name(git_submodule *submodule)
923{
924 assert(submodule);
925 return submodule->name;
926}
927
928const char *git_submodule_path(git_submodule *submodule)
929{
930 assert(submodule);
931 return submodule->path;
932}
933
934const char *git_submodule_url(git_submodule *submodule)
935{
936 assert(submodule);
937 return submodule->url;
938}
939
52fba18f
JM
940int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *url)
941{
52fba18f 942 int error = 0;
f00f005b 943 git_buf normalized = GIT_BUF_INIT;
52fba18f 944
1e4976cb
RB
945 assert(out && repo && url);
946
947 git_buf_sanitize(out);
9af14886 948
a58854a0 949 /* We do this in all platforms in case someone on Windows created the .gitmodules */
f00f005b 950 if (strchr(url, '\\')) {
a58854a0 951 if ((error = git_path_normalize_slashes(&normalized, url)) < 0)
f00f005b
CMN
952 return error;
953
f00f005b
CMN
954 url = normalized.ptr;
955 }
956
a58854a0 957
e402d2f1 958 if (git_path_is_relative(url)) {
f2fb4bac 959 if (!(error = get_url_base(out, repo)))
52fba18f
JM
960 error = git_path_apply_relative(out, url);
961 } else if (strchr(url, ':') != NULL || url[0] == '/') {
962 error = git_buf_sets(out, url);
963 } else {
909d5494 964 giterr_set(GITERR_SUBMODULE, "invalid format for submodule URL");
52fba18f
JM
965 error = -1;
966 }
967
f00f005b 968 git_buf_free(&normalized);
52fba18f
JM
969 return error;
970}
971
486ba4cd
CMN
972static int write_var(git_repository *repo, const char *name, const char *var, const char *val)
973{
974 git_buf key = GIT_BUF_INIT;
975 git_config_backend *mods;
976 int error;
977
978 mods = open_gitmodules(repo, GITMODULES_CREATE);
979 if (!mods)
980 return -1;
981
982 if ((error = git_buf_printf(&key, "submodule.%s.%s", name, var)) < 0)
983 goto cleanup;
984
985 if (val)
986 error = git_config_file_set_string(mods, key.ptr, val);
987 else
988 error = git_config_file_delete(mods, key.ptr);
989
990 git_buf_free(&key);
991
992cleanup:
993 git_config_file_free(mods);
994 return error;
995}
996
c4e3a3db
CMN
997static int write_mapped_var(git_repository *repo, const char *name, git_cvar_map *maps, size_t nmaps, const char *var, int ival)
998{
999 git_cvar_t type;
1000 const char *val;
1001
1002 if (git_config_lookup_map_enum(&type, &val, maps, nmaps, ival) < 0) {
1003 giterr_set(GITERR_SUBMODULE, "invalid value for %s", var);
1004 return -1;
1005 }
1006
1007 if (type == GIT_CVAR_TRUE)
1008 val = "true";
1009
1010 return write_var(repo, name, var, val);
1011}
1012
10311979
RK
1013const char *git_submodule_branch(git_submodule *submodule)
1014{
1015 assert(submodule);
1016 return submodule->branch;
1017}
1018
486ba4cd 1019int git_submodule_set_branch(git_repository *repo, const char *name, const char *branch)
129788a6 1020{
129788a6 1021
486ba4cd 1022 assert(repo && name);
129788a6 1023
486ba4cd 1024 return write_var(repo, name, "branch", branch);
129788a6
PS
1025}
1026
d6073b30 1027int git_submodule_set_url(git_repository *repo, const char *name, const char *url)
aa13bf05 1028{
d6073b30 1029 assert(repo && name && url);
aa13bf05 1030
d6073b30 1031 return write_var(repo, name, "url", url);
aa13bf05
RB
1032}
1033
9cd42358 1034const git_oid *git_submodule_index_id(git_submodule *submodule)
aa13bf05
RB
1035{
1036 assert(submodule);
1037
1038 if (submodule->flags & GIT_SUBMODULE_STATUS__INDEX_OID_VALID)
1039 return &submodule->index_oid;
1040 else
1041 return NULL;
1042}
1043
9cd42358 1044const git_oid *git_submodule_head_id(git_submodule *submodule)
aa13bf05
RB
1045{
1046 assert(submodule);
1047
1048 if (submodule->flags & GIT_SUBMODULE_STATUS__HEAD_OID_VALID)
1049 return &submodule->head_oid;
1050 else
1051 return NULL;
1052}
1053
9cd42358 1054const git_oid *git_submodule_wd_id(git_submodule *submodule)
aa13bf05
RB
1055{
1056 assert(submodule);
1057
e807860f 1058 /* load unless we think we have a valid oid */
aa13bf05
RB
1059 if (!(submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)) {
1060 git_repository *subrepo;
1061
1062 /* calling submodule open grabs the HEAD OID if possible */
1aad6137 1063 if (!git_submodule_open_bare(&subrepo, submodule))
aa13bf05 1064 git_repository_free(subrepo);
5f4a61ae
RB
1065 else
1066 giterr_clear();
aa13bf05
RB
1067 }
1068
1069 if (submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)
1070 return &submodule->wd_oid;
1071 else
1072 return NULL;
1073}
1074
1075git_submodule_ignore_t git_submodule_ignore(git_submodule *submodule)
1076{
1077 assert(submodule);
f9775a37
RB
1078 return (submodule->ignore < GIT_SUBMODULE_IGNORE_NONE) ?
1079 GIT_SUBMODULE_IGNORE_NONE : submodule->ignore;
aa13bf05
RB
1080}
1081
e8a39f8e
CMN
1082int git_submodule_set_ignore(git_repository *repo, const char *name, git_submodule_ignore_t ignore)
1083{
c4e3a3db 1084 assert(repo && name);
e8a39f8e 1085
c4e3a3db 1086 return write_mapped_var(repo, name, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), "ignore", ignore);
e8a39f8e
CMN
1087}
1088
9d1f97df 1089git_submodule_update_t git_submodule_update_strategy(git_submodule *submodule)
aa13bf05
RB
1090{
1091 assert(submodule);
f9775a37
RB
1092 return (submodule->update < GIT_SUBMODULE_UPDATE_CHECKOUT) ?
1093 GIT_SUBMODULE_UPDATE_CHECKOUT : submodule->update;
aa13bf05
RB
1094}
1095
e8a39f8e 1096int git_submodule_set_update(git_repository *repo, const char *name, git_submodule_update_t update)
aa13bf05 1097{
c4e3a3db 1098 assert(repo && name);
aa13bf05 1099
c4e3a3db 1100 return write_mapped_var(repo, name, _sm_update_map, ARRAY_SIZE(_sm_update_map), "update", update);
aa13bf05
RB
1101}
1102
fccadba2 1103git_submodule_recurse_t git_submodule_fetch_recurse_submodules(
17b06f4d
RB
1104 git_submodule *submodule)
1105{
1106 assert(submodule);
1107 return submodule->fetch_recurse;
1108}
1109
4e636423 1110int git_submodule_set_fetch_recurse_submodules(git_repository *repo, const char *name, git_submodule_recurse_t recurse)
17b06f4d 1111{
4e636423
CMN
1112 assert(repo && name);
1113
c4e3a3db 1114 return write_mapped_var(repo, name, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), "fetchRecurseSubmodules", recurse);
17b06f4d
RB
1115}
1116
9d1f97df
JM
1117static int submodule_repo_create(
1118 git_repository **out,
1119 git_repository *parent_repo,
1120 const char *path)
1121{
1122 int error = 0;
1123 git_buf workdir = GIT_BUF_INIT, repodir = GIT_BUF_INIT;
1124 git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
1125 git_repository *subrepo = NULL;
1126
1127 initopt.flags =
1128 GIT_REPOSITORY_INIT_MKPATH |
1129 GIT_REPOSITORY_INIT_NO_REINIT |
1130 GIT_REPOSITORY_INIT_NO_DOTGIT_DIR |
1131 GIT_REPOSITORY_INIT_RELATIVE_GITLINK;
1132
1133 /* Workdir: path to sub-repo working directory */
1134 error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
1135 if (error < 0)
1136 goto cleanup;
1137
1138 initopt.workdir_path = workdir.ptr;
1139
1140 /**
1141 * Repodir: path to the sub-repo. sub-repo goes in:
3679ebae 1142 * <repo-dir>/modules/<name>/ with a gitlink in the
9d1f97df
JM
1143 * sub-repo workdir directory to that repository.
1144 */
c5f3da96
PS
1145 error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
1146 if (error < 0)
1147 goto cleanup;
1148 error = git_buf_joinpath(&repodir, repodir.ptr, path);
9d1f97df
JM
1149 if (error < 0)
1150 goto cleanup;
1151
1152 error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
1153
1154cleanup:
1155 git_buf_free(&workdir);
1156 git_buf_free(&repodir);
1157
1158 *out = subrepo;
1159
1160 return error;
1161}
1162
1163/**
1164 * Callback to override sub-repository creation when
1165 * cloning a sub-repository.
1166 */
1167static int git_submodule_update_repo_init_cb(
1168 git_repository **out,
1169 const char *path,
1170 int bare,
1171 void *payload)
1172{
5018e2c6
ET
1173 git_submodule *sm;
1174
9d1f97df 1175 GIT_UNUSED(bare);
5018e2c6
ET
1176
1177 sm = payload;
9d1f97df
JM
1178
1179 return submodule_repo_create(out, sm->repo, path);
1180}
1181
c868981f
DC
1182int git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version)
1183{
1184 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1185 opts, version, git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_INIT);
1186 return 0;
1187}
1188
9d1f97df
JM
1189int git_submodule_update(git_submodule *sm, int init, git_submodule_update_options *_update_options)
1190{
1191 int error;
1192 unsigned int submodule_status;
1193 git_config *config = NULL;
1194 const char *submodule_url;
1195 git_repository *sub_repo = NULL;
1196 git_remote *remote = NULL;
1197 git_object *target_commit = NULL;
1198 git_buf buf = GIT_BUF_INIT;
1199 git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
1200 git_clone_options clone_options = GIT_CLONE_OPTIONS_INIT;
1201
1202 assert(sm);
1203
1204 if (_update_options)
1205 memcpy(&update_options, _update_options, sizeof(git_submodule_update_options));
1206
1207 GITERR_CHECK_VERSION(&update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
1208
1209 /* Copy over the remote callbacks */
8f0104ec 1210 memcpy(&clone_options.fetch_opts, &update_options.fetch_opts, sizeof(git_fetch_options));
9d1f97df
JM
1211
1212 /* Get the status of the submodule to determine if it is already initialized */
c2418f46 1213 if ((error = git_submodule_status(&submodule_status, sm->repo, sm->name, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0)
9d1f97df
JM
1214 goto done;
1215
1216 /*
1217 * If submodule work dir is not already initialized, check to see
1218 * what we need to do (initialize, clone, return error...)
1219 */
1220 if (submodule_status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) {
1221 /*
1222 * Work dir is not initialized, check to see if the submodule
1223 * info has been copied into .git/config
1224 */
1225 if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
1226 (error = git_buf_printf(&buf, "submodule.%s.url", git_submodule_name(sm))) < 0)
1227 goto done;
1228
1229 if ((error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0) {
1230 /*
1231 * If the error is not "not found" or if it is "not found" and we are not
1232 * initializing the submodule, then return error.
1233 */
1234 if (error != GIT_ENOTFOUND)
1235 goto done;
1236
de43efcf 1237 if (!init) {
909d5494 1238 giterr_set(GITERR_SUBMODULE, "submodule is not initialized");
9d1f97df
JM
1239 error = GIT_ERROR;
1240 goto done;
1241 }
1242
1243 /* The submodule has not been initialized yet - initialize it now.*/
1244 if ((error = git_submodule_init(sm, 0)) < 0)
1245 goto done;
1246
1247 git_config_free(config);
1248 config = NULL;
1249
1250 if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
1251 (error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0)
1252 goto done;
1253 }
1254
1255 /** submodule is initialized - now clone it **/
1256 /* override repo creation */
1257 clone_options.repository_cb = git_submodule_update_repo_init_cb;
1258 clone_options.repository_cb_payload = sm;
1259
1260 /*
3679ebae 1261 * Do not perform checkout as part of clone, instead we
9d1f97df
JM
1262 * will checkout the specific commit manually.
1263 */
1264 clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
9d1f97df
JM
1265
1266 if ((error = git_clone(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 ||
4e498646 1267 (error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0 ||
9d1f97df
JM
1268 (error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0)
1269 goto done;
1270 } else {
32ecc98e
PS
1271 const git_oid *oid;
1272
9d1f97df
JM
1273 /**
1274 * Work dir is initialized - look up the commit in the parent repository's index,
1275 * update the workdir contents of the subrepository, and set the subrepository's
1276 * head to the new commit.
1277 */
de43efcf
JH
1278 if ((error = git_submodule_open(&sub_repo, sm)) < 0)
1279 goto done;
1280
32ecc98e
PS
1281 if ((oid = git_submodule_index_id(sm)) == NULL) {
1282 giterr_set(GITERR_SUBMODULE, "could not get ID of submodule in index");
1283 error = -1;
1284 goto done;
1285 }
1286
de43efcf 1287 /* Look up the target commit in the submodule. */
32ecc98e 1288 if ((error = git_object_lookup(&target_commit, sub_repo, oid, GIT_OBJ_COMMIT)) < 0) {
de43efcf
JH
1289 /* If it isn't found then fetch and try again. */
1290 if (error != GIT_ENOTFOUND || !update_options.allow_fetch ||
1291 (error = lookup_default_remote(&remote, sub_repo)) < 0 ||
1292 (error = git_remote_fetch(remote, NULL, &update_options.fetch_opts, NULL)) < 0 ||
1293 (error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJ_COMMIT)) < 0)
1294 goto done;
1295 }
1296
1297 if ((error = git_checkout_tree(sub_repo, target_commit, &update_options.checkout_opts)) != 0 ||
4e498646 1298 (error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0)
9d1f97df
JM
1299 goto done;
1300
1301 /* Invalidate the wd flags as the workdir has been updated. */
1302 sm->flags = sm->flags &
1303 ~(GIT_SUBMODULE_STATUS_IN_WD |
1304 GIT_SUBMODULE_STATUS__WD_OID_VALID |
1305 GIT_SUBMODULE_STATUS__WD_SCANNED);
1306 }
1307
1308done:
1309 git_buf_free(&buf);
1310 git_config_free(config);
1311 git_object_free(target_commit);
1312 git_remote_free(remote);
1313 git_repository_free(sub_repo);
1314
1315 return error;
1316}
1317
8286300a 1318int git_submodule_init(git_submodule *sm, int overwrite)
aa13bf05
RB
1319{
1320 int error;
f9775a37 1321 const char *val;
b2ab887e 1322 git_buf key = GIT_BUF_INIT, effective_submodule_url = GIT_BUF_INIT;
8286300a 1323 git_config *cfg = NULL;
aa13bf05 1324
8286300a 1325 if (!sm->url) {
aa13bf05 1326 giterr_set(GITERR_SUBMODULE,
909d5494 1327 "no URL configured for submodule '%s'", sm->name);
aa13bf05
RB
1328 return -1;
1329 }
1330
8286300a 1331 if ((error = git_repository_config(&cfg, sm->repo)) < 0)
aa13bf05
RB
1332 return error;
1333
8286300a
RB
1334 /* write "submodule.NAME.url" */
1335
9d1f97df 1336 if ((error = git_submodule_resolve_url(&effective_submodule_url, sm->repo, sm->url)) < 0 ||
b2ab887e 1337 (error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
8286300a 1338 (error = git_config__update_entry(
b2ab887e 1339 cfg, key.ptr, effective_submodule_url.ptr, overwrite != 0, false)) < 0)
8286300a
RB
1340 goto cleanup;
1341
aa13bf05
RB
1342 /* write "submodule.NAME.update" if not default */
1343
8286300a
RB
1344 val = (sm->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ?
1345 NULL : git_submodule_update_to_str(sm->update);
1346
1347 if ((error = git_buf_printf(&key, "submodule.%s.update", sm->name)) < 0 ||
1348 (error = git_config__update_entry(
1349 cfg, key.ptr, val, overwrite != 0, false)) < 0)
1350 goto cleanup;
1351
1352 /* success */
1353
1354cleanup:
1355 git_config_free(cfg);
1356 git_buf_free(&key);
b2ab887e 1357 git_buf_free(&effective_submodule_url);
aa13bf05
RB
1358
1359 return error;
1360}
1361
8286300a 1362int git_submodule_sync(git_submodule *sm)
aa13bf05 1363{
8286300a
RB
1364 int error = 0;
1365 git_config *cfg = NULL;
1366 git_buf key = GIT_BUF_INIT;
e402d2f1 1367 git_repository *smrepo = NULL;
8286300a
RB
1368
1369 if (!sm->url) {
aa13bf05 1370 giterr_set(GITERR_SUBMODULE,
909d5494 1371 "no URL configured for submodule '%s'", sm->name);
aa13bf05
RB
1372 return -1;
1373 }
1374
1375 /* copy URL over to config only if it already exists */
1376
8286300a
RB
1377 if (!(error = git_repository_config__weakptr(&cfg, sm->repo)) &&
1378 !(error = git_buf_printf(&key, "submodule.%s.url", sm->name)))
1379 error = git_config__update_entry(cfg, key.ptr, sm->url, true, true);
1380
1381 /* if submodule exists in the working directory, update remote url */
1382
e402d2f1
RB
1383 if (!error &&
1384 (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) != 0 &&
1385 !(error = git_submodule_open(&smrepo, sm)))
1386 {
eedeeb9e
RB
1387 git_buf remote_name = GIT_BUF_INIT;
1388
1389 if ((error = git_repository_config__weakptr(&cfg, smrepo)) < 0)
1390 /* return error from reading submodule config */;
1391 else if ((error = lookup_head_remote_key(&remote_name, smrepo)) < 0) {
e402d2f1 1392 giterr_clear();
e6903ea2 1393 error = git_buf_sets(&key, "remote.origin.url");
eedeeb9e
RB
1394 } else {
1395 error = git_buf_join3(
e6903ea2 1396 &key, '.', "remote", remote_name.ptr, "url");
eedeeb9e 1397 git_buf_free(&remote_name);
8286300a
RB
1398 }
1399
eedeeb9e
RB
1400 if (!error)
1401 error = git_config__update_entry(cfg, key.ptr, sm->url, true, false);
8286300a 1402
8286300a
RB
1403 git_repository_free(smrepo);
1404 }
1405
1406 git_buf_free(&key);
1407
1408 return error;
aa13bf05
RB
1409}
1410
1aad6137
RB
1411static int git_submodule__open(
1412 git_repository **subrepo, git_submodule *sm, bool bare)
aa13bf05
RB
1413{
1414 int error;
1415 git_buf path = GIT_BUF_INIT;
1aad6137
RB
1416 unsigned int flags = GIT_REPOSITORY_OPEN_NO_SEARCH;
1417 const char *wd;
aa13bf05 1418
1aad6137 1419 assert(sm && subrepo);
aa13bf05 1420
1aad6137
RB
1421 if (git_repository__ensure_not_bare(
1422 sm->repo, "open submodule repository") < 0)
1423 return GIT_EBAREREPO;
aa13bf05 1424
1aad6137 1425 wd = git_repository_workdir(sm->repo);
aa13bf05 1426
1aad6137
RB
1427 if (git_buf_joinpath(&path, wd, sm->path) < 0 ||
1428 git_buf_joinpath(&path, path.ptr, DOT_GIT) < 0)
aa13bf05
RB
1429 return -1;
1430
1aad6137
RB
1431 sm->flags = sm->flags &
1432 ~(GIT_SUBMODULE_STATUS_IN_WD |
1433 GIT_SUBMODULE_STATUS__WD_OID_VALID |
1434 GIT_SUBMODULE_STATUS__WD_SCANNED);
aa13bf05 1435
1aad6137
RB
1436 if (bare)
1437 flags |= GIT_REPOSITORY_OPEN_BARE;
aa13bf05 1438
1aad6137 1439 error = git_repository_open_ext(subrepo, path.ptr, flags, wd);
e807860f 1440
1aad6137
RB
1441 /* if we opened the submodule successfully, grab HEAD OID, etc. */
1442 if (!error) {
1443 sm->flags |= GIT_SUBMODULE_STATUS_IN_WD |
1444 GIT_SUBMODULE_STATUS__WD_SCANNED;
e807860f 1445
1aad6137
RB
1446 if (!git_reference_name_to_id(&sm->wd_oid, *subrepo, GIT_HEAD_FILE))
1447 sm->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID;
1448 else
1449 giterr_clear();
1450 } else if (git_path_exists(path.ptr)) {
1451 sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED |
1452 GIT_SUBMODULE_STATUS_IN_WD;
1453 } else {
1454 git_buf_rtruncate_at_char(&path, '/'); /* remove "/.git" */
e807860f 1455
1aad6137
RB
1456 if (git_path_isdir(path.ptr))
1457 sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
1458 }
e807860f 1459
1aad6137 1460 git_buf_free(&path);
e807860f 1461
1aad6137
RB
1462 return error;
1463}
e807860f 1464
1aad6137
RB
1465int git_submodule_open_bare(git_repository **subrepo, git_submodule *sm)
1466{
1467 return git_submodule__open(subrepo, sm, true);
1468}
aa13bf05 1469
1aad6137
RB
1470int git_submodule_open(git_repository **subrepo, git_submodule *sm)
1471{
1472 return git_submodule__open(subrepo, sm, false);
aa13bf05
RB
1473}
1474
1aad6137
RB
1475static void submodule_update_from_index_entry(
1476 git_submodule *sm, const git_index_entry *ie)
aa13bf05 1477{
1aad6137 1478 bool already_found = (sm->flags & GIT_SUBMODULE_STATUS_IN_INDEX) != 0;
aa13bf05 1479
1aad6137
RB
1480 if (!S_ISGITLINK(ie->mode)) {
1481 if (!already_found)
1482 sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
1483 } else {
1484 if (already_found)
1485 sm->flags |= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
1486 else
d541170c 1487 git_oid_cpy(&sm->index_oid, &ie->id);
aa13bf05 1488
1aad6137
RB
1489 sm->flags |= GIT_SUBMODULE_STATUS_IN_INDEX |
1490 GIT_SUBMODULE_STATUS__INDEX_OID_VALID;
1491 }
1492}
1493
1494static int submodule_update_index(git_submodule *sm)
1495{
1496 git_index *index;
1497 const git_index_entry *ie;
aa13bf05 1498
1aad6137 1499 if (git_repository_index__weakptr(&index, sm->repo) < 0)
aa13bf05
RB
1500 return -1;
1501
1aad6137 1502 sm->flags = sm->flags &
5f4a61ae
RB
1503 ~(GIT_SUBMODULE_STATUS_IN_INDEX |
1504 GIT_SUBMODULE_STATUS__INDEX_OID_VALID);
1505
1aad6137
RB
1506 if (!(ie = git_index_get_bypath(index, sm->path, 0)))
1507 return 0;
aa13bf05 1508
1aad6137
RB
1509 submodule_update_from_index_entry(sm, ie);
1510
1511 return 0;
1512}
1513
1514static void submodule_update_from_head_data(
1515 git_submodule *sm, mode_t mode, const git_oid *id)
1516{
1517 if (!S_ISGITLINK(mode))
1518 sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
1519 else {
1520 git_oid_cpy(&sm->head_oid, id);
1521
1522 sm->flags |= GIT_SUBMODULE_STATUS_IN_HEAD |
1523 GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
aa13bf05 1524 }
1aad6137 1525}
aa13bf05 1526
1aad6137
RB
1527static int submodule_update_head(git_submodule *submodule)
1528{
1529 git_tree *head = NULL;
b3a559dd 1530 git_tree_entry *te = NULL;
aa13bf05 1531
1aad6137
RB
1532 submodule->flags = submodule->flags &
1533 ~(GIT_SUBMODULE_STATUS_IN_HEAD |
1534 GIT_SUBMODULE_STATUS__HEAD_OID_VALID);
aa13bf05 1535
1aad6137
RB
1536 /* if we can't look up file in current head, then done */
1537 if (git_repository_head_tree(&head, submodule->repo) < 0 ||
1538 git_tree_entry_bypath(&te, head, submodule->path) < 0)
1539 giterr_clear();
1540 else
60a194aa 1541 submodule_update_from_head_data(submodule, te->attr, git_tree_entry_id(te));
aa13bf05 1542
b3a559dd 1543 git_tree_entry_free(te);
1aad6137
RB
1544 git_tree_free(head);
1545 return 0;
1546}
5f4a61ae 1547
69b6ffc4 1548int git_submodule_reload(git_submodule *sm, int force)
1aad6137 1549{
4b3ec53c 1550 int error = 0, isvalid;
f17525b0 1551 git_config *mods;
aa13bf05 1552
a15c7802
RB
1553 GIT_UNUSED(force);
1554
69b6ffc4
RB
1555 assert(sm);
1556
4b3ec53c
XL
1557 isvalid = git_submodule_name_is_valid(sm->repo, sm->name, 0);
1558 if (isvalid <= 0) {
1559 /* This should come with a warning, but we've no API for that */
1560 return isvalid;
1561 }
1562
f4b02671
ET
1563 if (!git_repository_is_bare(sm->repo)) {
1564 /* refresh config data */
4b3ec53c
XL
1565 if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND)
1566 return error;
f4b02671
ET
1567 if (mods != NULL) {
1568 error = submodule_read_config(sm, mods);
1569 git_config_free(mods);
aa13bf05 1570
f4b02671
ET
1571 if (error < 0)
1572 return error;
1573 }
591e8295 1574
f4b02671
ET
1575 /* refresh wd data */
1576 sm->flags &=
1577 ~(GIT_SUBMODULE_STATUS_IN_WD |
1578 GIT_SUBMODULE_STATUS__WD_OID_VALID |
1579 GIT_SUBMODULE_STATUS__WD_FLAGS);
aa13bf05 1580
f4b02671 1581 error = submodule_load_from_wd_lite(sm);
96869a4e 1582 }
5f4a61ae 1583
f4b02671
ET
1584 if (error == 0 && (error = submodule_update_index(sm)) == 0)
1585 error = submodule_update_head(sm);
5f4a61ae 1586
f4b02671 1587 return error;
aa13bf05
RB
1588}
1589
1aad6137
RB
1590static void submodule_copy_oid_maybe(
1591 git_oid *tgt, const git_oid *src, bool valid)
aa13bf05 1592{
1aad6137
RB
1593 if (tgt) {
1594 if (valid)
1595 memcpy(tgt, src, sizeof(*tgt));
1596 else
1597 memset(tgt, 0, sizeof(*tgt));
1598 }
1599}
5f4a61ae 1600
1aad6137
RB
1601int git_submodule__status(
1602 unsigned int *out_status,
1603 git_oid *out_head_id,
1604 git_oid *out_index_id,
1605 git_oid *out_wd_id,
1606 git_submodule *sm,
1607 git_submodule_ignore_t ign)
1608{
1609 unsigned int status;
1610 git_repository *smrepo = NULL;
aa13bf05 1611
c2418f46 1612 if (ign == GIT_SUBMODULE_IGNORE_UNSPECIFIED)
1aad6137 1613 ign = sm->ignore;
0c8858de 1614
1aad6137
RB
1615 /* only return location info if ignore == all */
1616 if (ign == GIT_SUBMODULE_IGNORE_ALL) {
1617 *out_status = (sm->flags & GIT_SUBMODULE_STATUS__IN_FLAGS);
1618 return 0;
5f4a61ae 1619 }
aa13bf05 1620
673dff88
BP
1621 /* If the user has requested caching submodule state, performing these
1622 * expensive operations (especially `submodule_update_head`, which is
1623 * bottlenecked on `git_repository_head_tree`) eliminates much of the
1624 * advantage. We will, therefore, interpret the request for caching to
1625 * apply here to and skip them.
1626 */
1aad6137 1627
673dff88
BP
1628 if (sm->repo->submodule_cache == NULL) {
1629 /* refresh the index OID */
1630 if (submodule_update_index(sm) < 0)
1631 return -1;
1632
1633 /* refresh the HEAD OID */
1634 if (submodule_update_head(sm) < 0)
1635 return -1;
1636 }
aa13bf05 1637
1aad6137
RB
1638 /* for ignore == dirty, don't scan the working directory */
1639 if (ign == GIT_SUBMODULE_IGNORE_DIRTY) {
1640 /* git_submodule_open_bare will load WD OID data */
1641 if (git_submodule_open_bare(&smrepo, sm) < 0)
1642 giterr_clear();
1643 else
1644 git_repository_free(smrepo);
1645 smrepo = NULL;
1646 } else if (git_submodule_open(&smrepo, sm) < 0) {
1647 giterr_clear();
1648 smrepo = NULL;
1649 }
1650
1651 status = GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(sm->flags);
1652
1653 submodule_get_index_status(&status, sm);
1654 submodule_get_wd_status(&status, sm, smrepo, ign);
1655
1656 git_repository_free(smrepo);
1657
1658 *out_status = status;
1659
1660 submodule_copy_oid_maybe(out_head_id, &sm->head_oid,
1661 (sm->flags & GIT_SUBMODULE_STATUS__HEAD_OID_VALID) != 0);
1662 submodule_copy_oid_maybe(out_index_id, &sm->index_oid,
1663 (sm->flags & GIT_SUBMODULE_STATUS__INDEX_OID_VALID) != 0);
1664 submodule_copy_oid_maybe(out_wd_id, &sm->wd_oid,
1665 (sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) != 0);
1666
1667 return 0;
aa13bf05
RB
1668}
1669
c6f489c9 1670int git_submodule_status(unsigned int *status, git_repository *repo, const char *name, git_submodule_ignore_t ignore)
a9a73007 1671{
64bbd47a
CMN
1672 git_submodule *sm;
1673 int error;
1674
1675 assert(status && repo && name);
1676
1677 if ((error = git_submodule_lookup(&sm, repo, name)) < 0)
1678 return error;
1679
c6f489c9 1680 error = git_submodule__status(status, NULL, NULL, NULL, sm, ignore);
64bbd47a 1681 git_submodule_free(sm);
a9a73007 1682
64bbd47a 1683 return error;
1aad6137 1684}
a9a73007 1685
1aad6137
RB
1686int git_submodule_location(unsigned int *location, git_submodule *sm)
1687{
1688 assert(location && sm);
1689
1690 return git_submodule__status(
1691 location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL);
a9a73007
RB
1692}
1693
aa13bf05
RB
1694/*
1695 * INTERNAL FUNCTIONS
1696 */
1697
69b6ffc4 1698static int submodule_alloc(
dfda2f68 1699 git_submodule **out, git_repository *repo, const char *name)
bfc9ca59 1700{
1aad6137 1701 size_t namelen;
0c8858de 1702 git_submodule *sm;
bfc9ca59 1703
1aad6137 1704 if (!name || !(namelen = strlen(name))) {
909d5494 1705 giterr_set(GITERR_SUBMODULE, "invalid submodule name");
69b6ffc4 1706 return -1;
bfc9ca59
RB
1707 }
1708
b8df28a5 1709 sm = git__calloc(1, sizeof(git_submodule));
69b6ffc4 1710 GITERR_CHECK_ALLOC(sm);
0c8858de 1711
1aad6137
RB
1712 sm->name = sm->path = git__strdup(name);
1713 if (!sm->name) {
1714 git__free(sm);
69b6ffc4 1715 return -1;
1aad6137 1716 }
aa13bf05 1717
1aad6137 1718 GIT_REFCOUNT_INC(sm);
f9775a37
RB
1719 sm->ignore = sm->ignore_default = GIT_SUBMODULE_IGNORE_NONE;
1720 sm->update = sm->update_default = GIT_SUBMODULE_UPDATE_CHECKOUT;
c0644c3f 1721 sm->fetch_recurse = sm->fetch_recurse_default = GIT_SUBMODULE_RECURSE_NO;
dfda2f68 1722 sm->repo = repo;
10311979 1723 sm->branch = NULL;
f9775a37 1724
69b6ffc4
RB
1725 *out = sm;
1726 return 0;
aa13bf05
RB
1727}
1728
1aad6137 1729static void submodule_release(git_submodule *sm)
aa13bf05
RB
1730{
1731 if (!sm)
1732 return;
1733
eeeb9654 1734 if (sm->repo) {
69b6ffc4 1735 sm->repo = NULL;
591e8295
RB
1736 }
1737
1aad6137
RB
1738 if (sm->path != sm->name)
1739 git__free(sm->path);
1740 git__free(sm->name);
1741 git__free(sm->url);
acdc7cff 1742 git__free(sm->branch);
1aad6137
RB
1743 git__memzero(sm, sizeof(*sm));
1744 git__free(sm);
1745}
aa13bf05 1746
1aad6137
RB
1747void git_submodule_free(git_submodule *sm)
1748{
1749 if (!sm)
1750 return;
1751 GIT_REFCOUNT_DEC(sm, submodule_release);
aa13bf05
RB
1752}
1753
0c8858de
RB
1754static int submodule_config_error(const char *property, const char *value)
1755{
1756 giterr_set(GITERR_INVALID,
909d5494 1757 "invalid value for submodule '%s' property: '%s'", property, value);
0c8858de 1758 return -1;
bfc9ca59
RB
1759}
1760
f9775a37
RB
1761int git_submodule_parse_ignore(git_submodule_ignore_t *out, const char *value)
1762{
1763 int val;
1764
1765 if (git_config_lookup_map_value(
1766 &val, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value) < 0) {
1767 *out = GIT_SUBMODULE_IGNORE_NONE;
1768 return submodule_config_error("ignore", value);
1769 }
1770
1771 *out = (git_submodule_ignore_t)val;
1772 return 0;
1773}
1774
1775int git_submodule_parse_update(git_submodule_update_t *out, const char *value)
1776{
1777 int val;
1778
1779 if (git_config_lookup_map_value(
1780 &val, _sm_update_map, ARRAY_SIZE(_sm_update_map), value) < 0) {
1781 *out = GIT_SUBMODULE_UPDATE_CHECKOUT;
1782 return submodule_config_error("update", value);
1783 }
1784
1785 *out = (git_submodule_update_t)val;
1786 return 0;
1787}
1788
fccadba2
L
1789int git_submodule_parse_recurse(git_submodule_recurse_t *out, const char *value)
1790{
1791 int val;
1792
1793 if (git_config_lookup_map_value(
1794 &val, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), value) < 0) {
1795 *out = GIT_SUBMODULE_RECURSE_YES;
1796 return submodule_config_error("recurse", value);
1797 }
1798
1799 *out = (git_submodule_recurse_t)val;
1800 return 0;
1801}
1802
f17525b0 1803static int get_value(const char **out, git_config *cfg, git_buf *buf, const char *name, const char *field)
bfc9ca59 1804{
f17525b0 1805 int error;
bfc9ca59 1806
f17525b0 1807 git_buf_clear(buf);
bfc9ca59 1808
f17525b0
CMN
1809 if ((error = git_buf_printf(buf, "submodule.%s.%s", name, field)) < 0 ||
1810 (error = git_config_get_string(out, cfg, buf->ptr)) < 0)
1811 return error;
dfda2f68 1812
f17525b0
CMN
1813 return error;
1814}
dfda2f68 1815
f17525b0
CMN
1816static int submodule_read_config(git_submodule *sm, git_config *cfg)
1817{
1818 git_buf key = GIT_BUF_INIT;
1819 const char *value;
1820 int error, in_config = 0;
aa13bf05 1821
f17525b0
CMN
1822 /*
1823 * TODO: Look up path in index and if it is present but not a GITLINK
1824 * then this should be deleted (at least to match git's behavior)
0c8858de 1825 */
01fed0a8 1826
f17525b0
CMN
1827 if ((error = get_value(&value, cfg, &key, sm->name, "path")) == 0) {
1828 in_config = 1;
1829 /*
1830 * TODO: if case insensitive filesystem, then the following strcmp
0c8858de
RB
1831 * should be strcasecmp
1832 */
f17525b0 1833 if (strcmp(sm->name, value) != 0) {
5c5df666
CMN
1834 if (sm->path != sm->name)
1835 git__free(sm->path);
f17525b0
CMN
1836 sm->path = git__strdup(value);
1837 GITERR_CHECK_ALLOC(sm->path);
96869a4e 1838 }
f17525b0 1839 } else if (error != GIT_ENOTFOUND) {
ab8f2c66 1840 goto cleanup;
bfc9ca59 1841 }
96869a4e 1842
f17525b0
CMN
1843 if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) {
1844 in_config = 1;
1845 sm->url = git__strdup(value);
1846 GITERR_CHECK_ALLOC(sm->url);
1847 } else if (error != GIT_ENOTFOUND) {
ab8f2c66 1848 goto cleanup;
4ece3e22
RB
1849 }
1850
f17525b0
CMN
1851 if ((error = get_value(&value, cfg, &key, sm->name, "branch")) == 0) {
1852 in_config = 1;
1853 sm->branch = git__strdup(value);
1854 GITERR_CHECK_ALLOC(sm->branch);
1855 } else if (error != GIT_ENOTFOUND) {
ab8f2c66 1856 goto cleanup;
bfc9ca59 1857 }
10311979 1858
f17525b0
CMN
1859 if ((error = get_value(&value, cfg, &key, sm->name, "update")) == 0) {
1860 in_config = 1;
96869a4e 1861 if ((error = git_submodule_parse_update(&sm->update, value)) < 0)
ab8f2c66 1862 goto cleanup;
f9775a37 1863 sm->update_default = sm->update;
f17525b0 1864 } else if (error != GIT_ENOTFOUND) {
ab8f2c66 1865 goto cleanup;
bfc9ca59 1866 }
f17525b0
CMN
1867
1868 if ((error = get_value(&value, cfg, &key, sm->name, "fetchRecurseSubmodules")) == 0) {
1869 in_config = 1;
591e8295 1870 if ((error = git_submodule_parse_recurse(&sm->fetch_recurse, value)) < 0)
ab8f2c66 1871 goto cleanup;
c0644c3f 1872 sm->fetch_recurse_default = sm->fetch_recurse;
f17525b0 1873 } else if (error != GIT_ENOTFOUND) {
ab8f2c66 1874 goto cleanup;
bfc9ca59 1875 }
f17525b0
CMN
1876
1877 if ((error = get_value(&value, cfg, &key, sm->name, "ignore")) == 0) {
1878 in_config = 1;
96869a4e 1879 if ((error = git_submodule_parse_ignore(&sm->ignore, value)) < 0)
ab8f2c66 1880 goto cleanup;
f9775a37 1881 sm->ignore_default = sm->ignore;
f17525b0 1882 } else if (error != GIT_ENOTFOUND) {
ab8f2c66 1883 goto cleanup;
bfc9ca59 1884 }
f17525b0
CMN
1885
1886 if (in_config)
1887 sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
1888
ab8f2c66
CMN
1889 error = 0;
1890
1891cleanup:
1892 git_buf_free(&key);
1893 return error;
f17525b0
CMN
1894}
1895
1896static int submodule_load_each(const git_config_entry *entry, void *payload)
1897{
1898 lfc_data *data = payload;
1899 const char *namestart, *property;
1900 git_strmap_iter pos;
1901 git_strmap *map = data->map;
1902 git_buf name = GIT_BUF_INIT;
1903 git_submodule *sm;
4b3ec53c 1904 int error, isvalid;
f17525b0
CMN
1905
1906 if (git__prefixcmp(entry->name, "submodule.") != 0)
1907 return 0;
1908
1909 namestart = entry->name + strlen("submodule.");
1910 property = strrchr(namestart, '.');
1911
1912 if (!property || (property == namestart))
1913 return 0;
1914
1915 property++;
1916
1917 if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0)
1918 return error;
1919
4b3ec53c
XL
1920 isvalid = git_submodule_name_is_valid(data->repo, name.ptr, 0);
1921 if (isvalid <= 0) {
1922 error = isvalid;
1923 goto done;
1924 }
1925
f17525b0
CMN
1926 /*
1927 * Now that we have the submodule's name, we can use that to
1928 * figure out whether it's in the map. If it's not, we create
1929 * a new submodule, load the config and insert it. If it's
1930 * already inserted, we've already loaded it, so we skip.
1931 */
1932 pos = git_strmap_lookup_index(map, name.ptr);
ab8f2c66
CMN
1933 if (git_strmap_valid_index(map, pos)) {
1934 error = 0;
1935 goto done;
1936 }
f17525b0
CMN
1937
1938 if ((error = submodule_alloc(&sm, data->repo, name.ptr)) < 0)
1939 goto done;
1940
1941 if ((error = submodule_read_config(sm, data->mods)) < 0) {
1942 git_submodule_free(sm);
1943 goto done;
1944 }
1945
73028af8 1946 git_strmap_insert(map, sm->name, sm, &error);
f17525b0
CMN
1947 assert(error != 0);
1948 if (error < 0)
1949 goto done;
1950
1951 error = 0;
bfc9ca59 1952
96869a4e
RB
1953done:
1954 git_buf_free(&name);
25e0b157 1955 return error;
bfc9ca59
RB
1956}
1957
591e8295 1958static int submodule_load_from_wd_lite(git_submodule *sm)
aa13bf05 1959{
aa13bf05
RB
1960 git_buf path = GIT_BUF_INIT;
1961
1aad6137 1962 if (git_buf_joinpath(&path, git_repository_workdir(sm->repo), sm->path) < 0)
25e0b157 1963 return -1;
aa13bf05
RB
1964
1965 if (git_path_isdir(path.ptr))
1966 sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
1967
1968 if (git_path_contains(&path, DOT_GIT))
1969 sm->flags |= GIT_SUBMODULE_STATUS_IN_WD;
1970
1971 git_buf_free(&path);
aa13bf05
RB
1972 return 0;
1973}
1974
f17525b0 1975/**
4b3ec53c 1976 * Requests a snapshot of $WORK_TREE/.gitmodules.
f17525b0 1977 *
4b3ec53c 1978 * Returns GIT_ENOTFOUND in case no .gitmodules file exist
f17525b0 1979 */
4b3ec53c 1980static int gitmodules_snapshot(git_config **snap, git_repository *repo)
f17525b0
CMN
1981{
1982 const char *workdir = git_repository_workdir(repo);
4b3ec53c 1983 git_config *mods = NULL;
f17525b0 1984 git_buf path = GIT_BUF_INIT;
4b3ec53c 1985 int error;
f17525b0 1986
4b3ec53c
XL
1987 if (!workdir)
1988 return GIT_ENOTFOUND;
f17525b0 1989
4b3ec53c
XL
1990 if ((error = git_buf_joinpath(&path, workdir, GIT_MODULES_FILE)) < 0)
1991 return error;
f17525b0 1992
4b3ec53c
XL
1993 if ((error = git_config_open_ondisk(&mods, path.ptr)) < 0)
1994 goto cleanup;
1995
1996 if ((error = git_config_snapshot(snap, mods)) < 0)
1997 goto cleanup;
f17525b0 1998
4b3ec53c
XL
1999 error = 0;
2000
2001cleanup:
2002 if (mods)
f17525b0 2003 git_config_free(mods);
4b3ec53c 2004 git_buf_free(&path);
f17525b0 2005
4b3ec53c 2006 return error;
f17525b0
CMN
2007}
2008
54b2a37a 2009static git_config_backend *open_gitmodules(
dfda2f68 2010 git_repository *repo,
a4ccd2b0 2011 int okay_to_create)
aa13bf05 2012{
dfda2f68 2013 const char *workdir = git_repository_workdir(repo);
aa13bf05 2014 git_buf path = GIT_BUF_INIT;
54b2a37a 2015 git_config_backend *mods = NULL;
aa13bf05
RB
2016
2017 if (workdir != NULL) {
2018 if (git_buf_joinpath(&path, workdir, GIT_MODULES_FILE) != 0)
2019 return NULL;
2020
2021 if (okay_to_create || git_path_isfile(path.ptr)) {
2022 /* git_config_file__ondisk should only fail if OOM */
2023 if (git_config_file__ondisk(&mods, path.ptr) < 0)
0c8858de 2024 mods = NULL;
aa13bf05 2025 /* open should only fail here if the file is malformed */
eae0bfdc 2026 else if (git_config_file_open(mods, GIT_CONFIG_LEVEL_LOCAL, repo) < 0) {
aa13bf05
RB
2027 git_config_file_free(mods);
2028 mods = NULL;
2029 }
bfc9ca59 2030 }
bfc9ca59
RB
2031 }
2032
0c8858de
RB
2033 git_buf_free(&path);
2034
aa13bf05
RB
2035 return mods;
2036}
2037
18cc7d28
RB
2038/* Lookup name of remote of the local tracking branch HEAD points to */
2039static int lookup_head_remote_key(git_buf *remote_name, git_repository *repo)
bfc9ca59 2040{
aa13bf05 2041 int error;
18cc7d28
RB
2042 git_reference *head = NULL;
2043 git_buf upstream_name = GIT_BUF_INIT;
2044
2045 /* lookup and dereference HEAD */
2046 if ((error = git_repository_head(&head, repo)) < 0)
2047 return error;
2048
9d1f97df
JM
2049 /**
2050 * If head does not refer to a branch, then return
2051 * GIT_ENOTFOUND to indicate that we could not find
2052 * a remote key for the local tracking branch HEAD points to.
2053 **/
2054 if (!git_reference_is_branch(head)) {
2055 giterr_set(GITERR_INVALID,
2056 "HEAD does not refer to a branch.");
2057 error = GIT_ENOTFOUND;
2058 goto done;
2059 }
2060
18cc7d28 2061 /* lookup remote tracking branch of HEAD */
9d1f97df
JM
2062 if ((error = git_branch_upstream_name(
2063 &upstream_name,
2064 repo,
2065 git_reference_name(head))) < 0)
2066 goto done;
18cc7d28 2067
9d1f97df
JM
2068 /* lookup remote of remote tracking branch */
2069 if ((error = git_branch_remote_name(remote_name, repo, upstream_name.ptr)) < 0)
2070 goto done;
aa13bf05 2071
9d1f97df
JM
2072done:
2073 git_buf_free(&upstream_name);
18cc7d28 2074 git_reference_free(head);
bfc9ca59 2075
f2fb4bac
JM
2076 return error;
2077}
e402d2f1 2078
18cc7d28
RB
2079/* Lookup the remote of the local tracking branch HEAD points to */
2080static int lookup_head_remote(git_remote **remote, git_repository *repo)
f2fb4bac
JM
2081{
2082 int error;
18cc7d28 2083 git_buf remote_name = GIT_BUF_INIT;
f2fb4bac 2084
18cc7d28
RB
2085 /* lookup remote of remote tracking branch name */
2086 if (!(error = lookup_head_remote_key(&remote_name, repo)))
209425ce 2087 error = git_remote_lookup(remote, repo, remote_name.ptr);
bfc9ca59 2088
18cc7d28 2089 git_buf_free(&remote_name);
aa13bf05 2090
f2fb4bac
JM
2091 return error;
2092}
aa13bf05 2093
18cc7d28
RB
2094/* Lookup remote, either from HEAD or fall back on origin */
2095static int lookup_default_remote(git_remote **remote, git_repository *repo)
f2fb4bac 2096{
18cc7d28 2097 int error = lookup_head_remote(remote, repo);
aa13bf05 2098
18cc7d28
RB
2099 /* if that failed, use 'origin' instead */
2100 if (error == GIT_ENOTFOUND)
209425ce 2101 error = git_remote_lookup(remote, repo, "origin");
aa13bf05 2102
18cc7d28
RB
2103 if (error == GIT_ENOTFOUND)
2104 giterr_set(
2105 GITERR_SUBMODULE,
909d5494 2106 "cannot get default remote for submodule - no local tracking "
18cc7d28 2107 "branch for HEAD and origin does not exist");
aa13bf05
RB
2108
2109 return error;
bfc9ca59
RB
2110}
2111
18cc7d28 2112static int get_url_base(git_buf *url, git_repository *repo)
e402d2f1
RB
2113{
2114 int error;
b0c9bc92 2115 git_worktree *wt = NULL;
18cc7d28 2116 git_remote *remote = NULL;
f2fb4bac 2117
b0c9bc92 2118 if ((error = lookup_default_remote(&remote, repo)) == 0) {
18cc7d28 2119 error = git_buf_sets(url, git_remote_url(remote));
b0c9bc92
PS
2120 goto out;
2121 } else if (error != GIT_ENOTFOUND)
2122 goto out;
2123 else
18cc7d28 2124 giterr_clear();
b0c9bc92
PS
2125
2126 /* if repository does not have a default remote, use workdir instead */
2127 if (git_repository_is_worktree(repo)) {
2128 if ((error = git_worktree_open_from_repository(&wt, repo)) < 0)
2129 goto out;
2130 error = git_buf_sets(url, wt->parent_path);
2131 } else
18cc7d28 2132 error = git_buf_sets(url, git_repository_workdir(repo));
b0c9bc92
PS
2133
2134out:
2135 git_remote_free(remote);
2136 git_worktree_free(wt);
e402d2f1 2137
e402d2f1
RB
2138 return error;
2139}
2140
1aad6137 2141static void submodule_get_index_status(unsigned int *status, git_submodule *sm)
aa13bf05 2142{
9cd42358
RB
2143 const git_oid *head_oid = git_submodule_head_id(sm);
2144 const git_oid *index_oid = git_submodule_index_id(sm);
aa13bf05 2145
1aad6137
RB
2146 *status = *status & ~GIT_SUBMODULE_STATUS__INDEX_FLAGS;
2147
5f4a61ae
RB
2148 if (!head_oid) {
2149 if (index_oid)
2150 *status |= GIT_SUBMODULE_STATUS_INDEX_ADDED;
2151 }
2152 else if (!index_oid)
2153 *status |= GIT_SUBMODULE_STATUS_INDEX_DELETED;
2154 else if (!git_oid_equal(head_oid, index_oid))
2155 *status |= GIT_SUBMODULE_STATUS_INDEX_MODIFIED;
aa13bf05
RB
2156}
2157
bc737620 2158
1aad6137
RB
2159static void submodule_get_wd_status(
2160 unsigned int *status,
2161 git_submodule *sm,
2162 git_repository *sm_repo,
2163 git_submodule_ignore_t ign)
bfc9ca59 2164{
1aad6137
RB
2165 const git_oid *index_oid = git_submodule_index_id(sm);
2166 const git_oid *wd_oid =
2167 (sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) ? &sm->wd_oid : NULL;
2168 git_tree *sm_head = NULL;
4bf630b6 2169 git_index *index = NULL;
1aad6137 2170 git_diff_options opt = GIT_DIFF_OPTIONS_INIT;
3ff1d123 2171 git_diff *diff;
bfc9ca59 2172
1aad6137 2173 *status = *status & ~GIT_SUBMODULE_STATUS__WD_FLAGS;
aa13bf05 2174
5f4a61ae
RB
2175 if (!index_oid) {
2176 if (wd_oid)
2177 *status |= GIT_SUBMODULE_STATUS_WD_ADDED;
aa13bf05 2178 }
5f4a61ae
RB
2179 else if (!wd_oid) {
2180 if ((sm->flags & GIT_SUBMODULE_STATUS__WD_SCANNED) != 0 &&
2181 (sm->flags & GIT_SUBMODULE_STATUS_IN_WD) == 0)
2182 *status |= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED;
2183 else
2184 *status |= GIT_SUBMODULE_STATUS_WD_DELETED;
aa13bf05 2185 }
5f4a61ae
RB
2186 else if (!git_oid_equal(index_oid, wd_oid))
2187 *status |= GIT_SUBMODULE_STATUS_WD_MODIFIED;
aa13bf05 2188
1aad6137
RB
2189 /* if we have no repo, then we're done */
2190 if (!sm_repo)
2191 return;
bfc9ca59 2192
1aad6137
RB
2193 /* the diffs below could be optimized with an early termination
2194 * option to the git_diff functions, but for now this is sufficient
2195 * (and certainly no worse that what core git does).
2196 */
bfc9ca59 2197
1aad6137
RB
2198 if (ign == GIT_SUBMODULE_IGNORE_NONE)
2199 opt.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
aa13bf05 2200
4bf630b6
RB
2201 (void)git_repository_index__weakptr(&index, sm_repo);
2202
605da51a 2203 /* if we don't have an unborn head, check diff with index */
1aad6137
RB
2204 if (git_repository_head_tree(&sm_head, sm_repo) < 0)
2205 giterr_clear();
2206 else {
2207 /* perform head to index diff on submodule */
4bf630b6 2208 if (git_diff_tree_to_index(&diff, sm_repo, sm_head, index, &opt) < 0)
1aad6137
RB
2209 giterr_clear();
2210 else {
5f69a31f 2211 if (git_diff_num_deltas(diff) > 0)
5f4a61ae 2212 *status |= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED;
3ff1d123 2213 git_diff_free(diff);
5f4a61ae
RB
2214 diff = NULL;
2215 }
aa13bf05 2216
5f4a61ae 2217 git_tree_free(sm_head);
1aad6137 2218 }
bfc9ca59 2219
1aad6137 2220 /* perform index-to-workdir diff on submodule */
4bf630b6 2221 if (git_diff_index_to_workdir(&diff, sm_repo, index, &opt) < 0)
1aad6137
RB
2222 giterr_clear();
2223 else {
2224 size_t untracked =
2225 git_diff_num_deltas_of_type(diff, GIT_DELTA_UNTRACKED);
bfc9ca59 2226
1aad6137
RB
2227 if (untracked > 0)
2228 *status |= GIT_SUBMODULE_STATUS_WD_UNTRACKED;
bfc9ca59 2229
1aad6137
RB
2230 if (git_diff_num_deltas(diff) != untracked)
2231 *status |= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED;
aa13bf05 2232
3ff1d123 2233 git_diff_free(diff);
1aad6137 2234 diff = NULL;
5f4a61ae 2235 }
bfc9ca59 2236}