]> git.ipfire.org Git - thirdparty/git.git/blobdiff - hook.c
Merge branch 'hn/reftable-coverity-fixes'
[thirdparty/git.git] / hook.c
diff --git a/hook.c b/hook.c
index 55e1145a4b7b8c59276f082ab0b240817702ace4..69a215b2c3c2c3b95a799a56325de9111873b39e 100644 (file)
--- a/hook.c
+++ b/hook.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "hook.h"
 #include "run-command.h"
+#include "config.h"
 
 const char *find_hook(const char *name)
 {
@@ -40,3 +41,133 @@ int hook_exists(const char *name)
 {
        return !!find_hook(name);
 }
+
+static int pick_next_hook(struct child_process *cp,
+                         struct strbuf *out,
+                         void *pp_cb,
+                         void **pp_task_cb)
+{
+       struct hook_cb_data *hook_cb = pp_cb;
+       const char *hook_path = hook_cb->hook_path;
+
+       if (!hook_path)
+               return 0;
+
+       cp->no_stdin = 1;
+       strvec_pushv(&cp->env_array, hook_cb->options->env.v);
+       cp->stdout_to_stderr = 1;
+       cp->trace2_hook_name = hook_cb->hook_name;
+       cp->dir = hook_cb->options->dir;
+
+       strvec_push(&cp->args, hook_path);
+       strvec_pushv(&cp->args, hook_cb->options->args.v);
+
+       /* Provide context for errors if necessary */
+       *pp_task_cb = (char *)hook_path;
+
+       /*
+        * This pick_next_hook() will be called again, we're only
+        * running one hook, so indicate that no more work will be
+        * done.
+        */
+       hook_cb->hook_path = NULL;
+
+       return 1;
+}
+
+static int notify_start_failure(struct strbuf *out,
+                               void *pp_cb,
+                               void *pp_task_cp)
+{
+       struct hook_cb_data *hook_cb = pp_cb;
+       const char *hook_path = pp_task_cp;
+
+       hook_cb->rc |= 1;
+
+       strbuf_addf(out, _("Couldn't start hook '%s'\n"),
+                   hook_path);
+
+       return 1;
+}
+
+static int notify_hook_finished(int result,
+                               struct strbuf *out,
+                               void *pp_cb,
+                               void *pp_task_cb)
+{
+       struct hook_cb_data *hook_cb = pp_cb;
+
+       hook_cb->rc |= result;
+
+       return 0;
+}
+
+static void run_hooks_opt_clear(struct run_hooks_opt *options)
+{
+       strvec_clear(&options->env);
+       strvec_clear(&options->args);
+}
+
+int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
+{
+       struct strbuf abs_path = STRBUF_INIT;
+       struct hook_cb_data cb_data = {
+               .rc = 0,
+               .hook_name = hook_name,
+               .options = options,
+       };
+       const char *const hook_path = find_hook(hook_name);
+       int jobs = 1;
+       int ret = 0;
+
+       if (!options)
+               BUG("a struct run_hooks_opt must be provided to run_hooks");
+
+       if (!hook_path && !options->error_if_missing)
+               goto cleanup;
+
+       if (!hook_path) {
+               ret = error("cannot find a hook named %s", hook_name);
+               goto cleanup;
+       }
+
+       cb_data.hook_path = hook_path;
+       if (options->dir) {
+               strbuf_add_absolute_path(&abs_path, hook_path);
+               cb_data.hook_path = abs_path.buf;
+       }
+
+       run_processes_parallel_tr2(jobs,
+                                  pick_next_hook,
+                                  notify_start_failure,
+                                  notify_hook_finished,
+                                  &cb_data,
+                                  "hook",
+                                  hook_name);
+       ret = cb_data.rc;
+cleanup:
+       strbuf_release(&abs_path);
+       run_hooks_opt_clear(options);
+       return ret;
+}
+
+int run_hooks(const char *hook_name)
+{
+       struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
+       return run_hooks_opt(hook_name, &opt);
+}
+
+int run_hooks_l(const char *hook_name, ...)
+{
+       struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+       va_list ap;
+       const char *arg;
+
+       va_start(ap, hook_name);
+       while ((arg = va_arg(ap, const char *)))
+               strvec_push(&opt.args, arg);
+       va_end(ap);
+
+       return run_hooks_opt(hook_name, &opt);
+}