submodule: use new config API for worktree configurations
We remove the extracted functions and directly parse into and read out of the cache. This allows us to have one unified way of accessing submodule configuration values specific to single submodules. Regardless whether we need to access a configuration from history or from the worktree. Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Heiko Voigt committed
Aug 17, 2015 at 17:21 UTC
851e18c3859ad0f9f7e91fdb4d6cce5a8272420b
9 files changed
+104
-138
Documentation/technical/api-submodule-config.txt
+18
-1
@@ -10,10 +10,18 @@ submodule path or name.
10
Usage
11
-----
12
13
+To initialize the cache with configurations from the worktree the caller
14
+typically first calls `gitmodules_config()` to read values from the
15
+worktree .gitmodules and then to overlay the local git config values
16
+`parse_submodule_config_option()` from the config parsing
17
+infrastructure.
18
+
19
The caller can look up information about submodules by using the
20
`submodule_from_path()` or `submodule_from_name()` functions. They return
21
a `struct submodule` which contains the values. The API automatically
16
-initializes and allocates the needed infrastructure on-demand.
22
+initializes and allocates the needed infrastructure on-demand. If the
23
+caller does only want to lookup values from revisions the initialization
24
+can be skipped.
25
26
If the internal cache might grow too big or when the caller is done with
27
the API, all internally cached values can be freed with submodule_free().
@@ -34,6 +42,11 @@ Functions
42
43
Use these to free the internally cached values.
44
45
+`int parse_submodule_config_option(const char *var, const char *value)`::
46
+
47
+ Can be passed to the config parsing infrastructure to parse
48
+ local (worktree) submodule configurations.
49
+
50
`const struct submodule *submodule_from_path(const unsigned char *commit_sha1, const char *path)`::
51
52
Lookup values for one submodule by its commit_sha1 and path.
@@ -42,4 +55,8 @@ Functions
55
56
The same as above but lookup by name.
57
58
+If given the null_sha1 as commit_sha1 the local configuration of a
59
+submodule will be returned (e.g. consolidated values from local git
60
+configuration and the .gitmodules file in the worktree).
61
+
62
For an example usage see test-submodule-config.c.
builtin/checkout.c
+1
@@ -18,6 +18,7 @@
18
#include "xdiff-interface.h"
19
#include "ll-merge.h"
20
#include "resolve-undo.h"
21
+#include "submodule-config.h"
22
#include "submodule.h"
23
#include "argv-array.h"
24
#include "sigchain.h"
diff.c
+1
@@ -13,6 +13,7 @@
13
#include "utf8.h"
14
#include "userdiff.h"
15
#include "sigchain.h"
16
+#include "submodule-config.h"
17
#include "submodule.h"
18
#include "ll-merge.h"
19
#include "string-list.h"
submodule-config.c
+12
@@ -422,6 +422,18 @@ static void ensure_cache_init(void)
422
is_cache_init = 1;
423
}
424
425
+int parse_submodule_config_option(const char *var, const char *value)
426
+{
427
+ struct parse_config_parameter parameter;
428
+ parameter.cache = &cache;
429
+ parameter.commit_sha1 = NULL;
430
+ parameter.gitmodules_sha1 = null_sha1;
431
+ parameter.overwrite = 1;
432
+
433
+ ensure_cache_init();
434
+ return parse_config(var, value, ¶meter);
435
+}
436
+
437
const struct submodule *submodule_from_name(const unsigned char *commit_sha1,
438
const char *name)
439
{
submodule-config.h
+1
@@ -18,6 +18,7 @@ struct submodule {
18
unsigned char gitmodules_sha1[20];
19
};
20
21
+int parse_submodule_config_option(const char *var, const char *value);
22
const struct submodule *submodule_from_name(const unsigned char *commit_sha1,
23
const char *name);
24
const struct submodule *submodule_from_path(const unsigned char *commit_sha1,
submodule.c
+26
-134
@@ -1,4 +1,5 @@
1
#include "cache.h"
2
+#include "submodule-config.h"
3
#include "submodule.h"
4
#include "dir.h"
5
#include "diff.h"
@@ -12,9 +13,6 @@
13
#include "argv-array.h"
14
#include "blob.h"
15
15
-static struct string_list config_name_for_path;
16
-static struct string_list config_fetch_recurse_submodules_for_name;
17
-static struct string_list config_ignore_for_name;
16
static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
17
static struct string_list changed_submodule_paths;
18
static int initialized_fetch_ref_tips;
@@ -41,77 +39,6 @@ static int gitmodules_is_unmerged;
39
*/
40
static int gitmodules_is_modified;
41
44
-static const char *get_name_for_path(const char *path)
45
-{
46
- struct string_list_item *path_option;
47
- if (path == NULL) {
48
- if (config_name_for_path.nr > 0)
49
- return config_name_for_path.items[0].util;
50
- else
51
- return NULL;
52
- }
53
- path_option = unsorted_string_list_lookup(&config_name_for_path, path);
54
- if (!path_option)
55
- return NULL;
56
- return path_option->util;
57
-}
58
-
59
-static void set_name_for_path(const char *path, const char *name, int namelen)
60
-{
61
- struct string_list_item *config;
62
- config = unsorted_string_list_lookup(&config_name_for_path, path);
63
- if (config)
64
- free(config->util);
65
- else
66
- config = string_list_append(&config_name_for_path, xstrdup(path));
67
- config->util = xmemdupz(name, namelen);
68
-}
69
-
70
-static const char *get_ignore_for_name(const char *name)
71
-{
72
- struct string_list_item *ignore_option;
73
- ignore_option = unsorted_string_list_lookup(&config_ignore_for_name, name);
74
- if (!ignore_option)
75
- return NULL;
76
-
77
- return ignore_option->util;
78
-}
79
-
80
-static void set_ignore_for_name(const char *name, int namelen, const char *ignore)
81
-{
82
- struct string_list_item *config;
83
- char *name_cstr = xmemdupz(name, namelen);
84
- config = unsorted_string_list_lookup(&config_ignore_for_name, name_cstr);
85
- if (config) {
86
- free(config->util);
87
- free(name_cstr);
88
- } else
89
- config = string_list_append(&config_ignore_for_name, name_cstr);
90
- config->util = xstrdup(ignore);
91
-}
92
-
93
-static int get_fetch_recurse_for_name(const char *name)
94
-{
95
- struct string_list_item *fetch_recurse;
96
- fetch_recurse = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, name);
97
- if (!fetch_recurse)
98
- return RECURSE_SUBMODULES_NONE;
99
-
100
- return (intptr_t) fetch_recurse->util;
101
-}
102
-
103
-static void set_fetch_recurse_for_name(const char *name, int namelen, int fetch_recurse)
104
-{
105
- struct string_list_item *config;
106
- char *name_cstr = xmemdupz(name, namelen);
107
- config = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, name_cstr);
108
- if (!config)
109
- config = string_list_append(&config_fetch_recurse_submodules_for_name, name_cstr);
110
- else
111
- free(name_cstr);
112
- config->util = (void *)(intptr_t) fetch_recurse;
113
-}
114
-
42
int is_staging_gitmodules_ok(void)
43
{
44
return !gitmodules_is_modified;
@@ -125,7 +52,7 @@ int is_staging_gitmodules_ok(void)
52
int update_path_in_gitmodules(const char *oldpath, const char *newpath)
53
{
54
struct strbuf entry = STRBUF_INIT;
128
- const char *path;
55
+ const struct submodule *submodule;
56
57
if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
58
return -1;
@@ -133,13 +60,13 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
60
if (gitmodules_is_unmerged)
61
die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
62
136
- path = get_name_for_path(oldpath);
137
- if (!path) {
63
+ submodule = submodule_from_path(null_sha1, oldpath);
64
+ if (!submodule || !submodule->name) {
65
warning(_("Could not find section in .gitmodules where path=%s"), oldpath);
66
return -1;
67
}
68
strbuf_addstr(&entry, "submodule.");
142
- strbuf_addstr(&entry, path);
69
+ strbuf_addstr(&entry, submodule->name);
70
strbuf_addstr(&entry, ".path");
71
if (git_config_set_in_file(".gitmodules", entry.buf, newpath) < 0) {
72
/* Maybe the user already did that, don't error out here */
@@ -159,7 +86,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
86
int remove_path_from_gitmodules(const char *path)
87
{
88
struct strbuf sect = STRBUF_INIT;
162
- const char *path_option;
89
+ const struct submodule *submodule;
90
91
if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
92
return -1;
@@ -167,13 +94,13 @@ int remove_path_from_gitmodules(const char *path)
94
if (gitmodules_is_unmerged)
95
die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
96
170
- path_option = get_name_for_path(path);
171
- if (!path_option) {
97
+ submodule = submodule_from_path(null_sha1, path);
98
+ if (!submodule || !submodule->name) {
99
warning(_("Could not find section in .gitmodules where path=%s"), path);
100
return -1;
101
}
102
strbuf_addstr(§, "submodule.");
176
- strbuf_addstr(§, path_option);
103
+ strbuf_addstr(§, submodule->name);
104
if (git_config_rename_section_in_file(".gitmodules", sect.buf, NULL) < 0) {
105
/* Maybe the user already did that, don't error out here */
106
warning(_("Could not remove .gitmodules entry for %s"), path);
@@ -235,11 +162,10 @@ done:
162
void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
163
const char *path)
164
{
238
- const char *name = get_name_for_path(path);
239
- if (name) {
240
- const char *ignore = get_ignore_for_name(name);
241
- if (ignore)
242
- handle_ignore_submodules_arg(diffopt, ignore);
165
+ const struct submodule *submodule = submodule_from_path(null_sha1, path);
166
+ if (submodule) {
167
+ if (submodule->ignore)
168
+ handle_ignore_submodules_arg(diffopt, submodule->ignore);
169
else if (gitmodules_is_unmerged)
170
DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
171
}
@@ -288,42 +214,6 @@ void gitmodules_config(void)
214
}
215
}
216
291
-int parse_submodule_config_option(const char *var, const char *value)
292
-{
293
- const char *name, *key;
294
- int namelen;
295
-
296
- if (parse_config_key(var, "submodule", &name, &namelen, &key) < 0 || !name)
297
- return 0;
298
-
299
- if (!strcmp(key, "path")) {
300
- if (!value)
301
- return config_error_nonbool(var);
302
-
303
- set_name_for_path(value, name, namelen);
304
-
305
- } else if (!strcmp(key, "fetchrecursesubmodules")) {
306
- int fetch_recurse = parse_fetch_recurse_submodules_arg(var, value);
307
-
308
- set_fetch_recurse_for_name(name, namelen, fetch_recurse);
309
-
310
- } else if (!strcmp(key, "ignore")) {
311
-
312
- if (!value)
313
- return config_error_nonbool(var);
314
-
315
- if (strcmp(value, "untracked") && strcmp(value, "dirty") &&
316
- strcmp(value, "all") && strcmp(value, "none")) {
317
- warning("Invalid parameter \"%s\" for config option \"submodule.%s.ignore\"", value, var);
318
- return 0;
319
- }
320
-
321
- set_ignore_for_name(name, namelen, value);
322
- return 0;
323
- }
324
- return 0;
325
-}
326
-
217
void handle_ignore_submodules_arg(struct diff_options *diffopt,
218
const char *arg)
219
{
@@ -699,7 +589,7 @@ static void calculate_changed_submodule_paths(void)
589
struct argv_array argv = ARGV_ARRAY_INIT;
590
591
/* No need to check if there are no submodules configured */
702
- if (!get_name_for_path(NULL))
592
+ if (!submodule_from_path(NULL, NULL))
593
return;
594
595
init_revisions(&rev, NULL);
@@ -746,7 +636,6 @@ int fetch_populated_submodules(const struct argv_array *options,
636
int i, result = 0;
637
struct child_process cp = CHILD_PROCESS_INIT;
638
struct argv_array argv = ARGV_ARRAY_INIT;
749
- const char *name_for_path;
639
const char *work_tree = get_git_work_tree();
640
if (!work_tree)
641
goto out;
@@ -771,23 +660,26 @@ int fetch_populated_submodules(const struct argv_array *options,
660
struct strbuf submodule_git_dir = STRBUF_INIT;
661
struct strbuf submodule_prefix = STRBUF_INIT;
662
const struct cache_entry *ce = active_cache[i];
774
- const char *git_dir, *name, *default_argv;
663
+ const char *git_dir, *default_argv;
664
+ const struct submodule *submodule;
665
666
if (!S_ISGITLINK(ce->ce_mode))
667
continue;
668
779
- name = ce->name;
780
- name_for_path = get_name_for_path(ce->name);
781
- if (name_for_path)
782
- name = name_for_path;
669
+ submodule = submodule_from_path(null_sha1, ce->name);
670
+ if (!submodule)
671
+ submodule = submodule_from_name(null_sha1, ce->name);
672
673
default_argv = "yes";
674
if (command_line_option == RECURSE_SUBMODULES_DEFAULT) {
786
- int fetch_recurse_option = get_fetch_recurse_for_name(name);
787
- if (fetch_recurse_option != RECURSE_SUBMODULES_NONE) {
788
- if (fetch_recurse_option == RECURSE_SUBMODULES_OFF)
675
+ if (submodule &&
676
+ submodule->fetch_recurse !=
677
+ RECURSE_SUBMODULES_NONE) {
678
+ if (submodule->fetch_recurse ==
679
+ RECURSE_SUBMODULES_OFF)
680
continue;
790
- if (fetch_recurse_option == RECURSE_SUBMODULES_ON_DEMAND) {
681
+ if (submodule->fetch_recurse ==
682
+ RECURSE_SUBMODULES_ON_DEMAND) {
683
if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
684
continue;
685
default_argv = "on-demand";
submodule.h
-1
@@ -20,7 +20,6 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
20
const char *path);
21
int submodule_config(const char *var, const char *value, void *cb);
22
void gitmodules_config(void);
23
-int parse_submodule_config_option(const char *var, const char *value);
23
void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);
24
int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
25
void show_submodule_summary(FILE *f, const char *path,
t/t7411-submodule-config.sh
+35
-2
@@ -5,8 +5,8 @@
5
6
test_description='Test submodules config cache infrastructure
7
8
-This test verifies that parsing .gitmodules configuration directly
9
-from the database works.
8
+This test verifies that parsing .gitmodules configurations directly
9
+from the database and from the worktree works.
10
'
11
12
TEST_NO_CREATE_REPO=1
@@ -82,4 +82,37 @@ test_expect_success 'error in one submodule config lets continue' '
82
)
83
'
84
85
+cat >super/expect_url <<EOF
86
+Submodule url: 'git@somewhere.else.net:a.git' for path 'b'
87
+Submodule url: 'git@somewhere.else.net:submodule.git' for path 'submodule'
88
+EOF
89
+
90
+cat >super/expect_local_path <<EOF
91
+Submodule name: 'a' for path 'c'
92
+Submodule name: 'submodule' for path 'submodule'
93
+EOF
94
+
95
+test_expect_success 'reading of local configuration' '
96
+ (cd super &&
97
+ old_a=$(git config submodule.a.url) &&
98
+ old_submodule=$(git config submodule.submodule.url) &&
99
+ git config submodule.a.url git@somewhere.else.net:a.git &&
100
+ git config submodule.submodule.url git@somewhere.else.net:submodule.git &&
101
+ test-submodule-config --url \
102
+ "" b \
103
+ "" submodule \
104
+ >actual &&
105
+ test_cmp expect_url actual &&
106
+ git config submodule.a.path c &&
107
+ test-submodule-config \
108
+ "" c \
109
+ "" submodule \
110
+ >actual &&
111
+ test_cmp expect_local_path actual &&
112
+ git config submodule.a.url $old_a &&
113
+ git config submodule.submodule.url $old_submodule &&
114
+ git config --unset submodule.a.path c
115
+ )
116
+'
117
+
118
test_done
test-submodule-config.c
+10
@@ -1,5 +1,6 @@
1
#include "cache.h"
2
#include "submodule-config.h"
3
+#include "submodule.h"
4
5
static void die_usage(int argc, char **argv, const char *msg)
6
{
@@ -8,6 +9,11 @@ static void die_usage(int argc, char **argv, const char *msg)
9
exit(1);
10
}
11
12
+static int git_test_config(const char *var, const char *value, void *cb)
13
+{
14
+ return parse_submodule_config_option(var, value);
15
+}
16
+
17
int main(int argc, char **argv)
18
{
19
char **arg = argv;
@@ -29,6 +35,10 @@ int main(int argc, char **argv)
35
if (my_argc % 2 != 0)
36
die_usage(argc, argv, "Wrong number of arguments.");
37
38
+ setup_git_directory();
39
+ gitmodules_config();
40
+ git_config(git_test_config, NULL);
41
+
42
while (*arg) {
43
unsigned char commit_sha1[20];
44
const struct submodule *submodule;