Skip to content

Commit 851e18c

Browse files
hvoigtgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]> Signed-off-by: Stefan Beller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0d9f282 commit 851e18c

File tree

9 files changed

+104
-138
lines changed

9 files changed

+104
-138
lines changed

Documentation/technical/api-submodule-config.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,18 @@ submodule path or name.
1010
Usage
1111
-----
1212

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+
1319
The caller can look up information about submodules by using the
1420
`submodule_from_path()` or `submodule_from_name()` functions. They return
1521
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.
1725

1826
If the internal cache might grow too big or when the caller is done with
1927
the API, all internally cached values can be freed with submodule_free().
@@ -34,6 +42,11 @@ Functions
3442

3543
Use these to free the internally cached values.
3644

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+
3750
`const struct submodule *submodule_from_path(const unsigned char *commit_sha1, const char *path)`::
3851

3952
Lookup values for one submodule by its commit_sha1 and path.
@@ -42,4 +55,8 @@ Functions
4255

4356
The same as above but lookup by name.
4457

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+
4562
For an example usage see test-submodule-config.c.

builtin/checkout.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "xdiff-interface.h"
1919
#include "ll-merge.h"
2020
#include "resolve-undo.h"
21+
#include "submodule-config.h"
2122
#include "submodule.h"
2223
#include "argv-array.h"
2324
#include "sigchain.h"

diff.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "utf8.h"
1414
#include "userdiff.h"
1515
#include "sigchain.h"
16+
#include "submodule-config.h"
1617
#include "submodule.h"
1718
#include "ll-merge.h"
1819
#include "string-list.h"

submodule-config.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,18 @@ static void ensure_cache_init(void)
422422
is_cache_init = 1;
423423
}
424424

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, &parameter);
435+
}
436+
425437
const struct submodule *submodule_from_name(const unsigned char *commit_sha1,
426438
const char *name)
427439
{

submodule-config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ struct submodule {
1818
unsigned char gitmodules_sha1[20];
1919
};
2020

21+
int parse_submodule_config_option(const char *var, const char *value);
2122
const struct submodule *submodule_from_name(const unsigned char *commit_sha1,
2223
const char *name);
2324
const struct submodule *submodule_from_path(const unsigned char *commit_sha1,

submodule.c

Lines changed: 26 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "cache.h"
2+
#include "submodule-config.h"
23
#include "submodule.h"
34
#include "dir.h"
45
#include "diff.h"
@@ -12,9 +13,6 @@
1213
#include "argv-array.h"
1314
#include "blob.h"
1415

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;
1816
static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
1917
static struct string_list changed_submodule_paths;
2018
static int initialized_fetch_ref_tips;
@@ -41,77 +39,6 @@ static int gitmodules_is_unmerged;
4139
*/
4240
static int gitmodules_is_modified;
4341

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-
11542
int is_staging_gitmodules_ok(void)
11643
{
11744
return !gitmodules_is_modified;
@@ -125,21 +52,21 @@ int is_staging_gitmodules_ok(void)
12552
int update_path_in_gitmodules(const char *oldpath, const char *newpath)
12653
{
12754
struct strbuf entry = STRBUF_INIT;
128-
const char *path;
55+
const struct submodule *submodule;
12956

13057
if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
13158
return -1;
13259

13360
if (gitmodules_is_unmerged)
13461
die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
13562

136-
path = get_name_for_path(oldpath);
137-
if (!path) {
63+
submodule = submodule_from_path(null_sha1, oldpath);
64+
if (!submodule || !submodule->name) {
13865
warning(_("Could not find section in .gitmodules where path=%s"), oldpath);
13966
return -1;
14067
}
14168
strbuf_addstr(&entry, "submodule.");
142-
strbuf_addstr(&entry, path);
69+
strbuf_addstr(&entry, submodule->name);
14370
strbuf_addstr(&entry, ".path");
14471
if (git_config_set_in_file(".gitmodules", entry.buf, newpath) < 0) {
14572
/* Maybe the user already did that, don't error out here */
@@ -159,21 +86,21 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
15986
int remove_path_from_gitmodules(const char *path)
16087
{
16188
struct strbuf sect = STRBUF_INIT;
162-
const char *path_option;
89+
const struct submodule *submodule;
16390

16491
if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
16592
return -1;
16693

16794
if (gitmodules_is_unmerged)
16895
die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
16996

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) {
17299
warning(_("Could not find section in .gitmodules where path=%s"), path);
173100
return -1;
174101
}
175102
strbuf_addstr(&sect, "submodule.");
176-
strbuf_addstr(&sect, path_option);
103+
strbuf_addstr(&sect, submodule->name);
177104
if (git_config_rename_section_in_file(".gitmodules", sect.buf, NULL) < 0) {
178105
/* Maybe the user already did that, don't error out here */
179106
warning(_("Could not remove .gitmodules entry for %s"), path);
@@ -235,11 +162,10 @@ static int add_submodule_odb(const char *path)
235162
void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
236163
const char *path)
237164
{
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);
243169
else if (gitmodules_is_unmerged)
244170
DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
245171
}
@@ -288,42 +214,6 @@ void gitmodules_config(void)
288214
}
289215
}
290216

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-
327217
void handle_ignore_submodules_arg(struct diff_options *diffopt,
328218
const char *arg)
329219
{
@@ -699,7 +589,7 @@ static void calculate_changed_submodule_paths(void)
699589
struct argv_array argv = ARGV_ARRAY_INIT;
700590

701591
/* No need to check if there are no submodules configured */
702-
if (!get_name_for_path(NULL))
592+
if (!submodule_from_path(NULL, NULL))
703593
return;
704594

705595
init_revisions(&rev, NULL);
@@ -746,7 +636,6 @@ int fetch_populated_submodules(const struct argv_array *options,
746636
int i, result = 0;
747637
struct child_process cp = CHILD_PROCESS_INIT;
748638
struct argv_array argv = ARGV_ARRAY_INIT;
749-
const char *name_for_path;
750639
const char *work_tree = get_git_work_tree();
751640
if (!work_tree)
752641
goto out;
@@ -771,23 +660,26 @@ int fetch_populated_submodules(const struct argv_array *options,
771660
struct strbuf submodule_git_dir = STRBUF_INIT;
772661
struct strbuf submodule_prefix = STRBUF_INIT;
773662
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;
775665

776666
if (!S_ISGITLINK(ce->ce_mode))
777667
continue;
778668

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);
783672

784673
default_argv = "yes";
785674
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)
789680
continue;
790-
if (fetch_recurse_option == RECURSE_SUBMODULES_ON_DEMAND) {
681+
if (submodule->fetch_recurse ==
682+
RECURSE_SUBMODULES_ON_DEMAND) {
791683
if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
792684
continue;
793685
default_argv = "on-demand";

submodule.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
2020
const char *path);
2121
int submodule_config(const char *var, const char *value, void *cb);
2222
void gitmodules_config(void);
23-
int parse_submodule_config_option(const char *var, const char *value);
2423
void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);
2524
int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
2625
void show_submodule_summary(FILE *f, const char *path,

t/t7411-submodule-config.sh

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
test_description='Test submodules config cache infrastructure
77
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.
1010
'
1111

1212
TEST_NO_CREATE_REPO=1
@@ -82,4 +82,37 @@ test_expect_success 'error in one submodule config lets continue' '
8282
)
8383
'
8484

85+
cat >super/expect_url <<EOF
86+
Submodule url: '[email protected]:a.git' for path 'b'
87+
Submodule url: '[email protected]: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 [email protected]:a.git &&
100+
git config submodule.submodule.url [email protected]: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+
85118
test_done

0 commit comments

Comments
 (0)