abspath.h: move absolute path functions from cache.h
[git/debian.git] / submodule-config.c
blob38663801aa48c6cd8ade292fafab79d202205210
1 #include "cache.h"
2 #include "alloc.h"
3 #include "dir.h"
4 #include "gettext.h"
5 #include "hex.h"
6 #include "repository.h"
7 #include "config.h"
8 #include "submodule-config.h"
9 #include "submodule.h"
10 #include "strbuf.h"
11 #include "object-store.h"
12 #include "parse-options.h"
13 #include "tree-walk.h"
16 * submodule cache lookup structure
17 * There is one shared set of 'struct submodule' entries which can be
18 * looked up by their sha1 blob id of the .gitmodules file and either
19 * using path or name as key.
20 * for_path stores submodule entries with path as key
21 * for_name stores submodule entries with name as key
23 struct submodule_cache {
24 struct hashmap for_path;
25 struct hashmap for_name;
26 unsigned initialized:1;
27 unsigned gitmodules_read:1;
31 * thin wrapper struct needed to insert 'struct submodule' entries to
32 * the hashmap
34 struct submodule_entry {
35 struct hashmap_entry ent;
36 struct submodule *config;
39 enum lookup_type {
40 lookup_name,
41 lookup_path
44 static int config_path_cmp(const void *cmp_data UNUSED,
45 const struct hashmap_entry *eptr,
46 const struct hashmap_entry *entry_or_key,
47 const void *keydata UNUSED)
49 const struct submodule_entry *a, *b;
51 a = container_of(eptr, const struct submodule_entry, ent);
52 b = container_of(entry_or_key, const struct submodule_entry, ent);
54 return strcmp(a->config->path, b->config->path) ||
55 !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
58 static int config_name_cmp(const void *cmp_data UNUSED,
59 const struct hashmap_entry *eptr,
60 const struct hashmap_entry *entry_or_key,
61 const void *keydata UNUSED)
63 const struct submodule_entry *a, *b;
65 a = container_of(eptr, const struct submodule_entry, ent);
66 b = container_of(entry_or_key, const struct submodule_entry, ent);
68 return strcmp(a->config->name, b->config->name) ||
69 !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
72 static struct submodule_cache *submodule_cache_alloc(void)
74 return xcalloc(1, sizeof(struct submodule_cache));
77 static void submodule_cache_init(struct submodule_cache *cache)
79 hashmap_init(&cache->for_path, config_path_cmp, NULL, 0);
80 hashmap_init(&cache->for_name, config_name_cmp, NULL, 0);
81 cache->initialized = 1;
84 static void free_one_config(struct submodule_entry *entry)
86 free((void *) entry->config->path);
87 free((void *) entry->config->name);
88 free((void *) entry->config->branch);
89 free((void *) entry->config->update_strategy.command);
90 free(entry->config);
93 static void submodule_cache_clear(struct submodule_cache *cache)
95 struct hashmap_iter iter;
96 struct submodule_entry *entry;
98 if (!cache->initialized)
99 return;
102 * We iterate over the name hash here to be symmetric with the
103 * allocation of struct submodule entries. Each is allocated by
104 * their .gitmodules blob sha1 and submodule name.
106 hashmap_for_each_entry(&cache->for_name, &iter, entry,
107 ent /* member name */)
108 free_one_config(entry);
110 hashmap_clear_and_free(&cache->for_path, struct submodule_entry, ent);
111 hashmap_clear_and_free(&cache->for_name, struct submodule_entry, ent);
112 cache->initialized = 0;
113 cache->gitmodules_read = 0;
116 void submodule_cache_free(struct submodule_cache *cache)
118 submodule_cache_clear(cache);
119 free(cache);
122 static unsigned int hash_oid_string(const struct object_id *oid,
123 const char *string)
125 return memhash(oid->hash, the_hash_algo->rawsz) + strhash(string);
128 static void cache_put_path(struct submodule_cache *cache,
129 struct submodule *submodule)
131 unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
132 submodule->path);
133 struct submodule_entry *e = xmalloc(sizeof(*e));
134 hashmap_entry_init(&e->ent, hash);
135 e->config = submodule;
136 hashmap_put(&cache->for_path, &e->ent);
139 static void cache_remove_path(struct submodule_cache *cache,
140 struct submodule *submodule)
142 unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
143 submodule->path);
144 struct submodule_entry e;
145 struct submodule_entry *removed;
146 hashmap_entry_init(&e.ent, hash);
147 e.config = submodule;
148 removed = hashmap_remove_entry(&cache->for_path, &e, ent, NULL);
149 free(removed);
152 static void cache_add(struct submodule_cache *cache,
153 struct submodule *submodule)
155 unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,
156 submodule->name);
157 struct submodule_entry *e = xmalloc(sizeof(*e));
158 hashmap_entry_init(&e->ent, hash);
159 e->config = submodule;
160 hashmap_add(&cache->for_name, &e->ent);
163 static const struct submodule *cache_lookup_path(struct submodule_cache *cache,
164 const struct object_id *gitmodules_oid, const char *path)
166 struct submodule_entry *entry;
167 unsigned int hash = hash_oid_string(gitmodules_oid, path);
168 struct submodule_entry key;
169 struct submodule key_config;
171 oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
172 key_config.path = path;
174 hashmap_entry_init(&key.ent, hash);
175 key.config = &key_config;
177 entry = hashmap_get_entry(&cache->for_path, &key, ent, NULL);
178 if (entry)
179 return entry->config;
180 return NULL;
183 static struct submodule *cache_lookup_name(struct submodule_cache *cache,
184 const struct object_id *gitmodules_oid, const char *name)
186 struct submodule_entry *entry;
187 unsigned int hash = hash_oid_string(gitmodules_oid, name);
188 struct submodule_entry key;
189 struct submodule key_config;
191 oidcpy(&key_config.gitmodules_oid, gitmodules_oid);
192 key_config.name = name;
194 hashmap_entry_init(&key.ent, hash);
195 key.config = &key_config;
197 entry = hashmap_get_entry(&cache->for_name, &key, ent, NULL);
198 if (entry)
199 return entry->config;
200 return NULL;
203 int check_submodule_name(const char *name)
205 /* Disallow empty names */
206 if (!*name)
207 return -1;
210 * Look for '..' as a path component. Check is_xplatform_dir_sep() as
211 * separators rather than is_dir_sep(), because we want the name rules
212 * to be consistent across platforms.
214 goto in_component; /* always start inside component */
215 while (*name) {
216 char c = *name++;
217 if (is_xplatform_dir_sep(c)) {
218 in_component:
219 if (name[0] == '.' && name[1] == '.' &&
220 (!name[2] || is_xplatform_dir_sep(name[2])))
221 return -1;
225 return 0;
228 static int name_and_item_from_var(const char *var, struct strbuf *name,
229 struct strbuf *item)
231 const char *subsection, *key;
232 size_t subsection_len;
233 int parse;
234 parse = parse_config_key(var, "submodule", &subsection,
235 &subsection_len, &key);
236 if (parse < 0 || !subsection)
237 return 0;
239 strbuf_add(name, subsection, subsection_len);
240 if (check_submodule_name(name->buf) < 0) {
241 warning(_("ignoring suspicious submodule name: %s"), name->buf);
242 strbuf_release(name);
243 return 0;
246 strbuf_addstr(item, key);
248 return 1;
251 static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache,
252 const struct object_id *gitmodules_oid, const char *name)
254 struct submodule *submodule;
255 struct strbuf name_buf = STRBUF_INIT;
257 submodule = cache_lookup_name(cache, gitmodules_oid, name);
258 if (submodule)
259 return submodule;
261 submodule = xmalloc(sizeof(*submodule));
263 strbuf_addstr(&name_buf, name);
264 submodule->name = strbuf_detach(&name_buf, NULL);
266 submodule->path = NULL;
267 submodule->url = NULL;
268 submodule->update_strategy.type = SM_UPDATE_UNSPECIFIED;
269 submodule->update_strategy.command = NULL;
270 submodule->fetch_recurse = RECURSE_SUBMODULES_NONE;
271 submodule->ignore = NULL;
272 submodule->branch = NULL;
273 submodule->recommend_shallow = -1;
275 oidcpy(&submodule->gitmodules_oid, gitmodules_oid);
277 cache_add(cache, submodule);
279 return submodule;
282 static int parse_fetch_recurse(const char *opt, const char *arg,
283 int die_on_error)
285 switch (git_parse_maybe_bool(arg)) {
286 case 1:
287 return RECURSE_SUBMODULES_ON;
288 case 0:
289 return RECURSE_SUBMODULES_OFF;
290 default:
291 if (!strcmp(arg, "on-demand"))
292 return RECURSE_SUBMODULES_ON_DEMAND;
294 * Please update $__git_fetch_recurse_submodules in
295 * git-completion.bash when you add new options.
297 if (die_on_error)
298 die("bad %s argument: %s", opt, arg);
299 else
300 return RECURSE_SUBMODULES_ERROR;
304 int parse_submodule_fetchjobs(const char *var, const char *value)
306 int fetchjobs = git_config_int(var, value);
307 if (fetchjobs < 0)
308 die(_("negative values not allowed for submodule.fetchJobs"));
309 if (!fetchjobs)
310 fetchjobs = online_cpus();
311 return fetchjobs;
314 int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
316 return parse_fetch_recurse(opt, arg, 1);
319 int option_fetch_parse_recurse_submodules(const struct option *opt,
320 const char *arg, int unset)
322 int *v;
324 if (!opt->value)
325 return -1;
327 v = opt->value;
329 if (unset) {
330 *v = RECURSE_SUBMODULES_OFF;
331 } else {
332 if (arg)
333 *v = parse_fetch_recurse_submodules_arg(opt->long_name, arg);
334 else
335 *v = RECURSE_SUBMODULES_ON;
337 return 0;
340 static int parse_update_recurse(const char *opt, const char *arg,
341 int die_on_error)
343 switch (git_parse_maybe_bool(arg)) {
344 case 1:
345 return RECURSE_SUBMODULES_ON;
346 case 0:
347 return RECURSE_SUBMODULES_OFF;
348 default:
349 if (die_on_error)
350 die("bad %s argument: %s", opt, arg);
351 return RECURSE_SUBMODULES_ERROR;
355 int parse_update_recurse_submodules_arg(const char *opt, const char *arg)
357 return parse_update_recurse(opt, arg, 1);
360 static int parse_push_recurse(const char *opt, const char *arg,
361 int die_on_error)
363 switch (git_parse_maybe_bool(arg)) {
364 case 1:
365 /* There's no simple "on" value when pushing */
366 if (die_on_error)
367 die("bad %s argument: %s", opt, arg);
368 else
369 return RECURSE_SUBMODULES_ERROR;
370 case 0:
371 return RECURSE_SUBMODULES_OFF;
372 default:
373 if (!strcmp(arg, "on-demand"))
374 return RECURSE_SUBMODULES_ON_DEMAND;
375 else if (!strcmp(arg, "check"))
376 return RECURSE_SUBMODULES_CHECK;
377 else if (!strcmp(arg, "only"))
378 return RECURSE_SUBMODULES_ONLY;
380 * Please update $__git_push_recurse_submodules in
381 * git-completion.bash when you add new modes.
383 else if (die_on_error)
384 die("bad %s argument: %s", opt, arg);
385 else
386 return RECURSE_SUBMODULES_ERROR;
390 int parse_push_recurse_submodules_arg(const char *opt, const char *arg)
392 return parse_push_recurse(opt, arg, 1);
395 static void warn_multiple_config(const struct object_id *treeish_name,
396 const char *name, const char *option)
398 const char *commit_string = "WORKTREE";
399 if (treeish_name)
400 commit_string = oid_to_hex(treeish_name);
401 warning("%s:.gitmodules, multiple configurations found for "
402 "'submodule.%s.%s'. Skipping second one!",
403 commit_string, name, option);
406 static void warn_command_line_option(const char *var, const char *value)
408 warning(_("ignoring '%s' which may be interpreted as"
409 " a command-line option: %s"), var, value);
412 struct parse_config_parameter {
413 struct submodule_cache *cache;
414 const struct object_id *treeish_name;
415 const struct object_id *gitmodules_oid;
416 int overwrite;
420 * Parse a config item from .gitmodules.
422 * This does not handle submodule-related configuration from the main
423 * config store (.git/config, etc). Callers are responsible for
424 * checking for overrides in the main config store when appropriate.
426 static int parse_config(const char *var, const char *value, void *data)
428 struct parse_config_parameter *me = data;
429 struct submodule *submodule;
430 struct strbuf name = STRBUF_INIT, item = STRBUF_INIT;
431 int ret = 0;
433 /* this also ensures that we only parse submodule entries */
434 if (!name_and_item_from_var(var, &name, &item))
435 return 0;
437 submodule = lookup_or_create_by_name(me->cache,
438 me->gitmodules_oid,
439 name.buf);
441 if (!strcmp(item.buf, "path")) {
442 if (!value)
443 ret = config_error_nonbool(var);
444 else if (looks_like_command_line_option(value))
445 warn_command_line_option(var, value);
446 else if (!me->overwrite && submodule->path)
447 warn_multiple_config(me->treeish_name, submodule->name,
448 "path");
449 else {
450 if (submodule->path)
451 cache_remove_path(me->cache, submodule);
452 free((void *) submodule->path);
453 submodule->path = xstrdup(value);
454 cache_put_path(me->cache, submodule);
456 } else if (!strcmp(item.buf, "fetchrecursesubmodules")) {
457 /* when parsing worktree configurations we can die early */
458 int die_on_error = is_null_oid(me->gitmodules_oid);
459 if (!me->overwrite &&
460 submodule->fetch_recurse != RECURSE_SUBMODULES_NONE)
461 warn_multiple_config(me->treeish_name, submodule->name,
462 "fetchrecursesubmodules");
463 else
464 submodule->fetch_recurse = parse_fetch_recurse(
465 var, value,
466 die_on_error);
467 } else if (!strcmp(item.buf, "ignore")) {
468 if (!value)
469 ret = config_error_nonbool(var);
470 else if (!me->overwrite && submodule->ignore)
471 warn_multiple_config(me->treeish_name, submodule->name,
472 "ignore");
473 else if (strcmp(value, "untracked") &&
474 strcmp(value, "dirty") &&
475 strcmp(value, "all") &&
476 strcmp(value, "none"))
477 warning("Invalid parameter '%s' for config option "
478 "'submodule.%s.ignore'", value, name.buf);
479 else {
480 free((void *) submodule->ignore);
481 submodule->ignore = xstrdup(value);
483 } else if (!strcmp(item.buf, "url")) {
484 if (!value) {
485 ret = config_error_nonbool(var);
486 } else if (looks_like_command_line_option(value)) {
487 warn_command_line_option(var, value);
488 } else if (!me->overwrite && submodule->url) {
489 warn_multiple_config(me->treeish_name, submodule->name,
490 "url");
491 } else {
492 free((void *) submodule->url);
493 submodule->url = xstrdup(value);
495 } else if (!strcmp(item.buf, "update")) {
496 if (!value)
497 ret = config_error_nonbool(var);
498 else if (!me->overwrite &&
499 submodule->update_strategy.type != SM_UPDATE_UNSPECIFIED)
500 warn_multiple_config(me->treeish_name, submodule->name,
501 "update");
502 else if (parse_submodule_update_strategy(value,
503 &submodule->update_strategy) < 0 ||
504 submodule->update_strategy.type == SM_UPDATE_COMMAND)
505 die(_("invalid value for '%s'"), var);
506 } else if (!strcmp(item.buf, "shallow")) {
507 if (!me->overwrite && submodule->recommend_shallow != -1)
508 warn_multiple_config(me->treeish_name, submodule->name,
509 "shallow");
510 else
511 submodule->recommend_shallow =
512 git_config_bool(var, value);
513 } else if (!strcmp(item.buf, "branch")) {
514 if (!me->overwrite && submodule->branch)
515 warn_multiple_config(me->treeish_name, submodule->name,
516 "branch");
517 else {
518 free((void *)submodule->branch);
519 submodule->branch = xstrdup(value);
523 strbuf_release(&name);
524 strbuf_release(&item);
526 return ret;
529 static int gitmodule_oid_from_commit(const struct object_id *treeish_name,
530 struct object_id *gitmodules_oid,
531 struct strbuf *rev)
533 int ret = 0;
535 if (is_null_oid(treeish_name)) {
536 oidclr(gitmodules_oid);
537 return 1;
540 strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name));
541 if (get_oid(rev->buf, gitmodules_oid) >= 0)
542 ret = 1;
544 return ret;
547 /* This does a lookup of a submodule configuration by name or by path
548 * (key) with on-demand reading of the appropriate .gitmodules from
549 * revisions.
551 static const struct submodule *config_from(struct submodule_cache *cache,
552 const struct object_id *treeish_name, const char *key,
553 enum lookup_type lookup_type)
555 struct strbuf rev = STRBUF_INIT;
556 unsigned long config_size;
557 char *config = NULL;
558 struct object_id oid;
559 enum object_type type;
560 const struct submodule *submodule = NULL;
561 struct parse_config_parameter parameter;
564 * If any parameter except the cache is a NULL pointer just
565 * return the first submodule. Can be used to check whether
566 * there are any submodules parsed.
568 if (!treeish_name || !key) {
569 struct hashmap_iter iter;
570 struct submodule_entry *entry;
572 entry = hashmap_iter_first_entry(&cache->for_name, &iter,
573 struct submodule_entry,
574 ent /* member name */);
575 if (!entry)
576 return NULL;
577 return entry->config;
580 if (!gitmodule_oid_from_commit(treeish_name, &oid, &rev))
581 goto out;
583 switch (lookup_type) {
584 case lookup_name:
585 submodule = cache_lookup_name(cache, &oid, key);
586 break;
587 case lookup_path:
588 submodule = cache_lookup_path(cache, &oid, key);
589 break;
591 if (submodule)
592 goto out;
594 config = read_object_file(&oid, &type, &config_size);
595 if (!config || type != OBJ_BLOB)
596 goto out;
598 /* fill the submodule config into the cache */
599 parameter.cache = cache;
600 parameter.treeish_name = treeish_name;
601 parameter.gitmodules_oid = &oid;
602 parameter.overwrite = 0;
603 git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
604 config, config_size, &parameter, NULL);
605 strbuf_release(&rev);
606 free(config);
608 switch (lookup_type) {
609 case lookup_name:
610 return cache_lookup_name(cache, &oid, key);
611 case lookup_path:
612 return cache_lookup_path(cache, &oid, key);
613 default:
614 return NULL;
617 out:
618 strbuf_release(&rev);
619 free(config);
620 return submodule;
623 static void submodule_cache_check_init(struct repository *repo)
625 if (repo->submodule_cache && repo->submodule_cache->initialized)
626 return;
628 if (!repo->submodule_cache)
629 repo->submodule_cache = submodule_cache_alloc();
631 submodule_cache_init(repo->submodule_cache);
635 * Note: This function is private for a reason, the '.gitmodules' file should
636 * not be used as a mechanism to retrieve arbitrary configuration stored in
637 * the repository.
639 * Runs the provided config function on the '.gitmodules' file found in the
640 * working directory.
642 static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
644 if (repo->worktree) {
645 struct git_config_source config_source = {
646 0, .scope = CONFIG_SCOPE_SUBMODULE
648 const struct config_options opts = { 0 };
649 struct object_id oid;
650 char *file;
651 char *oidstr = NULL;
653 file = repo_worktree_path(repo, GITMODULES_FILE);
654 if (file_exists(file)) {
655 config_source.file = file;
656 } else if (repo_get_oid(repo, GITMODULES_INDEX, &oid) >= 0 ||
657 repo_get_oid(repo, GITMODULES_HEAD, &oid) >= 0) {
658 config_source.repo = repo;
659 config_source.blob = oidstr = xstrdup(oid_to_hex(&oid));
660 if (repo != the_repository)
661 add_submodule_odb_by_path(repo->objects->odb->path);
662 } else {
663 goto out;
666 config_with_options(fn, data, &config_source, &opts);
668 out:
669 free(oidstr);
670 free(file);
674 static int gitmodules_cb(const char *var, const char *value, void *data)
676 struct repository *repo = data;
677 struct parse_config_parameter parameter;
679 parameter.cache = repo->submodule_cache;
680 parameter.treeish_name = NULL;
681 parameter.gitmodules_oid = null_oid();
682 parameter.overwrite = 1;
684 return parse_config(var, value, &parameter);
687 void repo_read_gitmodules(struct repository *repo, int skip_if_read)
689 submodule_cache_check_init(repo);
691 if (repo->submodule_cache->gitmodules_read && skip_if_read)
692 return;
694 if (repo_read_index(repo) < 0)
695 return;
697 if (!is_gitmodules_unmerged(repo->index))
698 config_from_gitmodules(gitmodules_cb, repo, repo);
700 repo->submodule_cache->gitmodules_read = 1;
703 void gitmodules_config_oid(const struct object_id *commit_oid)
705 struct strbuf rev = STRBUF_INIT;
706 struct object_id oid;
708 submodule_cache_check_init(the_repository);
710 if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
711 git_config_from_blob_oid(gitmodules_cb, rev.buf,
712 the_repository, &oid, the_repository);
714 strbuf_release(&rev);
716 the_repository->submodule_cache->gitmodules_read = 1;
719 const struct submodule *submodule_from_name(struct repository *r,
720 const struct object_id *treeish_name,
721 const char *name)
723 repo_read_gitmodules(r, 1);
724 return config_from(r->submodule_cache, treeish_name, name, lookup_name);
727 const struct submodule *submodule_from_path(struct repository *r,
728 const struct object_id *treeish_name,
729 const char *path)
731 repo_read_gitmodules(r, 1);
732 return config_from(r->submodule_cache, treeish_name, path, lookup_path);
736 * Used internally by submodules_of_tree(). Recurses into 'treeish_name'
737 * and appends submodule entries to 'out'. The submodule_cache expects
738 * a root-level treeish_name and paths, so keep track of these values
739 * with 'root_tree' and 'prefix'.
741 static void traverse_tree_submodules(struct repository *r,
742 const struct object_id *root_tree,
743 char *prefix,
744 const struct object_id *treeish_name,
745 struct submodule_entry_list *out)
747 struct tree_desc tree;
748 struct submodule_tree_entry *st_entry;
749 struct name_entry *name_entry;
750 char *tree_path = NULL;
752 name_entry = xmalloc(sizeof(*name_entry));
754 fill_tree_descriptor(r, &tree, treeish_name);
755 while (tree_entry(&tree, name_entry)) {
756 if (prefix)
757 tree_path =
758 mkpathdup("%s/%s", prefix, name_entry->path);
759 else
760 tree_path = xstrdup(name_entry->path);
762 if (S_ISGITLINK(name_entry->mode) &&
763 is_tree_submodule_active(r, root_tree, tree_path)) {
764 ALLOC_GROW(out->entries, out->entry_nr + 1,
765 out->entry_alloc);
766 st_entry = &out->entries[out->entry_nr++];
768 st_entry->name_entry = xmalloc(sizeof(*st_entry->name_entry));
769 *st_entry->name_entry = *name_entry;
770 st_entry->submodule =
771 submodule_from_path(r, root_tree, tree_path);
772 st_entry->repo = xmalloc(sizeof(*st_entry->repo));
773 if (repo_submodule_init(st_entry->repo, r, tree_path,
774 root_tree))
775 FREE_AND_NULL(st_entry->repo);
777 } else if (S_ISDIR(name_entry->mode))
778 traverse_tree_submodules(r, root_tree, tree_path,
779 &name_entry->oid, out);
780 free(tree_path);
784 void submodules_of_tree(struct repository *r,
785 const struct object_id *treeish_name,
786 struct submodule_entry_list *out)
788 CALLOC_ARRAY(out->entries, 0);
789 out->entry_nr = 0;
790 out->entry_alloc = 0;
792 traverse_tree_submodules(r, treeish_name, NULL, treeish_name, out);
795 void submodule_free(struct repository *r)
797 if (r->submodule_cache)
798 submodule_cache_clear(r->submodule_cache);
801 static int config_print_callback(const char *var, const char *value, void *cb_data)
803 char *wanted_key = cb_data;
805 if (!strcmp(wanted_key, var))
806 printf("%s\n", value);
808 return 0;
811 int print_config_from_gitmodules(struct repository *repo, const char *key)
813 int ret;
814 char *store_key;
816 ret = git_config_parse_key(key, &store_key, NULL);
817 if (ret < 0)
818 return CONFIG_INVALID_KEY;
820 config_from_gitmodules(config_print_callback, repo, store_key);
822 free(store_key);
823 return 0;
826 int config_set_in_gitmodules_file_gently(const char *key, const char *value)
828 int ret;
830 ret = git_config_set_in_file_gently(GITMODULES_FILE, key, value);
831 if (ret < 0)
832 /* Maybe the user already did that, don't error out here */
833 warning(_("Could not update .gitmodules entry %s"), key);
835 return ret;
838 struct fetch_config {
839 int *max_children;
840 int *recurse_submodules;
843 static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
845 struct fetch_config *config = cb;
846 if (!strcmp(var, "submodule.fetchjobs")) {
847 if (config->max_children)
848 *(config->max_children) =
849 parse_submodule_fetchjobs(var, value);
850 return 0;
851 } else if (!strcmp(var, "fetch.recursesubmodules")) {
852 if (config->recurse_submodules)
853 *(config->recurse_submodules) =
854 parse_fetch_recurse_submodules_arg(var, value);
855 return 0;
858 return 0;
861 void fetch_config_from_gitmodules(int *max_children, int *recurse_submodules)
863 struct fetch_config config = {
864 .max_children = max_children,
865 .recurse_submodules = recurse_submodules
867 config_from_gitmodules(gitmodules_fetch_config, the_repository, &config);
870 static int gitmodules_update_clone_config(const char *var, const char *value,
871 void *cb)
873 int *max_jobs = cb;
874 if (!strcmp(var, "submodule.fetchjobs"))
875 *max_jobs = parse_submodule_fetchjobs(var, value);
876 return 0;
879 void update_clone_config_from_gitmodules(int *max_jobs)
881 config_from_gitmodules(gitmodules_update_clone_config, the_repository, &max_jobs);