]> git.neil.brown.name Git - git.git/blob - submodule-config.c
Merge branch 'pw/rebase-i-regression-fix-tests'
[git.git] / submodule-config.c
1 #include "cache.h"
2 #include "config.h"
3 #include "submodule-config.h"
4 #include "submodule.h"
5 #include "strbuf.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 static int parse_update_recurse(const char *opt, const char *arg,
239                                 int die_on_error)
240 {
241         switch (git_config_maybe_bool(opt, arg)) {
242         case 1:
243                 return RECURSE_SUBMODULES_ON;
244         case 0:
245                 return RECURSE_SUBMODULES_OFF;
246         default:
247                 if (die_on_error)
248                         die("bad %s argument: %s", opt, arg);
249                 return RECURSE_SUBMODULES_ERROR;
250         }
251 }
252
253 int parse_update_recurse_submodules_arg(const char *opt, const char *arg)
254 {
255         return parse_update_recurse(opt, arg, 1);
256 }
257
258 static int parse_push_recurse(const char *opt, const char *arg,
259                                int die_on_error)
260 {
261         switch (git_config_maybe_bool(opt, arg)) {
262         case 1:
263                 /* There's no simple "on" value when pushing */
264                 if (die_on_error)
265                         die("bad %s argument: %s", opt, arg);
266                 else
267                         return RECURSE_SUBMODULES_ERROR;
268         case 0:
269                 return RECURSE_SUBMODULES_OFF;
270         default:
271                 if (!strcmp(arg, "on-demand"))
272                         return RECURSE_SUBMODULES_ON_DEMAND;
273                 else if (!strcmp(arg, "check"))
274                         return RECURSE_SUBMODULES_CHECK;
275                 else if (!strcmp(arg, "only"))
276                         return RECURSE_SUBMODULES_ONLY;
277                 else if (die_on_error)
278                         die("bad %s argument: %s", opt, arg);
279                 else
280                         return RECURSE_SUBMODULES_ERROR;
281         }
282 }
283
284 int parse_push_recurse_submodules_arg(const char *opt, const char *arg)
285 {
286         return parse_push_recurse(opt, arg, 1);
287 }
288
289 static void warn_multiple_config(const unsigned char *treeish_name,
290                                  const char *name, const char *option)
291 {
292         const char *commit_string = "WORKTREE";
293         if (treeish_name)
294                 commit_string = sha1_to_hex(treeish_name);
295         warning("%s:.gitmodules, multiple configurations found for "
296                         "'submodule.%s.%s'. Skipping second one!",
297                         commit_string, name, option);
298 }
299
300 struct parse_config_parameter {
301         struct submodule_cache *cache;
302         const unsigned char *treeish_name;
303         const unsigned char *gitmodules_sha1;
304         int overwrite;
305 };
306
307 static int parse_config(const char *var, const char *value, void *data)
308 {
309         struct parse_config_parameter *me = data;
310         struct submodule *submodule;
311         struct strbuf name = STRBUF_INIT, item = STRBUF_INIT;
312         int ret = 0;
313
314         /* this also ensures that we only parse submodule entries */
315         if (!name_and_item_from_var(var, &name, &item))
316                 return 0;
317
318         submodule = lookup_or_create_by_name(me->cache,
319                                              me->gitmodules_sha1,
320                                              name.buf);
321
322         if (!strcmp(item.buf, "path")) {
323                 if (!value)
324                         ret = config_error_nonbool(var);
325                 else if (!me->overwrite && submodule->path)
326                         warn_multiple_config(me->treeish_name, submodule->name,
327                                         "path");
328                 else {
329                         if (submodule->path)
330                                 cache_remove_path(me->cache, submodule);
331                         free((void *) submodule->path);
332                         submodule->path = xstrdup(value);
333                         cache_put_path(me->cache, submodule);
334                 }
335         } else if (!strcmp(item.buf, "fetchrecursesubmodules")) {
336                 /* when parsing worktree configurations we can die early */
337                 int die_on_error = is_null_sha1(me->gitmodules_sha1);
338                 if (!me->overwrite &&
339                     submodule->fetch_recurse != RECURSE_SUBMODULES_NONE)
340                         warn_multiple_config(me->treeish_name, submodule->name,
341                                         "fetchrecursesubmodules");
342                 else
343                         submodule->fetch_recurse = parse_fetch_recurse(
344                                                                 var, value,
345                                                                 die_on_error);
346         } else if (!strcmp(item.buf, "ignore")) {
347                 if (!value)
348                         ret = config_error_nonbool(var);
349                 else if (!me->overwrite && submodule->ignore)
350                         warn_multiple_config(me->treeish_name, submodule->name,
351                                         "ignore");
352                 else if (strcmp(value, "untracked") &&
353                          strcmp(value, "dirty") &&
354                          strcmp(value, "all") &&
355                          strcmp(value, "none"))
356                         warning("Invalid parameter '%s' for config option "
357                                         "'submodule.%s.ignore'", value, name.buf);
358                 else {
359                         free((void *) submodule->ignore);
360                         submodule->ignore = xstrdup(value);
361                 }
362         } else if (!strcmp(item.buf, "url")) {
363                 if (!value) {
364                         ret = config_error_nonbool(var);
365                 } else if (!me->overwrite && submodule->url) {
366                         warn_multiple_config(me->treeish_name, submodule->name,
367                                         "url");
368                 } else {
369                         free((void *) submodule->url);
370                         submodule->url = xstrdup(value);
371                 }
372         } else if (!strcmp(item.buf, "update")) {
373                 if (!value)
374                         ret = config_error_nonbool(var);
375                 else if (!me->overwrite &&
376                          submodule->update_strategy.type != SM_UPDATE_UNSPECIFIED)
377                         warn_multiple_config(me->treeish_name, submodule->name,
378                                              "update");
379                 else if (parse_submodule_update_strategy(value,
380                          &submodule->update_strategy) < 0)
381                                 die(_("invalid value for %s"), var);
382         } else if (!strcmp(item.buf, "shallow")) {
383                 if (!me->overwrite && submodule->recommend_shallow != -1)
384                         warn_multiple_config(me->treeish_name, submodule->name,
385                                              "shallow");
386                 else
387                         submodule->recommend_shallow =
388                                 git_config_bool(var, value);
389         } else if (!strcmp(item.buf, "branch")) {
390                 if (!me->overwrite && submodule->branch)
391                         warn_multiple_config(me->treeish_name, submodule->name,
392                                              "branch");
393                 else {
394                         free((void *)submodule->branch);
395                         submodule->branch = xstrdup(value);
396                 }
397         }
398
399         strbuf_release(&name);
400         strbuf_release(&item);
401
402         return ret;
403 }
404
405 int gitmodule_sha1_from_commit(const unsigned char *treeish_name,
406                                       unsigned char *gitmodules_sha1,
407                                       struct strbuf *rev)
408 {
409         int ret = 0;
410
411         if (is_null_sha1(treeish_name)) {
412                 hashclr(gitmodules_sha1);
413                 return 1;
414         }
415
416         strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(treeish_name));
417         if (get_sha1(rev->buf, gitmodules_sha1) >= 0)
418                 ret = 1;
419
420         return ret;
421 }
422
423 /* This does a lookup of a submodule configuration by name or by path
424  * (key) with on-demand reading of the appropriate .gitmodules from
425  * revisions.
426  */
427 static const struct submodule *config_from(struct submodule_cache *cache,
428                 const unsigned char *treeish_name, const char *key,
429                 enum lookup_type lookup_type)
430 {
431         struct strbuf rev = STRBUF_INIT;
432         unsigned long config_size;
433         char *config = NULL;
434         unsigned char sha1[20];
435         enum object_type type;
436         const struct submodule *submodule = NULL;
437         struct parse_config_parameter parameter;
438
439         /*
440          * If any parameter except the cache is a NULL pointer just
441          * return the first submodule. Can be used to check whether
442          * there are any submodules parsed.
443          */
444         if (!treeish_name || !key) {
445                 struct hashmap_iter iter;
446                 struct submodule_entry *entry;
447
448                 entry = hashmap_iter_first(&cache->for_name, &iter);
449                 if (!entry)
450                         return NULL;
451                 return entry->config;
452         }
453
454         if (!gitmodule_sha1_from_commit(treeish_name, sha1, &rev))
455                 goto out;
456
457         switch (lookup_type) {
458         case lookup_name:
459                 submodule = cache_lookup_name(cache, sha1, key);
460                 break;
461         case lookup_path:
462                 submodule = cache_lookup_path(cache, sha1, key);
463                 break;
464         }
465         if (submodule)
466                 goto out;
467
468         config = read_sha1_file(sha1, &type, &config_size);
469         if (!config || type != OBJ_BLOB)
470                 goto out;
471
472         /* fill the submodule config into the cache */
473         parameter.cache = cache;
474         parameter.treeish_name = treeish_name;
475         parameter.gitmodules_sha1 = sha1;
476         parameter.overwrite = 0;
477         git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
478                         config, config_size, &parameter);
479         strbuf_release(&rev);
480         free(config);
481
482         switch (lookup_type) {
483         case lookup_name:
484                 return cache_lookup_name(cache, sha1, key);
485         case lookup_path:
486                 return cache_lookup_path(cache, sha1, key);
487         default:
488                 return NULL;
489         }
490
491 out:
492         strbuf_release(&rev);
493         free(config);
494         return submodule;
495 }
496
497 static void ensure_cache_init(void)
498 {
499         if (is_cache_init)
500                 return;
501
502         cache_init(&the_submodule_cache);
503         is_cache_init = 1;
504 }
505
506 int parse_submodule_config_option(const char *var, const char *value)
507 {
508         struct parse_config_parameter parameter;
509         parameter.cache = &the_submodule_cache;
510         parameter.treeish_name = NULL;
511         parameter.gitmodules_sha1 = null_sha1;
512         parameter.overwrite = 1;
513
514         ensure_cache_init();
515         return parse_config(var, value, &parameter);
516 }
517
518 const struct submodule *submodule_from_name(const unsigned char *treeish_name,
519                 const char *name)
520 {
521         ensure_cache_init();
522         return config_from(&the_submodule_cache, treeish_name, name, lookup_name);
523 }
524
525 const struct submodule *submodule_from_path(const unsigned char *treeish_name,
526                 const char *path)
527 {
528         ensure_cache_init();
529         return config_from(&the_submodule_cache, treeish_name, path, lookup_path);
530 }
531
532 void submodule_free(void)
533 {
534         cache_free(&the_submodule_cache);
535         is_cache_init = 0;
536 }