diff options
| author | Junio C Hamano <gitster@pobox.com> | 2026-03-10 14:23:18 -0700 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2026-03-10 14:23:18 -0700 |
| commit | f330d46deeb143b6109143f37a47d025475d11d6 (patch) | |
| tree | c2b93a2ec12c0e9c8227be1a362c0fd261d6376a /builtin | |
| parent | 9a8aebae972de22ecd5adb92fec9d77147949c8a (diff) | |
| parent | ec1c4d974ac74afb4f0574d29f7bbb30c1c46431 (diff) | |
| download | git-f330d46deeb143b6109143f37a47d025475d11d6.tar.xz | |
Merge branch 'ar/config-hooks'
Allow hook commands to be defined (possibly centrally) in the
configuration files, and run multiple of them for the same hook
event.
* ar/config-hooks:
hook: add -z option to "git hook list"
hook: allow out-of-repo 'git hook' invocations
hook: allow event = "" to overwrite previous values
hook: allow disabling config hooks
hook: include hooks from the config
hook: add "git hook list" command
hook: run a list of hooks to prepare for multihook support
hook: add internal state alloc/free callbacks
Diffstat (limited to 'builtin')
| -rw-r--r-- | builtin/hook.c | 66 | ||||
| -rw-r--r-- | builtin/receive-pack.c | 33 |
2 files changed, 92 insertions, 7 deletions
diff --git a/builtin/hook.c b/builtin/hook.c index 7afec380d2..83020dfb4f 100644 --- a/builtin/hook.c +++ b/builtin/hook.c @@ -6,12 +6,16 @@ #include "hook.h" #include "parse-options.h" #include "strvec.h" +#include "abspath.h" #define BUILTIN_HOOK_RUN_USAGE \ N_("git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]") +#define BUILTIN_HOOK_LIST_USAGE \ + N_("git hook list [-z] <hook-name>") static const char * const builtin_hook_usage[] = { BUILTIN_HOOK_RUN_USAGE, + BUILTIN_HOOK_LIST_USAGE, NULL }; @@ -20,6 +24,67 @@ static const char * const builtin_hook_run_usage[] = { NULL }; +static int list(int argc, const char **argv, const char *prefix, + struct repository *repo) +{ + static const char *const builtin_hook_list_usage[] = { + BUILTIN_HOOK_LIST_USAGE, + NULL + }; + struct string_list *head; + struct string_list_item *item; + const char *hookname = NULL; + int line_terminator = '\n'; + int ret = 0; + + struct option list_options[] = { + OPT_SET_INT('z', NULL, &line_terminator, + N_("use NUL as line terminator"), '\0'), + OPT_END(), + }; + + argc = parse_options(argc, argv, prefix, list_options, + builtin_hook_list_usage, 0); + + /* + * The only unnamed argument provided should be the hook-name; if we add + * arguments later they probably should be caught by parse_options. + */ + if (argc != 1) + usage_msg_opt(_("You must specify a hook event name to list."), + builtin_hook_list_usage, list_options); + + hookname = argv[0]; + + head = list_hooks(repo, hookname, NULL); + + if (!head->nr) { + warning(_("No hooks found for event '%s'"), hookname); + ret = 1; /* no hooks found */ + goto cleanup; + } + + for_each_string_list_item(item, head) { + struct hook *h = item->util; + + switch (h->kind) { + case HOOK_TRADITIONAL: + printf("%s%c", _("hook from hookdir"), line_terminator); + break; + case HOOK_CONFIGURED: + printf("%s%c", h->u.configured.friendly_name, line_terminator); + break; + default: + BUG("unknown hook kind"); + } + } + +cleanup: + hook_list_clear(head, NULL); + free(head); + return ret; +} + static int run(int argc, const char **argv, const char *prefix, struct repository *repo UNUSED) { @@ -77,6 +142,7 @@ int cmd_hook(int argc, parse_opt_subcommand_fn *fn = NULL; struct option builtin_hook_options[] = { OPT_SUBCOMMAND("run", &fn, run), + OPT_SUBCOMMAND("list", &fn, list), OPT_END(), }; diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 55d39daa62..d6225df890 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -901,6 +901,26 @@ static int feed_receive_hook_cb(int hook_stdin_fd, void *pp_cb UNUSED, void *pp_ return state->cmd ? 0 : 1; /* 0 = more to come, 1 = EOF */ } +static void *receive_hook_feed_state_alloc(void *feed_pipe_ctx) +{ + struct receive_hook_feed_state *init_state = feed_pipe_ctx; + struct receive_hook_feed_state *data = xcalloc(1, sizeof(*data)); + data->report = init_state->report; + data->cmd = init_state->cmd; + data->skip_broken = init_state->skip_broken; + strbuf_init(&data->buf, 0); + return data; +} + +static void receive_hook_feed_state_free(void *data) +{ + struct receive_hook_feed_state *d = data; + if (!d) + return; + strbuf_release(&d->buf); + free(d); +} + static int run_receive_hook(struct command *commands, const char *hook_name, int skip_broken, @@ -908,7 +928,7 @@ static int run_receive_hook(struct command *commands, { struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT; struct command *iter = commands; - struct receive_hook_feed_state feed_state; + struct receive_hook_feed_state feed_init_state = { 0 }; struct async sideband_async; int sideband_async_started = 0; int saved_stderr = -1; @@ -941,16 +961,15 @@ static int run_receive_hook(struct command *commands, prepare_sideband_async(&sideband_async, &saved_stderr, &sideband_async_started); /* set up stdin callback */ - feed_state.cmd = commands; - feed_state.skip_broken = skip_broken; - feed_state.report = NULL; - strbuf_init(&feed_state.buf, 0); - opt.feed_pipe_cb_data = &feed_state; + feed_init_state.cmd = commands; + feed_init_state.skip_broken = skip_broken; + opt.feed_pipe_ctx = &feed_init_state; opt.feed_pipe = feed_receive_hook_cb; + opt.feed_pipe_cb_data_alloc = receive_hook_feed_state_alloc; + opt.feed_pipe_cb_data_free = receive_hook_feed_state_free; ret = run_hooks_opt(the_repository, hook_name, &opt); - strbuf_release(&feed_state.buf); finish_sideband_async(&sideband_async, saved_stderr, sideband_async_started); return ret; |
