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