environment: move access to "core.hooksPath" into repo settings

The "core.hooksPath" setting is stored in a global variable and populated via the `git_default_core_config`. This may cause issues in the case where one is handling multiple different repositories in a single process with different values for that config key, as we may or may not see the correct value in that case. Furthermore, global state blocks our path towards libification. Refactor the code so that we instead store the value in `struct repo_settings`. The value is computed as-needed and cached. The result should be functionally the same as there aren't ever any code paths where we'd execute hooks outside the context of a repository. Note that this requires us to change the passed-in repository in the `repo_git_path()` family of functions to be non-constant, as we call `adjust_git_path()` there. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Feb 7, 2025 at 12:03 UTC 6f3fbed8eda577703426d77dacc71ce0ba46634e
7 files changed +23 -17
config.c
-5
@@ -1436,11 +1436,6 @@ static int git_default_core_config(const char *var, const char *value,
1436 return git_config_pathname(&git_attributes_file, var, value);
1437 }
1438
1439 - if (!strcmp(var, "core.hookspath")) {
1440 - FREE_AND_NULL(git_hooks_path);
1441 - return git_config_pathname(&git_hooks_path, var, value);
1442 - }
1443 -
1439 if (!strcmp(var, "core.bare")) {
1440 is_bare_repository_cfg = git_config_bool(var, value);
1441 return 0;
environment.c
-1
@@ -42,7 +42,6 @@ char *git_log_output_encoding;
42 char *apply_default_whitespace;
43 char *apply_default_ignorewhitespace;
44 char *git_attributes_file;
45 -char *git_hooks_path;
45 int zlib_compression_level = Z_BEST_SPEED;
46 int pack_compression_level = Z_DEFAULT_COMPRESSION;
47 int fsync_object_files = -1;
environment.h
-1
@@ -160,7 +160,6 @@ extern int warn_on_object_refname_ambiguity;
160 extern char *apply_default_whitespace;
161 extern char *apply_default_ignorewhitespace;
162 extern char *git_attributes_file;
163 -extern char *git_hooks_path;
163 extern int zlib_compression_level;
164 extern int pack_compression_level;
165 extern size_t packed_git_window_size;
path.c
+8 -7
@@ -387,10 +387,11 @@ void report_linked_checkout_garbage(struct repository *r)
387 strbuf_release(&sb);
388 }
389
390 -static void adjust_git_path(const struct repository *repo,
390 +static void adjust_git_path(struct repository *repo,
391 struct strbuf *buf, int git_dir_len)
392 {
393 const char *base = buf->buf + git_dir_len;
394 +
395 if (is_dir_file(base, "info", "grafts"))
396 strbuf_splice(buf, 0, buf->len,
397 repo->graft_file, strlen(repo->graft_file));
@@ -399,8 +400,8 @@ static void adjust_git_path(const struct repository *repo,
400 repo->index_file, strlen(repo->index_file));
401 else if (dir_prefix(base, "objects"))
402 replace_dir(buf, git_dir_len + 7, repo->objects->odb->path);
402 - else if (git_hooks_path && dir_prefix(base, "hooks"))
403 - replace_dir(buf, git_dir_len + 5, git_hooks_path);
403 + else if (repo_settings_get_hooks_path(repo) && dir_prefix(base, "hooks"))
404 + replace_dir(buf, git_dir_len + 5, repo_settings_get_hooks_path(repo));
405 else if (repo->different_commondir)
406 update_common_dir(buf, git_dir_len, repo->commondir);
407 }
@@ -417,7 +418,7 @@ static void strbuf_worktree_gitdir(struct strbuf *buf,
418 repo_common_path_append(repo, buf, "worktrees/%s", wt->id);
419 }
420
420 -static void repo_git_pathv(const struct repository *repo,
421 +static void repo_git_pathv(struct repository *repo,
422 const struct worktree *wt, struct strbuf *buf,
423 const char *fmt, va_list args)
424 {
@@ -432,7 +433,7 @@ static void repo_git_pathv(const struct repository *repo,
433 strbuf_cleanup_path(buf);
434 }
435
435 -char *repo_git_path(const struct repository *repo,
436 +char *repo_git_path(struct repository *repo,
437 const char *fmt, ...)
438 {
439 struct strbuf path = STRBUF_INIT;
@@ -443,7 +444,7 @@ char *repo_git_path(const struct repository *repo,
444 return strbuf_detach(&path, NULL);
445 }
446
446 -const char *repo_git_path_append(const struct repository *repo,
447 +const char *repo_git_path_append(struct repository *repo,
448 struct strbuf *sb,
449 const char *fmt, ...)
450 {
@@ -454,7 +455,7 @@ const char *repo_git_path_append(const struct repository *repo,
455 return sb->buf;
456 }
457
457 -const char *repo_git_path_replace(const struct repository *repo,
458 +const char *repo_git_path_replace(struct repository *repo,
459 struct strbuf *sb,
460 const char *fmt, ...)
461 {
path.h
+3 -3
@@ -52,14 +52,14 @@ const char *repo_common_path_replace(const struct repository *repo,
52 * For an exhaustive list of the adjustments made look at `common_list` and
53 * `adjust_git_path` in path.c.
54 */
55 -char *repo_git_path(const struct repository *repo,
55 +char *repo_git_path(struct repository *repo,
56 const char *fmt, ...)
57 __attribute__((format (printf, 2, 3)));
58 -const char *repo_git_path_append(const struct repository *repo,
58 +const char *repo_git_path_append(struct repository *repo,
59 struct strbuf *sb,
60 const char *fmt, ...)
61 __attribute__((format (printf, 3, 4)));
62 -const char *repo_git_path_replace(const struct repository *repo,
62 +const char *repo_git_path_replace(struct repository *repo,
63 struct strbuf *sb,
64 const char *fmt, ...)
65 __attribute__((format (printf, 3, 4)));
repo-settings.c
+8
@@ -146,6 +146,7 @@ void repo_settings_clear(struct repository *r)
146 {
147 struct repo_settings empty = REPO_SETTINGS_INIT;
148 FREE_AND_NULL(r->settings.fsmonitor);
149 + FREE_AND_NULL(r->settings.hooks_path);
150 r->settings = empty;
151 }
152
@@ -173,3 +174,10 @@ int repo_settings_get_warn_ambiguous_refs(struct repository *repo)
174 &repo->settings.warn_ambiguous_refs, 1);
175 return repo->settings.warn_ambiguous_refs;
176 }
177 +
178 +const char *repo_settings_get_hooks_path(struct repository *repo)
179 +{
180 + if (!repo->settings.hooks_path)
181 + repo_config_get_pathname(repo, "core.hookspath", &repo->settings.hooks_path);
182 + return repo->settings.hooks_path;
183 +}
repo-settings.h
+4
@@ -61,6 +61,8 @@ struct repo_settings {
61 size_t delta_base_cache_limit;
62 size_t packed_git_window_size;
63 size_t packed_git_limit;
64 +
65 + char *hooks_path;
66 };
67 #define REPO_SETTINGS_INIT { \
68 .index_version = -1, \
@@ -79,5 +81,7 @@ void repo_settings_clear(struct repository *r);
81 enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo);
82 /* Read the value for "core.warnAmbiguousRefs". */
83 int repo_settings_get_warn_ambiguous_refs(struct repository *repo);
84 +/* Read the value for "core.hooksPath". */
85 +const char *repo_settings_get_hooks_path(struct repository *repo);
86
87 #endif /* REPO_SETTINGS_H */