builtin/fetch: factor submodule recurse parsing out to submodule config
[git] / submodule-config.c
1 #include "cache.h"
2 #include "submodule-config.h"
3 #include "submodule.h"
4 #include "strbuf.h"
5 #include "parse-options.h"
6
7 /*
8  * submodule cache lookup structure
9  * There is one shared set of 'struct submodule' entries which can be
10  * looked up by their sha1 blob id of the .gitmodule file and either
11  * using path or name as key.
12  * for_path stores submodule entries with path as key
13  * for_name stores submodule entries with name as key
14  */
15 struct submodule_cache {
16         struct hashmap for_path;
17         struct hashmap for_name;
18 };
19
20 /*
21  * thin wrapper struct needed to insert 'struct submodule' entries to
22  * the hashmap
23  */
24 struct submodule_entry {
25         struct hashmap_entry ent;
26         struct submodule *config;
27 };
28
29 enum lookup_type {
30         lookup_name,
31         lookup_path
32 };
33
34 static struct submodule_cache the_submodule_cache;
35 static int is_cache_init;
36
37 static int config_path_cmp(const struct submodule_entry *a,
38                            const struct submodule_entry *b,
39                            const void *unused)
40 {
41         return strcmp(a->config->path, b->config->path) ||
42                hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
43 }
44
45 static int config_name_cmp(const struct submodule_entry *a,
46                            const struct submodule_entry *b,
47                            const void *unused)
48 {
49         return strcmp(a->config->name, b->config->name) ||
50                hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
51 }
52
53 static void cache_init(struct submodule_cache *cache)
54 {
55         hashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, 0);
56         hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, 0);
57 }
58
59 static void free_one_config(struct submodule_entry *entry)
60 {
61         free((void *) entry->config->path);
62         free((void *) entry->config->name);
63         free((void *) entry->config->branch);
64         free((void *) entry->config->update_strategy.command);
65         free(entry->config);
66 }
67
68 static void cache_free(struct submodule_cache *cache)
69 {
70         struct hashmap_iter iter;
71         struct submodule_entry *entry;
72
73         /*
74          * We iterate over the name hash here to be symmetric with the
75          * allocation of struct submodule entries. Each is allocated by
76          * their .gitmodule blob sha1 and submodule name.
77          */
78         hashmap_iter_init(&cache->for_name, &iter);
79         while ((entry = hashmap_iter_next(&iter)))
80                 free_one_config(entry);
81
82         hashmap_free(&cache->for_path, 1);
83         hashmap_free(&cache->for_name, 1);
84 }
85
86 static unsigned int hash_sha1_string(const unsigned char *sha1,
87                                      const char *string)
88 {
89         return memhash(sha1, 20) + strhash(string);
90 }
91
92 static void cache_put_path(struct submodule_cache *cache,
93                            struct submodule *submodule)
94 {
95         unsigned int hash = hash_sha1_string(submodule->gitmodules_sha1,
96                                              submodule->path);
97         struct submodule_entry *e = xmalloc(sizeof(*e));
98         hashmap_entry_init(e, hash);
99         e->config = submodule;
100         hashmap_put(&cache->for_path, e);
101 }
102
103 static void cache_remove_path(struct submodule_cache *cache,
104                               struct submodule *submodule)
105 {
106         unsigned int hash = hash_sha1_string(submodule->gitmodules_sha1,
107                                              submodule->path);
108         struct submodule_entry e;
109         struct submodule_entry *removed;
110         hashmap_entry_init(&e, hash);
111         e.config = submodule;
112         removed = hashmap_remove(&cache->for_path, &e, NULL);
113         free(removed);
114 }
115
116 static void cache_add(struct submodule_cache *cache,
117                       struct submodule *submodule)
118 {
119         unsigned int hash = hash_sha1_string(submodule->gitmodules_sha1,
120                                              submodule->name);
121         struct submodule_entry *e = xmalloc(sizeof(*e));
122         hashmap_entry_init(e, hash);
123         e->config = submodule;
124         hashmap_add(&cache->for_name, e);
125 }
126
127 static const struct submodule *cache_lookup_path(struct submodule_cache *cache,
128                 const unsigned char *gitmodules_sha1, const char *path)
129 {
130         struct submodule_entry *entry;
131         unsigned int hash = hash_sha1_string(gitmodules_sha1, path);
132         struct submodule_entry key;
133         struct submodule key_config;
134
135         hashcpy(key_config.gitmodules_sha1, gitmodules_sha1);
136         key_config.path = path;
137
138         hashmap_entry_init(&key, hash);
139         key.config = &key_config;
140
141         entry = hashmap_get(&cache->for_path, &key, NULL);
142         if (entry)
143                 return entry->config;
144         return NULL;
145 }
146
147 static struct submodule *cache_lookup_name(struct submodule_cache *cache,
148                 const unsigned char *gitmodules_sha1, const char *name)
149 {
150         struct submodule_entry *entry;
151         unsigned int hash = hash_sha1_string(gitmodules_sha1, name);
152         struct submodule_entry key;
153         struct submodule key_config;
154
155         hashcpy(key_config.gitmodules_sha1, gitmodules_sha1);
156         key_config.name = name;
157
158         hashmap_entry_init(&key, hash);
159         key.config = &key_config;
160
161         entry = hashmap_get(&cache->for_name, &key, NULL);
162         if (entry)
163                 return entry->config;
164         return NULL;
165 }
166
167 static int name_and_item_from_var(const char *var, struct strbuf *name,
168                                   struct strbuf *item)
169 {
170         const char *subsection, *key;
171         int subsection_len, parse;
172         parse = parse_config_key(var, "submodule", &subsection,
173                         &subsection_len, &key);
174         if (parse < 0 || !subsection)
175                 return 0;
176
177         strbuf_add(name, subsection, subsection_len);
178         strbuf_addstr(item, key);
179
180         return 1;
181 }
182
183 static struct submodule *lookup_or_create_by_name(struct submodule_cache *cache,
184                 const unsigned char *gitmodules_sha1, const char *name)
185 {
186         struct submodule *submodule;
187         struct strbuf name_buf = STRBUF_INIT;
188
189         submodule = cache_lookup_name(cache, gitmodules_sha1, name);
190         if (submodule)
191                 return submodule;
192
193         submodule = xmalloc(sizeof(*submodule));
194
195         strbuf_addstr(&name_buf, name);
196         submodule->name = strbuf_detach(&name_buf, NULL);
197
198         submodule->path = NULL;
199         submodule->url = NULL;
200         submodule->update_strategy.type = SM_UPDATE_UNSPECIFIED;
201         submodule->update_strategy.command = NULL;
202         submodule->fetch_recurse = RECURSE_SUBMODULES_NONE;
203         submodule->ignore = NULL;
204         submodule->branch = NULL;
205         submodule->recommend_shallow = -1;
206
207         hashcpy(submodule->gitmodules_sha1, gitmodules_sha1);
208
209         cache_add(cache, submodule);
210
211         return submodule;
212 }
213
214 static int parse_fetch_recurse(const char *opt, const char *arg,
215                                int die_on_error)
216 {
217         switch (git_config_maybe_bool(opt, arg)) {
218         case 1:
219                 return RECURSE_SUBMODULES_ON;
220         case 0:
221                 return RECURSE_SUBMODULES_OFF;
222         default:
223                 if (!strcmp(arg, "on-demand"))
224                         return RECURSE_SUBMODULES_ON_DEMAND;
225
226                 if (die_on_error)
227                         die("bad %s argument: %s", opt, arg);
228                 else
229                         return RECURSE_SUBMODULES_ERROR;
230         }
231 }
232
233 int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
234 {
235         return parse_fetch_recurse(opt, arg, 1);
236 }
237
238 int option_fetch_parse_recurse_submodules(const struct option *opt,
239                                           const char *arg, int unset)
240 {
241         int *v;
242
243         if (!opt->value)
244                 return -1;
245
246         v = opt->value;
247
248         if (unset) {
249                 *v = RECURSE_SUBMODULES_OFF;
250         } else {
251                 if (arg)
252                         *v = parse_fetch_recurse_submodules_arg(opt->long_name, arg);
253                 else
254                         *v = RECURSE_SUBMODULES_ON;
255         }
256         return 0;
257 }
258
259 static int parse_update_recurse(const char *opt, const char *arg,
260                                 int die_on_error)
261 {
262         switch (git_config_maybe_bool(opt, arg)) {
263         case 1:
264                 return RECURSE_SUBMODULES_ON;
265         case 0:
266                 return RECURSE_SUBMODULES_OFF;
267         default:
268                 if (die_on_error)
269                         die("bad %s argument: %s", opt, arg);
270                 return RECURSE_SUBMODULES_ERROR;
271         }
272 }
273
274 int parse_update_recurse_submodules_arg(const char *opt, const char *arg)
275 {
276         return parse_update_recurse(opt, arg, 1);
277 }
278
279 static int parse_push_recurse(const char *opt, const char *arg,
280                                int die_on_error)
281 {
282         switch (git_config_maybe_bool(opt, arg)) {
283         case 1:
284                 /* There's no simple "on" value when pushing */
285                 if (die_on_error)
286                         die("bad %s argument: %s", opt, arg);
287                 else
288                         return RECURSE_SUBMODULES_ERROR;
289         case 0:
290                 return RECURSE_SUBMODULES_OFF;
291         default:
292                 if (!strcmp(arg, "on-demand"))
293                         return RECURSE_SUBMODULES_ON_DEMAND;
294                 else if (!strcmp(arg, "check"))
295                         return RECURSE_SUBMODULES_CHECK;
296                 else if (!strcmp(arg, "only"))
297                         return RECURSE_SUBMODULES_ONLY;
298                 else if (die_on_error)
299                         die("bad %s argument: %s", opt, arg);
300                 else
301                         return RECURSE_SUBMODULES_ERROR;
302         }
303 }
304
305 int parse_push_recurse_submodules_arg(const char *opt, const char *arg)
306 {
307         return parse_push_recurse(opt, arg, 1);
308 }
309
310 static void warn_multiple_config(const unsigned char *treeish_name,
311                                  const char *name, const char *option)
312 {
313         const char *commit_string = "WORKTREE";
314         if (treeish_name)
315                 commit_string = sha1_to_hex(treeish_name);
316         warning("%s:.gitmodules, multiple configurations found for "
317                         "'submodule.%s.%s'. Skipping second one!",
318                         commit_string, name, option);
319 }
320
321 struct parse_config_parameter {
322         struct submodule_cache *cache;
323         const unsigned char *treeish_name;
324         const unsigned char *gitmodules_sha1;
325         int overwrite;
326 };
327
328 static int parse_config(const char *var, const char *value, void *data)
329 {
330         struct parse_config_parameter *me = data;
331         struct submodule *submodule;
332         struct strbuf name = STRBUF_INIT, item = STRBUF_INIT;
333         int ret = 0;
334
335         /* this also ensures that we only parse submodule entries */
336         if (!name_and_item_from_var(var, &name, &item))
337                 return 0;
338
339         submodule = lookup_or_create_by_name(me->cache,
340                                              me->gitmodules_sha1,
341                                              name.buf);
342
343         if (!strcmp(item.buf, "path")) {
344                 if (!value)
345                         ret = config_error_nonbool(var);
346                 else if (!me->overwrite && submodule->path)
347                         warn_multiple_config(me->treeish_name, submodule->name,
348                                         "path");
349                 else {
350                         if (submodule->path)
351                                 cache_remove_path(me->cache, submodule);
352                         free((void *) submodule->path);
353                         submodule->path = xstrdup(value);
354                         cache_put_path(me->cache, submodule);
355                 }
356         } else if (!strcmp(item.buf, "fetchrecursesubmodules")) {
357                 /* when parsing worktree configurations we can die early */
358                 int die_on_error = is_null_sha1(me->gitmodules_sha1);
359                 if (!me->overwrite &&
360                     submodule->fetch_recurse != RECURSE_SUBMODULES_NONE)
361                         warn_multiple_config(me->treeish_name, submodule->name,
362                                         "fetchrecursesubmodules");
363                 else
364                         submodule->fetch_recurse = parse_fetch_recurse(
365                                                                 var, value,
366                                                                 die_on_error);
367         } else if (!strcmp(item.buf, "ignore")) {
368                 if (!value)
369                         ret = config_error_nonbool(var);
370                 else if (!me->overwrite && submodule->ignore)
371                         warn_multiple_config(me->treeish_name, submodule->name,
372                                         "ignore");
373                 else if (strcmp(value, "untracked") &&
374                          strcmp(value, "dirty") &&
375                          strcmp(value, "all") &&
376                          strcmp(value, "none"))
377                         warning("Invalid parameter '%s' for config option "
378                                         "'submodule.%s.ignore'", value, name.buf);
379                 else {
380                         free((void *) submodule->ignore);
381                         submodule->ignore = xstrdup(value);
382                 }
383         } else if (!strcmp(item.buf, "url")) {
384                 if (!value) {
385                         ret = config_error_nonbool(var);
386                 } else if (!me->overwrite && submodule->url) {
387                         warn_multiple_config(me->treeish_name, submodule->name,
388                                         "url");
389                 } else {
390                         free((void *) submodule->url);
391                         submodule->url = xstrdup(value);
392                 }
393         } else if (!strcmp(item.buf, "update")) {
394                 if (!value)
395                         ret = config_error_nonbool(var);
396                 else if (!me->overwrite &&
397                          submodule->update_strategy.type != SM_UPDATE_UNSPECIFIED)
398                         warn_multiple_config(me->treeish_name, submodule->name,
399                                              "update");
400                 else if (parse_submodule_update_strategy(value,
401                          &submodule->update_strategy) < 0)
402                                 die(_("invalid value for %s"), var);
403         } else if (!strcmp(item.buf, "shallow")) {
404                 if (!me->overwrite && submodule->recommend_shallow != -1)
405                         warn_multiple_config(me->treeish_name, submodule->name,
406                                              "shallow");
407                 else
408                         submodule->recommend_shallow =
409                                 git_config_bool(var, value);
410         } else if (!strcmp(item.buf, "branch")) {
411                 if (!me->overwrite && submodule->branch)
412                         warn_multiple_config(me->treeish_name, submodule->name,
413                                              "branch");
414                 else {
415                         free((void *)submodule->branch);
416                         submodule->branch = xstrdup(value);
417                 }
418         }
419
420         strbuf_release(&name);
421         strbuf_release(&item);
422
423         return ret;
424 }
425
426 int gitmodule_sha1_from_commit(const unsigned char *treeish_name,
427                                       unsigned char *gitmodules_sha1,
428                                       struct strbuf *rev)
429 {
430         int ret = 0;
431
432         if (is_null_sha1(treeish_name)) {
433                 hashclr(gitmodules_sha1);
434                 return 1;
435         }
436
437         strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(treeish_name));
438         if (get_sha1(rev->buf, gitmodules_sha1) >= 0)
439                 ret = 1;
440
441         return ret;
442 }
443
444 /* This does a lookup of a submodule configuration by name or by path
445  * (key) with on-demand reading of the appropriate .gitmodules from
446  * revisions.
447  */
448 static const struct submodule *config_from(struct submodule_cache *cache,
449                 const unsigned char *treeish_name, const char *key,
450                 enum lookup_type lookup_type)
451 {
452         struct strbuf rev = STRBUF_INIT;
453         unsigned long config_size;
454         char *config = NULL;
455         unsigned char sha1[20];
456         enum object_type type;
457         const struct submodule *submodule = NULL;
458         struct parse_config_parameter parameter;
459
460         /*
461          * If any parameter except the cache is a NULL pointer just
462          * return the first submodule. Can be used to check whether
463          * there are any submodules parsed.
464          */
465         if (!treeish_name || !key) {
466                 struct hashmap_iter iter;
467                 struct submodule_entry *entry;
468
469                 entry = hashmap_iter_first(&cache->for_name, &iter);
470                 if (!entry)
471                         return NULL;
472                 return entry->config;
473         }
474
475         if (!gitmodule_sha1_from_commit(treeish_name, sha1, &rev))
476                 goto out;
477
478         switch (lookup_type) {
479         case lookup_name:
480                 submodule = cache_lookup_name(cache, sha1, key);
481                 break;
482         case lookup_path:
483                 submodule = cache_lookup_path(cache, sha1, key);
484                 break;
485         }
486         if (submodule)
487                 goto out;
488
489         config = read_sha1_file(sha1, &type, &config_size);
490         if (!config || type != OBJ_BLOB)
491                 goto out;
492
493         /* fill the submodule config into the cache */
494         parameter.cache = cache;
495         parameter.treeish_name = treeish_name;
496         parameter.gitmodules_sha1 = sha1;
497         parameter.overwrite = 0;
498         git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
499                         config, config_size, &parameter);
500         strbuf_release(&rev);
501         free(config);
502
503         switch (lookup_type) {
504         case lookup_name:
505                 return cache_lookup_name(cache, sha1, key);
506         case lookup_path:
507                 return cache_lookup_path(cache, sha1, key);
508         default:
509                 return NULL;
510         }
511
512 out:
513         strbuf_release(&rev);
514         free(config);
515         return submodule;
516 }
517
518 static void ensure_cache_init(void)
519 {
520         if (is_cache_init)
521                 return;
522
523         cache_init(&the_submodule_cache);
524         is_cache_init = 1;
525 }
526
527 int parse_submodule_config_option(const char *var, const char *value)
528 {
529         struct parse_config_parameter parameter;
530         parameter.cache = &the_submodule_cache;
531         parameter.treeish_name = NULL;
532         parameter.gitmodules_sha1 = null_sha1;
533         parameter.overwrite = 1;
534
535         ensure_cache_init();
536         return parse_config(var, value, &parameter);
537 }
538
539 const struct submodule *submodule_from_name(const unsigned char *treeish_name,
540                 const char *name)
541 {
542         ensure_cache_init();
543         return config_from(&the_submodule_cache, treeish_name, name, lookup_name);
544 }
545
546 const struct submodule *submodule_from_path(const unsigned char *treeish_name,
547                 const char *path)
548 {
549         ensure_cache_init();
550         return config_from(&the_submodule_cache, treeish_name, path, lookup_path);
551 }
552
553 void submodule_free(void)
554 {
555         cache_free(&the_submodule_cache);
556         is_cache_init = 0;
557 }