config: add kvi.path, use it to evaluate includes

Include directives are evaluated using the path of the config file. To reduce the dependence on "config_reader.source", add a new "key_value_info.path" member and use that instead of "config_source.path". This allows us to remove a "struct config_reader *" field from "struct config_include_data", which will subsequently allow us to remove "struct config_reader" entirely. Signed-off-by: Glen Choo <chooglen@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Glen Choo committed Jun 28, 2023 at 19:26 UTC 908857a9f8a63c7d8fee1bd5f52b1aa1cf3434de
2 files changed +21 -21
config.c
+19 -21
@@ -162,7 +162,6 @@ struct config_include_data {
162 const struct config_options *opts;
163 struct git_config_source *config_source;
164 struct repository *repo;
165 - struct config_reader *config_reader;
165
166 /*
167 * All remote URLs discovered when reading all config files.
@@ -181,8 +180,7 @@ static const char include_depth_advice[] = N_(
180 "from\n"
181 " %s\n"
182 "This might be due to circular includes.");
184 -static int handle_path_include(struct config_source *cs,
185 - const struct key_value_info *kvi,
183 +static int handle_path_include(const struct key_value_info *kvi,
184 const char *path,
185 struct config_include_data *inc)
186 {
@@ -205,14 +203,14 @@ static int handle_path_include(struct config_source *cs,
203 if (!is_absolute_path(path)) {
204 char *slash;
205
208 - if (!cs || !cs->path) {
206 + if (!kvi || !kvi->path) {
207 ret = error(_("relative config includes must come from files"));
208 goto cleanup;
209 }
210
213 - slash = find_last_dir_sep(cs->path);
211 + slash = find_last_dir_sep(kvi->path);
212 if (slash)
215 - strbuf_add(&buf, cs->path, slash - cs->path + 1);
213 + strbuf_add(&buf, kvi->path, slash - kvi->path + 1);
214 strbuf_addstr(&buf, path);
215 path = buf.buf;
216 }
@@ -220,8 +218,8 @@ static int handle_path_include(struct config_source *cs,
218 if (!access_or_die(path, R_OK, 0)) {
219 if (++inc->depth > MAX_INCLUDE_DEPTH)
220 die(_(include_depth_advice), MAX_INCLUDE_DEPTH, path,
223 - !cs ? "<unknown>" :
224 - cs->name ? cs->name :
221 + !kvi ? "<unknown>" :
222 + kvi->filename ? kvi->filename :
223 "the command line");
224 ret = git_config_from_file_with_options(git_config_include, path, inc,
225 kvi->scope, NULL);
@@ -239,7 +237,7 @@ static void add_trailing_starstar_for_dir(struct strbuf *pat)
237 strbuf_addstr(pat, "**");
238 }
239
242 -static int prepare_include_condition_pattern(struct config_source *cs,
240 +static int prepare_include_condition_pattern(const struct key_value_info *kvi,
241 struct strbuf *pat)
242 {
243 struct strbuf path = STRBUF_INIT;
@@ -256,11 +254,11 @@ static int prepare_include_condition_pattern(struct config_source *cs,
254 if (pat->buf[0] == '.' && is_dir_sep(pat->buf[1])) {
255 const char *slash;
256
259 - if (!cs || !cs->path)
257 + if (!kvi || !kvi->path)
258 return error(_("relative config include "
259 "conditionals must come from files"));
260
263 - strbuf_realpath(&path, cs->path, 1);
261 + strbuf_realpath(&path, kvi->path, 1);
262 slash = find_last_dir_sep(path.buf);
263 if (!slash)
264 BUG("how is this possible?");
@@ -275,7 +273,7 @@ static int prepare_include_condition_pattern(struct config_source *cs,
273 return prefix;
274 }
275
278 -static int include_by_gitdir(struct config_source *cs,
276 +static int include_by_gitdir(const struct key_value_info *kvi,
277 const struct config_options *opts,
278 const char *cond, size_t cond_len, int icase)
279 {
@@ -292,7 +290,7 @@ static int include_by_gitdir(struct config_source *cs,
290
291 strbuf_realpath(&text, git_dir, 1);
292 strbuf_add(&pattern, cond, cond_len);
295 - prefix = prepare_include_condition_pattern(cs, &pattern);
293 + prefix = prepare_include_condition_pattern(kvi, &pattern);
294
295 again:
296 if (prefix < 0)
@@ -428,16 +426,16 @@ static int include_by_remote_url(struct config_include_data *inc,
426 inc->remote_urls);
427 }
428
431 -static int include_condition_is_true(struct config_source *cs,
429 +static int include_condition_is_true(const struct key_value_info *kvi,
430 struct config_include_data *inc,
431 const char *cond, size_t cond_len)
432 {
433 const struct config_options *opts = inc->opts;
434
435 if (skip_prefix_mem(cond, cond_len, "gitdir:", &cond, &cond_len))
438 - return include_by_gitdir(cs, opts, cond, cond_len, 0);
436 + return include_by_gitdir(kvi, opts, cond, cond_len, 0);
437 else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len))
440 - return include_by_gitdir(cs, opts, cond, cond_len, 1);
438 + return include_by_gitdir(kvi, opts, cond, cond_len, 1);
439 else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len))
440 return include_by_branch(cond, cond_len);
441 else if (skip_prefix_mem(cond, cond_len, "hasconfig:remote.*.url:", &cond,
@@ -453,7 +451,6 @@ static int git_config_include(const char *var, const char *value,
451 void *data)
452 {
453 struct config_include_data *inc = data;
456 - struct config_source *cs = inc->config_reader->source;
454 const char *cond, *key;
455 size_t cond_len;
456 int ret;
@@ -467,16 +464,16 @@ static int git_config_include(const char *var, const char *value,
464 return ret;
465
466 if (!strcmp(var, "include.path"))
470 - ret = handle_path_include(cs, ctx->kvi, value, inc);
467 + ret = handle_path_include(ctx->kvi, value, inc);
468
469 if (!parse_config_key(var, "includeif", &cond, &cond_len, &key) &&
473 - cond && include_condition_is_true(cs, inc, cond, cond_len) &&
470 + cond && include_condition_is_true(ctx->kvi, inc, cond, cond_len) &&
471 !strcmp(key, "path")) {
472 config_fn_t old_fn = inc->fn;
473
474 if (inc->opts->unconditional_remote_url)
475 inc->fn = forbid_remote_url;
479 - ret = handle_path_include(cs, ctx->kvi, value, inc);
476 + ret = handle_path_include(ctx->kvi, value, inc);
477 inc->fn = old_fn;
478 }
479
@@ -661,6 +658,7 @@ void kvi_from_param(struct key_value_info *out)
658 out->linenr = -1;
659 out->origin_type = CONFIG_ORIGIN_CMDLINE;
660 out->scope = CONFIG_SCOPE_COMMAND;
661 + out->path = NULL;
662 }
663
664 int git_config_parse_parameter(const char *text,
@@ -1064,6 +1062,7 @@ static void kvi_from_source(struct config_source *cs,
1062 out->origin_type = cs->origin_type;
1063 out->linenr = cs->linenr;
1064 out->scope = scope;
1065 + out->path = cs->path;
1066 }
1067
1068 static int git_parse_source(struct config_source *cs, config_fn_t fn,
@@ -2282,7 +2281,6 @@ int config_with_options(config_fn_t fn, void *data,
2281 inc.opts = opts;
2282 inc.repo = repo;
2283 inc.config_source = config_source;
2285 - inc.config_reader = &the_reader;
2284 fn = git_config_include;
2285 data = &inc;
2286 }
config.h
+2
@@ -116,12 +116,14 @@ struct key_value_info {
116 int linenr;
117 enum config_origin_type origin_type;
118 enum config_scope scope;
119 + const char *path;
120 };
121 #define KVI_INIT { \
122 .filename = NULL, \
123 .linenr = -1, \
124 .origin_type = CONFIG_ORIGIN_UNKNOWN, \
125 .scope = CONFIG_SCOPE_UNKNOWN, \
126 + .path = NULL, \
127 }
128
129 /* Captures additional information that a config callback can use. */