3 #include "run-command.h"
6 static int known_hook(const char *name)
9 size_t len = strlen(name);
10 for (p = hook_name_list; *p; p++) {
11 const char *hook = *p;
13 if (!strncmp(name, hook, len) && hook[len] == '\0')
16 if (!strcmp(name, "test-hook") ||
17 !strcmp(name, "does-not-exist"))
23 const char *find_hook(const char *name)
25 static struct strbuf path = STRBUF_INIT;
27 if (!known_hook(name))
28 die(_("the hook '%s' is not known to git, should be in hook-list.h via githooks(5)"),
32 strbuf_git_path(&path, "hooks/%s", name);
33 if (access(path.buf, X_OK) < 0) {
36 #ifdef STRIP_EXTENSION
37 strbuf_addstr(&path, STRIP_EXTENSION);
38 if (access(path.buf, X_OK) >= 0)
44 if (err == EACCES && advice_ignored_hook) {
45 static struct string_list advise_given = STRING_LIST_INIT_DUP;
47 if (!string_list_lookup(&advise_given, name)) {
48 string_list_insert(&advise_given, name);
49 advise(_("The '%s' hook was ignored because "
50 "it's not set as executable.\n"
51 "You can disable this warning with "
52 "`git config advice.ignoredHook false`."),
61 int hook_exists(const char *name)
63 return !!find_hook(name);
66 void run_hooks_opt_clear(struct run_hooks_opt *o)
68 strvec_clear(&o->env);
69 strvec_clear(&o->args);
72 int pipe_from_string_list(struct strbuf *pipe, void *pp_cb, void *pp_task_cb)
75 struct hook *ctx = pp_task_cb;
76 struct hook_cb_data *hook_cb = pp_cb;
77 struct string_list *to_pipe = hook_cb->options->feed_pipe_ctx;
79 /* Bootstrap the state manager if necessary. */
80 if (!ctx->feed_pipe_cb_data) {
81 ctx->feed_pipe_cb_data = xmalloc(sizeof(unsigned int));
82 *(int*)ctx->feed_pipe_cb_data = 0;
85 item_idx = ctx->feed_pipe_cb_data;
87 if (*item_idx < to_pipe->nr) {
88 strbuf_addf(pipe, "%s\n", to_pipe->items[*item_idx].string);
95 static int pick_next_hook(struct child_process *cp,
100 struct hook_cb_data *hook_cb = pp_cb;
101 struct hook *run_me = hook_cb->run_me;
104 BUG("did we not return 1 in notify_hook_finished?");
106 /* reopen the file for stdin; run_command closes it. */
107 if (hook_cb->options->path_to_stdin) {
109 cp->in = xopen(hook_cb->options->path_to_stdin, O_RDONLY);
110 } else if (hook_cb->options->feed_pipe) {
111 /* ask for start_command() to make a pipe for us */
117 cp->env = hook_cb->options->env.v;
118 cp->stdout_to_stderr = 1;
119 cp->trace2_hook_name = hook_cb->hook_name;
120 cp->dir = hook_cb->options->dir;
123 strvec_push(&cp->args, run_me->hook_path);
126 * add passed-in argv, without expanding - let the user get back
127 * exactly what they put in
129 strvec_pushv(&cp->args, hook_cb->options->args.v);
131 /* Provide context for errors if necessary */
132 *pp_task_cb = run_me;
137 static int notify_start_failure(struct strbuf *out,
141 struct hook_cb_data *hook_cb = pp_cb;
142 struct hook *attempted = pp_task_cp;
147 strbuf_addf(out, _("Couldn't start hook '%s'\n"),
148 attempted->hook_path);
153 static int notify_hook_finished(int result,
158 struct hook_cb_data *hook_cb = pp_cb;
161 hook_cb->rc |= result;
163 if (hook_cb->invoked_hook)
164 *hook_cb->invoked_hook = 1;
169 int run_found_hooks(const char *hook_name, const char *hook_path,
170 struct run_hooks_opt *options)
172 struct strbuf abs_path = STRBUF_INIT;
173 struct hook my_hook = {
174 .hook_path = hook_path,
176 struct hook_cb_data cb_data = {
178 .hook_name = hook_name,
180 .invoked_hook = options->invoked_hook,
182 if (options->absolute_path) {
183 strbuf_add_absolute_path(&abs_path, hook_path);
184 my_hook.hook_path = abs_path.buf;
186 cb_data.run_me = &my_hook;
188 if (options->jobs != 1)
189 BUG("we do not handle %d or any other != 1 job number yet", options->jobs);
191 run_processes_parallel_tr2(options->jobs,
193 notify_start_failure,
195 options->consume_sideband,
196 notify_hook_finished,
200 if (options->absolute_path)
201 strbuf_release(&abs_path);
206 int run_hooks(const char *hook_name, struct run_hooks_opt *options)
208 const char *hook_path;
211 BUG("a struct run_hooks_opt must be provided to run_hooks");
213 if (options->path_to_stdin && options->feed_pipe)
214 BUG("choose only one method to populate stdin");
216 hook_path = find_hook(hook_name);
218 /* Care about nonexistence? Use run_found_hooks() */
222 ret = run_found_hooks(hook_name, hook_path, options);