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