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