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