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