Elijah Newren | fc7bd51 | 2023-02-24 00:09:34 +0000 | [diff] [blame] | 1 | #include "git-compat-util.h" |
Calvin Wan | 5d1344b | 2023-06-06 19:48:39 +0000 | [diff] [blame] | 2 | #include "abspath.h" |
Elijah Newren | fc7bd51 | 2023-02-24 00:09:34 +0000 | [diff] [blame] | 3 | #include "advice.h" |
| 4 | #include "gettext.h" |
Ævar Arnfjörð Bjarmason | 5e3aba3 | 2021-09-26 21:03:26 +0200 | [diff] [blame] | 5 | #include "hook.h" |
Elijah Newren | d1cbe1e | 2023-04-22 20:17:20 +0000 | [diff] [blame] | 6 | #include "path.h" |
Ævar Arnfjörð Bjarmason | 5e3aba3 | 2021-09-26 21:03:26 +0200 | [diff] [blame] | 7 | #include "run-command.h" |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 8 | #include "config.h" |
Elijah Newren | fc7bd51 | 2023-02-24 00:09:34 +0000 | [diff] [blame] | 9 | #include "strbuf.h" |
Ævar Arnfjörð Bjarmason | 5e3aba3 | 2021-09-26 21:03:26 +0200 | [diff] [blame] | 10 | |
| 11 | const char *find_hook(const char *name) |
| 12 | { |
| 13 | static struct strbuf path = STRBUF_INIT; |
| 14 | |
| 15 | strbuf_reset(&path); |
| 16 | strbuf_git_path(&path, "hooks/%s", name); |
| 17 | if (access(path.buf, X_OK) < 0) { |
| 18 | int err = errno; |
| 19 | |
| 20 | #ifdef STRIP_EXTENSION |
| 21 | strbuf_addstr(&path, STRIP_EXTENSION); |
| 22 | if (access(path.buf, X_OK) >= 0) |
| 23 | return path.buf; |
| 24 | if (errno == EACCES) |
| 25 | err = errno; |
| 26 | #endif |
| 27 | |
| 28 | if (err == EACCES && advice_enabled(ADVICE_IGNORED_HOOK)) { |
| 29 | static struct string_list advise_given = STRING_LIST_INIT_DUP; |
| 30 | |
| 31 | if (!string_list_lookup(&advise_given, name)) { |
| 32 | string_list_insert(&advise_given, name); |
| 33 | advise(_("The '%s' hook was ignored because " |
| 34 | "it's not set as executable.\n" |
| 35 | "You can disable this warning with " |
| 36 | "`git config advice.ignoredHook false`."), |
| 37 | path.buf); |
| 38 | } |
| 39 | } |
| 40 | return NULL; |
| 41 | } |
| 42 | return path.buf; |
| 43 | } |
Emily Shaffer | 330155e | 2021-09-26 21:03:27 +0200 | [diff] [blame] | 44 | |
| 45 | int hook_exists(const char *name) |
| 46 | { |
| 47 | return !!find_hook(name); |
| 48 | } |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 49 | |
| 50 | static int pick_next_hook(struct child_process *cp, |
Jeff King | a5c76b3 | 2023-02-24 01:39:46 -0500 | [diff] [blame] | 51 | struct strbuf *out UNUSED, |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 52 | void *pp_cb, |
Jeff King | a5c76b3 | 2023-02-24 01:39:46 -0500 | [diff] [blame] | 53 | void **pp_task_cb UNUSED) |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 54 | { |
| 55 | struct hook_cb_data *hook_cb = pp_cb; |
| 56 | const char *hook_path = hook_cb->hook_path; |
| 57 | |
| 58 | if (!hook_path) |
| 59 | return 0; |
| 60 | |
| 61 | cp->no_stdin = 1; |
Ævar Arnfjörð Bjarmason | 29fda24 | 2022-06-02 11:09:50 +0200 | [diff] [blame] | 62 | strvec_pushv(&cp->env, hook_cb->options->env.v); |
Emily Shaffer | 917e080 | 2023-02-08 20:21:13 +0100 | [diff] [blame] | 63 | /* reopen the file for stdin; run_command closes it. */ |
| 64 | if (hook_cb->options->path_to_stdin) { |
| 65 | cp->no_stdin = 0; |
| 66 | cp->in = xopen(hook_cb->options->path_to_stdin, O_RDONLY); |
| 67 | } |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 68 | cp->stdout_to_stderr = 1; |
| 69 | cp->trace2_hook_name = hook_cb->hook_name; |
Emily Shaffer | 1a3017d | 2021-12-22 04:59:36 +0100 | [diff] [blame] | 70 | cp->dir = hook_cb->options->dir; |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 71 | |
| 72 | strvec_push(&cp->args, hook_path); |
| 73 | strvec_pushv(&cp->args, hook_cb->options->args.v); |
| 74 | |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 75 | /* |
| 76 | * This pick_next_hook() will be called again, we're only |
| 77 | * running one hook, so indicate that no more work will be |
| 78 | * done. |
| 79 | */ |
| 80 | hook_cb->hook_path = NULL; |
| 81 | |
| 82 | return 1; |
| 83 | } |
| 84 | |
Jeff King | a5c76b3 | 2023-02-24 01:39:46 -0500 | [diff] [blame] | 85 | static int notify_start_failure(struct strbuf *out UNUSED, |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 86 | void *pp_cb, |
Jeff King | a5c76b3 | 2023-02-24 01:39:46 -0500 | [diff] [blame] | 87 | void *pp_task_cp UNUSED) |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 88 | { |
| 89 | struct hook_cb_data *hook_cb = pp_cb; |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 90 | |
| 91 | hook_cb->rc |= 1; |
| 92 | |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 93 | return 1; |
| 94 | } |
| 95 | |
| 96 | static int notify_hook_finished(int result, |
Jeff King | a5c76b3 | 2023-02-24 01:39:46 -0500 | [diff] [blame] | 97 | struct strbuf *out UNUSED, |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 98 | void *pp_cb, |
Jeff King | a5c76b3 | 2023-02-24 01:39:46 -0500 | [diff] [blame] | 99 | void *pp_task_cb UNUSED) |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 100 | { |
| 101 | struct hook_cb_data *hook_cb = pp_cb; |
Ævar Arnfjörð Bjarmason | a8cc594 | 2022-03-07 13:33:46 +0100 | [diff] [blame] | 102 | struct run_hooks_opt *opt = hook_cb->options; |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 103 | |
| 104 | hook_cb->rc |= result; |
| 105 | |
Ævar Arnfjörð Bjarmason | a8cc594 | 2022-03-07 13:33:46 +0100 | [diff] [blame] | 106 | if (opt->invoked_hook) |
| 107 | *opt->invoked_hook = 1; |
| 108 | |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 109 | return 0; |
| 110 | } |
| 111 | |
| 112 | static void run_hooks_opt_clear(struct run_hooks_opt *options) |
| 113 | { |
| 114 | strvec_clear(&options->env); |
| 115 | strvec_clear(&options->args); |
| 116 | } |
| 117 | |
| 118 | int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options) |
| 119 | { |
Emily Shaffer | 1a3017d | 2021-12-22 04:59:36 +0100 | [diff] [blame] | 120 | struct strbuf abs_path = STRBUF_INIT; |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 121 | struct hook_cb_data cb_data = { |
| 122 | .rc = 0, |
| 123 | .hook_name = hook_name, |
| 124 | .options = options, |
| 125 | }; |
| 126 | const char *const hook_path = find_hook(hook_name); |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 127 | int ret = 0; |
Ævar Arnfjörð Bjarmason | 6e5ba0b | 2022-10-12 23:02:26 +0200 | [diff] [blame] | 128 | const struct run_process_parallel_opts opts = { |
| 129 | .tr2_category = "hook", |
| 130 | .tr2_label = hook_name, |
| 131 | |
| 132 | .processes = 1, |
| 133 | .ungroup = 1, |
| 134 | |
| 135 | .get_next_task = pick_next_hook, |
| 136 | .start_failure = notify_start_failure, |
| 137 | .task_finished = notify_hook_finished, |
| 138 | |
| 139 | .data = &cb_data, |
| 140 | }; |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 141 | |
| 142 | if (!options) |
| 143 | BUG("a struct run_hooks_opt must be provided to run_hooks"); |
| 144 | |
Ævar Arnfjörð Bjarmason | a8cc594 | 2022-03-07 13:33:46 +0100 | [diff] [blame] | 145 | if (options->invoked_hook) |
| 146 | *options->invoked_hook = 0; |
| 147 | |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 148 | if (!hook_path && !options->error_if_missing) |
| 149 | goto cleanup; |
| 150 | |
| 151 | if (!hook_path) { |
| 152 | ret = error("cannot find a hook named %s", hook_name); |
| 153 | goto cleanup; |
| 154 | } |
| 155 | |
| 156 | cb_data.hook_path = hook_path; |
Emily Shaffer | 1a3017d | 2021-12-22 04:59:36 +0100 | [diff] [blame] | 157 | if (options->dir) { |
| 158 | strbuf_add_absolute_path(&abs_path, hook_path); |
| 159 | cb_data.hook_path = abs_path.buf; |
| 160 | } |
| 161 | |
Ævar Arnfjörð Bjarmason | 6e5ba0b | 2022-10-12 23:02:26 +0200 | [diff] [blame] | 162 | run_processes_parallel(&opts); |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 163 | ret = cb_data.rc; |
| 164 | cleanup: |
Emily Shaffer | 1a3017d | 2021-12-22 04:59:36 +0100 | [diff] [blame] | 165 | strbuf_release(&abs_path); |
Emily Shaffer | 96e7225 | 2021-12-22 04:59:27 +0100 | [diff] [blame] | 166 | run_hooks_opt_clear(options); |
| 167 | return ret; |
| 168 | } |
Ævar Arnfjörð Bjarmason | 474c119 | 2021-12-22 04:59:28 +0100 | [diff] [blame] | 169 | |
| 170 | int run_hooks(const char *hook_name) |
| 171 | { |
| 172 | struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT; |
| 173 | |
| 174 | return run_hooks_opt(hook_name, &opt); |
| 175 | } |
Ævar Arnfjörð Bjarmason | ab81cf2 | 2021-12-22 04:59:31 +0100 | [diff] [blame] | 176 | |
| 177 | int run_hooks_l(const char *hook_name, ...) |
| 178 | { |
| 179 | struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT; |
| 180 | va_list ap; |
| 181 | const char *arg; |
| 182 | |
| 183 | va_start(ap, hook_name); |
| 184 | while ((arg = va_arg(ap, const char *))) |
| 185 | strvec_push(&opt.args, arg); |
| 186 | va_end(ap); |
| 187 | |
| 188 | return run_hooks_opt(hook_name, &opt); |
| 189 | } |