* [PATCH v3 01/13] hook: add 'run' subcommand
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 02/13] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
` (13 subsequent siblings)
14 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
In order to enable hooks to be run as an external process, by a
standalone Git command, or by tools which wrap Git, provide an external
means to run all configured hook commands for a given hook event.
Most of our hooks require more complex functionality than this, but
let's start with the bare minimum required to support our simplest
hooks.
In terms of implementation the usage_with_options() and "goto usage"
pattern here mirrors that of
builtin/{commit-graph,multi-pack-index}.c.
Some of the implementation here, such as a function being named
run_hooks() when it's tasked with running one hook, to using the
run_processes_parallel_tr2() API to run with jobs=1 is somewhere
between a bit odd and and an overkill for the current features of this
"hook run" command and the hook.[ch] API.
This code will eventually be able to run multiple hooks declared in
config in parallel, by starting out with these names and APIs we
reduce the later churn of renaming functions, switching from the
run_command() to run_processes_parallel_tr2() API etc.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
.gitignore | 1 +
Documentation/git-hook.txt | 37 +++++++++++
Documentation/githooks.txt | 4 ++
Makefile | 1 +
builtin.h | 1 +
builtin/hook.c | 85 ++++++++++++++++++++++++
command-list.txt | 1 +
git.c | 1 +
hook.c | 91 ++++++++++++++++++++++++++
hook.h | 34 ++++++++++
t/t1800-hook.sh | 129 +++++++++++++++++++++++++++++++++++++
11 files changed, 385 insertions(+)
create mode 100644 Documentation/git-hook.txt
create mode 100644 builtin/hook.c
create mode 100755 t/t1800-hook.sh
diff --git a/.gitignore b/.gitignore
index 054249b20a8..f817c509ec0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,6 +77,7 @@
/git-grep
/git-hash-object
/git-help
+/git-hook
/git-http-backend
/git-http-fetch
/git-http-push
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
new file mode 100644
index 00000000000..e39b1b5d069
--- /dev/null
+++ b/Documentation/git-hook.txt
@@ -0,0 +1,37 @@
+git-hook(1)
+===========
+
+NAME
+----
+git-hook - Run git hooks
+
+SYNOPSIS
+--------
+[verse]
+'git hook' run <hook-name> [-- <hook-args>]
+
+DESCRIPTION
+-----------
+
+A command interface to running git hooks (see linkgit:githooks[5]),
+for use by other scripted git commands.
+
+SUBCOMMANDS
+-----------
+
+run::
+ Run the `<hook-name>` hook. See linkgit:githooks[5] for
+ supported hook names.
++
+
+Any positional arguments to the hook should be passed after a
+mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
+linkgit:githooks[5] for arguments hooks might expect (if any).
+
+SEE ALSO
+--------
+linkgit:githooks[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index b51959ff941..a16e62bc8c8 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -698,6 +698,10 @@ and "0" meaning they were not.
Only one parameter should be set to "1" when the hook runs. The hook
running passing "1", "1" should not be possible.
+SEE ALSO
+--------
+linkgit:git-hook[1]
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 381bed2c1d2..1eef009def2 100644
--- a/Makefile
+++ b/Makefile
@@ -1107,6 +1107,7 @@ BUILTIN_OBJS += builtin/get-tar-commit-id.o
BUILTIN_OBJS += builtin/grep.o
BUILTIN_OBJS += builtin/hash-object.o
BUILTIN_OBJS += builtin/help.o
+BUILTIN_OBJS += builtin/hook.o
BUILTIN_OBJS += builtin/index-pack.o
BUILTIN_OBJS += builtin/init-db.o
BUILTIN_OBJS += builtin/interpret-trailers.o
diff --git a/builtin.h b/builtin.h
index 8a58743ed63..83379f3832c 100644
--- a/builtin.h
+++ b/builtin.h
@@ -164,6 +164,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
int cmd_grep(int argc, const char **argv, const char *prefix);
int cmd_hash_object(int argc, const char **argv, const char *prefix);
int cmd_help(int argc, const char **argv, const char *prefix);
+int cmd_hook(int argc, const char **argv, const char *prefix);
int cmd_index_pack(int argc, const char **argv, const char *prefix);
int cmd_init_db(int argc, const char **argv, const char *prefix);
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix);
diff --git a/builtin/hook.c b/builtin/hook.c
new file mode 100644
index 00000000000..41dd15550cf
--- /dev/null
+++ b/builtin/hook.c
@@ -0,0 +1,85 @@
+#include "cache.h"
+#include "builtin.h"
+#include "config.h"
+#include "hook.h"
+#include "parse-options.h"
+#include "strbuf.h"
+#include "strvec.h"
+
+#define BUILTIN_HOOK_RUN_USAGE \
+ N_("git hook run <hook-name> [-- <hook-args>]")
+
+static const char * const builtin_hook_usage[] = {
+ BUILTIN_HOOK_RUN_USAGE,
+ NULL
+};
+
+static const char * const builtin_hook_run_usage[] = {
+ BUILTIN_HOOK_RUN_USAGE,
+ NULL
+};
+
+static int run(int argc, const char **argv, const char *prefix)
+{
+ int i;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ const char *hook_name;
+ const char *hook_path;
+ struct option run_options[] = {
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, run_options,
+ builtin_hook_run_usage,
+ PARSE_OPT_KEEP_DASHDASH);
+
+ if (!argc)
+ goto usage;
+
+ /*
+ * Having a -- for "run" when providing <hook-args> is
+ * mandatory.
+ */
+ if (argc > 1 && strcmp(argv[1], "--") &&
+ strcmp(argv[1], "--end-of-options"))
+ goto usage;
+
+ /* Add our arguments, start after -- */
+ for (i = 2 ; i < argc; i++)
+ strvec_push(&opt.args, argv[i]);
+
+ /* Need to take into account core.hooksPath */
+ git_config(git_default_config, NULL);
+
+ hook_name = argv[0];
+ hook_path = find_hook(hook_name);
+ if (!hook_path) {
+ error("cannot find a hook named %s", hook_name);
+ return 1;
+ }
+
+ ret = run_hooks(hook_name, hook_path, &opt);
+ run_hooks_opt_clear(&opt);
+ return ret;
+usage:
+ usage_with_options(builtin_hook_run_usage, run_options);
+}
+
+int cmd_hook(int argc, const char **argv, const char *prefix)
+{
+ struct option builtin_hook_options[] = {
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, NULL, builtin_hook_options,
+ builtin_hook_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+ if (!argc)
+ goto usage;
+
+ if (!strcmp(argv[0], "run"))
+ return run(argc, argv, prefix);
+
+usage:
+ usage_with_options(builtin_hook_usage, builtin_hook_options);
+}
diff --git a/command-list.txt b/command-list.txt
index a289f09ed6f..17c3958802e 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -103,6 +103,7 @@ git-grep mainporcelain info
git-gui mainporcelain
git-hash-object plumbingmanipulators
git-help ancillaryinterrogators complete
+git-hook purehelpers
git-http-backend synchingrepositories
git-http-fetch synchelpers
git-http-push synchelpers
diff --git a/git.c b/git.c
index 5ff21be21f3..a5be02b04b8 100644
--- a/git.c
+++ b/git.c
@@ -538,6 +538,7 @@ static struct cmd_struct commands[] = {
{ "grep", cmd_grep, RUN_SETUP_GENTLY },
{ "hash-object", cmd_hash_object },
{ "help", cmd_help },
+ { "hook", cmd_hook, RUN_SETUP },
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY | NO_PARSEOPT },
{ "init", cmd_init_db },
{ "init-db", cmd_init_db },
diff --git a/hook.c b/hook.c
index 55e1145a4b7..20a1a4fec33 100644
--- 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,93 @@ int hook_exists(const char *name)
{
return !!find_hook(name);
}
+
+void run_hooks_opt_clear(struct run_hooks_opt *o)
+{
+ strvec_clear(&o->env);
+ strvec_clear(&o->args);
+}
+
+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;
+ cp->env = hook_cb->options->env.v;
+ cp->stdout_to_stderr = 1;
+ cp->trace2_hook_name = hook_cb->hook_name;
+
+ 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;
+}
+
+int run_hooks(const char *hook_name, const char *hook_path,
+ struct run_hooks_opt *options)
+{
+ struct hook_cb_data cb_data = {
+ .rc = 0,
+ .hook_name = hook_name,
+ .hook_path = hook_path,
+ .options = options,
+ };
+ int jobs = 1;
+
+ if (!options)
+ BUG("a struct run_hooks_opt must be provided to run_hooks");
+
+ run_processes_parallel_tr2(jobs,
+ pick_next_hook,
+ notify_start_failure,
+ notify_hook_finished,
+ &cb_data,
+ "hook",
+ hook_name);
+
+ return cb_data.rc;
+}
diff --git a/hook.h b/hook.h
index 6aa36fc7ff9..a9317c3f95e 100644
--- a/hook.h
+++ b/hook.h
@@ -1,5 +1,28 @@
#ifndef HOOK_H
#define HOOK_H
+#include "strvec.h"
+
+struct run_hooks_opt
+{
+ /* Environment vars to be set for each hook */
+ struct strvec env;
+
+ /* Args to be passed to each hook */
+ struct strvec args;
+};
+
+#define RUN_HOOKS_OPT_INIT { \
+ .env = STRVEC_INIT, \
+ .args = STRVEC_INIT, \
+}
+
+struct hook_cb_data {
+ /* rc reflects the cumulative failure state */
+ int rc;
+ const char *hook_name;
+ const char *hook_path;
+ struct run_hooks_opt *options;
+};
/*
* Returns the path to the hook file, or NULL if the hook is missing
@@ -13,4 +36,15 @@ const char *find_hook(const char *name);
*/
int hook_exists(const char *hookname);
+/**
+ * Clear data from an initialized "struct run_hooks_opt".
+ */
+void run_hooks_opt_clear(struct run_hooks_opt *o);
+
+/**
+ * Takes an already resolved hook found via find_hook() and runs
+ * it. Does not call run_hooks_opt_clear() for you.
+ */
+int run_hooks(const char *hookname, const char *hook_path,
+ struct run_hooks_opt *options);
#endif
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
new file mode 100755
index 00000000000..3aea1b105f0
--- /dev/null
+++ b/t/t1800-hook.sh
@@ -0,0 +1,129 @@
+#!/bin/sh
+
+test_description='git-hook command'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'git hook usage' '
+ test_expect_code 129 git hook &&
+ test_expect_code 129 git hook run &&
+ test_expect_code 129 git hook run -h &&
+ test_expect_code 129 git hook run --unknown 2>err &&
+ grep "unknown option" err
+'
+
+test_expect_success 'git hook run: nonexistent hook' '
+ cat >stderr.expect <<-\EOF &&
+ error: cannot find a hook named test-hook
+ EOF
+ test_expect_code 1 git hook run test-hook 2>stderr.actual &&
+ test_cmp stderr.expect stderr.actual
+'
+
+test_expect_success 'git hook run: basic' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo Test hook
+ EOF
+
+ cat >expect <<-\EOF &&
+ Test hook
+ EOF
+ git hook run test-hook 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git hook run: stdout and stderr both write to our stderr' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo >&1 Will end up on stderr
+ echo >&2 Will end up on stderr
+ EOF
+
+ cat >stderr.expect <<-\EOF &&
+ Will end up on stderr
+ Will end up on stderr
+ EOF
+ git hook run test-hook >stdout.actual 2>stderr.actual &&
+ test_cmp stderr.expect stderr.actual &&
+ test_must_be_empty stdout.actual
+'
+
+test_expect_success 'git hook run: exit codes are passed along' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 1
+ EOF
+
+ test_expect_code 1 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 2
+ EOF
+
+ test_expect_code 2 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 128
+ EOF
+
+ test_expect_code 128 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 129
+ EOF
+
+ test_expect_code 129 git hook run test-hook
+'
+
+test_expect_success 'git hook run arg u ments without -- is not allowed' '
+ test_expect_code 129 git hook run test-hook arg u ments
+'
+
+test_expect_success 'git hook run -- pass arguments' '
+ write_script .git/hooks/test-hook <<-\EOF &&
+ echo $1
+ echo $2
+ EOF
+
+ cat >expect <<-EOF &&
+ arg
+ u ments
+ EOF
+
+ git hook run test-hook -- arg "u ments" 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git hook run -- out-of-repo runs excluded' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo Test hook
+ EOF
+
+ nongit test_must_fail git hook run test-hook
+'
+
+test_expect_success 'git -c core.hooksPath=<PATH> hook run' '
+ mkdir my-hooks &&
+ write_script my-hooks/test-hook <<-\EOF &&
+ echo Hook ran $1 >>actual
+ EOF
+
+ cat >expect <<-\EOF &&
+ Test hook
+ Hook ran one
+ Hook ran two
+ Hook ran three
+ Hook ran four
+ EOF
+
+ # Test various ways of specifying the path. See also
+ # t1350-config-hooks-path.sh
+ >actual &&
+ git hook run test-hook -- ignored 2>>actual &&
+ git -c core.hooksPath=my-hooks hook run test-hook -- one 2>>actual &&
+ git -c core.hooksPath=my-hooks/ hook run test-hook -- two 2>>actual &&
+ git -c core.hooksPath="$PWD/my-hooks" hook run test-hook -- three 2>>actual &&
+ git -c core.hooksPath="$PWD/my-hooks/" hook run test-hook -- four 2>>actual &&
+ test_cmp expect actual
+'
+
+test_done
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v3 02/13] gc: use hook library for pre-auto-gc hook
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 01/13] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 03/13] rebase: convert pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
` (12 subsequent siblings)
14 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the pre-auto-gc hook away from run-command.h to and over to the
new hook.h library.
To do this introduce a simple run_hooks_oneshot() wrapper, we'll be
using it extensively for these simple cases of wanting to run a single
hook under a given name, and having it free the memory we allocate for
us.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/gc.c | 3 ++-
hook.c | 20 ++++++++++++++++++++
hook.h | 13 +++++++++++++
3 files changed, 35 insertions(+), 1 deletion(-)
diff --git a/builtin/gc.c b/builtin/gc.c
index 6b3de3dd514..95939e77f53 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -32,6 +32,7 @@
#include "remote.h"
#include "object-store.h"
#include "exec-cmd.h"
+#include "hook.h"
#define FAILED_RUN "failed to run %s"
@@ -394,7 +395,7 @@ static int need_to_gc(void)
else
return 0;
- if (run_hook_le(NULL, "pre-auto-gc", NULL))
+ if (run_hooks_oneshot("pre-auto-gc", NULL))
return 0;
return 1;
}
diff --git a/hook.c b/hook.c
index 20a1a4fec33..9951015dc66 100644
--- a/hook.c
+++ b/hook.c
@@ -131,3 +131,23 @@ int run_hooks(const char *hook_name, const char *hook_path,
return cb_data.rc;
}
+
+int run_hooks_oneshot(const char *hook_name, struct run_hooks_opt *options)
+{
+ const char *hook_path;
+ struct run_hooks_opt hook_opt_scratch = RUN_HOOKS_OPT_INIT;
+ int ret = 0;
+
+ if (!options)
+ options = &hook_opt_scratch;
+
+ hook_path = find_hook(hook_name);
+ if (!hook_path)
+ goto cleanup;
+
+ ret = run_hooks(hook_name, hook_path, options);
+cleanup:
+ run_hooks_opt_clear(options);
+
+ return ret;
+}
diff --git a/hook.h b/hook.h
index a9317c3f95e..9e4d10df63e 100644
--- a/hook.h
+++ b/hook.h
@@ -44,7 +44,20 @@ void run_hooks_opt_clear(struct run_hooks_opt *o);
/**
* Takes an already resolved hook found via find_hook() and runs
* it. Does not call run_hooks_opt_clear() for you.
+ *
+ * See run_hooks_oneshot() for the simpler one-shot API.
*/
int run_hooks(const char *hookname, const char *hook_path,
struct run_hooks_opt *options);
+
+/**
+ * Calls find_hook() on your "hook_name" and runs the hooks (if any)
+ * with run_hooks().
+ *
+ * If "options" is provided calls run_hooks_opt_clear() on it for
+ * you. If "options" is NULL the default options from
+ * RUN_HOOKS_OPT_INIT will be used.
+ */
+int run_hooks_oneshot(const char *hook_name, struct run_hooks_opt *options);
+
#endif
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v3 03/13] rebase: convert pre-rebase to use hook.h
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 01/13] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 02/13] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-29 5:48 ` Junio C Hamano
2021-10-19 23:20 ` [PATCH v3 04/13] am: convert applypatch " Ævar Arnfjörð Bjarmason
` (11 subsequent siblings)
14 siblings, 1 reply; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the pre-rebase hook away from run-command.h to and over to the
new hook.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/rebase.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 34b4744e5f3..758b5dfabe2 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -28,6 +28,7 @@
#include "sequencer.h"
#include "rebase-interactive.h"
#include "reset.h"
+#include "hook.h"
#define DEFAULT_REFLOG_ACTION "rebase"
@@ -1017,6 +1018,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
int reschedule_failed_exec = -1;
int allow_preemptive_ff = 1;
int preserve_merges_selected = 0;
+ struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
struct option builtin_rebase_options[] = {
OPT_STRING(0, "onto", &options.onto_name,
N_("revision"),
@@ -1711,9 +1713,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
}
/* If a hook exists, give it a chance to interrupt*/
+ strvec_push(&hook_opt.args, options.upstream_arg);
+ if (argc)
+ strvec_push(&hook_opt.args, argv[0]);
if (!ok_to_skip_pre_rebase &&
- run_hook_le(NULL, "pre-rebase", options.upstream_arg,
- argc ? argv[0] : NULL, NULL))
+ run_hooks_oneshot("pre-rebase", &hook_opt))
die(_("The pre-rebase hook refused to rebase."));
if (options.flags & REBASE_DIFFSTAT) {
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v3 03/13] rebase: convert pre-rebase to use hook.h
2021-10-19 23:20 ` [PATCH v3 03/13] rebase: convert pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-10-29 5:48 ` Junio C Hamano
0 siblings, 0 replies; 115+ messages in thread
From: Junio C Hamano @ 2021-10-29 5:48 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason
Cc: git, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
> From: Emily Shaffer <emilyshaffer@google.com>
>
> Move the pre-rebase hook away from run-command.h to and over to the
> new hook.h library.
>
> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
> builtin/rebase.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 34b4744e5f3..758b5dfabe2 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -28,6 +28,7 @@
> #include "sequencer.h"
> #include "rebase-interactive.h"
> #include "reset.h"
> +#include "hook.h"
>
> #define DEFAULT_REFLOG_ACTION "rebase"
>
> @@ -1017,6 +1018,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
> int reschedule_failed_exec = -1;
> int allow_preemptive_ff = 1;
> int preserve_merges_selected = 0;
> + struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
> struct option builtin_rebase_options[] = {
> OPT_STRING(0, "onto", &options.onto_name,
> N_("revision"),
> @@ -1711,9 +1713,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
> }
>
> /* If a hook exists, give it a chance to interrupt*/
> + strvec_push(&hook_opt.args, options.upstream_arg);
> + if (argc)
> + strvec_push(&hook_opt.args, argv[0]);
> if (!ok_to_skip_pre_rebase &&
> - run_hook_le(NULL, "pre-rebase", options.upstream_arg,
> - argc ? argv[0] : NULL, NULL))
> + run_hooks_oneshot("pre-rebase", &hook_opt))
> die(_("The pre-rebase hook refused to rebase."));
>
> if (options.flags & REBASE_DIFFSTAT) {
OK, so the convention is
* if there is no extra args the hook takes, you only give hook_name
and NULL;
* if there is even one arg the hook takes, you have to prepare the
opt struct and strvec_push() the arg yourself.
That would work, and it might be merely the matter of taste, but it
would have been nicer if the calling sequence to run_hooks_oneshot()
were more like run_hook_le().
But patches were already written, so let's keep reading.
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v3 04/13] am: convert applypatch to use hook.h
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (2 preceding siblings ...)
2021-10-19 23:20 ` [PATCH v3 03/13] rebase: convert pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 05/13] hooks: convert 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
` (10 subsequent siblings)
14 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Teach pre-applypatch, post-applypatch, and applypatch-msg to use the
hook.h library instead of the run-command.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/am.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/builtin/am.c b/builtin/am.c
index 8677ea2348a..5528f131a81 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -446,9 +446,11 @@ static void am_destroy(const struct am_state *state)
static int run_applypatch_msg_hook(struct am_state *state)
{
int ret;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
assert(state->msg);
- ret = run_hook_le(NULL, "applypatch-msg", am_path(state, "final-commit"), NULL);
+ strvec_push(&opt.args, am_path(state, "final-commit"));
+ ret = run_hooks_oneshot("applypatch-msg", &opt);
if (!ret) {
FREE_AND_NULL(state->msg);
@@ -1609,7 +1611,7 @@ static void do_commit(const struct am_state *state)
const char *reflog_msg, *author, *committer = NULL;
struct strbuf sb = STRBUF_INIT;
- if (run_hook_le(NULL, "pre-applypatch", NULL))
+ if (run_hooks_oneshot("pre-applypatch", NULL))
exit(1);
if (write_cache_as_tree(&tree, 0, NULL))
@@ -1661,7 +1663,7 @@ static void do_commit(const struct am_state *state)
fclose(fp);
}
- run_hook_le(NULL, "post-applypatch", NULL);
+ run_hooks_oneshot("post-applypatch", NULL);
strbuf_release(&sb);
}
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v3 05/13] hooks: convert 'post-checkout' hook to hook library
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (3 preceding siblings ...)
2021-10-19 23:20 ` [PATCH v3 04/13] am: convert applypatch " Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-29 5:55 ` Junio C Hamano
2021-10-19 23:20 ` [PATCH v3 06/13] merge: convert post-merge to use hook.h Ævar Arnfjörð Bjarmason
` (9 subsequent siblings)
14 siblings, 1 reply; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the running of the 'post-checkout' hook away from run-command.h
to the new hook.h library. For "worktree" this requires a change to it
to run the hooks from a given directory.
We could strictly speaking skip the "absolute_path" flag and just
check if "dir" is specified, but let's split them up for clarity, as
well as for any future user who'd like to set "dir" but not implicitly
change the argument to an absolute path.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/checkout.c | 14 +++++++++-----
builtin/clone.c | 7 +++++--
builtin/worktree.c | 28 ++++++++++++----------------
hook.c | 12 +++++++++++-
hook.h | 9 +++++++++
reset.c | 14 ++++++++++----
6 files changed, 56 insertions(+), 28 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index cbf73b8c9f6..54cbba821a8 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -9,6 +9,7 @@
#include "config.h"
#include "diff.h"
#include "dir.h"
+#include "hook.h"
#include "ll-merge.h"
#include "lockfile.h"
#include "merge-recursive.h"
@@ -106,13 +107,16 @@ struct branch_info {
static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
- return run_hook_le(NULL, "post-checkout",
- oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
- oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
- changed ? "1" : "0", NULL);
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
/* "new_commit" can be NULL when checking out from the index before
a commit exists. */
-
+ strvec_pushl(&opt.args,
+ oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
+ oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
+ changed ? "1" : "0",
+ NULL);
+ return run_hooks_oneshot("post-checkout", &opt);
}
static int update_some(const struct object_id *oid, struct strbuf *base,
diff --git a/builtin/clone.c b/builtin/clone.c
index 559acf9e036..53ca5ca0eb2 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -32,6 +32,7 @@
#include "connected.h"
#include "packfile.h"
#include "list-objects-filter-options.h"
+#include "hook.h"
/*
* Overall FIXMEs:
@@ -659,6 +660,7 @@ static int checkout(int submodule_progress)
struct tree *tree;
struct tree_desc t;
int err = 0;
+ struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
if (option_no_checkout)
return 0;
@@ -705,8 +707,9 @@ static int checkout(int submodule_progress)
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
- err |= run_hook_le(NULL, "post-checkout", oid_to_hex(null_oid()),
- oid_to_hex(&oid), "1", NULL);
+ strvec_pushl(&hook_opt.args, oid_to_hex(null_oid()), oid_to_hex(&oid),
+ "1", NULL);
+ err |= run_hooks_oneshot("post-checkout", &hook_opt);
if (!err && (option_recurse_submodules.nr > 0)) {
struct strvec args = STRVEC_INIT;
diff --git a/builtin/worktree.c b/builtin/worktree.c
index d22ece93e1a..330867c19bf 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -382,22 +382,18 @@ static int add_worktree(const char *path, const char *refname,
* is_junk is cleared, but do return appropriate code when hook fails.
*/
if (!ret && opts->checkout) {
- const char *hook = find_hook("post-checkout");
- if (hook) {
- const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL };
- cp.git_cmd = 0;
- cp.no_stdin = 1;
- cp.stdout_to_stderr = 1;
- cp.dir = path;
- cp.env = env;
- cp.argv = NULL;
- cp.trace2_hook_name = "post-checkout";
- strvec_pushl(&cp.args, absolute_path(hook),
- oid_to_hex(null_oid()),
- oid_to_hex(&commit->object.oid),
- "1", NULL);
- ret = run_command(&cp);
- }
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
+ strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL);
+ strvec_pushl(&opt.args,
+ oid_to_hex(null_oid()),
+ oid_to_hex(&commit->object.oid),
+ "1",
+ NULL);
+ opt.dir = path;
+ opt.absolute_path = 1;
+
+ ret = run_hooks_oneshot("post-checkout", &opt);
}
strvec_clear(&child_env);
diff --git a/hook.c b/hook.c
index 9951015dc66..bf34cd0a2c1 100644
--- a/hook.c
+++ b/hook.c
@@ -63,6 +63,7 @@ static int pick_next_hook(struct child_process *cp,
cp->env = 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);
@@ -110,10 +111,10 @@ static int notify_hook_finished(int result,
int run_hooks(const char *hook_name, const char *hook_path,
struct run_hooks_opt *options)
{
+ struct strbuf abs_path = STRBUF_INIT;
struct hook_cb_data cb_data = {
.rc = 0,
.hook_name = hook_name,
- .hook_path = hook_path,
.options = options,
};
int jobs = 1;
@@ -121,6 +122,12 @@ int run_hooks(const char *hook_name, const char *hook_path,
if (!options)
BUG("a struct run_hooks_opt must be provided to run_hooks");
+ if (options->absolute_path) {
+ strbuf_add_absolute_path(&abs_path, hook_path);
+ hook_path = abs_path.buf;
+ }
+ cb_data.hook_path = hook_path;
+
run_processes_parallel_tr2(jobs,
pick_next_hook,
notify_start_failure,
@@ -129,6 +136,9 @@ int run_hooks(const char *hook_name, const char *hook_path,
"hook",
hook_name);
+ if (options->absolute_path)
+ strbuf_release(&abs_path);
+
return cb_data.rc;
}
diff --git a/hook.h b/hook.h
index 9e4d10df63e..252a605b125 100644
--- a/hook.h
+++ b/hook.h
@@ -9,6 +9,15 @@ struct run_hooks_opt
/* Args to be passed to each hook */
struct strvec args;
+
+ /*
+ * Resolve and run the "absolute_path(hook)" instead of
+ * "hook". Used for "git worktree" hooks
+ */
+ int absolute_path;
+
+ /* Path to initial working directory for subprocess */
+ const char *dir;
};
#define RUN_HOOKS_OPT_INIT { \
diff --git a/reset.c b/reset.c
index f214df3d96c..4234dd345db 100644
--- a/reset.c
+++ b/reset.c
@@ -7,6 +7,7 @@
#include "tree-walk.h"
#include "tree.h"
#include "unpack-trees.h"
+#include "hook.h"
int reset_head(struct repository *r, struct object_id *oid, const char *action,
const char *switch_to_branch, unsigned flags,
@@ -126,10 +127,15 @@ int reset_head(struct repository *r, struct object_id *oid, const char *action,
ret = create_symref("HEAD", switch_to_branch,
reflog_head);
}
- if (run_hook)
- run_hook_le(NULL, "post-checkout",
- oid_to_hex(orig ? orig : null_oid()),
- oid_to_hex(oid), "1", NULL);
+ if (run_hook) {
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ strvec_pushl(&opt.args,
+ oid_to_hex(orig ? orig : null_oid()),
+ oid_to_hex(oid),
+ "1",
+ NULL);
+ run_hooks_oneshot("post-checkout", &opt);
+ }
leave_reset_head:
strbuf_release(&msg);
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v3 05/13] hooks: convert 'post-checkout' hook to hook library
2021-10-19 23:20 ` [PATCH v3 05/13] hooks: convert 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
@ 2021-10-29 5:55 ` Junio C Hamano
0 siblings, 0 replies; 115+ messages in thread
From: Junio C Hamano @ 2021-10-29 5:55 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason
Cc: git, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
> if (!ret && opts->checkout) {
> - const char *hook = find_hook("post-checkout");
> - if (hook) {
> - const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL };
> - cp.git_cmd = 0;
> - cp.no_stdin = 1;
> - cp.stdout_to_stderr = 1;
> - cp.dir = path;
> - cp.env = env;
> - cp.argv = NULL;
> - cp.trace2_hook_name = "post-checkout";
> - strvec_pushl(&cp.args, absolute_path(hook),
> - oid_to_hex(null_oid()),
> - oid_to_hex(&commit->object.oid),
> - "1", NULL);
> - ret = run_command(&cp);
> - }
> + struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
> +
> + strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL);
> + strvec_pushl(&opt.args,
> + oid_to_hex(null_oid()),
> + oid_to_hex(&commit->object.oid),
> + "1",
> + NULL);
> + opt.dir = path;
> + opt.absolute_path = 1;
> +
> + ret = run_hooks_oneshot("post-checkout", &opt);
I can see how passing opt from the caller gives more flexibility
like allowing to pass arbitrary environments. The interface still
looks a bit unwieldy as I expect passing command line args would be
a much more common need than tweaking the environment, but let's
keep reading.
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v3 06/13] merge: convert post-merge to use hook.h
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (4 preceding siblings ...)
2021-10-19 23:20 ` [PATCH v3 05/13] hooks: convert 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 07/13] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
` (8 subsequent siblings)
14 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Teach post-merge to use the hook.h library instead of the
run-command.h library to run hooks.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/merge.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/builtin/merge.c b/builtin/merge.c
index cc4a910c69b..c48b875b82b 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -448,6 +448,7 @@ static void finish(struct commit *head_commit,
const struct object_id *new_head, const char *msg)
{
struct strbuf reflog_message = STRBUF_INIT;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
const struct object_id *head = &head_commit->object.oid;
if (!msg)
@@ -488,7 +489,8 @@ static void finish(struct commit *head_commit,
}
/* Run a post-merge hook */
- run_hook_le(NULL, "post-merge", squash ? "1" : "0", NULL);
+ strvec_push(&opt.args, squash ? "1" : "0");
+ run_hooks_oneshot("post-merge", &opt);
apply_autostash(git_path_merge_autostash(the_repository));
strbuf_release(&reflog_message);
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v3 07/13] git hook run: add an --ignore-missing flag
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (5 preceding siblings ...)
2021-10-19 23:20 ` [PATCH v3 06/13] merge: convert post-merge to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-29 5:59 ` Junio C Hamano
2021-10-19 23:20 ` [PATCH v3 08/13] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
` (7 subsequent siblings)
14 siblings, 1 reply; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
For certain one-shot hooks we'd like to optimistically run them, and
not complain if they don't exist. This will be used by send-email in a
subsequent commit.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
Documentation/git-hook.txt | 10 +++++++++-
builtin/hook.c | 7 ++++++-
t/t1800-hook.sh | 5 +++++
3 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
index e39b1b5d069..77c3a8ad909 100644
--- a/Documentation/git-hook.txt
+++ b/Documentation/git-hook.txt
@@ -8,7 +8,7 @@ git-hook - Run git hooks
SYNOPSIS
--------
[verse]
-'git hook' run <hook-name> [-- <hook-args>]
+'git hook' run [--ignore-missing] <hook-name> [-- <hook-args>]
DESCRIPTION
-----------
@@ -28,6 +28,14 @@ Any positional arguments to the hook should be passed after a
mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
linkgit:githooks[5] for arguments hooks might expect (if any).
+OPTIONS
+-------
+
+--ignore-missing::
+ Ignore any missing hook by quietly returning zero. Used for
+ tools that want to do a blind one-shot run of a hook that may
+ or may not be present.
+
SEE ALSO
--------
linkgit:githooks[5]
diff --git a/builtin/hook.c b/builtin/hook.c
index 41dd15550cf..fa26454990d 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -7,7 +7,7 @@
#include "strvec.h"
#define BUILTIN_HOOK_RUN_USAGE \
- N_("git hook run <hook-name> [-- <hook-args>]")
+ N_("git hook run [--ignore-missing] <hook-name> [-- <hook-args>]")
static const char * const builtin_hook_usage[] = {
BUILTIN_HOOK_RUN_USAGE,
@@ -23,9 +23,12 @@ static int run(int argc, const char **argv, const char *prefix)
{
int i;
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ int ignore_missing = 0;
const char *hook_name;
const char *hook_path;
struct option run_options[] = {
+ OPT_BOOL(0, "ignore-missing", &ignore_missing,
+ N_("silently ignore missing requested <hook-name>")),
OPT_END(),
};
int ret;
@@ -53,6 +56,8 @@ static int run(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
hook_name = argv[0];
+ if (ignore_missing)
+ return run_hooks_oneshot(hook_name, &opt);
hook_path = find_hook(hook_name);
if (!hook_path) {
error("cannot find a hook named %s", hook_name);
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
index 3aea1b105f0..29718aa9913 100755
--- a/t/t1800-hook.sh
+++ b/t/t1800-hook.sh
@@ -21,6 +21,11 @@ test_expect_success 'git hook run: nonexistent hook' '
test_cmp stderr.expect stderr.actual
'
+test_expect_success 'git hook run: nonexistent hook with --ignore-missing' '
+ git hook run --ignore-missing does-not-exist 2>stderr.actual &&
+ test_must_be_empty stderr.actual
+'
+
test_expect_success 'git hook run: basic' '
write_script .git/hooks/test-hook <<-EOF &&
echo Test hook
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v3 07/13] git hook run: add an --ignore-missing flag
2021-10-19 23:20 ` [PATCH v3 07/13] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
@ 2021-10-29 5:59 ` Junio C Hamano
0 siblings, 0 replies; 115+ messages in thread
From: Junio C Hamano @ 2021-10-29 5:59 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason
Cc: git, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
> + int ignore_missing = 0;
> const char *hook_name;
> const char *hook_path;
> struct option run_options[] = {
> + OPT_BOOL(0, "ignore-missing", &ignore_missing,
> + N_("silently ignore missing requested <hook-name>")),
> OPT_END(),
> };
> int ret;
> @@ -53,6 +56,8 @@ static int run(int argc, const char **argv, const char *prefix)
> git_config(git_default_config, NULL);
>
> hook_name = argv[0];
> + if (ignore_missing)
> + return run_hooks_oneshot(hook_name, &opt);
> hook_path = find_hook(hook_name);
> if (!hook_path) {
> error("cannot find a hook named %s", hook_name);
Given that the rest of this "run()" function is more or less
identical to run_hooks_oneshot(), I have to wonder why we do not
give an .ignore_missing member to the hooks_opt structure to be done
with this. Otehrwise, every time the underlying run_hooks()
interface needs to change, we need to update two places, no?
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v3 08/13] send-email: use 'git hook run' for 'sendemail-validate'
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (6 preceding siblings ...)
2021-10-19 23:20 ` [PATCH v3 07/13] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 09/13] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
` (6 subsequent siblings)
14 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Change the "sendmail-validate" hook to be run via the "git hook run"
wrapper instead of via a direct invocation.
This is the smallest possibly change to get "send-email" using "git
hook run". We still check the hook itself with "-x", and set a
"GIT_DIR" variable, both of which are asserted by our tests. We'll
need to get rid of this special behavior if we start running N hooks,
but for now let's be as close to bug-for-bug compatible as possible.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
git-send-email.perl | 22 ++++++++++++++--------
t/t9001-send-email.sh | 4 ++--
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/git-send-email.perl b/git-send-email.perl
index 5262d88ee32..4c20c0bbb79 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -195,13 +195,13 @@ sub format_2822_time {
my $editor;
sub system_or_msg {
- my ($args, $msg) = @_;
+ my ($args, $msg, $cmd_name) = @_;
system(@$args);
my $signalled = $? & 127;
my $exit_code = $? >> 8;
return unless $signalled or $exit_code;
- my @sprintf_args = ($args->[0], $exit_code);
+ my @sprintf_args = ($cmd_name ? $cmd_name : $args->[0], $exit_code);
if (defined $msg) {
# Quiet the 'redundant' warning category, except we
# need to support down to Perl 5.8, so we can't do a
@@ -2039,10 +2039,10 @@ sub validate_patch {
my ($fn, $xfer_encoding) = @_;
if ($repo) {
+ my $hook_name = 'sendemail-validate';
my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
require File::Spec;
- my $validate_hook = File::Spec->catfile($hooks_path,
- 'sendemail-validate');
+ my $validate_hook = File::Spec->catfile($hooks_path, $hook_name);
my $hook_error;
if (-x $validate_hook) {
require Cwd;
@@ -2052,13 +2052,19 @@ sub validate_patch {
chdir($repo->wc_path() or $repo->repo_path())
or die("chdir: $!");
local $ENV{"GIT_DIR"} = $repo->repo_path();
- $hook_error = system_or_msg([$validate_hook, $target]);
+ my @cmd = ("git", "hook", "run", "--ignore-missing",
+ $hook_name, "--");
+ my @cmd_msg = (@cmd, "<patch>");
+ my @cmd_run = (@cmd, $target);
+ $hook_error = system_or_msg(\@cmd_run, undef, "@cmd_msg");
chdir($cwd_save) or die("chdir: $!");
}
if ($hook_error) {
- die sprintf(__("fatal: %s: rejected by sendemail-validate hook\n" .
- "%s\n" .
- "warning: no patches were sent\n"), $fn, $hook_error);
+ $hook_error = sprintf(__("fatal: %s: rejected by %s hook\n" .
+ $hook_error . "\n" .
+ "warning: no patches were sent\n"),
+ $fn, $hook_name);
+ die $hook_error;
}
}
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index aa0c20499ba..84d0f40d76a 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -539,7 +539,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'my-hooks/sendemail-validate'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
@@ -558,7 +558,7 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'$hooks_path/sendemail-validate'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v3 09/13] git-p4: use 'git hook' to run hooks
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (7 preceding siblings ...)
2021-10-19 23:20 ` [PATCH v3 08/13] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 10/13] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h Ævar Arnfjörð Bjarmason
` (5 subsequent siblings)
14 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Instead of duplicating the behavior of run-command.h:run_hook_le() in
Python, we can directly call 'git hook run'. We emulate the existence
check with the --ignore-missing flag.
We're dropping the "verbose" handling added in 9f59ca4d6af (git-p4:
create new function run_git_hook, 2020-02-11), those who want
diagnostic output about how hooks are run are now able to get that via
e.g. the trace2 facility and GIT_TRACE=1.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
git-p4.py | 70 +++++--------------------------------------------------
1 file changed, 6 insertions(+), 64 deletions(-)
diff --git a/git-p4.py b/git-p4.py
index 2b4500226aa..3b54168eb4a 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -208,70 +208,12 @@ def decode_path(path):
def run_git_hook(cmd, param=[]):
"""Execute a hook if the hook exists."""
- if verbose:
- sys.stderr.write("Looking for hook: %s\n" % cmd)
- sys.stderr.flush()
-
- hooks_path = gitConfig("core.hooksPath")
- if len(hooks_path) <= 0:
- hooks_path = os.path.join(os.environ["GIT_DIR"], "hooks")
-
- if not isinstance(param, list):
- param=[param]
-
- # resolve hook file name, OS depdenent
- hook_file = os.path.join(hooks_path, cmd)
- if platform.system() == 'Windows':
- if not os.path.isfile(hook_file):
- # look for the file with an extension
- files = glob.glob(hook_file + ".*")
- if not files:
- return True
- files.sort()
- hook_file = files.pop()
- while hook_file.upper().endswith(".SAMPLE"):
- # The file is a sample hook. We don't want it
- if len(files) > 0:
- hook_file = files.pop()
- else:
- return True
-
- if not os.path.isfile(hook_file) or not os.access(hook_file, os.X_OK):
- return True
-
- return run_hook_command(hook_file, param) == 0
-
-def run_hook_command(cmd, param):
- """Executes a git hook command
- cmd = the command line file to be executed. This can be
- a file that is run by OS association.
-
- param = a list of parameters to pass to the cmd command
-
- On windows, the extension is checked to see if it should
- be run with the Git for Windows Bash shell. If there
- is no file extension, the file is deemed a bash shell
- and will be handed off to sh.exe. Otherwise, Windows
- will be called with the shell to handle the file assocation.
-
- For non Windows operating systems, the file is called
- as an executable.
- """
- cli = [cmd] + param
- use_shell = False
- if platform.system() == 'Windows':
- (root,ext) = os.path.splitext(cmd)
- if ext == "":
- exe_path = os.environ.get("EXEPATH")
- if exe_path is None:
- exe_path = ""
- else:
- exe_path = os.path.join(exe_path, "bin")
- cli = [os.path.join(exe_path, "SH.EXE")] + cli
- else:
- use_shell = True
- return subprocess.call(cli, shell=use_shell)
-
+ args = ['git', 'hook', 'run', '--ignore-missing', cmd]
+ if param:
+ args.append("--")
+ for p in param:
+ args.append(p)
+ return subprocess.call(args) == 0
def write_pipe(c, stdin):
if verbose:
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v3 10/13] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (8 preceding siblings ...)
2021-10-19 23:20 ` [PATCH v3 09/13] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 11/13] read-cache: convert post-index-change to use hook.h Ævar Arnfjörð Bjarmason
` (4 subsequent siblings)
14 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move these hooks hook away from run-command.h to and over to the new
hook.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
commit.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/commit.c b/commit.c
index 551de4903c1..4e7cbd7585d 100644
--- a/commit.c
+++ b/commit.c
@@ -21,6 +21,7 @@
#include "commit-reach.h"
#include "run-command.h"
#include "shallow.h"
+#include "hook.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -1700,22 +1701,22 @@ size_t ignore_non_trailer(const char *buf, size_t len)
int run_commit_hook(int editor_is_used, const char *index_file,
const char *name, ...)
{
- struct strvec hook_env = STRVEC_INIT;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
va_list args;
- int ret;
+ const char *arg;
- strvec_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
+ strvec_pushf(&opt.env, "GIT_INDEX_FILE=%s", index_file);
/*
* Let the hook know that no editor will be launched.
*/
if (!editor_is_used)
- strvec_push(&hook_env, "GIT_EDITOR=:");
+ strvec_push(&opt.env, "GIT_EDITOR=:");
va_start(args, name);
- ret = run_hook_ve(hook_env.v, name, args);
+ while ((arg = va_arg(args, const char *)))
+ strvec_push(&opt.args, arg);
va_end(args);
- strvec_clear(&hook_env);
- return ret;
+ return run_hooks_oneshot(name, &opt);
}
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v3 11/13] read-cache: convert post-index-change to use hook.h
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (9 preceding siblings ...)
2021-10-19 23:20 ` [PATCH v3 10/13] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 12/13] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
` (3 subsequent siblings)
14 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the post-index-change hook away from run-command.h to and over to
the new hook.h library.
This removes the last direct user of "run_hook_ve()" outside of
run-command.c ("run_hook_le()" still uses it). So we can make the
function static now. A subsequent commit will remove this code
entirely when "run_hook_le()" itself goes away.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
read-cache.c | 11 ++++++++---
run-command.c | 2 +-
run-command.h | 1 -
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/read-cache.c b/read-cache.c
index 8a50ff66b30..6674df28ab3 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -28,6 +28,7 @@
#include "sparse-index.h"
#include "csum-file.h"
#include "promisor-remote.h"
+#include "hook.h"
/* Mask for the name length in ce_flags in the on-disk index */
@@ -3101,6 +3102,7 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l
{
int ret;
int was_full = !istate->sparse_index;
+ struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
ret = convert_to_sparse(istate, 0);
@@ -3129,9 +3131,12 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l
else
ret = close_lock_file_gently(lock);
- run_hook_le(NULL, "post-index-change",
- istate->updated_workdir ? "1" : "0",
- istate->updated_skipworktree ? "1" : "0", NULL);
+ strvec_pushl(&hook_opt.args,
+ istate->updated_workdir ? "1" : "0",
+ istate->updated_skipworktree ? "1" : "0",
+ NULL);
+ run_hooks_oneshot("post-index-change", &hook_opt);
+
istate->updated_workdir = 0;
istate->updated_skipworktree = 0;
diff --git a/run-command.c b/run-command.c
index 7ef5cc712a9..d92e670c8ed 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1323,7 +1323,7 @@ int async_with_fork(void)
#endif
}
-int run_hook_ve(const char *const *env, const char *name, va_list args)
+static int run_hook_ve(const char *const *env, const char *name, va_list args)
{
struct child_process hook = CHILD_PROCESS_INIT;
const char *p;
diff --git a/run-command.h b/run-command.h
index 49878262584..3fa7454cf8a 100644
--- a/run-command.h
+++ b/run-command.h
@@ -239,7 +239,6 @@ int run_command(struct child_process *);
*/
LAST_ARG_MUST_BE_NULL
int run_hook_le(const char *const *env, const char *name, ...);
-int run_hook_ve(const char *const *env, const char *name, va_list args);
/*
* Trigger an auto-gc
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v3 12/13] receive-pack: convert push-to-checkout hook to hook.h
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (10 preceding siblings ...)
2021-10-19 23:20 ` [PATCH v3 11/13] read-cache: convert post-index-change to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-19 23:20 ` [PATCH v3 13/13] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
` (2 subsequent siblings)
14 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the push-to-checkout hook away from run-command.h to and over to
the new hook.h library.
This removes the last direct user of run_hook_le(), so we could remove
that function now, but let's leave that to a follow-up cleanup commit.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/receive-pack.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 25cc0c907e1..22e7a431728 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1435,9 +1435,12 @@ static const char *push_to_checkout(unsigned char *hash,
struct strvec *env,
const char *work_tree)
{
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
- if (run_hook_le(env->v, push_to_checkout_hook,
- hash_to_hex(hash), NULL))
+ strvec_pushv(&opt.env, env->v);
+ strvec_push(&opt.args, hash_to_hex(hash));
+ if (run_hooks_oneshot(push_to_checkout_hook, &opt))
return "push-to-checkout hook declined";
else
return NULL;
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v3 13/13] run-command: remove old run_hook_{le,ve}() hook API
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (11 preceding siblings ...)
2021-10-19 23:20 ` [PATCH v3 12/13] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
@ 2021-10-19 23:20 ` Ævar Arnfjörð Bjarmason
2021-10-29 6:27 ` [PATCH v3 00/13] hook.[ch]: new library to run hooks + simple hook conversion Junio C Hamano
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
14 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-10-19 23:20 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
The new hook.h library has replaced all run-command.h hook-related
functionality. So let's delete this dead code.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
run-command.c | 32 --------------------------------
run-command.h | 16 ----------------
2 files changed, 48 deletions(-)
diff --git a/run-command.c b/run-command.c
index d92e670c8ed..8a21ff525f3 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1323,38 +1323,6 @@ int async_with_fork(void)
#endif
}
-static int run_hook_ve(const char *const *env, const char *name, va_list args)
-{
- struct child_process hook = CHILD_PROCESS_INIT;
- const char *p;
-
- p = find_hook(name);
- if (!p)
- return 0;
-
- strvec_push(&hook.args, p);
- while ((p = va_arg(args, const char *)))
- strvec_push(&hook.args, p);
- hook.env = env;
- hook.no_stdin = 1;
- hook.stdout_to_stderr = 1;
- hook.trace2_hook_name = name;
-
- return run_command(&hook);
-}
-
-int run_hook_le(const char *const *env, const char *name, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, name);
- ret = run_hook_ve(env, name, args);
- va_end(args);
-
- return ret;
-}
-
struct io_pump {
/* initialized by caller */
int fd;
diff --git a/run-command.h b/run-command.h
index 3fa7454cf8a..59e1fbff64c 100644
--- a/run-command.h
+++ b/run-command.h
@@ -224,22 +224,6 @@ int finish_command_in_signal(struct child_process *);
*/
int run_command(struct child_process *);
-/**
- * Run a hook.
- * The first argument is a pathname to an index file, or NULL
- * if the hook uses the default index file or no index is needed.
- * The second argument is the name of the hook.
- * The further arguments correspond to the hook arguments.
- * The last argument has to be NULL to terminate the arguments list.
- * If the hook does not exist or is not executable, the return
- * value will be zero.
- * If it is executable, the hook will be executed and the exit
- * status of the hook is returned.
- * On execution, .stdout_to_stderr and .no_stdin will be set.
- */
-LAST_ARG_MUST_BE_NULL
-int run_hook_le(const char *const *env, const char *name, ...);
-
/*
* Trigger an auto-gc
*/
--
2.33.1.1338.g20da966911a
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v3 00/13] hook.[ch]: new library to run hooks + simple hook conversion
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (12 preceding siblings ...)
2021-10-19 23:20 ` [PATCH v3 13/13] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
@ 2021-10-29 6:27 ` Junio C Hamano
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
14 siblings, 0 replies; 115+ messages in thread
From: Junio C Hamano @ 2021-10-29 6:27 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason
Cc: git, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
> Part 2 of the greater configurable hook saga, starting by converting
> some existing simple hooks to the new hook.[ch] library and "git hook
> run" utility.
These look mostly OK. Other than .ignore_missing stuff, I think I
agree with the direction of the overall series.
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v4 00/17] hook.[ch]: new library to run hooks + simple hook conversion
2021-10-19 23:20 ` [PATCH v3 " Ævar Arnfjörð Bjarmason
` (13 preceding siblings ...)
2021-10-29 6:27 ` [PATCH v3 00/13] hook.[ch]: new library to run hooks + simple hook conversion Junio C Hamano
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 01/17] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
` (17 more replies)
14 siblings, 18 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
Part 2 of the greater configurable hook saga, starting by converting
some existing simple hooks to the new hook.[ch] library and "git hook
run" utility. See [1] for the last iteration.
This re-roll should address Junio's comments on v3, i.e. there's now a
run_hooks_l() API similar to run_hook_le(). I also simplified the
callers of run_hooks(), which is now called run_hooks_opt().
Since no callers needed anything but a one-shot call the memory public
memory management API is gone, that'll eventually be needed for a "git
hook list" with configurable hooks, but let's introduce those API bits
then, not now.
This grew to 17 patches from 13 due to splitting up some commints for
ease of review, the overall diffstat got smaller. I picked a function
with the same width as the old function, so many of the diffs are
now simply a s/run_hook_le(NULL, /run_hooks_l(/.
1. https://lore.kernel.org/git/cover-v3-00.13-00000000000-20211019T231647Z-avarab@gmail.com/
Emily Shaffer (14):
hook: add 'run' subcommand
gc: use hook library for pre-auto-gc hook
am: convert {pre,post}-applypatch to use hook.h
rebase: convert pre-rebase to use hook.h
am: convert applypatch-msg to use hook.h
merge: convert post-merge to use hook.h
hooks: convert non-worktree 'post-checkout' hook to hook library
hooks: convert worktree 'post-checkout' hook to hook library
send-email: use 'git hook run' for 'sendemail-validate'
git-p4: use 'git hook' to run hooks
commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
read-cache: convert post-index-change to use hook.h
receive-pack: convert push-to-checkout hook to hook.h
run-command: remove old run_hook_{le,ve}() hook API
Ævar Arnfjörð Bjarmason (3):
hook API: add a run_hooks() wrapper
hook API: add a run_hooks_l() wrapper
git hook run: add an --ignore-missing flag
.gitignore | 1 +
Documentation/git-hook.txt | 45 +++++++++++++
Documentation/githooks.txt | 4 ++
Makefile | 1 +
builtin.h | 1 +
builtin/am.c | 6 +-
builtin/checkout.c | 3 +-
builtin/clone.c | 3 +-
builtin/gc.c | 3 +-
builtin/hook.c | 84 +++++++++++++++++++++++
builtin/merge.c | 2 +-
builtin/rebase.c | 3 +-
builtin/receive-pack.c | 7 +-
builtin/worktree.c | 27 +++-----
command-list.txt | 1 +
commit.c | 15 +++--
git-p4.py | 70 ++-----------------
git-send-email.perl | 22 +++---
git.c | 1 +
hook.c | 131 ++++++++++++++++++++++++++++++++++++
hook.h | 57 ++++++++++++++++
read-cache.c | 3 +-
reset.c | 3 +-
run-command.c | 32 ---------
run-command.h | 17 -----
t/t1800-hook.sh | 134 +++++++++++++++++++++++++++++++++++++
t/t9001-send-email.sh | 4 +-
27 files changed, 522 insertions(+), 158 deletions(-)
create mode 100644 Documentation/git-hook.txt
create mode 100644 builtin/hook.c
create mode 100755 t/t1800-hook.sh
Range-diff against v3:
1: 02fd699e699 ! 1: d97d6734961 hook: add 'run' subcommand
@@ Commit message
builtin/{commit-graph,multi-pack-index}.c.
Some of the implementation here, such as a function being named
- run_hooks() when it's tasked with running one hook, to using the
+ run_hooks_opt() when it's tasked with running one hook, to using the
run_processes_parallel_tr2() API to run with jobs=1 is somewhere
between a bit odd and and an overkill for the current features of this
"hook run" command and the hook.[ch] API.
@@ builtin/hook.c (new)
+ int i;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ const char *hook_name;
-+ const char *hook_path;
+ struct option run_options[] = {
+ OPT_END(),
+ };
@@ builtin/hook.c (new)
+ git_config(git_default_config, NULL);
+
+ hook_name = argv[0];
-+ hook_path = find_hook(hook_name);
-+ if (!hook_path) {
-+ error("cannot find a hook named %s", hook_name);
-+ return 1;
-+ }
-+
-+ ret = run_hooks(hook_name, hook_path, &opt);
-+ run_hooks_opt_clear(&opt);
++ opt.error_if_missing = 1;
++ ret = run_hooks_opt(hook_name, &opt);
++ if (ret < 0) /* error() return */
++ ret = 1;
+ return ret;
+usage:
+ usage_with_options(builtin_hook_run_usage, run_options);
@@ hook.c: int hook_exists(const char *name)
return !!find_hook(name);
}
+
-+void run_hooks_opt_clear(struct run_hooks_opt *o)
-+{
-+ strvec_clear(&o->env);
-+ strvec_clear(&o->args);
-+}
-+
+static int pick_next_hook(struct child_process *cp,
+ struct strbuf *out,
+ void *pp_cb,
@@ hook.c: int hook_exists(const char *name)
+ return 0;
+}
+
-+int run_hooks(const char *hook_name, const char *hook_path,
-+ struct run_hooks_opt *options)
++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 hook_cb_data cb_data = {
+ .rc = 0,
+ .hook_name = hook_name,
-+ .hook_path = hook_path,
+ .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;
+ run_processes_parallel_tr2(jobs,
+ pick_next_hook,
+ notify_start_failure,
@@ hook.c: int hook_exists(const char *name)
+ &cb_data,
+ "hook",
+ hook_name);
-+
-+ return cb_data.rc;
++ ret = cb_data.rc;
++cleanup:
++ run_hooks_opt_clear(options);
++ return ret;
+}
## hook.h ##
@@ hook.h
+
+ /* Args to be passed to each hook */
+ struct strvec args;
++
++ /* Emit an error if the hook is missing */
++ unsigned int error_if_missing:1;
+};
+
+#define RUN_HOOKS_OPT_INIT { \
@@ hook.h: const char *find_hook(const char *name);
int hook_exists(const char *hookname);
+/**
-+ * Clear data from an initialized "struct run_hooks_opt".
-+ */
-+void run_hooks_opt_clear(struct run_hooks_opt *o);
-+
-+/**
-+ * Takes an already resolved hook found via find_hook() and runs
-+ * it. Does not call run_hooks_opt_clear() for you.
++ * Takes a `hook_name`, resolves it to a path with find_hook(), and
++ * runs the hook for you with the options specified in "struct
++ * run_hooks opt". Will free memory associated with the "struct run_hooks_opt".
++ *
++ * Returns the status code of the run hook, or a negative value on
++ * error().
+ */
-+int run_hooks(const char *hookname, const char *hook_path,
-+ struct run_hooks_opt *options);
++int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
#endif
## t/t1800-hook.sh (new) ##
-: ----------- > 2: ca6464f7d5e hook API: add a run_hooks() wrapper
2: 42cc4d2c3c6 ! 3: 173860afca1 gc: use hook library for pre-auto-gc hook
@@ Commit message
gc: use hook library for pre-auto-gc hook
Move the pre-auto-gc hook away from run-command.h to and over to the
- new hook.h library.
-
- To do this introduce a simple run_hooks_oneshot() wrapper, we'll be
- using it extensively for these simple cases of wanting to run a single
- hook under a given name, and having it free the memory we allocate for
- us.
+ new hook.h library. This uses the new run_hooks() wrapper.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
@@ builtin/gc.c: static int need_to_gc(void)
return 0;
- if (run_hook_le(NULL, "pre-auto-gc", NULL))
-+ if (run_hooks_oneshot("pre-auto-gc", NULL))
++ if (run_hooks("pre-auto-gc"))
return 0;
return 1;
}
-
- ## hook.c ##
-@@ hook.c: int run_hooks(const char *hook_name, const char *hook_path,
-
- return cb_data.rc;
- }
-+
-+int run_hooks_oneshot(const char *hook_name, struct run_hooks_opt *options)
-+{
-+ const char *hook_path;
-+ struct run_hooks_opt hook_opt_scratch = RUN_HOOKS_OPT_INIT;
-+ int ret = 0;
-+
-+ if (!options)
-+ options = &hook_opt_scratch;
-+
-+ hook_path = find_hook(hook_name);
-+ if (!hook_path)
-+ goto cleanup;
-+
-+ ret = run_hooks(hook_name, hook_path, options);
-+cleanup:
-+ run_hooks_opt_clear(options);
-+
-+ return ret;
-+}
-
- ## hook.h ##
-@@ hook.h: void run_hooks_opt_clear(struct run_hooks_opt *o);
- /**
- * Takes an already resolved hook found via find_hook() and runs
- * it. Does not call run_hooks_opt_clear() for you.
-+ *
-+ * See run_hooks_oneshot() for the simpler one-shot API.
- */
- int run_hooks(const char *hookname, const char *hook_path,
- struct run_hooks_opt *options);
-+
-+/**
-+ * Calls find_hook() on your "hook_name" and runs the hooks (if any)
-+ * with run_hooks().
-+ *
-+ * If "options" is provided calls run_hooks_opt_clear() on it for
-+ * you. If "options" is NULL the default options from
-+ * RUN_HOOKS_OPT_INIT will be used.
-+ */
-+int run_hooks_oneshot(const char *hook_name, struct run_hooks_opt *options);
-+
- #endif
4: b26cef24f39 ! 4: 80a2171ddaf am: convert applypatch to use hook.h
@@ Metadata
Author: Emily Shaffer <emilyshaffer@google.com>
## Commit message ##
- am: convert applypatch to use hook.h
+ am: convert {pre,post}-applypatch to use hook.h
- Teach pre-applypatch, post-applypatch, and applypatch-msg to use the
- hook.h library instead of the run-command.h library.
+ Teach pre-applypatch and post-applypatch to use the hook.h library
+ instead of the run-command.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
## builtin/am.c ##
-@@ builtin/am.c: static void am_destroy(const struct am_state *state)
- static int run_applypatch_msg_hook(struct am_state *state)
- {
- int ret;
-+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
-
- assert(state->msg);
-- ret = run_hook_le(NULL, "applypatch-msg", am_path(state, "final-commit"), NULL);
-+ strvec_push(&opt.args, am_path(state, "final-commit"));
-+ ret = run_hooks_oneshot("applypatch-msg", &opt);
-
- if (!ret) {
- FREE_AND_NULL(state->msg);
@@ builtin/am.c: static void do_commit(const struct am_state *state)
const char *reflog_msg, *author, *committer = NULL;
struct strbuf sb = STRBUF_INIT;
- if (run_hook_le(NULL, "pre-applypatch", NULL))
-+ if (run_hooks_oneshot("pre-applypatch", NULL))
++ if (run_hooks("pre-applypatch"))
exit(1);
if (write_cache_as_tree(&tree, 0, NULL))
@@ builtin/am.c: static void do_commit(const struct am_state *state)
}
- run_hook_le(NULL, "post-applypatch", NULL);
-+ run_hooks_oneshot("post-applypatch", NULL);
++ run_hooks("post-applypatch");
strbuf_release(&sb);
}
-: ----------- > 5: 74f459db287 hook API: add a run_hooks_l() wrapper
3: cbbfd77a4f6 ! 6: 1fd70c0e88a rebase: convert pre-rebase to use hook.h
@@ Commit message
Move the pre-rebase hook away from run-command.h to and over to the
new hook.h library.
+ Since this hook needs arguments introduce a run_hooksl() wrapper, like
+ run_hooks(), but it takes varargs.
+
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
@@ builtin/rebase.c
#define DEFAULT_REFLOG_ACTION "rebase"
@@ builtin/rebase.c: int cmd_rebase(int argc, const char **argv, const char *prefix)
- int reschedule_failed_exec = -1;
- int allow_preemptive_ff = 1;
- int preserve_merges_selected = 0;
-+ struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
- struct option builtin_rebase_options[] = {
- OPT_STRING(0, "onto", &options.onto_name,
- N_("revision"),
-@@ builtin/rebase.c: int cmd_rebase(int argc, const char **argv, const char *prefix)
- }
/* If a hook exists, give it a chance to interrupt*/
-+ strvec_push(&hook_opt.args, options.upstream_arg);
-+ if (argc)
-+ strvec_push(&hook_opt.args, argv[0]);
if (!ok_to_skip_pre_rebase &&
- run_hook_le(NULL, "pre-rebase", options.upstream_arg,
-- argc ? argv[0] : NULL, NULL))
-+ run_hooks_oneshot("pre-rebase", &hook_opt))
++ run_hooks_l("pre-rebase", options.upstream_arg,
+ argc ? argv[0] : NULL, NULL))
die(_("The pre-rebase hook refused to rebase."));
- if (options.flags & REBASE_DIFFSTAT) {
-: ----------- > 7: ccba3ddf52e am: convert applypatch-msg to use hook.h
6: 7a9fd8627cd ! 8: 2c23e8645ec merge: convert post-merge to use hook.h
@@ Commit message
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
## builtin/merge.c ##
-@@ builtin/merge.c: static void finish(struct commit *head_commit,
- const struct object_id *new_head, const char *msg)
- {
- struct strbuf reflog_message = STRBUF_INIT;
-+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
- const struct object_id *head = &head_commit->object.oid;
-
- if (!msg)
@@ builtin/merge.c: static void finish(struct commit *head_commit,
}
/* Run a post-merge hook */
- run_hook_le(NULL, "post-merge", squash ? "1" : "0", NULL);
-+ strvec_push(&opt.args, squash ? "1" : "0");
-+ run_hooks_oneshot("post-merge", &opt);
++ run_hooks_l("post-merge", squash ? "1" : "0", NULL);
apply_autostash(git_path_merge_autostash(the_repository));
strbuf_release(&reflog_message);
-: ----------- > 9: cb95c79093b hooks: convert non-worktree 'post-checkout' hook to hook library
5: 2a747a65829 ! 10: f330600fec8 hooks: convert 'post-checkout' hook to hook library
@@ Metadata
Author: Emily Shaffer <emilyshaffer@google.com>
## Commit message ##
- hooks: convert 'post-checkout' hook to hook library
+ hooks: convert worktree 'post-checkout' hook to hook library
Move the running of the 'post-checkout' hook away from run-command.h
- to the new hook.h library. For "worktree" this requires a change to it
- to run the hooks from a given directory.
+ to the new hook.h library in builtin/worktree.c. For this special case
+ we need a change to the hook API to teach it to run the hook from a
+ given directory.
- We could strictly speaking skip the "absolute_path" flag and just
- check if "dir" is specified, but let's split them up for clarity, as
- well as for any future user who'd like to set "dir" but not implicitly
- change the argument to an absolute path.
+ We cannot skip the "absolute_path" flag and just check if "dir" is
+ specified as we'd then fail to find our hook in the new dir we'd
+ chdir() to. We currently don't have a use-case for running a hook not
+ in our "base" repository at a given absolute path, so let's have "dir"
+ imply absolute_path(find_hook(hook_name)).
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- ## builtin/checkout.c ##
-@@
- #include "config.h"
- #include "diff.h"
- #include "dir.h"
-+#include "hook.h"
- #include "ll-merge.h"
- #include "lockfile.h"
- #include "merge-recursive.h"
-@@ builtin/checkout.c: struct branch_info {
- static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
- int changed)
- {
-- return run_hook_le(NULL, "post-checkout",
-- oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
-- oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
-- changed ? "1" : "0", NULL);
-+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
-+
- /* "new_commit" can be NULL when checking out from the index before
- a commit exists. */
--
-+ strvec_pushl(&opt.args,
-+ oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
-+ oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
-+ changed ? "1" : "0",
-+ NULL);
-+ return run_hooks_oneshot("post-checkout", &opt);
- }
-
- static int update_some(const struct object_id *oid, struct strbuf *base,
-
- ## builtin/clone.c ##
-@@
- #include "connected.h"
- #include "packfile.h"
- #include "list-objects-filter-options.h"
-+#include "hook.h"
-
- /*
- * Overall FIXMEs:
-@@ builtin/clone.c: static int checkout(int submodule_progress)
- struct tree *tree;
- struct tree_desc t;
- int err = 0;
-+ struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
-
- if (option_no_checkout)
- return 0;
-@@ builtin/clone.c: static int checkout(int submodule_progress)
- if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
- die(_("unable to write new index file"));
-
-- err |= run_hook_le(NULL, "post-checkout", oid_to_hex(null_oid()),
-- oid_to_hex(&oid), "1", NULL);
-+ strvec_pushl(&hook_opt.args, oid_to_hex(null_oid()), oid_to_hex(&oid),
-+ "1", NULL);
-+ err |= run_hooks_oneshot("post-checkout", &hook_opt);
-
- if (!err && (option_recurse_submodules.nr > 0)) {
- struct strvec args = STRVEC_INIT;
-
## builtin/worktree.c ##
@@ builtin/worktree.c: static int add_worktree(const char *path, const char *refname,
* is_junk is cleared, but do return appropriate code when hook fails.
@@ builtin/worktree.c: static int add_worktree(const char *path, const char *refnam
+ "1",
+ NULL);
+ opt.dir = path;
-+ opt.absolute_path = 1;
+
-+ ret = run_hooks_oneshot("post-checkout", &opt);
++ ret = run_hooks_opt("post-checkout", &opt);
}
strvec_clear(&child_env);
@@ hook.c: static int pick_next_hook(struct child_process *cp,
strvec_push(&cp->args, hook_path);
strvec_pushv(&cp->args, hook_cb->options->args.v);
-@@ hook.c: static int notify_hook_finished(int result,
- int run_hooks(const char *hook_name, const char *hook_path,
- struct run_hooks_opt *options)
+@@ hook.c: static void run_hooks_opt_clear(struct run_hooks_opt *options)
+
+ 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,
-- .hook_path = hook_path,
- .options = options,
- };
- int jobs = 1;
-@@ hook.c: int run_hooks(const char *hook_name, const char *hook_path,
- if (!options)
- BUG("a struct run_hooks_opt must be provided to run_hooks");
+@@ hook.c: int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
+ }
-+ if (options->absolute_path) {
+ cb_data.hook_path = hook_path;
++ if (options->dir) {
+ strbuf_add_absolute_path(&abs_path, hook_path);
-+ hook_path = abs_path.buf;
++ cb_data.hook_path = abs_path.buf;
+ }
-+ cb_data.hook_path = hook_path;
+
run_processes_parallel_tr2(jobs,
pick_next_hook,
notify_start_failure,
-@@ hook.c: int run_hooks(const char *hook_name, const char *hook_path,
- "hook",
+@@ hook.c: int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
hook_name);
-
-+ if (options->absolute_path)
-+ strbuf_release(&abs_path);
-+
- return cb_data.rc;
+ ret = cb_data.rc;
+ cleanup:
++ strbuf_release(&abs_path);
+ run_hooks_opt_clear(options);
+ return ret;
}
-
## hook.h ##
@@ hook.h: struct run_hooks_opt
- /* Args to be passed to each hook */
- struct strvec args;
+ /* Emit an error if the hook is missing */
+ unsigned int error_if_missing:1;
+
-+ /*
-+ * Resolve and run the "absolute_path(hook)" instead of
-+ * "hook". Used for "git worktree" hooks
++ /**
++ * An optional initial working directory for the hook,
++ * translates to "struct child_process"'s "dir" member.
+ */
-+ int absolute_path;
-+
-+ /* Path to initial working directory for subprocess */
+ const char *dir;
};
#define RUN_HOOKS_OPT_INIT { \
-
- ## reset.c ##
-@@
- #include "tree-walk.h"
- #include "tree.h"
- #include "unpack-trees.h"
-+#include "hook.h"
-
- int reset_head(struct repository *r, struct object_id *oid, const char *action,
- const char *switch_to_branch, unsigned flags,
-@@ reset.c: int reset_head(struct repository *r, struct object_id *oid, const char *action,
- ret = create_symref("HEAD", switch_to_branch,
- reflog_head);
- }
-- if (run_hook)
-- run_hook_le(NULL, "post-checkout",
-- oid_to_hex(orig ? orig : null_oid()),
-- oid_to_hex(oid), "1", NULL);
-+ if (run_hook) {
-+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
-+ strvec_pushl(&opt.args,
-+ oid_to_hex(orig ? orig : null_oid()),
-+ oid_to_hex(oid),
-+ "1",
-+ NULL);
-+ run_hooks_oneshot("post-checkout", &opt);
-+ }
-
- leave_reset_head:
- strbuf_release(&msg);
7: 840fb530df3 ! 11: a0b6818c766 git hook run: add an --ignore-missing flag
@@ Commit message
git hook run: add an --ignore-missing flag
For certain one-shot hooks we'd like to optimistically run them, and
- not complain if they don't exist. This will be used by send-email in a
- subsequent commit.
+ not complain if they don't exist.
+
+ This was already supported by the underlying hook.c library, but had
+ not been exposed via "git hook run". The command version of this will
+ be used by send-email in a subsequent commit.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
@@ builtin/hook.c: static int run(int argc, const char **argv, const char *prefix)
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ int ignore_missing = 0;
const char *hook_name;
- const char *hook_path;
struct option run_options[] = {
+ OPT_BOOL(0, "ignore-missing", &ignore_missing,
+ N_("silently ignore missing requested <hook-name>")),
@@ builtin/hook.c: static int run(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
hook_name = argv[0];
-+ if (ignore_missing)
-+ return run_hooks_oneshot(hook_name, &opt);
- hook_path = find_hook(hook_name);
- if (!hook_path) {
- error("cannot find a hook named %s", hook_name);
+- opt.error_if_missing = 1;
++ if (!ignore_missing)
++ opt.error_if_missing = 1;
+ ret = run_hooks_opt(hook_name, &opt);
+ if (ret < 0) /* error() return */
+ ret = 1;
## t/t1800-hook.sh ##
@@ t/t1800-hook.sh: test_expect_success 'git hook run: nonexistent hook' '
8: 716ebabd794 = 12: efa35971e9f send-email: use 'git hook run' for 'sendemail-validate'
9: 95782109270 = 13: 98e0e3330fb git-p4: use 'git hook' to run hooks
10: 706426c8a79 ! 14: 79ea5a2a4f5 commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
@@ commit.c: size_t ignore_non_trailer(const char *buf, size_t len)
- strvec_clear(&hook_env);
- return ret;
-+ return run_hooks_oneshot(name, &opt);
++ return run_hooks_opt(name, &opt);
}
11: 39069a9c3ff ! 15: 81612f94707 read-cache: convert post-index-change to use hook.h
@@ read-cache.c
/* Mask for the name length in ce_flags in the on-disk index */
-@@ read-cache.c: static int do_write_locked_index(struct index_state *istate, struct lock_file *l
- {
- int ret;
- int was_full = !istate->sparse_index;
-+ struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
-
- ret = convert_to_sparse(istate, 0);
-
@@ read-cache.c: static int do_write_locked_index(struct index_state *istate, struct lock_file *l
else
ret = close_lock_file_gently(lock);
- run_hook_le(NULL, "post-index-change",
-- istate->updated_workdir ? "1" : "0",
-- istate->updated_skipworktree ? "1" : "0", NULL);
-+ strvec_pushl(&hook_opt.args,
-+ istate->updated_workdir ? "1" : "0",
-+ istate->updated_skipworktree ? "1" : "0",
-+ NULL);
-+ run_hooks_oneshot("post-index-change", &hook_opt);
-+
++ run_hooks_l("post-index-change",
+ istate->updated_workdir ? "1" : "0",
+ istate->updated_skipworktree ? "1" : "0", NULL);
istate->updated_workdir = 0;
- istate->updated_skipworktree = 0;
-
## run-command.c ##
@@ run-command.c: int async_with_fork(void)
12: 9818078f1e5 ! 16: 43ecd6697e0 receive-pack: convert push-to-checkout hook to hook.h
@@ builtin/receive-pack.c: static const char *push_to_checkout(unsigned char *hash,
- hash_to_hex(hash), NULL))
+ strvec_pushv(&opt.env, env->v);
+ strvec_push(&opt.args, hash_to_hex(hash));
-+ if (run_hooks_oneshot(push_to_checkout_hook, &opt))
++ if (run_hooks_opt(push_to_checkout_hook, &opt))
return "push-to-checkout hook declined";
else
return NULL;
13: 1bc080d3611 = 17: 9ef574fa30c run-command: remove old run_hook_{le,ve}() hook API
--
2.33.1.1570.g069344fdd45
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v4 01/17] hook: add 'run' subcommand
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 02/17] hook API: add a run_hooks() wrapper Ævar Arnfjörð Bjarmason
` (16 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
In order to enable hooks to be run as an external process, by a
standalone Git command, or by tools which wrap Git, provide an external
means to run all configured hook commands for a given hook event.
Most of our hooks require more complex functionality than this, but
let's start with the bare minimum required to support our simplest
hooks.
In terms of implementation the usage_with_options() and "goto usage"
pattern here mirrors that of
builtin/{commit-graph,multi-pack-index}.c.
Some of the implementation here, such as a function being named
run_hooks_opt() when it's tasked with running one hook, to using the
run_processes_parallel_tr2() API to run with jobs=1 is somewhere
between a bit odd and and an overkill for the current features of this
"hook run" command and the hook.[ch] API.
This code will eventually be able to run multiple hooks declared in
config in parallel, by starting out with these names and APIs we
reduce the later churn of renaming functions, switching from the
run_command() to run_processes_parallel_tr2() API etc.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
.gitignore | 1 +
Documentation/git-hook.txt | 37 +++++++++++
Documentation/githooks.txt | 4 ++
Makefile | 1 +
builtin.h | 1 +
builtin/hook.c | 80 +++++++++++++++++++++++
command-list.txt | 1 +
git.c | 1 +
hook.c | 102 +++++++++++++++++++++++++++++
hook.h | 35 ++++++++++
t/t1800-hook.sh | 129 +++++++++++++++++++++++++++++++++++++
11 files changed, 392 insertions(+)
create mode 100644 Documentation/git-hook.txt
create mode 100644 builtin/hook.c
create mode 100755 t/t1800-hook.sh
diff --git a/.gitignore b/.gitignore
index 054249b20a8..f817c509ec0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,6 +77,7 @@
/git-grep
/git-hash-object
/git-help
+/git-hook
/git-http-backend
/git-http-fetch
/git-http-push
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
new file mode 100644
index 00000000000..e39b1b5d069
--- /dev/null
+++ b/Documentation/git-hook.txt
@@ -0,0 +1,37 @@
+git-hook(1)
+===========
+
+NAME
+----
+git-hook - Run git hooks
+
+SYNOPSIS
+--------
+[verse]
+'git hook' run <hook-name> [-- <hook-args>]
+
+DESCRIPTION
+-----------
+
+A command interface to running git hooks (see linkgit:githooks[5]),
+for use by other scripted git commands.
+
+SUBCOMMANDS
+-----------
+
+run::
+ Run the `<hook-name>` hook. See linkgit:githooks[5] for
+ supported hook names.
++
+
+Any positional arguments to the hook should be passed after a
+mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
+linkgit:githooks[5] for arguments hooks might expect (if any).
+
+SEE ALSO
+--------
+linkgit:githooks[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index b51959ff941..a16e62bc8c8 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -698,6 +698,10 @@ and "0" meaning they were not.
Only one parameter should be set to "1" when the hook runs. The hook
running passing "1", "1" should not be possible.
+SEE ALSO
+--------
+linkgit:git-hook[1]
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 12be39ac497..6cd20534304 100644
--- a/Makefile
+++ b/Makefile
@@ -1107,6 +1107,7 @@ BUILTIN_OBJS += builtin/get-tar-commit-id.o
BUILTIN_OBJS += builtin/grep.o
BUILTIN_OBJS += builtin/hash-object.o
BUILTIN_OBJS += builtin/help.o
+BUILTIN_OBJS += builtin/hook.o
BUILTIN_OBJS += builtin/index-pack.o
BUILTIN_OBJS += builtin/init-db.o
BUILTIN_OBJS += builtin/interpret-trailers.o
diff --git a/builtin.h b/builtin.h
index 8a58743ed63..83379f3832c 100644
--- a/builtin.h
+++ b/builtin.h
@@ -164,6 +164,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
int cmd_grep(int argc, const char **argv, const char *prefix);
int cmd_hash_object(int argc, const char **argv, const char *prefix);
int cmd_help(int argc, const char **argv, const char *prefix);
+int cmd_hook(int argc, const char **argv, const char *prefix);
int cmd_index_pack(int argc, const char **argv, const char *prefix);
int cmd_init_db(int argc, const char **argv, const char *prefix);
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix);
diff --git a/builtin/hook.c b/builtin/hook.c
new file mode 100644
index 00000000000..9b67ff50cef
--- /dev/null
+++ b/builtin/hook.c
@@ -0,0 +1,80 @@
+#include "cache.h"
+#include "builtin.h"
+#include "config.h"
+#include "hook.h"
+#include "parse-options.h"
+#include "strbuf.h"
+#include "strvec.h"
+
+#define BUILTIN_HOOK_RUN_USAGE \
+ N_("git hook run <hook-name> [-- <hook-args>]")
+
+static const char * const builtin_hook_usage[] = {
+ BUILTIN_HOOK_RUN_USAGE,
+ NULL
+};
+
+static const char * const builtin_hook_run_usage[] = {
+ BUILTIN_HOOK_RUN_USAGE,
+ NULL
+};
+
+static int run(int argc, const char **argv, const char *prefix)
+{
+ int i;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ const char *hook_name;
+ struct option run_options[] = {
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, run_options,
+ builtin_hook_run_usage,
+ PARSE_OPT_KEEP_DASHDASH);
+
+ if (!argc)
+ goto usage;
+
+ /*
+ * Having a -- for "run" when providing <hook-args> is
+ * mandatory.
+ */
+ if (argc > 1 && strcmp(argv[1], "--") &&
+ strcmp(argv[1], "--end-of-options"))
+ goto usage;
+
+ /* Add our arguments, start after -- */
+ for (i = 2 ; i < argc; i++)
+ strvec_push(&opt.args, argv[i]);
+
+ /* Need to take into account core.hooksPath */
+ git_config(git_default_config, NULL);
+
+ hook_name = argv[0];
+ opt.error_if_missing = 1;
+ ret = run_hooks_opt(hook_name, &opt);
+ if (ret < 0) /* error() return */
+ ret = 1;
+ return ret;
+usage:
+ usage_with_options(builtin_hook_run_usage, run_options);
+}
+
+int cmd_hook(int argc, const char **argv, const char *prefix)
+{
+ struct option builtin_hook_options[] = {
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, NULL, builtin_hook_options,
+ builtin_hook_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+ if (!argc)
+ goto usage;
+
+ if (!strcmp(argv[0], "run"))
+ return run(argc, argv, prefix);
+
+usage:
+ usage_with_options(builtin_hook_usage, builtin_hook_options);
+}
diff --git a/command-list.txt b/command-list.txt
index eb9cee8dee9..0c9af14bdf3 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -103,6 +103,7 @@ git-grep mainporcelain info
git-gui mainporcelain
git-hash-object plumbingmanipulators
git-help ancillaryinterrogators complete
+git-hook purehelpers
git-http-backend synchingrepositories
git-http-fetch synchelpers
git-http-push synchelpers
diff --git a/git.c b/git.c
index 5ff21be21f3..a5be02b04b8 100644
--- a/git.c
+++ b/git.c
@@ -538,6 +538,7 @@ static struct cmd_struct commands[] = {
{ "grep", cmd_grep, RUN_SETUP_GENTLY },
{ "hash-object", cmd_hash_object },
{ "help", cmd_help },
+ { "hook", cmd_hook, RUN_SETUP },
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY | NO_PARSEOPT },
{ "init", cmd_init_db },
{ "init-db", cmd_init_db },
diff --git a/hook.c b/hook.c
index 55e1145a4b7..64d3608e45e 100644
--- 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,104 @@ 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;
+ cp->env = hook_cb->options->env.v;
+ cp->stdout_to_stderr = 1;
+ cp->trace2_hook_name = hook_cb->hook_name;
+
+ 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 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;
+ run_processes_parallel_tr2(jobs,
+ pick_next_hook,
+ notify_start_failure,
+ notify_hook_finished,
+ &cb_data,
+ "hook",
+ hook_name);
+ ret = cb_data.rc;
+cleanup:
+ run_hooks_opt_clear(options);
+ return ret;
+}
diff --git a/hook.h b/hook.h
index 6aa36fc7ff9..782385cc235 100644
--- a/hook.h
+++ b/hook.h
@@ -1,5 +1,31 @@
#ifndef HOOK_H
#define HOOK_H
+#include "strvec.h"
+
+struct run_hooks_opt
+{
+ /* Environment vars to be set for each hook */
+ struct strvec env;
+
+ /* Args to be passed to each hook */
+ struct strvec args;
+
+ /* Emit an error if the hook is missing */
+ unsigned int error_if_missing:1;
+};
+
+#define RUN_HOOKS_OPT_INIT { \
+ .env = STRVEC_INIT, \
+ .args = STRVEC_INIT, \
+}
+
+struct hook_cb_data {
+ /* rc reflects the cumulative failure state */
+ int rc;
+ const char *hook_name;
+ const char *hook_path;
+ struct run_hooks_opt *options;
+};
/*
* Returns the path to the hook file, or NULL if the hook is missing
@@ -13,4 +39,13 @@ const char *find_hook(const char *name);
*/
int hook_exists(const char *hookname);
+/**
+ * Takes a `hook_name`, resolves it to a path with find_hook(), and
+ * runs the hook for you with the options specified in "struct
+ * run_hooks opt". Will free memory associated with the "struct run_hooks_opt".
+ *
+ * Returns the status code of the run hook, or a negative value on
+ * error().
+ */
+int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
#endif
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
new file mode 100755
index 00000000000..3aea1b105f0
--- /dev/null
+++ b/t/t1800-hook.sh
@@ -0,0 +1,129 @@
+#!/bin/sh
+
+test_description='git-hook command'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'git hook usage' '
+ test_expect_code 129 git hook &&
+ test_expect_code 129 git hook run &&
+ test_expect_code 129 git hook run -h &&
+ test_expect_code 129 git hook run --unknown 2>err &&
+ grep "unknown option" err
+'
+
+test_expect_success 'git hook run: nonexistent hook' '
+ cat >stderr.expect <<-\EOF &&
+ error: cannot find a hook named test-hook
+ EOF
+ test_expect_code 1 git hook run test-hook 2>stderr.actual &&
+ test_cmp stderr.expect stderr.actual
+'
+
+test_expect_success 'git hook run: basic' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo Test hook
+ EOF
+
+ cat >expect <<-\EOF &&
+ Test hook
+ EOF
+ git hook run test-hook 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git hook run: stdout and stderr both write to our stderr' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo >&1 Will end up on stderr
+ echo >&2 Will end up on stderr
+ EOF
+
+ cat >stderr.expect <<-\EOF &&
+ Will end up on stderr
+ Will end up on stderr
+ EOF
+ git hook run test-hook >stdout.actual 2>stderr.actual &&
+ test_cmp stderr.expect stderr.actual &&
+ test_must_be_empty stdout.actual
+'
+
+test_expect_success 'git hook run: exit codes are passed along' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 1
+ EOF
+
+ test_expect_code 1 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 2
+ EOF
+
+ test_expect_code 2 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 128
+ EOF
+
+ test_expect_code 128 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 129
+ EOF
+
+ test_expect_code 129 git hook run test-hook
+'
+
+test_expect_success 'git hook run arg u ments without -- is not allowed' '
+ test_expect_code 129 git hook run test-hook arg u ments
+'
+
+test_expect_success 'git hook run -- pass arguments' '
+ write_script .git/hooks/test-hook <<-\EOF &&
+ echo $1
+ echo $2
+ EOF
+
+ cat >expect <<-EOF &&
+ arg
+ u ments
+ EOF
+
+ git hook run test-hook -- arg "u ments" 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git hook run -- out-of-repo runs excluded' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo Test hook
+ EOF
+
+ nongit test_must_fail git hook run test-hook
+'
+
+test_expect_success 'git -c core.hooksPath=<PATH> hook run' '
+ mkdir my-hooks &&
+ write_script my-hooks/test-hook <<-\EOF &&
+ echo Hook ran $1 >>actual
+ EOF
+
+ cat >expect <<-\EOF &&
+ Test hook
+ Hook ran one
+ Hook ran two
+ Hook ran three
+ Hook ran four
+ EOF
+
+ # Test various ways of specifying the path. See also
+ # t1350-config-hooks-path.sh
+ >actual &&
+ git hook run test-hook -- ignored 2>>actual &&
+ git -c core.hooksPath=my-hooks hook run test-hook -- one 2>>actual &&
+ git -c core.hooksPath=my-hooks/ hook run test-hook -- two 2>>actual &&
+ git -c core.hooksPath="$PWD/my-hooks" hook run test-hook -- three 2>>actual &&
+ git -c core.hooksPath="$PWD/my-hooks/" hook run test-hook -- four 2>>actual &&
+ test_cmp expect actual
+'
+
+test_done
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 02/17] hook API: add a run_hooks() wrapper
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 01/17] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 03/17] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
` (15 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
Add a run_hooks() wrapper, we'll use it in subsequent commits for the
simple cases of wanting to run a single hook under a given name,
without providing options such as "env" or "args".
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
hook.c | 7 +++++++
hook.h | 6 ++++++
2 files changed, 13 insertions(+)
diff --git a/hook.c b/hook.c
index 64d3608e45e..720994bf4f6 100644
--- a/hook.c
+++ b/hook.c
@@ -142,3 +142,10 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
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);
+}
diff --git a/hook.h b/hook.h
index 782385cc235..9c358789958 100644
--- a/hook.h
+++ b/hook.h
@@ -48,4 +48,10 @@ int hook_exists(const char *hookname);
* error().
*/
int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
+
+/**
+ * A wrapper for run_hooks_opt() which provides a dummy "struct
+ * run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
+ */
+int run_hooks(const char *hook_name);
#endif
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 03/17] gc: use hook library for pre-auto-gc hook
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 01/17] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 02/17] hook API: add a run_hooks() wrapper Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 04/17] am: convert {pre,post}-applypatch to use hook.h Ævar Arnfjörð Bjarmason
` (14 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the pre-auto-gc hook away from run-command.h to and over to the
new hook.h library. This uses the new run_hooks() wrapper.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/gc.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/builtin/gc.c b/builtin/gc.c
index 6b3de3dd514..f57cbd2d217 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -32,6 +32,7 @@
#include "remote.h"
#include "object-store.h"
#include "exec-cmd.h"
+#include "hook.h"
#define FAILED_RUN "failed to run %s"
@@ -394,7 +395,7 @@ static int need_to_gc(void)
else
return 0;
- if (run_hook_le(NULL, "pre-auto-gc", NULL))
+ if (run_hooks("pre-auto-gc"))
return 0;
return 1;
}
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 04/17] am: convert {pre,post}-applypatch to use hook.h
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (2 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 03/17] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 05/17] hook API: add a run_hooks_l() wrapper Ævar Arnfjörð Bjarmason
` (13 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Teach pre-applypatch and post-applypatch to use the hook.h library
instead of the run-command.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/am.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/builtin/am.c b/builtin/am.c
index 8677ea2348a..4b334cb7b12 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1609,7 +1609,7 @@ static void do_commit(const struct am_state *state)
const char *reflog_msg, *author, *committer = NULL;
struct strbuf sb = STRBUF_INIT;
- if (run_hook_le(NULL, "pre-applypatch", NULL))
+ if (run_hooks("pre-applypatch"))
exit(1);
if (write_cache_as_tree(&tree, 0, NULL))
@@ -1661,7 +1661,7 @@ static void do_commit(const struct am_state *state)
fclose(fp);
}
- run_hook_le(NULL, "post-applypatch", NULL);
+ run_hooks("post-applypatch");
strbuf_release(&sb);
}
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 05/17] hook API: add a run_hooks_l() wrapper
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (3 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 04/17] am: convert {pre,post}-applypatch to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 06/17] rebase: convert pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
` (12 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
Add a run_hooks_l() wrapper, we'll use it in subsequent commits for
the simple cases of wanting to run a single hook under a given name
along with a list of arguments.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
hook.c | 14 ++++++++++++++
hook.h | 10 ++++++++++
2 files changed, 24 insertions(+)
diff --git a/hook.c b/hook.c
index 720994bf4f6..cf6d099f83a 100644
--- a/hook.c
+++ b/hook.c
@@ -149,3 +149,17 @@ int run_hooks(const char *hook_name)
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);
+}
diff --git a/hook.h b/hook.h
index 9c358789958..54528395953 100644
--- a/hook.h
+++ b/hook.h
@@ -54,4 +54,14 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
* run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
*/
int run_hooks(const char *hook_name);
+
+/**
+ * Like run_hooks(), a wrapper for run_hooks_opt().
+ *
+ * In addition to the wrapping behavior provided by run_hooks(), this
+ * wrapper takes a list of strings terminated by a NULL
+ * argument. These things will be used as positional arguments to the
+ * hook. This function behaves like the old run_hook_le() API.
+ */
+int run_hooks_l(const char *hook_name, ...);
#endif
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 06/17] rebase: convert pre-rebase to use hook.h
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (4 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 05/17] hook API: add a run_hooks_l() wrapper Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 07/17] am: convert applypatch-msg " Ævar Arnfjörð Bjarmason
` (11 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the pre-rebase hook away from run-command.h to and over to the
new hook.h library.
Since this hook needs arguments introduce a run_hooksl() wrapper, like
run_hooks(), but it takes varargs.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/rebase.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 34b4744e5f3..ac4120013a0 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -28,6 +28,7 @@
#include "sequencer.h"
#include "rebase-interactive.h"
#include "reset.h"
+#include "hook.h"
#define DEFAULT_REFLOG_ACTION "rebase"
@@ -1712,7 +1713,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
/* If a hook exists, give it a chance to interrupt*/
if (!ok_to_skip_pre_rebase &&
- run_hook_le(NULL, "pre-rebase", options.upstream_arg,
+ run_hooks_l("pre-rebase", options.upstream_arg,
argc ? argv[0] : NULL, NULL))
die(_("The pre-rebase hook refused to rebase."));
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 07/17] am: convert applypatch-msg to use hook.h
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (5 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 06/17] rebase: convert pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 08/17] merge: convert post-merge " Ævar Arnfjörð Bjarmason
` (10 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Teach applypatch-msg to use the hook.h library instead of the
run-command.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/am.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/builtin/am.c b/builtin/am.c
index 4b334cb7b12..ae0c484dcba 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -448,7 +448,7 @@ static int run_applypatch_msg_hook(struct am_state *state)
int ret;
assert(state->msg);
- ret = run_hook_le(NULL, "applypatch-msg", am_path(state, "final-commit"), NULL);
+ ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
if (!ret) {
FREE_AND_NULL(state->msg);
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 08/17] merge: convert post-merge to use hook.h
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (6 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 07/17] am: convert applypatch-msg " Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 09/17] hooks: convert non-worktree 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
` (9 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Teach post-merge to use the hook.h library instead of the
run-command.h library to run hooks.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/merge.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/builtin/merge.c b/builtin/merge.c
index ea3112e0c0b..e6facd1c95d 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -488,7 +488,7 @@ static void finish(struct commit *head_commit,
}
/* Run a post-merge hook */
- run_hook_le(NULL, "post-merge", squash ? "1" : "0", NULL);
+ run_hooks_l("post-merge", squash ? "1" : "0", NULL);
apply_autostash(git_path_merge_autostash(the_repository));
strbuf_release(&reflog_message);
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 09/17] hooks: convert non-worktree 'post-checkout' hook to hook library
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (7 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 08/17] merge: convert post-merge " Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 10/17] hooks: convert worktree " Ævar Arnfjörð Bjarmason
` (8 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the running of the 'post-checkout' hook away from run-command.h
to the new hook.h library, except in the case of
builtin/worktree.c. That special-case will be handled in a subsequent
commit.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/checkout.c | 3 ++-
builtin/clone.c | 3 ++-
reset.c | 3 ++-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index cbf73b8c9f6..4af17d17217 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -9,6 +9,7 @@
#include "config.h"
#include "diff.h"
#include "dir.h"
+#include "hook.h"
#include "ll-merge.h"
#include "lockfile.h"
#include "merge-recursive.h"
@@ -106,7 +107,7 @@ struct branch_info {
static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
- return run_hook_le(NULL, "post-checkout",
+ return run_hooks_l("post-checkout",
oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
changed ? "1" : "0", NULL);
diff --git a/builtin/clone.c b/builtin/clone.c
index fb377b27657..ee27b9f8114 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -32,6 +32,7 @@
#include "connected.h"
#include "packfile.h"
#include "list-objects-filter-options.h"
+#include "hook.h"
/*
* Overall FIXMEs:
@@ -705,7 +706,7 @@ static int checkout(int submodule_progress)
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
- err |= run_hook_le(NULL, "post-checkout", oid_to_hex(null_oid()),
+ err |= run_hooks_l("post-checkout", oid_to_hex(null_oid()),
oid_to_hex(&oid), "1", NULL);
if (!err && (option_recurse_submodules.nr > 0)) {
diff --git a/reset.c b/reset.c
index f214df3d96c..0881e636915 100644
--- a/reset.c
+++ b/reset.c
@@ -7,6 +7,7 @@
#include "tree-walk.h"
#include "tree.h"
#include "unpack-trees.h"
+#include "hook.h"
int reset_head(struct repository *r, struct object_id *oid, const char *action,
const char *switch_to_branch, unsigned flags,
@@ -127,7 +128,7 @@ int reset_head(struct repository *r, struct object_id *oid, const char *action,
reflog_head);
}
if (run_hook)
- run_hook_le(NULL, "post-checkout",
+ run_hooks_l("post-checkout",
oid_to_hex(orig ? orig : null_oid()),
oid_to_hex(oid), "1", NULL);
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 10/17] hooks: convert worktree 'post-checkout' hook to hook library
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (8 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 09/17] hooks: convert non-worktree 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 11/17] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
` (7 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the running of the 'post-checkout' hook away from run-command.h
to the new hook.h library in builtin/worktree.c. For this special case
we need a change to the hook API to teach it to run the hook from a
given directory.
We cannot skip the "absolute_path" flag and just check if "dir" is
specified as we'd then fail to find our hook in the new dir we'd
chdir() to. We currently don't have a use-case for running a hook not
in our "base" repository at a given absolute path, so let's have "dir"
imply absolute_path(find_hook(hook_name)).
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/worktree.c | 27 +++++++++++----------------
hook.c | 8 ++++++++
hook.h | 6 ++++++
3 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/builtin/worktree.c b/builtin/worktree.c
index d22ece93e1a..4d9df5ecc4c 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -382,22 +382,17 @@ static int add_worktree(const char *path, const char *refname,
* is_junk is cleared, but do return appropriate code when hook fails.
*/
if (!ret && opts->checkout) {
- const char *hook = find_hook("post-checkout");
- if (hook) {
- const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL };
- cp.git_cmd = 0;
- cp.no_stdin = 1;
- cp.stdout_to_stderr = 1;
- cp.dir = path;
- cp.env = env;
- cp.argv = NULL;
- cp.trace2_hook_name = "post-checkout";
- strvec_pushl(&cp.args, absolute_path(hook),
- oid_to_hex(null_oid()),
- oid_to_hex(&commit->object.oid),
- "1", NULL);
- ret = run_command(&cp);
- }
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
+ strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL);
+ strvec_pushl(&opt.args,
+ oid_to_hex(null_oid()),
+ oid_to_hex(&commit->object.oid),
+ "1",
+ NULL);
+ opt.dir = path;
+
+ ret = run_hooks_opt("post-checkout", &opt);
}
strvec_clear(&child_env);
diff --git a/hook.c b/hook.c
index cf6d099f83a..95f5b926354 100644
--- a/hook.c
+++ b/hook.c
@@ -57,6 +57,7 @@ static int pick_next_hook(struct child_process *cp,
cp->env = 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);
@@ -109,6 +110,7 @@ static void run_hooks_opt_clear(struct run_hooks_opt *options)
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,
@@ -130,6 +132,11 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
}
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,
@@ -139,6 +146,7 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
hook_name);
ret = cb_data.rc;
cleanup:
+ strbuf_release(&abs_path);
run_hooks_opt_clear(options);
return ret;
}
diff --git a/hook.h b/hook.h
index 54528395953..18d90aedf14 100644
--- a/hook.h
+++ b/hook.h
@@ -12,6 +12,12 @@ struct run_hooks_opt
/* Emit an error if the hook is missing */
unsigned int error_if_missing:1;
+
+ /**
+ * An optional initial working directory for the hook,
+ * translates to "struct child_process"'s "dir" member.
+ */
+ const char *dir;
};
#define RUN_HOOKS_OPT_INIT { \
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 11/17] git hook run: add an --ignore-missing flag
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (9 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 10/17] hooks: convert worktree " Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 12/17] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
` (6 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
For certain one-shot hooks we'd like to optimistically run them, and
not complain if they don't exist.
This was already supported by the underlying hook.c library, but had
not been exposed via "git hook run". The command version of this will
be used by send-email in a subsequent commit.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
Documentation/git-hook.txt | 10 +++++++++-
builtin/hook.c | 8 ++++++--
t/t1800-hook.sh | 5 +++++
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
index e39b1b5d069..77c3a8ad909 100644
--- a/Documentation/git-hook.txt
+++ b/Documentation/git-hook.txt
@@ -8,7 +8,7 @@ git-hook - Run git hooks
SYNOPSIS
--------
[verse]
-'git hook' run <hook-name> [-- <hook-args>]
+'git hook' run [--ignore-missing] <hook-name> [-- <hook-args>]
DESCRIPTION
-----------
@@ -28,6 +28,14 @@ Any positional arguments to the hook should be passed after a
mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
linkgit:githooks[5] for arguments hooks might expect (if any).
+OPTIONS
+-------
+
+--ignore-missing::
+ Ignore any missing hook by quietly returning zero. Used for
+ tools that want to do a blind one-shot run of a hook that may
+ or may not be present.
+
SEE ALSO
--------
linkgit:githooks[5]
diff --git a/builtin/hook.c b/builtin/hook.c
index 9b67ff50cef..54e5c6ec933 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -7,7 +7,7 @@
#include "strvec.h"
#define BUILTIN_HOOK_RUN_USAGE \
- N_("git hook run <hook-name> [-- <hook-args>]")
+ N_("git hook run [--ignore-missing] <hook-name> [-- <hook-args>]")
static const char * const builtin_hook_usage[] = {
BUILTIN_HOOK_RUN_USAGE,
@@ -23,8 +23,11 @@ static int run(int argc, const char **argv, const char *prefix)
{
int i;
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ int ignore_missing = 0;
const char *hook_name;
struct option run_options[] = {
+ OPT_BOOL(0, "ignore-missing", &ignore_missing,
+ N_("silently ignore missing requested <hook-name>")),
OPT_END(),
};
int ret;
@@ -52,7 +55,8 @@ static int run(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
hook_name = argv[0];
- opt.error_if_missing = 1;
+ if (!ignore_missing)
+ opt.error_if_missing = 1;
ret = run_hooks_opt(hook_name, &opt);
if (ret < 0) /* error() return */
ret = 1;
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
index 3aea1b105f0..29718aa9913 100755
--- a/t/t1800-hook.sh
+++ b/t/t1800-hook.sh
@@ -21,6 +21,11 @@ test_expect_success 'git hook run: nonexistent hook' '
test_cmp stderr.expect stderr.actual
'
+test_expect_success 'git hook run: nonexistent hook with --ignore-missing' '
+ git hook run --ignore-missing does-not-exist 2>stderr.actual &&
+ test_must_be_empty stderr.actual
+'
+
test_expect_success 'git hook run: basic' '
write_script .git/hooks/test-hook <<-EOF &&
echo Test hook
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 12/17] send-email: use 'git hook run' for 'sendemail-validate'
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (10 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 11/17] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 13/17] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
` (5 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Change the "sendmail-validate" hook to be run via the "git hook run"
wrapper instead of via a direct invocation.
This is the smallest possibly change to get "send-email" using "git
hook run". We still check the hook itself with "-x", and set a
"GIT_DIR" variable, both of which are asserted by our tests. We'll
need to get rid of this special behavior if we start running N hooks,
but for now let's be as close to bug-for-bug compatible as possible.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
git-send-email.perl | 22 ++++++++++++++--------
t/t9001-send-email.sh | 4 ++--
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/git-send-email.perl b/git-send-email.perl
index 5262d88ee32..4c20c0bbb79 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -195,13 +195,13 @@ sub format_2822_time {
my $editor;
sub system_or_msg {
- my ($args, $msg) = @_;
+ my ($args, $msg, $cmd_name) = @_;
system(@$args);
my $signalled = $? & 127;
my $exit_code = $? >> 8;
return unless $signalled or $exit_code;
- my @sprintf_args = ($args->[0], $exit_code);
+ my @sprintf_args = ($cmd_name ? $cmd_name : $args->[0], $exit_code);
if (defined $msg) {
# Quiet the 'redundant' warning category, except we
# need to support down to Perl 5.8, so we can't do a
@@ -2039,10 +2039,10 @@ sub validate_patch {
my ($fn, $xfer_encoding) = @_;
if ($repo) {
+ my $hook_name = 'sendemail-validate';
my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
require File::Spec;
- my $validate_hook = File::Spec->catfile($hooks_path,
- 'sendemail-validate');
+ my $validate_hook = File::Spec->catfile($hooks_path, $hook_name);
my $hook_error;
if (-x $validate_hook) {
require Cwd;
@@ -2052,13 +2052,19 @@ sub validate_patch {
chdir($repo->wc_path() or $repo->repo_path())
or die("chdir: $!");
local $ENV{"GIT_DIR"} = $repo->repo_path();
- $hook_error = system_or_msg([$validate_hook, $target]);
+ my @cmd = ("git", "hook", "run", "--ignore-missing",
+ $hook_name, "--");
+ my @cmd_msg = (@cmd, "<patch>");
+ my @cmd_run = (@cmd, $target);
+ $hook_error = system_or_msg(\@cmd_run, undef, "@cmd_msg");
chdir($cwd_save) or die("chdir: $!");
}
if ($hook_error) {
- die sprintf(__("fatal: %s: rejected by sendemail-validate hook\n" .
- "%s\n" .
- "warning: no patches were sent\n"), $fn, $hook_error);
+ $hook_error = sprintf(__("fatal: %s: rejected by %s hook\n" .
+ $hook_error . "\n" .
+ "warning: no patches were sent\n"),
+ $fn, $hook_name);
+ die $hook_error;
}
}
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index aa0c20499ba..84d0f40d76a 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -539,7 +539,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'my-hooks/sendemail-validate'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
@@ -558,7 +558,7 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'$hooks_path/sendemail-validate'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 13/17] git-p4: use 'git hook' to run hooks
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (11 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 12/17] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 14/17] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h Ævar Arnfjörð Bjarmason
` (4 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Instead of duplicating the behavior of run-command.h:run_hook_le() in
Python, we can directly call 'git hook run'. We emulate the existence
check with the --ignore-missing flag.
We're dropping the "verbose" handling added in 9f59ca4d6af (git-p4:
create new function run_git_hook, 2020-02-11), those who want
diagnostic output about how hooks are run are now able to get that via
e.g. the trace2 facility and GIT_TRACE=1.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
git-p4.py | 70 +++++--------------------------------------------------
1 file changed, 6 insertions(+), 64 deletions(-)
diff --git a/git-p4.py b/git-p4.py
index 2b4500226aa..3b54168eb4a 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -208,70 +208,12 @@ def decode_path(path):
def run_git_hook(cmd, param=[]):
"""Execute a hook if the hook exists."""
- if verbose:
- sys.stderr.write("Looking for hook: %s\n" % cmd)
- sys.stderr.flush()
-
- hooks_path = gitConfig("core.hooksPath")
- if len(hooks_path) <= 0:
- hooks_path = os.path.join(os.environ["GIT_DIR"], "hooks")
-
- if not isinstance(param, list):
- param=[param]
-
- # resolve hook file name, OS depdenent
- hook_file = os.path.join(hooks_path, cmd)
- if platform.system() == 'Windows':
- if not os.path.isfile(hook_file):
- # look for the file with an extension
- files = glob.glob(hook_file + ".*")
- if not files:
- return True
- files.sort()
- hook_file = files.pop()
- while hook_file.upper().endswith(".SAMPLE"):
- # The file is a sample hook. We don't want it
- if len(files) > 0:
- hook_file = files.pop()
- else:
- return True
-
- if not os.path.isfile(hook_file) or not os.access(hook_file, os.X_OK):
- return True
-
- return run_hook_command(hook_file, param) == 0
-
-def run_hook_command(cmd, param):
- """Executes a git hook command
- cmd = the command line file to be executed. This can be
- a file that is run by OS association.
-
- param = a list of parameters to pass to the cmd command
-
- On windows, the extension is checked to see if it should
- be run with the Git for Windows Bash shell. If there
- is no file extension, the file is deemed a bash shell
- and will be handed off to sh.exe. Otherwise, Windows
- will be called with the shell to handle the file assocation.
-
- For non Windows operating systems, the file is called
- as an executable.
- """
- cli = [cmd] + param
- use_shell = False
- if platform.system() == 'Windows':
- (root,ext) = os.path.splitext(cmd)
- if ext == "":
- exe_path = os.environ.get("EXEPATH")
- if exe_path is None:
- exe_path = ""
- else:
- exe_path = os.path.join(exe_path, "bin")
- cli = [os.path.join(exe_path, "SH.EXE")] + cli
- else:
- use_shell = True
- return subprocess.call(cli, shell=use_shell)
-
+ args = ['git', 'hook', 'run', '--ignore-missing', cmd]
+ if param:
+ args.append("--")
+ for p in param:
+ args.append(p)
+ return subprocess.call(args) == 0
def write_pipe(c, stdin):
if verbose:
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 14/17] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (12 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 13/17] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 15/17] read-cache: convert post-index-change to use hook.h Ævar Arnfjörð Bjarmason
` (3 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move these hooks hook away from run-command.h to and over to the new
hook.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
commit.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/commit.c b/commit.c
index 551de4903c1..581d7dc216c 100644
--- a/commit.c
+++ b/commit.c
@@ -21,6 +21,7 @@
#include "commit-reach.h"
#include "run-command.h"
#include "shallow.h"
+#include "hook.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -1700,22 +1701,22 @@ size_t ignore_non_trailer(const char *buf, size_t len)
int run_commit_hook(int editor_is_used, const char *index_file,
const char *name, ...)
{
- struct strvec hook_env = STRVEC_INIT;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
va_list args;
- int ret;
+ const char *arg;
- strvec_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
+ strvec_pushf(&opt.env, "GIT_INDEX_FILE=%s", index_file);
/*
* Let the hook know that no editor will be launched.
*/
if (!editor_is_used)
- strvec_push(&hook_env, "GIT_EDITOR=:");
+ strvec_push(&opt.env, "GIT_EDITOR=:");
va_start(args, name);
- ret = run_hook_ve(hook_env.v, name, args);
+ while ((arg = va_arg(args, const char *)))
+ strvec_push(&opt.args, arg);
va_end(args);
- strvec_clear(&hook_env);
- return ret;
+ return run_hooks_opt(name, &opt);
}
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 15/17] read-cache: convert post-index-change to use hook.h
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (13 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 14/17] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 16/17] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
` (2 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the post-index-change hook away from run-command.h to and over to
the new hook.h library.
This removes the last direct user of "run_hook_ve()" outside of
run-command.c ("run_hook_le()" still uses it). So we can make the
function static now. A subsequent commit will remove this code
entirely when "run_hook_le()" itself goes away.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
read-cache.c | 3 ++-
run-command.c | 2 +-
run-command.h | 1 -
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/read-cache.c b/read-cache.c
index f3986596623..4352661549f 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -28,6 +28,7 @@
#include "sparse-index.h"
#include "csum-file.h"
#include "promisor-remote.h"
+#include "hook.h"
/* Mask for the name length in ce_flags in the on-disk index */
@@ -3129,7 +3130,7 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l
else
ret = close_lock_file_gently(lock);
- run_hook_le(NULL, "post-index-change",
+ run_hooks_l("post-index-change",
istate->updated_workdir ? "1" : "0",
istate->updated_skipworktree ? "1" : "0", NULL);
istate->updated_workdir = 0;
diff --git a/run-command.c b/run-command.c
index 7ef5cc712a9..d92e670c8ed 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1323,7 +1323,7 @@ int async_with_fork(void)
#endif
}
-int run_hook_ve(const char *const *env, const char *name, va_list args)
+static int run_hook_ve(const char *const *env, const char *name, va_list args)
{
struct child_process hook = CHILD_PROCESS_INIT;
const char *p;
diff --git a/run-command.h b/run-command.h
index 49878262584..3fa7454cf8a 100644
--- a/run-command.h
+++ b/run-command.h
@@ -239,7 +239,6 @@ int run_command(struct child_process *);
*/
LAST_ARG_MUST_BE_NULL
int run_hook_le(const char *const *env, const char *name, ...);
-int run_hook_ve(const char *const *env, const char *name, va_list args);
/*
* Trigger an auto-gc
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 16/17] receive-pack: convert push-to-checkout hook to hook.h
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (14 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 15/17] read-cache: convert post-index-change to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-01 18:56 ` [PATCH v4 17/17] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the push-to-checkout hook away from run-command.h to and over to
the new hook.h library.
This removes the last direct user of run_hook_le(), so we could remove
that function now, but let's leave that to a follow-up cleanup commit.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/receive-pack.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 49b846d9605..5d6d8dd9a26 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1439,9 +1439,12 @@ static const char *push_to_checkout(unsigned char *hash,
struct strvec *env,
const char *work_tree)
{
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
- if (run_hook_le(env->v, push_to_checkout_hook,
- hash_to_hex(hash), NULL))
+ strvec_pushv(&opt.env, env->v);
+ strvec_push(&opt.args, hash_to_hex(hash));
+ if (run_hooks_opt(push_to_checkout_hook, &opt))
return "push-to-checkout hook declined";
else
return NULL;
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v4 17/17] run-command: remove old run_hook_{le,ve}() hook API
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (15 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 16/17] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
@ 2021-11-01 18:56 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-01 18:56 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Phillip Wood, René Scharfe, Emily Shaffer,
Bagas Sanjaya, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
The new hook.h library has replaced all run-command.h hook-related
functionality. So let's delete this dead code.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
run-command.c | 32 --------------------------------
run-command.h | 16 ----------------
2 files changed, 48 deletions(-)
diff --git a/run-command.c b/run-command.c
index d92e670c8ed..8a21ff525f3 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1323,38 +1323,6 @@ int async_with_fork(void)
#endif
}
-static int run_hook_ve(const char *const *env, const char *name, va_list args)
-{
- struct child_process hook = CHILD_PROCESS_INIT;
- const char *p;
-
- p = find_hook(name);
- if (!p)
- return 0;
-
- strvec_push(&hook.args, p);
- while ((p = va_arg(args, const char *)))
- strvec_push(&hook.args, p);
- hook.env = env;
- hook.no_stdin = 1;
- hook.stdout_to_stderr = 1;
- hook.trace2_hook_name = name;
-
- return run_command(&hook);
-}
-
-int run_hook_le(const char *const *env, const char *name, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, name);
- ret = run_hook_ve(env, name, args);
- va_end(args);
-
- return ret;
-}
-
struct io_pump {
/* initialized by caller */
int fd;
diff --git a/run-command.h b/run-command.h
index 3fa7454cf8a..59e1fbff64c 100644
--- a/run-command.h
+++ b/run-command.h
@@ -224,22 +224,6 @@ int finish_command_in_signal(struct child_process *);
*/
int run_command(struct child_process *);
-/**
- * Run a hook.
- * The first argument is a pathname to an index file, or NULL
- * if the hook uses the default index file or no index is needed.
- * The second argument is the name of the hook.
- * The further arguments correspond to the hook arguments.
- * The last argument has to be NULL to terminate the arguments list.
- * If the hook does not exist or is not executable, the return
- * value will be zero.
- * If it is executable, the hook will be executed and the exit
- * status of the hook is returned.
- * On execution, .stdout_to_stderr and .no_stdin will be set.
- */
-LAST_ARG_MUST_BE_NULL
-int run_hook_le(const char *const *env, const char *name, ...);
-
/*
* Trigger an auto-gc
*/
--
2.33.1.1570.g069344fdd45
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion
2021-11-01 18:56 ` [PATCH v4 00/17] " Ævar Arnfjörð Bjarmason
` (16 preceding siblings ...)
2021-11-01 18:56 ` [PATCH v4 17/17] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:45 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 01/17] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
` (17 more replies)
17 siblings, 18 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:45 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
A trivial update to the v4 of the series to migrate hook execution to
the new hook.c hook execution library. For a meaningful overall
summary see v4's CL[1].
The only update here is to stop using the "env" member of "struct
child_process" in favor of "env_array".
This is in preparation for a re-roll of another series[2] to remove
"argv" (and soon in a re-roll, "env") from that API. Without this
update the two would semantically conflict.
1. https://lore.kernel.org/git/cover-v4-00.17-00000000000-20211101T184938Z-avarab@gmail.com/
2. https://lore.kernel.org/git/cover-0.5-00000000000-20211122T153605Z-avarab@gmail.com/
Emily Shaffer (14):
hook: add 'run' subcommand
gc: use hook library for pre-auto-gc hook
am: convert {pre,post}-applypatch to use hook.h
rebase: convert pre-rebase to use hook.h
am: convert applypatch-msg to use hook.h
merge: convert post-merge to use hook.h
hooks: convert non-worktree 'post-checkout' hook to hook library
hooks: convert worktree 'post-checkout' hook to hook library
send-email: use 'git hook run' for 'sendemail-validate'
git-p4: use 'git hook' to run hooks
commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
read-cache: convert post-index-change to use hook.h
receive-pack: convert push-to-checkout hook to hook.h
run-command: remove old run_hook_{le,ve}() hook API
Ævar Arnfjörð Bjarmason (3):
hook API: add a run_hooks() wrapper
hook API: add a run_hooks_l() wrapper
git hook run: add an --ignore-missing flag
.gitignore | 1 +
Documentation/git-hook.txt | 45 +++++++++++++
Documentation/githooks.txt | 4 ++
Makefile | 1 +
builtin.h | 1 +
builtin/am.c | 6 +-
builtin/checkout.c | 3 +-
builtin/clone.c | 3 +-
builtin/gc.c | 3 +-
builtin/hook.c | 84 +++++++++++++++++++++++
builtin/merge.c | 2 +-
builtin/rebase.c | 3 +-
builtin/receive-pack.c | 7 +-
builtin/worktree.c | 27 +++-----
command-list.txt | 1 +
commit.c | 15 +++--
git-p4.py | 70 ++-----------------
git-send-email.perl | 22 +++---
git.c | 1 +
hook.c | 131 ++++++++++++++++++++++++++++++++++++
hook.h | 57 ++++++++++++++++
read-cache.c | 3 +-
reset.c | 3 +-
run-command.c | 32 ---------
run-command.h | 17 -----
t/t1800-hook.sh | 134 +++++++++++++++++++++++++++++++++++++
t/t9001-send-email.sh | 4 +-
27 files changed, 522 insertions(+), 158 deletions(-)
create mode 100644 Documentation/git-hook.txt
create mode 100644 builtin/hook.c
create mode 100755 t/t1800-hook.sh
Range-diff against v4:
1: d97d6734961 ! 1: 4ca52feebb8 hook: add 'run' subcommand
@@ hook.c: int hook_exists(const char *name)
+ return 0;
+
+ cp->no_stdin = 1;
-+ cp->env = hook_cb->options->env.v;
++ strvec_pushv(&cp->env_array, hook_cb->options->env.v);
+ cp->stdout_to_stderr = 1;
+ cp->trace2_hook_name = hook_cb->hook_name;
+
2: ca6464f7d5e = 2: 6275b97a306 hook API: add a run_hooks() wrapper
3: 173860afca1 = 3: b5b3051b2e5 gc: use hook library for pre-auto-gc hook
4: 80a2171ddaf = 4: c88eb5d4c25 am: convert {pre,post}-applypatch to use hook.h
5: 74f459db287 = 5: 1d8f7b7e4c1 hook API: add a run_hooks_l() wrapper
6: 1fd70c0e88a = 6: d49a1444345 rebase: convert pre-rebase to use hook.h
7: ccba3ddf52e = 7: 191fdad0165 am: convert applypatch-msg to use hook.h
8: 2c23e8645ec = 8: 119b92fbeae merge: convert post-merge to use hook.h
9: cb95c79093b = 9: 359ba416e84 hooks: convert non-worktree 'post-checkout' hook to hook library
10: f330600fec8 ! 10: b7599be95a7 hooks: convert worktree 'post-checkout' hook to hook library
@@ builtin/worktree.c: static int add_worktree(const char *path, const char *refnam
## hook.c ##
@@ hook.c: static int pick_next_hook(struct child_process *cp,
- cp->env = hook_cb->options->env.v;
+ 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;
11: a0b6818c766 = 11: f1c84d7f627 git hook run: add an --ignore-missing flag
12: efa35971e9f = 12: 4e0f94d9102 send-email: use 'git hook run' for 'sendemail-validate'
13: 98e0e3330fb = 13: e858f332a62 git-p4: use 'git hook' to run hooks
14: 79ea5a2a4f5 = 14: 9a5956cc028 commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
15: 81612f94707 = 15: 6fd47c4c499 read-cache: convert post-index-change to use hook.h
16: 43ecd6697e0 = 16: b201ea46f4b receive-pack: convert push-to-checkout hook to hook.h
17: 9ef574fa30c = 17: 281d17b04db run-command: remove old run_hook_{le,ve}() hook API
--
2.34.0.831.gd33babec0d1
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v5 01/17] hook: add 'run' subcommand
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 02/17] hook API: add a run_hooks() wrapper Ævar Arnfjörð Bjarmason
` (16 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
In order to enable hooks to be run as an external process, by a
standalone Git command, or by tools which wrap Git, provide an external
means to run all configured hook commands for a given hook event.
Most of our hooks require more complex functionality than this, but
let's start with the bare minimum required to support our simplest
hooks.
In terms of implementation the usage_with_options() and "goto usage"
pattern here mirrors that of
builtin/{commit-graph,multi-pack-index}.c.
Some of the implementation here, such as a function being named
run_hooks_opt() when it's tasked with running one hook, to using the
run_processes_parallel_tr2() API to run with jobs=1 is somewhere
between a bit odd and and an overkill for the current features of this
"hook run" command and the hook.[ch] API.
This code will eventually be able to run multiple hooks declared in
config in parallel, by starting out with these names and APIs we
reduce the later churn of renaming functions, switching from the
run_command() to run_processes_parallel_tr2() API etc.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
.gitignore | 1 +
Documentation/git-hook.txt | 37 +++++++++++
Documentation/githooks.txt | 4 ++
Makefile | 1 +
builtin.h | 1 +
builtin/hook.c | 80 +++++++++++++++++++++++
command-list.txt | 1 +
git.c | 1 +
hook.c | 102 +++++++++++++++++++++++++++++
hook.h | 35 ++++++++++
t/t1800-hook.sh | 129 +++++++++++++++++++++++++++++++++++++
11 files changed, 392 insertions(+)
create mode 100644 Documentation/git-hook.txt
create mode 100644 builtin/hook.c
create mode 100755 t/t1800-hook.sh
diff --git a/.gitignore b/.gitignore
index 054249b20a8..f817c509ec0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,6 +77,7 @@
/git-grep
/git-hash-object
/git-help
+/git-hook
/git-http-backend
/git-http-fetch
/git-http-push
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
new file mode 100644
index 00000000000..e39b1b5d069
--- /dev/null
+++ b/Documentation/git-hook.txt
@@ -0,0 +1,37 @@
+git-hook(1)
+===========
+
+NAME
+----
+git-hook - Run git hooks
+
+SYNOPSIS
+--------
+[verse]
+'git hook' run <hook-name> [-- <hook-args>]
+
+DESCRIPTION
+-----------
+
+A command interface to running git hooks (see linkgit:githooks[5]),
+for use by other scripted git commands.
+
+SUBCOMMANDS
+-----------
+
+run::
+ Run the `<hook-name>` hook. See linkgit:githooks[5] for
+ supported hook names.
++
+
+Any positional arguments to the hook should be passed after a
+mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
+linkgit:githooks[5] for arguments hooks might expect (if any).
+
+SEE ALSO
+--------
+linkgit:githooks[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index b51959ff941..a16e62bc8c8 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -698,6 +698,10 @@ and "0" meaning they were not.
Only one parameter should be set to "1" when the hook runs. The hook
running passing "1", "1" should not be possible.
+SEE ALSO
+--------
+linkgit:git-hook[1]
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 12be39ac497..6cd20534304 100644
--- a/Makefile
+++ b/Makefile
@@ -1107,6 +1107,7 @@ BUILTIN_OBJS += builtin/get-tar-commit-id.o
BUILTIN_OBJS += builtin/grep.o
BUILTIN_OBJS += builtin/hash-object.o
BUILTIN_OBJS += builtin/help.o
+BUILTIN_OBJS += builtin/hook.o
BUILTIN_OBJS += builtin/index-pack.o
BUILTIN_OBJS += builtin/init-db.o
BUILTIN_OBJS += builtin/interpret-trailers.o
diff --git a/builtin.h b/builtin.h
index 8a58743ed63..83379f3832c 100644
--- a/builtin.h
+++ b/builtin.h
@@ -164,6 +164,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
int cmd_grep(int argc, const char **argv, const char *prefix);
int cmd_hash_object(int argc, const char **argv, const char *prefix);
int cmd_help(int argc, const char **argv, const char *prefix);
+int cmd_hook(int argc, const char **argv, const char *prefix);
int cmd_index_pack(int argc, const char **argv, const char *prefix);
int cmd_init_db(int argc, const char **argv, const char *prefix);
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix);
diff --git a/builtin/hook.c b/builtin/hook.c
new file mode 100644
index 00000000000..9b67ff50cef
--- /dev/null
+++ b/builtin/hook.c
@@ -0,0 +1,80 @@
+#include "cache.h"
+#include "builtin.h"
+#include "config.h"
+#include "hook.h"
+#include "parse-options.h"
+#include "strbuf.h"
+#include "strvec.h"
+
+#define BUILTIN_HOOK_RUN_USAGE \
+ N_("git hook run <hook-name> [-- <hook-args>]")
+
+static const char * const builtin_hook_usage[] = {
+ BUILTIN_HOOK_RUN_USAGE,
+ NULL
+};
+
+static const char * const builtin_hook_run_usage[] = {
+ BUILTIN_HOOK_RUN_USAGE,
+ NULL
+};
+
+static int run(int argc, const char **argv, const char *prefix)
+{
+ int i;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ const char *hook_name;
+ struct option run_options[] = {
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, run_options,
+ builtin_hook_run_usage,
+ PARSE_OPT_KEEP_DASHDASH);
+
+ if (!argc)
+ goto usage;
+
+ /*
+ * Having a -- for "run" when providing <hook-args> is
+ * mandatory.
+ */
+ if (argc > 1 && strcmp(argv[1], "--") &&
+ strcmp(argv[1], "--end-of-options"))
+ goto usage;
+
+ /* Add our arguments, start after -- */
+ for (i = 2 ; i < argc; i++)
+ strvec_push(&opt.args, argv[i]);
+
+ /* Need to take into account core.hooksPath */
+ git_config(git_default_config, NULL);
+
+ hook_name = argv[0];
+ opt.error_if_missing = 1;
+ ret = run_hooks_opt(hook_name, &opt);
+ if (ret < 0) /* error() return */
+ ret = 1;
+ return ret;
+usage:
+ usage_with_options(builtin_hook_run_usage, run_options);
+}
+
+int cmd_hook(int argc, const char **argv, const char *prefix)
+{
+ struct option builtin_hook_options[] = {
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, NULL, builtin_hook_options,
+ builtin_hook_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+ if (!argc)
+ goto usage;
+
+ if (!strcmp(argv[0], "run"))
+ return run(argc, argv, prefix);
+
+usage:
+ usage_with_options(builtin_hook_usage, builtin_hook_options);
+}
diff --git a/command-list.txt b/command-list.txt
index eb9cee8dee9..0c9af14bdf3 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -103,6 +103,7 @@ git-grep mainporcelain info
git-gui mainporcelain
git-hash-object plumbingmanipulators
git-help ancillaryinterrogators complete
+git-hook purehelpers
git-http-backend synchingrepositories
git-http-fetch synchelpers
git-http-push synchelpers
diff --git a/git.c b/git.c
index 5ff21be21f3..a5be02b04b8 100644
--- a/git.c
+++ b/git.c
@@ -538,6 +538,7 @@ static struct cmd_struct commands[] = {
{ "grep", cmd_grep, RUN_SETUP_GENTLY },
{ "hash-object", cmd_hash_object },
{ "help", cmd_help },
+ { "hook", cmd_hook, RUN_SETUP },
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY | NO_PARSEOPT },
{ "init", cmd_init_db },
{ "init-db", cmd_init_db },
diff --git a/hook.c b/hook.c
index 55e1145a4b7..a0917cf877c 100644
--- 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,104 @@ 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;
+
+ 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 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;
+ run_processes_parallel_tr2(jobs,
+ pick_next_hook,
+ notify_start_failure,
+ notify_hook_finished,
+ &cb_data,
+ "hook",
+ hook_name);
+ ret = cb_data.rc;
+cleanup:
+ run_hooks_opt_clear(options);
+ return ret;
+}
diff --git a/hook.h b/hook.h
index 6aa36fc7ff9..782385cc235 100644
--- a/hook.h
+++ b/hook.h
@@ -1,5 +1,31 @@
#ifndef HOOK_H
#define HOOK_H
+#include "strvec.h"
+
+struct run_hooks_opt
+{
+ /* Environment vars to be set for each hook */
+ struct strvec env;
+
+ /* Args to be passed to each hook */
+ struct strvec args;
+
+ /* Emit an error if the hook is missing */
+ unsigned int error_if_missing:1;
+};
+
+#define RUN_HOOKS_OPT_INIT { \
+ .env = STRVEC_INIT, \
+ .args = STRVEC_INIT, \
+}
+
+struct hook_cb_data {
+ /* rc reflects the cumulative failure state */
+ int rc;
+ const char *hook_name;
+ const char *hook_path;
+ struct run_hooks_opt *options;
+};
/*
* Returns the path to the hook file, or NULL if the hook is missing
@@ -13,4 +39,13 @@ const char *find_hook(const char *name);
*/
int hook_exists(const char *hookname);
+/**
+ * Takes a `hook_name`, resolves it to a path with find_hook(), and
+ * runs the hook for you with the options specified in "struct
+ * run_hooks opt". Will free memory associated with the "struct run_hooks_opt".
+ *
+ * Returns the status code of the run hook, or a negative value on
+ * error().
+ */
+int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
#endif
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
new file mode 100755
index 00000000000..3aea1b105f0
--- /dev/null
+++ b/t/t1800-hook.sh
@@ -0,0 +1,129 @@
+#!/bin/sh
+
+test_description='git-hook command'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'git hook usage' '
+ test_expect_code 129 git hook &&
+ test_expect_code 129 git hook run &&
+ test_expect_code 129 git hook run -h &&
+ test_expect_code 129 git hook run --unknown 2>err &&
+ grep "unknown option" err
+'
+
+test_expect_success 'git hook run: nonexistent hook' '
+ cat >stderr.expect <<-\EOF &&
+ error: cannot find a hook named test-hook
+ EOF
+ test_expect_code 1 git hook run test-hook 2>stderr.actual &&
+ test_cmp stderr.expect stderr.actual
+'
+
+test_expect_success 'git hook run: basic' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo Test hook
+ EOF
+
+ cat >expect <<-\EOF &&
+ Test hook
+ EOF
+ git hook run test-hook 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git hook run: stdout and stderr both write to our stderr' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo >&1 Will end up on stderr
+ echo >&2 Will end up on stderr
+ EOF
+
+ cat >stderr.expect <<-\EOF &&
+ Will end up on stderr
+ Will end up on stderr
+ EOF
+ git hook run test-hook >stdout.actual 2>stderr.actual &&
+ test_cmp stderr.expect stderr.actual &&
+ test_must_be_empty stdout.actual
+'
+
+test_expect_success 'git hook run: exit codes are passed along' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 1
+ EOF
+
+ test_expect_code 1 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 2
+ EOF
+
+ test_expect_code 2 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 128
+ EOF
+
+ test_expect_code 128 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 129
+ EOF
+
+ test_expect_code 129 git hook run test-hook
+'
+
+test_expect_success 'git hook run arg u ments without -- is not allowed' '
+ test_expect_code 129 git hook run test-hook arg u ments
+'
+
+test_expect_success 'git hook run -- pass arguments' '
+ write_script .git/hooks/test-hook <<-\EOF &&
+ echo $1
+ echo $2
+ EOF
+
+ cat >expect <<-EOF &&
+ arg
+ u ments
+ EOF
+
+ git hook run test-hook -- arg "u ments" 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git hook run -- out-of-repo runs excluded' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo Test hook
+ EOF
+
+ nongit test_must_fail git hook run test-hook
+'
+
+test_expect_success 'git -c core.hooksPath=<PATH> hook run' '
+ mkdir my-hooks &&
+ write_script my-hooks/test-hook <<-\EOF &&
+ echo Hook ran $1 >>actual
+ EOF
+
+ cat >expect <<-\EOF &&
+ Test hook
+ Hook ran one
+ Hook ran two
+ Hook ran three
+ Hook ran four
+ EOF
+
+ # Test various ways of specifying the path. See also
+ # t1350-config-hooks-path.sh
+ >actual &&
+ git hook run test-hook -- ignored 2>>actual &&
+ git -c core.hooksPath=my-hooks hook run test-hook -- one 2>>actual &&
+ git -c core.hooksPath=my-hooks/ hook run test-hook -- two 2>>actual &&
+ git -c core.hooksPath="$PWD/my-hooks" hook run test-hook -- three 2>>actual &&
+ git -c core.hooksPath="$PWD/my-hooks/" hook run test-hook -- four 2>>actual &&
+ test_cmp expect actual
+'
+
+test_done
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 02/17] hook API: add a run_hooks() wrapper
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 01/17] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 03/17] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
` (15 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
Add a run_hooks() wrapper, we'll use it in subsequent commits for the
simple cases of wanting to run a single hook under a given name,
without providing options such as "env" or "args".
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
hook.c | 7 +++++++
hook.h | 6 ++++++
2 files changed, 13 insertions(+)
diff --git a/hook.c b/hook.c
index a0917cf877c..d67a114e62d 100644
--- a/hook.c
+++ b/hook.c
@@ -142,3 +142,10 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
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);
+}
diff --git a/hook.h b/hook.h
index 782385cc235..9c358789958 100644
--- a/hook.h
+++ b/hook.h
@@ -48,4 +48,10 @@ int hook_exists(const char *hookname);
* error().
*/
int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
+
+/**
+ * A wrapper for run_hooks_opt() which provides a dummy "struct
+ * run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
+ */
+int run_hooks(const char *hook_name);
#endif
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 03/17] gc: use hook library for pre-auto-gc hook
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 01/17] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 02/17] hook API: add a run_hooks() wrapper Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 04/17] am: convert {pre,post}-applypatch to use hook.h Ævar Arnfjörð Bjarmason
` (14 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the pre-auto-gc hook away from run-command.h to and over to the
new hook.h library. This uses the new run_hooks() wrapper.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/gc.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/builtin/gc.c b/builtin/gc.c
index bcef6a4c8da..4bbc58aae5b 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -32,6 +32,7 @@
#include "remote.h"
#include "object-store.h"
#include "exec-cmd.h"
+#include "hook.h"
#define FAILED_RUN "failed to run %s"
@@ -394,7 +395,7 @@ static int need_to_gc(void)
else
return 0;
- if (run_hook_le(NULL, "pre-auto-gc", NULL))
+ if (run_hooks("pre-auto-gc"))
return 0;
return 1;
}
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 04/17] am: convert {pre,post}-applypatch to use hook.h
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (2 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 03/17] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 05/17] hook API: add a run_hooks_l() wrapper Ævar Arnfjörð Bjarmason
` (13 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Teach pre-applypatch and post-applypatch to use the hook.h library
instead of the run-command.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/am.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/builtin/am.c b/builtin/am.c
index 8677ea2348a..4b334cb7b12 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1609,7 +1609,7 @@ static void do_commit(const struct am_state *state)
const char *reflog_msg, *author, *committer = NULL;
struct strbuf sb = STRBUF_INIT;
- if (run_hook_le(NULL, "pre-applypatch", NULL))
+ if (run_hooks("pre-applypatch"))
exit(1);
if (write_cache_as_tree(&tree, 0, NULL))
@@ -1661,7 +1661,7 @@ static void do_commit(const struct am_state *state)
fclose(fp);
}
- run_hook_le(NULL, "post-applypatch", NULL);
+ run_hooks("post-applypatch");
strbuf_release(&sb);
}
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 05/17] hook API: add a run_hooks_l() wrapper
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (3 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 04/17] am: convert {pre,post}-applypatch to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 06/17] rebase: convert pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
` (12 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
Add a run_hooks_l() wrapper, we'll use it in subsequent commits for
the simple cases of wanting to run a single hook under a given name
along with a list of arguments.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
hook.c | 14 ++++++++++++++
hook.h | 10 ++++++++++
2 files changed, 24 insertions(+)
diff --git a/hook.c b/hook.c
index d67a114e62d..1ad123422b2 100644
--- a/hook.c
+++ b/hook.c
@@ -149,3 +149,17 @@ int run_hooks(const char *hook_name)
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);
+}
diff --git a/hook.h b/hook.h
index 9c358789958..54528395953 100644
--- a/hook.h
+++ b/hook.h
@@ -54,4 +54,14 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
* run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
*/
int run_hooks(const char *hook_name);
+
+/**
+ * Like run_hooks(), a wrapper for run_hooks_opt().
+ *
+ * In addition to the wrapping behavior provided by run_hooks(), this
+ * wrapper takes a list of strings terminated by a NULL
+ * argument. These things will be used as positional arguments to the
+ * hook. This function behaves like the old run_hook_le() API.
+ */
+int run_hooks_l(const char *hook_name, ...);
#endif
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 06/17] rebase: convert pre-rebase to use hook.h
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (4 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 05/17] hook API: add a run_hooks_l() wrapper Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 07/17] am: convert applypatch-msg " Ævar Arnfjörð Bjarmason
` (11 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the pre-rebase hook away from run-command.h to and over to the
new hook.h library.
Since this hook needs arguments introduce a run_hooksl() wrapper, like
run_hooks(), but it takes varargs.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/rebase.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 34b4744e5f3..ac4120013a0 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -28,6 +28,7 @@
#include "sequencer.h"
#include "rebase-interactive.h"
#include "reset.h"
+#include "hook.h"
#define DEFAULT_REFLOG_ACTION "rebase"
@@ -1712,7 +1713,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
/* If a hook exists, give it a chance to interrupt*/
if (!ok_to_skip_pre_rebase &&
- run_hook_le(NULL, "pre-rebase", options.upstream_arg,
+ run_hooks_l("pre-rebase", options.upstream_arg,
argc ? argv[0] : NULL, NULL))
die(_("The pre-rebase hook refused to rebase."));
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 07/17] am: convert applypatch-msg to use hook.h
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (5 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 06/17] rebase: convert pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 08/17] merge: convert post-merge " Ævar Arnfjörð Bjarmason
` (10 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Teach applypatch-msg to use the hook.h library instead of the
run-command.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/am.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/builtin/am.c b/builtin/am.c
index 4b334cb7b12..ae0c484dcba 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -448,7 +448,7 @@ static int run_applypatch_msg_hook(struct am_state *state)
int ret;
assert(state->msg);
- ret = run_hook_le(NULL, "applypatch-msg", am_path(state, "final-commit"), NULL);
+ ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
if (!ret) {
FREE_AND_NULL(state->msg);
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 08/17] merge: convert post-merge to use hook.h
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (6 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 07/17] am: convert applypatch-msg " Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 09/17] hooks: convert non-worktree 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
` (9 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Teach post-merge to use the hook.h library instead of the
run-command.h library to run hooks.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/merge.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/builtin/merge.c b/builtin/merge.c
index ea3112e0c0b..e6facd1c95d 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -488,7 +488,7 @@ static void finish(struct commit *head_commit,
}
/* Run a post-merge hook */
- run_hook_le(NULL, "post-merge", squash ? "1" : "0", NULL);
+ run_hooks_l("post-merge", squash ? "1" : "0", NULL);
apply_autostash(git_path_merge_autostash(the_repository));
strbuf_release(&reflog_message);
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 09/17] hooks: convert non-worktree 'post-checkout' hook to hook library
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (7 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 08/17] merge: convert post-merge " Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 10/17] hooks: convert worktree " Ævar Arnfjörð Bjarmason
` (8 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the running of the 'post-checkout' hook away from run-command.h
to the new hook.h library, except in the case of
builtin/worktree.c. That special-case will be handled in a subsequent
commit.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/checkout.c | 3 ++-
builtin/clone.c | 3 ++-
reset.c | 3 ++-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index cbf73b8c9f6..4af17d17217 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -9,6 +9,7 @@
#include "config.h"
#include "diff.h"
#include "dir.h"
+#include "hook.h"
#include "ll-merge.h"
#include "lockfile.h"
#include "merge-recursive.h"
@@ -106,7 +107,7 @@ struct branch_info {
static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
- return run_hook_le(NULL, "post-checkout",
+ return run_hooks_l("post-checkout",
oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
changed ? "1" : "0", NULL);
diff --git a/builtin/clone.c b/builtin/clone.c
index fb377b27657..ee27b9f8114 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -32,6 +32,7 @@
#include "connected.h"
#include "packfile.h"
#include "list-objects-filter-options.h"
+#include "hook.h"
/*
* Overall FIXMEs:
@@ -705,7 +706,7 @@ static int checkout(int submodule_progress)
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
- err |= run_hook_le(NULL, "post-checkout", oid_to_hex(null_oid()),
+ err |= run_hooks_l("post-checkout", oid_to_hex(null_oid()),
oid_to_hex(&oid), "1", NULL);
if (!err && (option_recurse_submodules.nr > 0)) {
diff --git a/reset.c b/reset.c
index f214df3d96c..0881e636915 100644
--- a/reset.c
+++ b/reset.c
@@ -7,6 +7,7 @@
#include "tree-walk.h"
#include "tree.h"
#include "unpack-trees.h"
+#include "hook.h"
int reset_head(struct repository *r, struct object_id *oid, const char *action,
const char *switch_to_branch, unsigned flags,
@@ -127,7 +128,7 @@ int reset_head(struct repository *r, struct object_id *oid, const char *action,
reflog_head);
}
if (run_hook)
- run_hook_le(NULL, "post-checkout",
+ run_hooks_l("post-checkout",
oid_to_hex(orig ? orig : null_oid()),
oid_to_hex(oid), "1", NULL);
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 10/17] hooks: convert worktree 'post-checkout' hook to hook library
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (8 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 09/17] hooks: convert non-worktree 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 11/17] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
` (7 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the running of the 'post-checkout' hook away from run-command.h
to the new hook.h library in builtin/worktree.c. For this special case
we need a change to the hook API to teach it to run the hook from a
given directory.
We cannot skip the "absolute_path" flag and just check if "dir" is
specified as we'd then fail to find our hook in the new dir we'd
chdir() to. We currently don't have a use-case for running a hook not
in our "base" repository at a given absolute path, so let's have "dir"
imply absolute_path(find_hook(hook_name)).
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/worktree.c | 27 +++++++++++----------------
hook.c | 8 ++++++++
hook.h | 6 ++++++
3 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/builtin/worktree.c b/builtin/worktree.c
index d22ece93e1a..4d9df5ecc4c 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -382,22 +382,17 @@ static int add_worktree(const char *path, const char *refname,
* is_junk is cleared, but do return appropriate code when hook fails.
*/
if (!ret && opts->checkout) {
- const char *hook = find_hook("post-checkout");
- if (hook) {
- const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL };
- cp.git_cmd = 0;
- cp.no_stdin = 1;
- cp.stdout_to_stderr = 1;
- cp.dir = path;
- cp.env = env;
- cp.argv = NULL;
- cp.trace2_hook_name = "post-checkout";
- strvec_pushl(&cp.args, absolute_path(hook),
- oid_to_hex(null_oid()),
- oid_to_hex(&commit->object.oid),
- "1", NULL);
- ret = run_command(&cp);
- }
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
+ strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL);
+ strvec_pushl(&opt.args,
+ oid_to_hex(null_oid()),
+ oid_to_hex(&commit->object.oid),
+ "1",
+ NULL);
+ opt.dir = path;
+
+ ret = run_hooks_opt("post-checkout", &opt);
}
strvec_clear(&child_env);
diff --git a/hook.c b/hook.c
index 1ad123422b2..69a215b2c3c 100644
--- a/hook.c
+++ b/hook.c
@@ -57,6 +57,7 @@ static int pick_next_hook(struct child_process *cp,
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);
@@ -109,6 +110,7 @@ static void run_hooks_opt_clear(struct run_hooks_opt *options)
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,
@@ -130,6 +132,11 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
}
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,
@@ -139,6 +146,7 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
hook_name);
ret = cb_data.rc;
cleanup:
+ strbuf_release(&abs_path);
run_hooks_opt_clear(options);
return ret;
}
diff --git a/hook.h b/hook.h
index 54528395953..18d90aedf14 100644
--- a/hook.h
+++ b/hook.h
@@ -12,6 +12,12 @@ struct run_hooks_opt
/* Emit an error if the hook is missing */
unsigned int error_if_missing:1;
+
+ /**
+ * An optional initial working directory for the hook,
+ * translates to "struct child_process"'s "dir" member.
+ */
+ const char *dir;
};
#define RUN_HOOKS_OPT_INIT { \
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 11/17] git hook run: add an --ignore-missing flag
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (9 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 10/17] hooks: convert worktree " Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 12/17] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
` (6 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
For certain one-shot hooks we'd like to optimistically run them, and
not complain if they don't exist.
This was already supported by the underlying hook.c library, but had
not been exposed via "git hook run". The command version of this will
be used by send-email in a subsequent commit.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
Documentation/git-hook.txt | 10 +++++++++-
builtin/hook.c | 8 ++++++--
t/t1800-hook.sh | 5 +++++
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
index e39b1b5d069..77c3a8ad909 100644
--- a/Documentation/git-hook.txt
+++ b/Documentation/git-hook.txt
@@ -8,7 +8,7 @@ git-hook - Run git hooks
SYNOPSIS
--------
[verse]
-'git hook' run <hook-name> [-- <hook-args>]
+'git hook' run [--ignore-missing] <hook-name> [-- <hook-args>]
DESCRIPTION
-----------
@@ -28,6 +28,14 @@ Any positional arguments to the hook should be passed after a
mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
linkgit:githooks[5] for arguments hooks might expect (if any).
+OPTIONS
+-------
+
+--ignore-missing::
+ Ignore any missing hook by quietly returning zero. Used for
+ tools that want to do a blind one-shot run of a hook that may
+ or may not be present.
+
SEE ALSO
--------
linkgit:githooks[5]
diff --git a/builtin/hook.c b/builtin/hook.c
index 9b67ff50cef..54e5c6ec933 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -7,7 +7,7 @@
#include "strvec.h"
#define BUILTIN_HOOK_RUN_USAGE \
- N_("git hook run <hook-name> [-- <hook-args>]")
+ N_("git hook run [--ignore-missing] <hook-name> [-- <hook-args>]")
static const char * const builtin_hook_usage[] = {
BUILTIN_HOOK_RUN_USAGE,
@@ -23,8 +23,11 @@ static int run(int argc, const char **argv, const char *prefix)
{
int i;
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ int ignore_missing = 0;
const char *hook_name;
struct option run_options[] = {
+ OPT_BOOL(0, "ignore-missing", &ignore_missing,
+ N_("silently ignore missing requested <hook-name>")),
OPT_END(),
};
int ret;
@@ -52,7 +55,8 @@ static int run(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
hook_name = argv[0];
- opt.error_if_missing = 1;
+ if (!ignore_missing)
+ opt.error_if_missing = 1;
ret = run_hooks_opt(hook_name, &opt);
if (ret < 0) /* error() return */
ret = 1;
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
index 3aea1b105f0..29718aa9913 100755
--- a/t/t1800-hook.sh
+++ b/t/t1800-hook.sh
@@ -21,6 +21,11 @@ test_expect_success 'git hook run: nonexistent hook' '
test_cmp stderr.expect stderr.actual
'
+test_expect_success 'git hook run: nonexistent hook with --ignore-missing' '
+ git hook run --ignore-missing does-not-exist 2>stderr.actual &&
+ test_must_be_empty stderr.actual
+'
+
test_expect_success 'git hook run: basic' '
write_script .git/hooks/test-hook <<-EOF &&
echo Test hook
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 12/17] send-email: use 'git hook run' for 'sendemail-validate'
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (10 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 11/17] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 13/17] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
` (5 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Change the "sendmail-validate" hook to be run via the "git hook run"
wrapper instead of via a direct invocation.
This is the smallest possibly change to get "send-email" using "git
hook run". We still check the hook itself with "-x", and set a
"GIT_DIR" variable, both of which are asserted by our tests. We'll
need to get rid of this special behavior if we start running N hooks,
but for now let's be as close to bug-for-bug compatible as possible.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
git-send-email.perl | 22 ++++++++++++++--------
t/t9001-send-email.sh | 4 ++--
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/git-send-email.perl b/git-send-email.perl
index 5262d88ee32..4c20c0bbb79 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -195,13 +195,13 @@ sub format_2822_time {
my $editor;
sub system_or_msg {
- my ($args, $msg) = @_;
+ my ($args, $msg, $cmd_name) = @_;
system(@$args);
my $signalled = $? & 127;
my $exit_code = $? >> 8;
return unless $signalled or $exit_code;
- my @sprintf_args = ($args->[0], $exit_code);
+ my @sprintf_args = ($cmd_name ? $cmd_name : $args->[0], $exit_code);
if (defined $msg) {
# Quiet the 'redundant' warning category, except we
# need to support down to Perl 5.8, so we can't do a
@@ -2039,10 +2039,10 @@ sub validate_patch {
my ($fn, $xfer_encoding) = @_;
if ($repo) {
+ my $hook_name = 'sendemail-validate';
my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
require File::Spec;
- my $validate_hook = File::Spec->catfile($hooks_path,
- 'sendemail-validate');
+ my $validate_hook = File::Spec->catfile($hooks_path, $hook_name);
my $hook_error;
if (-x $validate_hook) {
require Cwd;
@@ -2052,13 +2052,19 @@ sub validate_patch {
chdir($repo->wc_path() or $repo->repo_path())
or die("chdir: $!");
local $ENV{"GIT_DIR"} = $repo->repo_path();
- $hook_error = system_or_msg([$validate_hook, $target]);
+ my @cmd = ("git", "hook", "run", "--ignore-missing",
+ $hook_name, "--");
+ my @cmd_msg = (@cmd, "<patch>");
+ my @cmd_run = (@cmd, $target);
+ $hook_error = system_or_msg(\@cmd_run, undef, "@cmd_msg");
chdir($cwd_save) or die("chdir: $!");
}
if ($hook_error) {
- die sprintf(__("fatal: %s: rejected by sendemail-validate hook\n" .
- "%s\n" .
- "warning: no patches were sent\n"), $fn, $hook_error);
+ $hook_error = sprintf(__("fatal: %s: rejected by %s hook\n" .
+ $hook_error . "\n" .
+ "warning: no patches were sent\n"),
+ $fn, $hook_name);
+ die $hook_error;
}
}
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index aa0c20499ba..84d0f40d76a 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -539,7 +539,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'my-hooks/sendemail-validate'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
@@ -558,7 +558,7 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'$hooks_path/sendemail-validate'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 13/17] git-p4: use 'git hook' to run hooks
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (11 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 12/17] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 14/17] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h Ævar Arnfjörð Bjarmason
` (4 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Instead of duplicating the behavior of run-command.h:run_hook_le() in
Python, we can directly call 'git hook run'. We emulate the existence
check with the --ignore-missing flag.
We're dropping the "verbose" handling added in 9f59ca4d6af (git-p4:
create new function run_git_hook, 2020-02-11), those who want
diagnostic output about how hooks are run are now able to get that via
e.g. the trace2 facility and GIT_TRACE=1.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
git-p4.py | 70 +++++--------------------------------------------------
1 file changed, 6 insertions(+), 64 deletions(-)
diff --git a/git-p4.py b/git-p4.py
index 2b4500226aa..3b54168eb4a 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -208,70 +208,12 @@ def decode_path(path):
def run_git_hook(cmd, param=[]):
"""Execute a hook if the hook exists."""
- if verbose:
- sys.stderr.write("Looking for hook: %s\n" % cmd)
- sys.stderr.flush()
-
- hooks_path = gitConfig("core.hooksPath")
- if len(hooks_path) <= 0:
- hooks_path = os.path.join(os.environ["GIT_DIR"], "hooks")
-
- if not isinstance(param, list):
- param=[param]
-
- # resolve hook file name, OS depdenent
- hook_file = os.path.join(hooks_path, cmd)
- if platform.system() == 'Windows':
- if not os.path.isfile(hook_file):
- # look for the file with an extension
- files = glob.glob(hook_file + ".*")
- if not files:
- return True
- files.sort()
- hook_file = files.pop()
- while hook_file.upper().endswith(".SAMPLE"):
- # The file is a sample hook. We don't want it
- if len(files) > 0:
- hook_file = files.pop()
- else:
- return True
-
- if not os.path.isfile(hook_file) or not os.access(hook_file, os.X_OK):
- return True
-
- return run_hook_command(hook_file, param) == 0
-
-def run_hook_command(cmd, param):
- """Executes a git hook command
- cmd = the command line file to be executed. This can be
- a file that is run by OS association.
-
- param = a list of parameters to pass to the cmd command
-
- On windows, the extension is checked to see if it should
- be run with the Git for Windows Bash shell. If there
- is no file extension, the file is deemed a bash shell
- and will be handed off to sh.exe. Otherwise, Windows
- will be called with the shell to handle the file assocation.
-
- For non Windows operating systems, the file is called
- as an executable.
- """
- cli = [cmd] + param
- use_shell = False
- if platform.system() == 'Windows':
- (root,ext) = os.path.splitext(cmd)
- if ext == "":
- exe_path = os.environ.get("EXEPATH")
- if exe_path is None:
- exe_path = ""
- else:
- exe_path = os.path.join(exe_path, "bin")
- cli = [os.path.join(exe_path, "SH.EXE")] + cli
- else:
- use_shell = True
- return subprocess.call(cli, shell=use_shell)
-
+ args = ['git', 'hook', 'run', '--ignore-missing', cmd]
+ if param:
+ args.append("--")
+ for p in param:
+ args.append(p)
+ return subprocess.call(args) == 0
def write_pipe(c, stdin):
if verbose:
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 14/17] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (12 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 13/17] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 15/17] read-cache: convert post-index-change to use hook.h Ævar Arnfjörð Bjarmason
` (3 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move these hooks hook away from run-command.h to and over to the new
hook.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
commit.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/commit.c b/commit.c
index 551de4903c1..581d7dc216c 100644
--- a/commit.c
+++ b/commit.c
@@ -21,6 +21,7 @@
#include "commit-reach.h"
#include "run-command.h"
#include "shallow.h"
+#include "hook.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -1700,22 +1701,22 @@ size_t ignore_non_trailer(const char *buf, size_t len)
int run_commit_hook(int editor_is_used, const char *index_file,
const char *name, ...)
{
- struct strvec hook_env = STRVEC_INIT;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
va_list args;
- int ret;
+ const char *arg;
- strvec_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
+ strvec_pushf(&opt.env, "GIT_INDEX_FILE=%s", index_file);
/*
* Let the hook know that no editor will be launched.
*/
if (!editor_is_used)
- strvec_push(&hook_env, "GIT_EDITOR=:");
+ strvec_push(&opt.env, "GIT_EDITOR=:");
va_start(args, name);
- ret = run_hook_ve(hook_env.v, name, args);
+ while ((arg = va_arg(args, const char *)))
+ strvec_push(&opt.args, arg);
va_end(args);
- strvec_clear(&hook_env);
- return ret;
+ return run_hooks_opt(name, &opt);
}
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 15/17] read-cache: convert post-index-change to use hook.h
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (13 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 14/17] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 16/17] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
` (2 subsequent siblings)
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the post-index-change hook away from run-command.h to and over to
the new hook.h library.
This removes the last direct user of "run_hook_ve()" outside of
run-command.c ("run_hook_le()" still uses it). So we can make the
function static now. A subsequent commit will remove this code
entirely when "run_hook_le()" itself goes away.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
read-cache.c | 3 ++-
run-command.c | 2 +-
run-command.h | 1 -
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/read-cache.c b/read-cache.c
index f3986596623..4352661549f 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -28,6 +28,7 @@
#include "sparse-index.h"
#include "csum-file.h"
#include "promisor-remote.h"
+#include "hook.h"
/* Mask for the name length in ce_flags in the on-disk index */
@@ -3129,7 +3130,7 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l
else
ret = close_lock_file_gently(lock);
- run_hook_le(NULL, "post-index-change",
+ run_hooks_l("post-index-change",
istate->updated_workdir ? "1" : "0",
istate->updated_skipworktree ? "1" : "0", NULL);
istate->updated_workdir = 0;
diff --git a/run-command.c b/run-command.c
index f40df01c772..d7d64701ede 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1323,7 +1323,7 @@ int async_with_fork(void)
#endif
}
-int run_hook_ve(const char *const *env, const char *name, va_list args)
+static int run_hook_ve(const char *const *env, const char *name, va_list args)
{
struct child_process hook = CHILD_PROCESS_INIT;
const char *p;
diff --git a/run-command.h b/run-command.h
index 49878262584..3fa7454cf8a 100644
--- a/run-command.h
+++ b/run-command.h
@@ -239,7 +239,6 @@ int run_command(struct child_process *);
*/
LAST_ARG_MUST_BE_NULL
int run_hook_le(const char *const *env, const char *name, ...);
-int run_hook_ve(const char *const *env, const char *name, va_list args);
/*
* Trigger an auto-gc
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 16/17] receive-pack: convert push-to-checkout hook to hook.h
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (14 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 15/17] read-cache: convert post-index-change to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-11-23 11:46 ` [PATCH v5 17/17] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the push-to-checkout hook away from run-command.h to and over to
the new hook.h library.
This removes the last direct user of run_hook_le(), so we could remove
that function now, but let's leave that to a follow-up cleanup commit.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/receive-pack.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 49b846d9605..5d6d8dd9a26 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1439,9 +1439,12 @@ static const char *push_to_checkout(unsigned char *hash,
struct strvec *env,
const char *work_tree)
{
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
- if (run_hook_le(env->v, push_to_checkout_hook,
- hash_to_hex(hash), NULL))
+ strvec_pushv(&opt.env, env->v);
+ strvec_push(&opt.args, hash_to_hex(hash));
+ if (run_hooks_opt(push_to_checkout_hook, &opt))
return "push-to-checkout hook declined";
else
return NULL;
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v5 17/17] run-command: remove old run_hook_{le,ve}() hook API
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (15 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 16/17] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
@ 2021-11-23 11:46 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
17 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-11-23 11:46 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
The new hook.h library has replaced all run-command.h hook-related
functionality. So let's delete this dead code.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
run-command.c | 32 --------------------------------
run-command.h | 16 ----------------
2 files changed, 48 deletions(-)
diff --git a/run-command.c b/run-command.c
index d7d64701ede..7ecff26c1dc 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1323,38 +1323,6 @@ int async_with_fork(void)
#endif
}
-static int run_hook_ve(const char *const *env, const char *name, va_list args)
-{
- struct child_process hook = CHILD_PROCESS_INIT;
- const char *p;
-
- p = find_hook(name);
- if (!p)
- return 0;
-
- strvec_push(&hook.args, p);
- while ((p = va_arg(args, const char *)))
- strvec_push(&hook.args, p);
- hook.env = env;
- hook.no_stdin = 1;
- hook.stdout_to_stderr = 1;
- hook.trace2_hook_name = name;
-
- return run_command(&hook);
-}
-
-int run_hook_le(const char *const *env, const char *name, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, name);
- ret = run_hook_ve(env, name, args);
- va_end(args);
-
- return ret;
-}
-
struct io_pump {
/* initialized by caller */
int fd;
diff --git a/run-command.h b/run-command.h
index 3fa7454cf8a..59e1fbff64c 100644
--- a/run-command.h
+++ b/run-command.h
@@ -224,22 +224,6 @@ int finish_command_in_signal(struct child_process *);
*/
int run_command(struct child_process *);
-/**
- * Run a hook.
- * The first argument is a pathname to an index file, or NULL
- * if the hook uses the default index file or no index is needed.
- * The second argument is the name of the hook.
- * The further arguments correspond to the hook arguments.
- * The last argument has to be NULL to terminate the arguments list.
- * If the hook does not exist or is not executable, the return
- * value will be zero.
- * If it is executable, the hook will be executed and the exit
- * status of the hook is returned.
- * On execution, .stdout_to_stderr and .no_stdin will be set.
- */
-LAST_ARG_MUST_BE_NULL
-int run_hook_le(const char *const *env, const char *name, ...);
-
/*
* Trigger an auto-gc
*/
--
2.34.0.831.gd33babec0d1
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion
2021-11-23 11:45 ` [PATCH v5 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (16 preceding siblings ...)
2021-11-23 11:46 ` [PATCH v5 17/17] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 01/17] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
` (18 more replies)
17 siblings, 19 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
A trivial update to v5 to rebase it past conflicts with topics that
recently landed on "master". For v5 see:
https://lore.kernel.org/git/cover-v5-00.17-00000000000-20211123T114206Z-avarab@gmail.com/
Emily Shaffer (14):
hook: add 'run' subcommand
gc: use hook library for pre-auto-gc hook
am: convert {pre,post}-applypatch to use hook.h
rebase: convert pre-rebase to use hook.h
am: convert applypatch-msg to use hook.h
merge: convert post-merge to use hook.h
hooks: convert non-worktree 'post-checkout' hook to hook library
hooks: convert worktree 'post-checkout' hook to hook library
send-email: use 'git hook run' for 'sendemail-validate'
git-p4: use 'git hook' to run hooks
commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
read-cache: convert post-index-change to use hook.h
receive-pack: convert push-to-checkout hook to hook.h
run-command: remove old run_hook_{le,ve}() hook API
Ævar Arnfjörð Bjarmason (3):
hook API: add a run_hooks() wrapper
hook API: add a run_hooks_l() wrapper
git hook run: add an --ignore-missing flag
.gitignore | 1 +
Documentation/git-hook.txt | 45 +++++++++++++
Documentation/githooks.txt | 4 ++
Makefile | 1 +
builtin.h | 1 +
builtin/am.c | 6 +-
builtin/checkout.c | 3 +-
builtin/clone.c | 3 +-
builtin/gc.c | 3 +-
builtin/hook.c | 84 +++++++++++++++++++++++
builtin/merge.c | 2 +-
builtin/rebase.c | 3 +-
builtin/receive-pack.c | 7 +-
builtin/worktree.c | 26 +++----
command-list.txt | 1 +
commit.c | 15 +++--
git-p4.py | 70 ++-----------------
git-send-email.perl | 22 +++---
git.c | 1 +
hook.c | 131 ++++++++++++++++++++++++++++++++++++
hook.h | 57 ++++++++++++++++
read-cache.c | 3 +-
reset.c | 3 +-
run-command.c | 33 ---------
run-command.h | 17 -----
t/t1800-hook.sh | 134 +++++++++++++++++++++++++++++++++++++
t/t9001-send-email.sh | 4 +-
27 files changed, 522 insertions(+), 158 deletions(-)
create mode 100644 Documentation/git-hook.txt
create mode 100644 builtin/hook.c
create mode 100755 t/t1800-hook.sh
Range-diff against v5:
1: 4ca52feebb8 = 1: ba6fd47482e hook: add 'run' subcommand
2: 6275b97a306 = 2: cfba5c139e7 hook API: add a run_hooks() wrapper
3: b5b3051b2e5 = 3: a4cca074bcb gc: use hook library for pre-auto-gc hook
4: c88eb5d4c25 = 4: ce57ce1adcb am: convert {pre,post}-applypatch to use hook.h
5: 1d8f7b7e4c1 = 5: d6162fbef80 hook API: add a run_hooks_l() wrapper
6: d49a1444345 = 6: 4c1a8951fc5 rebase: convert pre-rebase to use hook.h
7: 191fdad0165 = 7: d8aa5e8345f am: convert applypatch-msg to use hook.h
8: 119b92fbeae = 8: 6f8d3754b4f merge: convert post-merge to use hook.h
9: 359ba416e84 ! 9: d3107034806 hooks: convert non-worktree 'post-checkout' hook to hook library
@@ builtin/checkout.c
#include "ll-merge.h"
#include "lockfile.h"
#include "merge-recursive.h"
-@@ builtin/checkout.c: struct branch_info {
+@@ builtin/checkout.c: static void branch_info_release(struct branch_info *info)
static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
10: b7599be95a7 ! 10: bff7c1513ca hooks: convert worktree 'post-checkout' hook to hook library
@@ builtin/worktree.c: static int add_worktree(const char *path, const char *refnam
- const char *hook = find_hook("post-checkout");
- if (hook) {
- const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL };
-- cp.git_cmd = 0;
+- struct child_process cp = CHILD_PROCESS_INIT;
- cp.no_stdin = 1;
- cp.stdout_to_stderr = 1;
- cp.dir = path;
-- cp.env = env;
-- cp.argv = NULL;
+- strvec_pushv(&cp.env_array, env);
- cp.trace2_hook_name = "post-checkout";
- strvec_pushl(&cp.args, absolute_path(hook),
- oid_to_hex(null_oid()),
11: f1c84d7f627 = 11: 7d9c0a73568 git hook run: add an --ignore-missing flag
12: 4e0f94d9102 = 12: 8ea3b250dff send-email: use 'git hook run' for 'sendemail-validate'
13: e858f332a62 = 13: a184afd1ffd git-p4: use 'git hook' to run hooks
14: 9a5956cc028 = 14: 1a43e50617f commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
15: 6fd47c4c499 = 15: 08b7e63ba5b read-cache: convert post-index-change to use hook.h
16: b201ea46f4b = 16: c47b36ab41a receive-pack: convert push-to-checkout hook to hook.h
17: 281d17b04db ! 17: 7b99a4b633c run-command: remove old run_hook_{le,ve}() hook API
@@ run-command.c: int async_with_fork(void)
- strvec_push(&hook.args, p);
- while ((p = va_arg(args, const char *)))
- strvec_push(&hook.args, p);
-- hook.env = env;
+- if (env)
+- strvec_pushv(&hook.env_array, (const char **)env);
- hook.no_stdin = 1;
- hook.stdout_to_stderr = 1;
- hook.trace2_hook_name = name;
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v6 01/17] hook: add 'run' subcommand
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2022-01-07 21:53 ` Emily Shaffer
2021-12-22 3:59 ` [PATCH v6 02/17] hook API: add a run_hooks() wrapper Ævar Arnfjörð Bjarmason
` (17 subsequent siblings)
18 siblings, 1 reply; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
In order to enable hooks to be run as an external process, by a
standalone Git command, or by tools which wrap Git, provide an external
means to run all configured hook commands for a given hook event.
Most of our hooks require more complex functionality than this, but
let's start with the bare minimum required to support our simplest
hooks.
In terms of implementation the usage_with_options() and "goto usage"
pattern here mirrors that of
builtin/{commit-graph,multi-pack-index}.c.
Some of the implementation here, such as a function being named
run_hooks_opt() when it's tasked with running one hook, to using the
run_processes_parallel_tr2() API to run with jobs=1 is somewhere
between a bit odd and and an overkill for the current features of this
"hook run" command and the hook.[ch] API.
This code will eventually be able to run multiple hooks declared in
config in parallel, by starting out with these names and APIs we
reduce the later churn of renaming functions, switching from the
run_command() to run_processes_parallel_tr2() API etc.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
.gitignore | 1 +
Documentation/git-hook.txt | 37 +++++++++++
Documentation/githooks.txt | 4 ++
Makefile | 1 +
builtin.h | 1 +
builtin/hook.c | 80 +++++++++++++++++++++++
command-list.txt | 1 +
git.c | 1 +
hook.c | 102 +++++++++++++++++++++++++++++
hook.h | 35 ++++++++++
t/t1800-hook.sh | 129 +++++++++++++++++++++++++++++++++++++
11 files changed, 392 insertions(+)
create mode 100644 Documentation/git-hook.txt
create mode 100644 builtin/hook.c
create mode 100755 t/t1800-hook.sh
diff --git a/.gitignore b/.gitignore
index 054249b20a8..f817c509ec0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,6 +77,7 @@
/git-grep
/git-hash-object
/git-help
+/git-hook
/git-http-backend
/git-http-fetch
/git-http-push
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
new file mode 100644
index 00000000000..e39b1b5d069
--- /dev/null
+++ b/Documentation/git-hook.txt
@@ -0,0 +1,37 @@
+git-hook(1)
+===========
+
+NAME
+----
+git-hook - Run git hooks
+
+SYNOPSIS
+--------
+[verse]
+'git hook' run <hook-name> [-- <hook-args>]
+
+DESCRIPTION
+-----------
+
+A command interface to running git hooks (see linkgit:githooks[5]),
+for use by other scripted git commands.
+
+SUBCOMMANDS
+-----------
+
+run::
+ Run the `<hook-name>` hook. See linkgit:githooks[5] for
+ supported hook names.
++
+
+Any positional arguments to the hook should be passed after a
+mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
+linkgit:githooks[5] for arguments hooks might expect (if any).
+
+SEE ALSO
+--------
+linkgit:githooks[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index b51959ff941..a16e62bc8c8 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -698,6 +698,10 @@ and "0" meaning they were not.
Only one parameter should be set to "1" when the hook runs. The hook
running passing "1", "1" should not be possible.
+SEE ALSO
+--------
+linkgit:git-hook[1]
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 75ed168adbc..9a3cbc8c414 100644
--- a/Makefile
+++ b/Makefile
@@ -1109,6 +1109,7 @@ BUILTIN_OBJS += builtin/get-tar-commit-id.o
BUILTIN_OBJS += builtin/grep.o
BUILTIN_OBJS += builtin/hash-object.o
BUILTIN_OBJS += builtin/help.o
+BUILTIN_OBJS += builtin/hook.o
BUILTIN_OBJS += builtin/index-pack.o
BUILTIN_OBJS += builtin/init-db.o
BUILTIN_OBJS += builtin/interpret-trailers.o
diff --git a/builtin.h b/builtin.h
index 8a58743ed63..83379f3832c 100644
--- a/builtin.h
+++ b/builtin.h
@@ -164,6 +164,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
int cmd_grep(int argc, const char **argv, const char *prefix);
int cmd_hash_object(int argc, const char **argv, const char *prefix);
int cmd_help(int argc, const char **argv, const char *prefix);
+int cmd_hook(int argc, const char **argv, const char *prefix);
int cmd_index_pack(int argc, const char **argv, const char *prefix);
int cmd_init_db(int argc, const char **argv, const char *prefix);
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix);
diff --git a/builtin/hook.c b/builtin/hook.c
new file mode 100644
index 00000000000..9b67ff50cef
--- /dev/null
+++ b/builtin/hook.c
@@ -0,0 +1,80 @@
+#include "cache.h"
+#include "builtin.h"
+#include "config.h"
+#include "hook.h"
+#include "parse-options.h"
+#include "strbuf.h"
+#include "strvec.h"
+
+#define BUILTIN_HOOK_RUN_USAGE \
+ N_("git hook run <hook-name> [-- <hook-args>]")
+
+static const char * const builtin_hook_usage[] = {
+ BUILTIN_HOOK_RUN_USAGE,
+ NULL
+};
+
+static const char * const builtin_hook_run_usage[] = {
+ BUILTIN_HOOK_RUN_USAGE,
+ NULL
+};
+
+static int run(int argc, const char **argv, const char *prefix)
+{
+ int i;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ const char *hook_name;
+ struct option run_options[] = {
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, run_options,
+ builtin_hook_run_usage,
+ PARSE_OPT_KEEP_DASHDASH);
+
+ if (!argc)
+ goto usage;
+
+ /*
+ * Having a -- for "run" when providing <hook-args> is
+ * mandatory.
+ */
+ if (argc > 1 && strcmp(argv[1], "--") &&
+ strcmp(argv[1], "--end-of-options"))
+ goto usage;
+
+ /* Add our arguments, start after -- */
+ for (i = 2 ; i < argc; i++)
+ strvec_push(&opt.args, argv[i]);
+
+ /* Need to take into account core.hooksPath */
+ git_config(git_default_config, NULL);
+
+ hook_name = argv[0];
+ opt.error_if_missing = 1;
+ ret = run_hooks_opt(hook_name, &opt);
+ if (ret < 0) /* error() return */
+ ret = 1;
+ return ret;
+usage:
+ usage_with_options(builtin_hook_run_usage, run_options);
+}
+
+int cmd_hook(int argc, const char **argv, const char *prefix)
+{
+ struct option builtin_hook_options[] = {
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, NULL, builtin_hook_options,
+ builtin_hook_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+ if (!argc)
+ goto usage;
+
+ if (!strcmp(argv[0], "run"))
+ return run(argc, argv, prefix);
+
+usage:
+ usage_with_options(builtin_hook_usage, builtin_hook_options);
+}
diff --git a/command-list.txt b/command-list.txt
index 675c28f0bd0..9bd6f3c48f4 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -103,6 +103,7 @@ git-grep mainporcelain info
git-gui mainporcelain
git-hash-object plumbingmanipulators
git-help ancillaryinterrogators complete
+git-hook purehelpers
git-http-backend synchingrepositories
git-http-fetch synchelpers
git-http-push synchelpers
diff --git a/git.c b/git.c
index 7edafd8ecff..7030f1180b3 100644
--- a/git.c
+++ b/git.c
@@ -541,6 +541,7 @@ static struct cmd_struct commands[] = {
{ "grep", cmd_grep, RUN_SETUP_GENTLY },
{ "hash-object", cmd_hash_object },
{ "help", cmd_help },
+ { "hook", cmd_hook, RUN_SETUP },
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY | NO_PARSEOPT },
{ "init", cmd_init_db },
{ "init-db", cmd_init_db },
diff --git a/hook.c b/hook.c
index 55e1145a4b7..a0917cf877c 100644
--- 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,104 @@ 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;
+
+ 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 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;
+ run_processes_parallel_tr2(jobs,
+ pick_next_hook,
+ notify_start_failure,
+ notify_hook_finished,
+ &cb_data,
+ "hook",
+ hook_name);
+ ret = cb_data.rc;
+cleanup:
+ run_hooks_opt_clear(options);
+ return ret;
+}
diff --git a/hook.h b/hook.h
index 6aa36fc7ff9..782385cc235 100644
--- a/hook.h
+++ b/hook.h
@@ -1,5 +1,31 @@
#ifndef HOOK_H
#define HOOK_H
+#include "strvec.h"
+
+struct run_hooks_opt
+{
+ /* Environment vars to be set for each hook */
+ struct strvec env;
+
+ /* Args to be passed to each hook */
+ struct strvec args;
+
+ /* Emit an error if the hook is missing */
+ unsigned int error_if_missing:1;
+};
+
+#define RUN_HOOKS_OPT_INIT { \
+ .env = STRVEC_INIT, \
+ .args = STRVEC_INIT, \
+}
+
+struct hook_cb_data {
+ /* rc reflects the cumulative failure state */
+ int rc;
+ const char *hook_name;
+ const char *hook_path;
+ struct run_hooks_opt *options;
+};
/*
* Returns the path to the hook file, or NULL if the hook is missing
@@ -13,4 +39,13 @@ const char *find_hook(const char *name);
*/
int hook_exists(const char *hookname);
+/**
+ * Takes a `hook_name`, resolves it to a path with find_hook(), and
+ * runs the hook for you with the options specified in "struct
+ * run_hooks opt". Will free memory associated with the "struct run_hooks_opt".
+ *
+ * Returns the status code of the run hook, or a negative value on
+ * error().
+ */
+int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
#endif
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
new file mode 100755
index 00000000000..3aea1b105f0
--- /dev/null
+++ b/t/t1800-hook.sh
@@ -0,0 +1,129 @@
+#!/bin/sh
+
+test_description='git-hook command'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'git hook usage' '
+ test_expect_code 129 git hook &&
+ test_expect_code 129 git hook run &&
+ test_expect_code 129 git hook run -h &&
+ test_expect_code 129 git hook run --unknown 2>err &&
+ grep "unknown option" err
+'
+
+test_expect_success 'git hook run: nonexistent hook' '
+ cat >stderr.expect <<-\EOF &&
+ error: cannot find a hook named test-hook
+ EOF
+ test_expect_code 1 git hook run test-hook 2>stderr.actual &&
+ test_cmp stderr.expect stderr.actual
+'
+
+test_expect_success 'git hook run: basic' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo Test hook
+ EOF
+
+ cat >expect <<-\EOF &&
+ Test hook
+ EOF
+ git hook run test-hook 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git hook run: stdout and stderr both write to our stderr' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo >&1 Will end up on stderr
+ echo >&2 Will end up on stderr
+ EOF
+
+ cat >stderr.expect <<-\EOF &&
+ Will end up on stderr
+ Will end up on stderr
+ EOF
+ git hook run test-hook >stdout.actual 2>stderr.actual &&
+ test_cmp stderr.expect stderr.actual &&
+ test_must_be_empty stdout.actual
+'
+
+test_expect_success 'git hook run: exit codes are passed along' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 1
+ EOF
+
+ test_expect_code 1 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 2
+ EOF
+
+ test_expect_code 2 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 128
+ EOF
+
+ test_expect_code 128 git hook run test-hook &&
+
+ write_script .git/hooks/test-hook <<-EOF &&
+ exit 129
+ EOF
+
+ test_expect_code 129 git hook run test-hook
+'
+
+test_expect_success 'git hook run arg u ments without -- is not allowed' '
+ test_expect_code 129 git hook run test-hook arg u ments
+'
+
+test_expect_success 'git hook run -- pass arguments' '
+ write_script .git/hooks/test-hook <<-\EOF &&
+ echo $1
+ echo $2
+ EOF
+
+ cat >expect <<-EOF &&
+ arg
+ u ments
+ EOF
+
+ git hook run test-hook -- arg "u ments" 2>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git hook run -- out-of-repo runs excluded' '
+ write_script .git/hooks/test-hook <<-EOF &&
+ echo Test hook
+ EOF
+
+ nongit test_must_fail git hook run test-hook
+'
+
+test_expect_success 'git -c core.hooksPath=<PATH> hook run' '
+ mkdir my-hooks &&
+ write_script my-hooks/test-hook <<-\EOF &&
+ echo Hook ran $1 >>actual
+ EOF
+
+ cat >expect <<-\EOF &&
+ Test hook
+ Hook ran one
+ Hook ran two
+ Hook ran three
+ Hook ran four
+ EOF
+
+ # Test various ways of specifying the path. See also
+ # t1350-config-hooks-path.sh
+ >actual &&
+ git hook run test-hook -- ignored 2>>actual &&
+ git -c core.hooksPath=my-hooks hook run test-hook -- one 2>>actual &&
+ git -c core.hooksPath=my-hooks/ hook run test-hook -- two 2>>actual &&
+ git -c core.hooksPath="$PWD/my-hooks" hook run test-hook -- three 2>>actual &&
+ git -c core.hooksPath="$PWD/my-hooks/" hook run test-hook -- four 2>>actual &&
+ test_cmp expect actual
+'
+
+test_done
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v6 01/17] hook: add 'run' subcommand
2021-12-22 3:59 ` [PATCH v6 01/17] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
@ 2022-01-07 21:53 ` Emily Shaffer
2022-01-07 23:08 ` Junio C Hamano
0 siblings, 1 reply; 115+ messages in thread
From: Emily Shaffer @ 2022-01-07 21:53 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason
Cc: git, Junio C Hamano, Bagas Sanjaya, René Scharfe,
Phillip Wood
On Wed, Dec 22, 2021 at 04:59:27AM +0100, Ævar Arnfjörð Bjarmason wrote:
> diff --git a/hook.h b/hook.h
> +struct run_hooks_opt
> +{
> + /* Environment vars to be set for each hook */
> + struct strvec env;
> +
> + /* Args to be passed to each hook */
> + struct strvec args;
> +
> + /* Emit an error if the hook is missing */
> + unsigned int error_if_missing:1;
I wonder if it's premature to include error_if_missing, if we will
always set it to 1 until way down in patch 11.
But I do not care all that much - at this point, I'll be honest, I'd
just like to see the series merged.
> diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
> new file mode 100755
> +test_expect_success 'git hook run: nonexistent hook' '
> + cat >stderr.expect <<-\EOF &&
> + error: cannot find a hook named test-hook
> + EOF
> + test_expect_code 1 git hook run test-hook 2>stderr.actual &&
> + test_cmp stderr.expect stderr.actual
> +'
It's a little unclear to me what "nonexistent" means - does it mean that
it's a hook unknown to Git (e.g. not in hook-list.h)? Does it mean that
the hook path doesn't exist? Does it mean the hook path is not
executable?
I had to poke in the code a little bit but it looks like this whole
known_hook() distinction has disappeared, so maybe I only find it
confusing because I reviewed previous iterations.
It might be nice to at least leave a comment on this test case and point
out that it relies on nobody having created a test-hook script in an
earlier test. Or to clean up that path just in case, at the beginning of
this one. I could see someone well-meaning adding another test before
this for something simple and breaking this test.
No serious concerns here though - just a couple thoughts.
- Emily
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v6 01/17] hook: add 'run' subcommand
2022-01-07 21:53 ` Emily Shaffer
@ 2022-01-07 23:08 ` Junio C Hamano
0 siblings, 0 replies; 115+ messages in thread
From: Junio C Hamano @ 2022-01-07 23:08 UTC (permalink / raw)
To: Emily Shaffer
Cc: Ævar Arnfjörð Bjarmason, git, Bagas Sanjaya,
René Scharfe, Phillip Wood
Emily Shaffer <emilyshaffer@google.com> writes:
> On Wed, Dec 22, 2021 at 04:59:27AM +0100, Ævar Arnfjörð Bjarmason wrote:
>> diff --git a/hook.h b/hook.h
>> +struct run_hooks_opt
>> +{
>> + /* Environment vars to be set for each hook */
>> + struct strvec env;
>> +
>> + /* Args to be passed to each hook */
>> + struct strvec args;
>> +
>> + /* Emit an error if the hook is missing */
>> + unsigned int error_if_missing:1;
>
> I wonder if it's premature to include error_if_missing, if we will
> always set it to 1 until way down in patch 11.
>
> But I do not care all that much - at this point, I'll be honest, I'd
> just like to see the series merged.
>
>> diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
>> new file mode 100755
>> +test_expect_success 'git hook run: nonexistent hook' '
>> + cat >stderr.expect <<-\EOF &&
>> + error: cannot find a hook named test-hook
>> + EOF
>> + test_expect_code 1 git hook run test-hook 2>stderr.actual &&
>> + test_cmp stderr.expect stderr.actual
>> +'
>
> It's a little unclear to me what "nonexistent" means - does it mean that
> it's a hook unknown to Git (e.g. not in hook-list.h)? Does it mean that
> the hook path doesn't exist? Does it mean the hook path is not
> executable?
I think I saw the same puzzlement from another reviewer. It needs
to be clarified if the documentation patch does not do a good job.
> It might be nice to at least leave a comment on this test case and point
> out that it relies on nobody having created a test-hook script in an
> earlier test. Or to clean up that path just in case, at the beginning of
> this one.
Yup, I agree that the latter is a good practice.
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v6 02/17] hook API: add a run_hooks() wrapper
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 01/17] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2022-01-06 18:53 ` Glen Choo
2021-12-22 3:59 ` [PATCH v6 03/17] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
` (16 subsequent siblings)
18 siblings, 1 reply; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
Add a run_hooks() wrapper, we'll use it in subsequent commits for the
simple cases of wanting to run a single hook under a given name,
without providing options such as "env" or "args".
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
hook.c | 7 +++++++
hook.h | 6 ++++++
2 files changed, 13 insertions(+)
diff --git a/hook.c b/hook.c
index a0917cf877c..d67a114e62d 100644
--- a/hook.c
+++ b/hook.c
@@ -142,3 +142,10 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
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);
+}
diff --git a/hook.h b/hook.h
index 782385cc235..9c358789958 100644
--- a/hook.h
+++ b/hook.h
@@ -48,4 +48,10 @@ int hook_exists(const char *hookname);
* error().
*/
int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
+
+/**
+ * A wrapper for run_hooks_opt() which provides a dummy "struct
+ * run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
+ */
+int run_hooks(const char *hook_name);
#endif
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v6 02/17] hook API: add a run_hooks() wrapper
2021-12-22 3:59 ` [PATCH v6 02/17] hook API: add a run_hooks() wrapper Ævar Arnfjörð Bjarmason
@ 2022-01-06 18:53 ` Glen Choo
0 siblings, 0 replies; 115+ messages in thread
From: Glen Choo @ 2022-01-06 18:53 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason, git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
> Add a run_hooks() wrapper, we'll use it in subsequent commits for the
> simple cases of wanting to run a single hook under a given name,
> without providing options such as "env" or "args".
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
> hook.c | 7 +++++++
> hook.h | 6 ++++++
> 2 files changed, 13 insertions(+)
>
> diff --git a/hook.c b/hook.c
> index a0917cf877c..d67a114e62d 100644
> --- a/hook.c
> +++ b/hook.c
> @@ -142,3 +142,10 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
> 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);
> +}
> diff --git a/hook.h b/hook.h
> index 782385cc235..9c358789958 100644
> --- a/hook.h
> +++ b/hook.h
> @@ -48,4 +48,10 @@ int hook_exists(const char *hookname);
> * error().
> */
> int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
> +
> +/**
> + * A wrapper for run_hooks_opt() which provides a dummy "struct
> + * run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
> + */
> +int run_hooks(const char *hook_name);
> #endif
> --
> 2.34.1.1146.gb52885e7c44
This patch looks good. As a matter of personal taste, it's not ideal
that this is dead code, but it gets tested immediately in the subsequent
patches anyway, and those patches are pretty clear.
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v6 03/17] gc: use hook library for pre-auto-gc hook
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 01/17] hook: add 'run' subcommand Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 02/17] hook API: add a run_hooks() wrapper Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 04/17] am: convert {pre,post}-applypatch to use hook.h Ævar Arnfjörð Bjarmason
` (15 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the pre-auto-gc hook away from run-command.h to and over to the
new hook.h library. This uses the new run_hooks() wrapper.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/gc.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/builtin/gc.c b/builtin/gc.c
index bcef6a4c8da..4bbc58aae5b 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -32,6 +32,7 @@
#include "remote.h"
#include "object-store.h"
#include "exec-cmd.h"
+#include "hook.h"
#define FAILED_RUN "failed to run %s"
@@ -394,7 +395,7 @@ static int need_to_gc(void)
else
return 0;
- if (run_hook_le(NULL, "pre-auto-gc", NULL))
+ if (run_hooks("pre-auto-gc"))
return 0;
return 1;
}
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 04/17] am: convert {pre,post}-applypatch to use hook.h
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (2 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 03/17] gc: use hook library for pre-auto-gc hook Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 05/17] hook API: add a run_hooks_l() wrapper Ævar Arnfjörð Bjarmason
` (14 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Teach pre-applypatch and post-applypatch to use the hook.h library
instead of the run-command.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/am.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/builtin/am.c b/builtin/am.c
index 8677ea2348a..4b334cb7b12 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1609,7 +1609,7 @@ static void do_commit(const struct am_state *state)
const char *reflog_msg, *author, *committer = NULL;
struct strbuf sb = STRBUF_INIT;
- if (run_hook_le(NULL, "pre-applypatch", NULL))
+ if (run_hooks("pre-applypatch"))
exit(1);
if (write_cache_as_tree(&tree, 0, NULL))
@@ -1661,7 +1661,7 @@ static void do_commit(const struct am_state *state)
fclose(fp);
}
- run_hook_le(NULL, "post-applypatch", NULL);
+ run_hooks("post-applypatch");
strbuf_release(&sb);
}
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 05/17] hook API: add a run_hooks_l() wrapper
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (3 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 04/17] am: convert {pre,post}-applypatch to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2022-01-06 18:56 ` Glen Choo
2022-01-07 21:56 ` Emily Shaffer
2021-12-22 3:59 ` [PATCH v6 06/17] rebase: convert pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
` (13 subsequent siblings)
18 siblings, 2 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
Add a run_hooks_l() wrapper, we'll use it in subsequent commits for
the simple cases of wanting to run a single hook under a given name
along with a list of arguments.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
hook.c | 14 ++++++++++++++
hook.h | 10 ++++++++++
2 files changed, 24 insertions(+)
diff --git a/hook.c b/hook.c
index d67a114e62d..1ad123422b2 100644
--- a/hook.c
+++ b/hook.c
@@ -149,3 +149,17 @@ int run_hooks(const char *hook_name)
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);
+}
diff --git a/hook.h b/hook.h
index 9c358789958..54528395953 100644
--- a/hook.h
+++ b/hook.h
@@ -54,4 +54,14 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
* run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
*/
int run_hooks(const char *hook_name);
+
+/**
+ * Like run_hooks(), a wrapper for run_hooks_opt().
+ *
+ * In addition to the wrapping behavior provided by run_hooks(), this
+ * wrapper takes a list of strings terminated by a NULL
+ * argument. These things will be used as positional arguments to the
+ * hook. This function behaves like the old run_hook_le() API.
+ */
+int run_hooks_l(const char *hook_name, ...);
#endif
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v6 05/17] hook API: add a run_hooks_l() wrapper
2021-12-22 3:59 ` [PATCH v6 05/17] hook API: add a run_hooks_l() wrapper Ævar Arnfjörð Bjarmason
@ 2022-01-06 18:56 ` Glen Choo
2022-01-07 21:56 ` Emily Shaffer
1 sibling, 0 replies; 115+ messages in thread
From: Glen Choo @ 2022-01-06 18:56 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason, git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
> Add a run_hooks_l() wrapper, we'll use it in subsequent commits for
> the simple cases of wanting to run a single hook under a given name
> along with a list of arguments.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
> hook.c | 14 ++++++++++++++
> hook.h | 10 ++++++++++
> 2 files changed, 24 insertions(+)
>
> diff --git a/hook.c b/hook.c
> index d67a114e62d..1ad123422b2 100644
> --- a/hook.c
> +++ b/hook.c
> @@ -149,3 +149,17 @@ int run_hooks(const char *hook_name)
>
> 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);
> +}
> diff --git a/hook.h b/hook.h
> index 9c358789958..54528395953 100644
> --- a/hook.h
> +++ b/hook.h
> @@ -54,4 +54,14 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
> * run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
> */
> int run_hooks(const char *hook_name);
> +
> +/**
> + * Like run_hooks(), a wrapper for run_hooks_opt().
> + *
> + * In addition to the wrapping behavior provided by run_hooks(), this
> + * wrapper takes a list of strings terminated by a NULL
> + * argument. These things will be used as positional arguments to the
> + * hook. This function behaves like the old run_hook_le() API.
> + */
> +int run_hooks_l(const char *hook_name, ...);
> #endif
> --
> 2.34.1.1146.gb52885e7c44
Same comments as patch 2 [1], i.e. this looks good; it's technically
dead code, but that's mostly a matter of taste.
[1] https://lore.kernel.org/git/kl6lmtk87l1t.fsf@chooglen-macbookpro.roam.corp.google.com
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v6 05/17] hook API: add a run_hooks_l() wrapper
2021-12-22 3:59 ` [PATCH v6 05/17] hook API: add a run_hooks_l() wrapper Ævar Arnfjörð Bjarmason
2022-01-06 18:56 ` Glen Choo
@ 2022-01-07 21:56 ` Emily Shaffer
1 sibling, 0 replies; 115+ messages in thread
From: Emily Shaffer @ 2022-01-07 21:56 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason
Cc: git, Junio C Hamano, Bagas Sanjaya, René Scharfe,
Phillip Wood
On Wed, Dec 22, 2021 at 04:59:31AM +0100, Ævar Arnfjörð Bjarmason wrote:
>
> Add a run_hooks_l() wrapper, we'll use it in subsequent commits for
> the simple cases of wanting to run a single hook under a given name
> along with a list of arguments.
I've got a slight allergy to varargs, just as personal preference, but
there's no denying that this makes the following callsite conversions
extremely mechanical and easy to review.
Does this calling convention make it easier for us to try and inline
results from something like oid_to_hex(), which may become stale,
compared to needing to put together a struct with args? I think probably
it's fine - because strvec_push() creates a copy, and run_hooks_l() is
not something we'd want to call multiple times in parallel (I hope).
Anyway,
Reviewed-by: Emily Shaffer <emilyshaffer@google.com>
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
> hook.c | 14 ++++++++++++++
> hook.h | 10 ++++++++++
> 2 files changed, 24 insertions(+)
>
> diff --git a/hook.c b/hook.c
> index d67a114e62d..1ad123422b2 100644
> --- a/hook.c
> +++ b/hook.c
> @@ -149,3 +149,17 @@ int run_hooks(const char *hook_name)
>
> 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);
> +}
> diff --git a/hook.h b/hook.h
> index 9c358789958..54528395953 100644
> --- a/hook.h
> +++ b/hook.h
> @@ -54,4 +54,14 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
> * run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
> */
> int run_hooks(const char *hook_name);
> +
> +/**
> + * Like run_hooks(), a wrapper for run_hooks_opt().
> + *
> + * In addition to the wrapping behavior provided by run_hooks(), this
> + * wrapper takes a list of strings terminated by a NULL
> + * argument. These things will be used as positional arguments to the
> + * hook. This function behaves like the old run_hook_le() API.
> + */
> +int run_hooks_l(const char *hook_name, ...);
> #endif
> --
> 2.34.1.1146.gb52885e7c44
>
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v6 06/17] rebase: convert pre-rebase to use hook.h
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (4 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 05/17] hook API: add a run_hooks_l() wrapper Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 07/17] am: convert applypatch-msg " Ævar Arnfjörð Bjarmason
` (12 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the pre-rebase hook away from run-command.h to and over to the
new hook.h library.
Since this hook needs arguments introduce a run_hooksl() wrapper, like
run_hooks(), but it takes varargs.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/rebase.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 34b4744e5f3..ac4120013a0 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -28,6 +28,7 @@
#include "sequencer.h"
#include "rebase-interactive.h"
#include "reset.h"
+#include "hook.h"
#define DEFAULT_REFLOG_ACTION "rebase"
@@ -1712,7 +1713,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
/* If a hook exists, give it a chance to interrupt*/
if (!ok_to_skip_pre_rebase &&
- run_hook_le(NULL, "pre-rebase", options.upstream_arg,
+ run_hooks_l("pre-rebase", options.upstream_arg,
argc ? argv[0] : NULL, NULL))
die(_("The pre-rebase hook refused to rebase."));
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 07/17] am: convert applypatch-msg to use hook.h
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (5 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 06/17] rebase: convert pre-rebase to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 08/17] merge: convert post-merge " Ævar Arnfjörð Bjarmason
` (11 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Teach applypatch-msg to use the hook.h library instead of the
run-command.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/am.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/builtin/am.c b/builtin/am.c
index 4b334cb7b12..ae0c484dcba 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -448,7 +448,7 @@ static int run_applypatch_msg_hook(struct am_state *state)
int ret;
assert(state->msg);
- ret = run_hook_le(NULL, "applypatch-msg", am_path(state, "final-commit"), NULL);
+ ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
if (!ret) {
FREE_AND_NULL(state->msg);
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 08/17] merge: convert post-merge to use hook.h
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (6 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 07/17] am: convert applypatch-msg " Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 09/17] hooks: convert non-worktree 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
` (10 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Teach post-merge to use the hook.h library instead of the
run-command.h library to run hooks.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/merge.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/builtin/merge.c b/builtin/merge.c
index 5f0476b0b76..5be3009c2a2 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -487,7 +487,7 @@ static void finish(struct commit *head_commit,
}
/* Run a post-merge hook */
- run_hook_le(NULL, "post-merge", squash ? "1" : "0", NULL);
+ run_hooks_l("post-merge", squash ? "1" : "0", NULL);
apply_autostash(git_path_merge_autostash(the_repository));
strbuf_release(&reflog_message);
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 09/17] hooks: convert non-worktree 'post-checkout' hook to hook library
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (7 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 08/17] merge: convert post-merge " Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 10/17] hooks: convert worktree " Ævar Arnfjörð Bjarmason
` (9 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the running of the 'post-checkout' hook away from run-command.h
to the new hook.h library, except in the case of
builtin/worktree.c. That special-case will be handled in a subsequent
commit.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/checkout.c | 3 ++-
builtin/clone.c | 3 ++-
reset.c | 3 ++-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 72beeb49aa9..e2e95445407 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -9,6 +9,7 @@
#include "config.h"
#include "diff.h"
#include "dir.h"
+#include "hook.h"
#include "ll-merge.h"
#include "lockfile.h"
#include "merge-recursive.h"
@@ -114,7 +115,7 @@ static void branch_info_release(struct branch_info *info)
static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
- return run_hook_le(NULL, "post-checkout",
+ return run_hooks_l("post-checkout",
oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
changed ? "1" : "0", NULL);
diff --git a/builtin/clone.c b/builtin/clone.c
index fb377b27657..ee27b9f8114 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -32,6 +32,7 @@
#include "connected.h"
#include "packfile.h"
#include "list-objects-filter-options.h"
+#include "hook.h"
/*
* Overall FIXMEs:
@@ -705,7 +706,7 @@ static int checkout(int submodule_progress)
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
- err |= run_hook_le(NULL, "post-checkout", oid_to_hex(null_oid()),
+ err |= run_hooks_l("post-checkout", oid_to_hex(null_oid()),
oid_to_hex(&oid), "1", NULL);
if (!err && (option_recurse_submodules.nr > 0)) {
diff --git a/reset.c b/reset.c
index f214df3d96c..0881e636915 100644
--- a/reset.c
+++ b/reset.c
@@ -7,6 +7,7 @@
#include "tree-walk.h"
#include "tree.h"
#include "unpack-trees.h"
+#include "hook.h"
int reset_head(struct repository *r, struct object_id *oid, const char *action,
const char *switch_to_branch, unsigned flags,
@@ -127,7 +128,7 @@ int reset_head(struct repository *r, struct object_id *oid, const char *action,
reflog_head);
}
if (run_hook)
- run_hook_le(NULL, "post-checkout",
+ run_hooks_l("post-checkout",
oid_to_hex(orig ? orig : null_oid()),
oid_to_hex(oid), "1", NULL);
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 10/17] hooks: convert worktree 'post-checkout' hook to hook library
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (8 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 09/17] hooks: convert non-worktree 'post-checkout' hook to hook library Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 11/17] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
` (8 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the running of the 'post-checkout' hook away from run-command.h
to the new hook.h library in builtin/worktree.c. For this special case
we need a change to the hook API to teach it to run the hook from a
given directory.
We cannot skip the "absolute_path" flag and just check if "dir" is
specified as we'd then fail to find our hook in the new dir we'd
chdir() to. We currently don't have a use-case for running a hook not
in our "base" repository at a given absolute path, so let's have "dir"
imply absolute_path(find_hook(hook_name)).
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/worktree.c | 26 +++++++++++---------------
hook.c | 8 ++++++++
hook.h | 6 ++++++
3 files changed, 25 insertions(+), 15 deletions(-)
diff --git a/builtin/worktree.c b/builtin/worktree.c
index a396cfdc64e..6f03afad974 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -382,21 +382,17 @@ static int add_worktree(const char *path, const char *refname,
* is_junk is cleared, but do return appropriate code when hook fails.
*/
if (!ret && opts->checkout) {
- const char *hook = find_hook("post-checkout");
- if (hook) {
- const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL };
- struct child_process cp = CHILD_PROCESS_INIT;
- cp.no_stdin = 1;
- cp.stdout_to_stderr = 1;
- cp.dir = path;
- strvec_pushv(&cp.env_array, env);
- cp.trace2_hook_name = "post-checkout";
- strvec_pushl(&cp.args, absolute_path(hook),
- oid_to_hex(null_oid()),
- oid_to_hex(&commit->object.oid),
- "1", NULL);
- ret = run_command(&cp);
- }
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
+ strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL);
+ strvec_pushl(&opt.args,
+ oid_to_hex(null_oid()),
+ oid_to_hex(&commit->object.oid),
+ "1",
+ NULL);
+ opt.dir = path;
+
+ ret = run_hooks_opt("post-checkout", &opt);
}
strvec_clear(&child_env);
diff --git a/hook.c b/hook.c
index 1ad123422b2..69a215b2c3c 100644
--- a/hook.c
+++ b/hook.c
@@ -57,6 +57,7 @@ static int pick_next_hook(struct child_process *cp,
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);
@@ -109,6 +110,7 @@ static void run_hooks_opt_clear(struct run_hooks_opt *options)
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,
@@ -130,6 +132,11 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
}
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,
@@ -139,6 +146,7 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
hook_name);
ret = cb_data.rc;
cleanup:
+ strbuf_release(&abs_path);
run_hooks_opt_clear(options);
return ret;
}
diff --git a/hook.h b/hook.h
index 54528395953..18d90aedf14 100644
--- a/hook.h
+++ b/hook.h
@@ -12,6 +12,12 @@ struct run_hooks_opt
/* Emit an error if the hook is missing */
unsigned int error_if_missing:1;
+
+ /**
+ * An optional initial working directory for the hook,
+ * translates to "struct child_process"'s "dir" member.
+ */
+ const char *dir;
};
#define RUN_HOOKS_OPT_INIT { \
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 11/17] git hook run: add an --ignore-missing flag
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (9 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 10/17] hooks: convert worktree " Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2022-01-06 19:33 ` Glen Choo
2021-12-22 3:59 ` [PATCH v6 12/17] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
` (7 subsequent siblings)
18 siblings, 1 reply; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
For certain one-shot hooks we'd like to optimistically run them, and
not complain if they don't exist.
This was already supported by the underlying hook.c library, but had
not been exposed via "git hook run". The command version of this will
be used by send-email in a subsequent commit.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
Documentation/git-hook.txt | 10 +++++++++-
builtin/hook.c | 8 ++++++--
t/t1800-hook.sh | 5 +++++
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
index e39b1b5d069..77c3a8ad909 100644
--- a/Documentation/git-hook.txt
+++ b/Documentation/git-hook.txt
@@ -8,7 +8,7 @@ git-hook - Run git hooks
SYNOPSIS
--------
[verse]
-'git hook' run <hook-name> [-- <hook-args>]
+'git hook' run [--ignore-missing] <hook-name> [-- <hook-args>]
DESCRIPTION
-----------
@@ -28,6 +28,14 @@ Any positional arguments to the hook should be passed after a
mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
linkgit:githooks[5] for arguments hooks might expect (if any).
+OPTIONS
+-------
+
+--ignore-missing::
+ Ignore any missing hook by quietly returning zero. Used for
+ tools that want to do a blind one-shot run of a hook that may
+ or may not be present.
+
SEE ALSO
--------
linkgit:githooks[5]
diff --git a/builtin/hook.c b/builtin/hook.c
index 9b67ff50cef..54e5c6ec933 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -7,7 +7,7 @@
#include "strvec.h"
#define BUILTIN_HOOK_RUN_USAGE \
- N_("git hook run <hook-name> [-- <hook-args>]")
+ N_("git hook run [--ignore-missing] <hook-name> [-- <hook-args>]")
static const char * const builtin_hook_usage[] = {
BUILTIN_HOOK_RUN_USAGE,
@@ -23,8 +23,11 @@ static int run(int argc, const char **argv, const char *prefix)
{
int i;
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+ int ignore_missing = 0;
const char *hook_name;
struct option run_options[] = {
+ OPT_BOOL(0, "ignore-missing", &ignore_missing,
+ N_("silently ignore missing requested <hook-name>")),
OPT_END(),
};
int ret;
@@ -52,7 +55,8 @@ static int run(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
hook_name = argv[0];
- opt.error_if_missing = 1;
+ if (!ignore_missing)
+ opt.error_if_missing = 1;
ret = run_hooks_opt(hook_name, &opt);
if (ret < 0) /* error() return */
ret = 1;
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
index 3aea1b105f0..29718aa9913 100755
--- a/t/t1800-hook.sh
+++ b/t/t1800-hook.sh
@@ -21,6 +21,11 @@ test_expect_success 'git hook run: nonexistent hook' '
test_cmp stderr.expect stderr.actual
'
+test_expect_success 'git hook run: nonexistent hook with --ignore-missing' '
+ git hook run --ignore-missing does-not-exist 2>stderr.actual &&
+ test_must_be_empty stderr.actual
+'
+
test_expect_success 'git hook run: basic' '
write_script .git/hooks/test-hook <<-EOF &&
echo Test hook
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v6 11/17] git hook run: add an --ignore-missing flag
2021-12-22 3:59 ` [PATCH v6 11/17] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
@ 2022-01-06 19:33 ` Glen Choo
0 siblings, 0 replies; 115+ messages in thread
From: Glen Choo @ 2022-01-06 19:33 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason, git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
> For certain one-shot hooks we'd like to optimistically run them, and
> not complain if they don't exist.
>
> This was already supported by the underlying hook.c library, but had
> not been exposed via "git hook run". The command version of this will
> be used by send-email in a subsequent commit.
>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
> Documentation/git-hook.txt | 10 +++++++++-
> builtin/hook.c | 8 ++++++--
> t/t1800-hook.sh | 5 +++++
> 3 files changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
> index e39b1b5d069..77c3a8ad909 100644
> --- a/Documentation/git-hook.txt
> +++ b/Documentation/git-hook.txt
> @@ -8,7 +8,7 @@ git-hook - Run git hooks
> SYNOPSIS
> --------
> [verse]
> -'git hook' run <hook-name> [-- <hook-args>]
> +'git hook' run [--ignore-missing] <hook-name> [-- <hook-args>]
>
> DESCRIPTION
> -----------
> @@ -28,6 +28,14 @@ Any positional arguments to the hook should be passed after a
> mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
> linkgit:githooks[5] for arguments hooks might expect (if any).
>
> +OPTIONS
> +-------
> +
> +--ignore-missing::
> + Ignore any missing hook by quietly returning zero. Used for
> + tools that want to do a blind one-shot run of a hook that may
> + or may not be present.
The most obvious question whenever a new option is introduced is "Is
this a descriptive and consistent option name?" The answer we came to in
review club is yes, "--ignore-missing" is good :)
However, the description isn't 100% clear about what it means for a hook
to be missing (possible confusion: is a missing hook a hook that isn't
documented in Documentation/githooks.txt?). I suspect that your wording
is intentionally open-ended because Git will eventually look for hooks
in the config as well as `.git/hooks`. Nevertheless, it would help to
get a precise definition in the docs so that readers know what to expect
and we can advise() users consistently.
> +
> SEE ALSO
> --------
> linkgit:githooks[5]
> diff --git a/builtin/hook.c b/builtin/hook.c
> index 9b67ff50cef..54e5c6ec933 100644
> --- a/builtin/hook.c
> +++ b/builtin/hook.c
> @@ -7,7 +7,7 @@
> #include "strvec.h"
>
> #define BUILTIN_HOOK_RUN_USAGE \
> - N_("git hook run <hook-name> [-- <hook-args>]")
> + N_("git hook run [--ignore-missing] <hook-name> [-- <hook-args>]")
>
> static const char * const builtin_hook_usage[] = {
> BUILTIN_HOOK_RUN_USAGE,
> @@ -23,8 +23,11 @@ static int run(int argc, const char **argv, const char *prefix)
> {
> int i;
> struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
> + int ignore_missing = 0;
> const char *hook_name;
> struct option run_options[] = {
> + OPT_BOOL(0, "ignore-missing", &ignore_missing,
> + N_("silently ignore missing requested <hook-name>")),
> OPT_END(),
> };
> int ret;
> @@ -52,7 +55,8 @@ static int run(int argc, const char **argv, const char *prefix)
> git_config(git_default_config, NULL);
>
> hook_name = argv[0];
> - opt.error_if_missing = 1;
> + if (!ignore_missing)
> + opt.error_if_missing = 1;
It's not clear why --ignore-missing isn't just the default behavior (and
judging from the lines above, it looks like it used to be?). After some
debate, most of the Google reviewers liked this new default, but it was
difficult to assess the merits of the decision because the thought
process wasn't obvious.
Here's the line of reasoning: if we only consider the hooks in-tree, it
certainly seems like none of the callers actually want to error out if
the hook is missing. This suggests that the default behavior of ignoring
missing hooks is actually what we want, so why change the default
behavior and add another option to worry about?
I can propose at least one reason, which is that "git hook" is also
meant to be invoked by end users in the shell and not just by programs.
I used to use npm quite a lot, and a pattern I am quite fond of is to
have an npm script called "precommit" which runs my linters and
formatters, and I'd make `npm run precommit` part of my pre-commit hook.
But a nice benefit is that I can also run `npm run precommit` at any
time to run all of my tooling, regardless of whether or not I am making
a commit. It would be pretty neat to be able to do away with npm and
just use `git hook run pre-commit'. In this scenario, I would certainly
expect `git hook run pre-commit` to fail if there is no `pre-commit`
hook, so yes, this new default behavior can make sense.
But I can't tell if this is something you had intended all along, or if
you had something else in mind. If anything, the original cover letter
[1] _almost_ seems to suggest otherwise.
The new "git hook" command is (for now) only for the benefit of
in-tree non-C programs that need to run hooks, and this series
converts git-send-email and git-p4 to use it.
It's worth explaining the rationale in the commit message.
> ret = run_hooks_opt(hook_name, &opt);
> if (ret < 0) /* error() return */
> ret = 1;
> diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
> index 3aea1b105f0..29718aa9913 100755
> --- a/t/t1800-hook.sh
> +++ b/t/t1800-hook.sh
> @@ -21,6 +21,11 @@ test_expect_success 'git hook run: nonexistent hook' '
> test_cmp stderr.expect stderr.actual
> '
>
> +test_expect_success 'git hook run: nonexistent hook with --ignore-missing' '
> + git hook run --ignore-missing does-not-exist 2>stderr.actual &&
> + test_must_be_empty stderr.actual
> +'
> +
For completeness, this should include a test for the non-exceptional
case i.e. when the hook isn't missing.
> test_expect_success 'git hook run: basic' '
> write_script .git/hooks/test-hook <<-EOF &&
> echo Test hook
> --
> 2.34.1.1146.gb52885e7c44
[1] https://lore.kernel.org/git/cover-00.13-00000000000-20211012T131934Z-avarab@gmail.com/
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v6 12/17] send-email: use 'git hook run' for 'sendemail-validate'
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (10 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 11/17] git hook run: add an --ignore-missing flag Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 13/17] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
` (6 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Change the "sendmail-validate" hook to be run via the "git hook run"
wrapper instead of via a direct invocation.
This is the smallest possibly change to get "send-email" using "git
hook run". We still check the hook itself with "-x", and set a
"GIT_DIR" variable, both of which are asserted by our tests. We'll
need to get rid of this special behavior if we start running N hooks,
but for now let's be as close to bug-for-bug compatible as possible.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
git-send-email.perl | 22 ++++++++++++++--------
t/t9001-send-email.sh | 4 ++--
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/git-send-email.perl b/git-send-email.perl
index 04087221aa7..a98460bdb96 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -225,13 +225,13 @@ sub format_2822_time {
my $editor;
sub system_or_msg {
- my ($args, $msg) = @_;
+ my ($args, $msg, $cmd_name) = @_;
system(@$args);
my $signalled = $? & 127;
my $exit_code = $? >> 8;
return unless $signalled or $exit_code;
- my @sprintf_args = ($args->[0], $exit_code);
+ my @sprintf_args = ($cmd_name ? $cmd_name : $args->[0], $exit_code);
if (defined $msg) {
# Quiet the 'redundant' warning category, except we
# need to support down to Perl 5.8, so we can't do a
@@ -2075,10 +2075,10 @@ sub validate_patch {
my ($fn, $xfer_encoding) = @_;
if ($repo) {
+ my $hook_name = 'sendemail-validate';
my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
require File::Spec;
- my $validate_hook = File::Spec->catfile($hooks_path,
- 'sendemail-validate');
+ my $validate_hook = File::Spec->catfile($hooks_path, $hook_name);
my $hook_error;
if (-x $validate_hook) {
require Cwd;
@@ -2088,13 +2088,19 @@ sub validate_patch {
chdir($repo->wc_path() or $repo->repo_path())
or die("chdir: $!");
local $ENV{"GIT_DIR"} = $repo->repo_path();
- $hook_error = system_or_msg([$validate_hook, $target]);
+ my @cmd = ("git", "hook", "run", "--ignore-missing",
+ $hook_name, "--");
+ my @cmd_msg = (@cmd, "<patch>");
+ my @cmd_run = (@cmd, $target);
+ $hook_error = system_or_msg(\@cmd_run, undef, "@cmd_msg");
chdir($cwd_save) or die("chdir: $!");
}
if ($hook_error) {
- die sprintf(__("fatal: %s: rejected by sendemail-validate hook\n" .
- "%s\n" .
- "warning: no patches were sent\n"), $fn, $hook_error);
+ $hook_error = sprintf(__("fatal: %s: rejected by %s hook\n" .
+ $hook_error . "\n" .
+ "warning: no patches were sent\n"),
+ $fn, $hook_name);
+ die $hook_error;
}
}
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index aa0c20499ba..84d0f40d76a 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -539,7 +539,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'my-hooks/sendemail-validate'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
@@ -558,7 +558,7 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
- fatal: command '"'"'$hooks_path/sendemail-validate'"'"' died with exit code 1
+ fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 13/17] git-p4: use 'git hook' to run hooks
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (11 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 12/17] send-email: use 'git hook run' for 'sendemail-validate' Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 14/17] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h Ævar Arnfjörð Bjarmason
` (5 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Instead of duplicating the behavior of run-command.h:run_hook_le() in
Python, we can directly call 'git hook run'. We emulate the existence
check with the --ignore-missing flag.
We're dropping the "verbose" handling added in 9f59ca4d6af (git-p4:
create new function run_git_hook, 2020-02-11), those who want
diagnostic output about how hooks are run are now able to get that via
e.g. the trace2 facility and GIT_TRACE=1.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
git-p4.py | 70 +++++--------------------------------------------------
1 file changed, 6 insertions(+), 64 deletions(-)
diff --git a/git-p4.py b/git-p4.py
index 2b4500226aa..3b54168eb4a 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -208,70 +208,12 @@ def decode_path(path):
def run_git_hook(cmd, param=[]):
"""Execute a hook if the hook exists."""
- if verbose:
- sys.stderr.write("Looking for hook: %s\n" % cmd)
- sys.stderr.flush()
-
- hooks_path = gitConfig("core.hooksPath")
- if len(hooks_path) <= 0:
- hooks_path = os.path.join(os.environ["GIT_DIR"], "hooks")
-
- if not isinstance(param, list):
- param=[param]
-
- # resolve hook file name, OS depdenent
- hook_file = os.path.join(hooks_path, cmd)
- if platform.system() == 'Windows':
- if not os.path.isfile(hook_file):
- # look for the file with an extension
- files = glob.glob(hook_file + ".*")
- if not files:
- return True
- files.sort()
- hook_file = files.pop()
- while hook_file.upper().endswith(".SAMPLE"):
- # The file is a sample hook. We don't want it
- if len(files) > 0:
- hook_file = files.pop()
- else:
- return True
-
- if not os.path.isfile(hook_file) or not os.access(hook_file, os.X_OK):
- return True
-
- return run_hook_command(hook_file, param) == 0
-
-def run_hook_command(cmd, param):
- """Executes a git hook command
- cmd = the command line file to be executed. This can be
- a file that is run by OS association.
-
- param = a list of parameters to pass to the cmd command
-
- On windows, the extension is checked to see if it should
- be run with the Git for Windows Bash shell. If there
- is no file extension, the file is deemed a bash shell
- and will be handed off to sh.exe. Otherwise, Windows
- will be called with the shell to handle the file assocation.
-
- For non Windows operating systems, the file is called
- as an executable.
- """
- cli = [cmd] + param
- use_shell = False
- if platform.system() == 'Windows':
- (root,ext) = os.path.splitext(cmd)
- if ext == "":
- exe_path = os.environ.get("EXEPATH")
- if exe_path is None:
- exe_path = ""
- else:
- exe_path = os.path.join(exe_path, "bin")
- cli = [os.path.join(exe_path, "SH.EXE")] + cli
- else:
- use_shell = True
- return subprocess.call(cli, shell=use_shell)
-
+ args = ['git', 'hook', 'run', '--ignore-missing', cmd]
+ if param:
+ args.append("--")
+ for p in param:
+ args.append(p)
+ return subprocess.call(args) == 0
def write_pipe(c, stdin):
if verbose:
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 14/17] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (12 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 13/17] git-p4: use 'git hook' to run hooks Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 15/17] read-cache: convert post-index-change to use hook.h Ævar Arnfjörð Bjarmason
` (4 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move these hooks hook away from run-command.h to and over to the new
hook.h library.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
commit.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/commit.c b/commit.c
index a348f085b2b..931f65d56d6 100644
--- a/commit.c
+++ b/commit.c
@@ -21,6 +21,7 @@
#include "commit-reach.h"
#include "run-command.h"
#include "shallow.h"
+#include "hook.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -1702,22 +1703,22 @@ size_t ignore_non_trailer(const char *buf, size_t len)
int run_commit_hook(int editor_is_used, const char *index_file,
const char *name, ...)
{
- struct strvec hook_env = STRVEC_INIT;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
va_list args;
- int ret;
+ const char *arg;
- strvec_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file);
+ strvec_pushf(&opt.env, "GIT_INDEX_FILE=%s", index_file);
/*
* Let the hook know that no editor will be launched.
*/
if (!editor_is_used)
- strvec_push(&hook_env, "GIT_EDITOR=:");
+ strvec_push(&opt.env, "GIT_EDITOR=:");
va_start(args, name);
- ret = run_hook_ve(hook_env.v, name, args);
+ while ((arg = va_arg(args, const char *)))
+ strvec_push(&opt.args, arg);
va_end(args);
- strvec_clear(&hook_env);
- return ret;
+ return run_hooks_opt(name, &opt);
}
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 15/17] read-cache: convert post-index-change to use hook.h
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (13 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 14/17] commit: convert {pre-commit,prepare-commit-msg} hook to hook.h Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 16/17] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
` (3 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the post-index-change hook away from run-command.h to and over to
the new hook.h library.
This removes the last direct user of "run_hook_ve()" outside of
run-command.c ("run_hook_le()" still uses it). So we can make the
function static now. A subsequent commit will remove this code
entirely when "run_hook_le()" itself goes away.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
read-cache.c | 3 ++-
run-command.c | 2 +-
run-command.h | 1 -
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/read-cache.c b/read-cache.c
index cbe73f14e5e..a7fbf144fec 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -28,6 +28,7 @@
#include "sparse-index.h"
#include "csum-file.h"
#include "promisor-remote.h"
+#include "hook.h"
/* Mask for the name length in ce_flags in the on-disk index */
@@ -3150,7 +3151,7 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l
else
ret = close_lock_file_gently(lock);
- run_hook_le(NULL, "post-index-change",
+ run_hooks_l("post-index-change",
istate->updated_workdir ? "1" : "0",
istate->updated_skipworktree ? "1" : "0", NULL);
istate->updated_workdir = 0;
diff --git a/run-command.c b/run-command.c
index 3ea2c2fc101..ea09de040a7 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1313,7 +1313,7 @@ int async_with_fork(void)
#endif
}
-int run_hook_ve(const char *const *env, const char *name, va_list args)
+static int run_hook_ve(const char *const *env, const char *name, va_list args)
{
struct child_process hook = CHILD_PROCESS_INIT;
const char *p;
diff --git a/run-command.h b/run-command.h
index 2be5f5d6422..88a398c300a 100644
--- a/run-command.h
+++ b/run-command.h
@@ -235,7 +235,6 @@ int run_command(struct child_process *);
*/
LAST_ARG_MUST_BE_NULL
int run_hook_le(const char *const *env, const char *name, ...);
-int run_hook_ve(const char *const *env, const char *name, va_list args);
/*
* Trigger an auto-gc
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 16/17] receive-pack: convert push-to-checkout hook to hook.h
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (14 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 15/17] read-cache: convert post-index-change to use hook.h Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2021-12-22 3:59 ` [PATCH v6 17/17] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
` (2 subsequent siblings)
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
Move the push-to-checkout hook away from run-command.h to and over to
the new hook.h library.
This removes the last direct user of run_hook_le(), so we could remove
that function now, but let's leave that to a follow-up cleanup commit.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
builtin/receive-pack.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 4f92e6f059d..e99b1ecd103 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1424,9 +1424,12 @@ static const char *push_to_checkout(unsigned char *hash,
struct strvec *env,
const char *work_tree)
{
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
- if (run_hook_le(env->v, push_to_checkout_hook,
- hash_to_hex(hash), NULL))
+ strvec_pushv(&opt.env, env->v);
+ strvec_push(&opt.args, hash_to_hex(hash));
+ if (run_hooks_opt(push_to_checkout_hook, &opt))
return "push-to-checkout hook declined";
else
return NULL;
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v6 17/17] run-command: remove old run_hook_{le,ve}() hook API
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (15 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 16/17] receive-pack: convert push-to-checkout hook to hook.h Ævar Arnfjörð Bjarmason
@ 2021-12-22 3:59 ` Ævar Arnfjörð Bjarmason
2022-01-06 18:47 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Glen Choo
2022-01-07 21:48 ` Emily Shaffer
18 siblings, 0 replies; 115+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-12-22 3:59 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
From: Emily Shaffer <emilyshaffer@google.com>
The new hook.h library has replaced all run-command.h hook-related
functionality. So let's delete this dead code.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
run-command.c | 33 ---------------------------------
run-command.h | 16 ----------------
2 files changed, 49 deletions(-)
diff --git a/run-command.c b/run-command.c
index ea09de040a7..f32e4fe1326 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1313,39 +1313,6 @@ int async_with_fork(void)
#endif
}
-static int run_hook_ve(const char *const *env, const char *name, va_list args)
-{
- struct child_process hook = CHILD_PROCESS_INIT;
- const char *p;
-
- p = find_hook(name);
- if (!p)
- return 0;
-
- strvec_push(&hook.args, p);
- while ((p = va_arg(args, const char *)))
- strvec_push(&hook.args, p);
- if (env)
- strvec_pushv(&hook.env_array, (const char **)env);
- hook.no_stdin = 1;
- hook.stdout_to_stderr = 1;
- hook.trace2_hook_name = name;
-
- return run_command(&hook);
-}
-
-int run_hook_le(const char *const *env, const char *name, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, name);
- ret = run_hook_ve(env, name, args);
- va_end(args);
-
- return ret;
-}
-
struct io_pump {
/* initialized by caller */
int fd;
diff --git a/run-command.h b/run-command.h
index 88a398c300a..07bed6c31b4 100644
--- a/run-command.h
+++ b/run-command.h
@@ -220,22 +220,6 @@ int finish_command_in_signal(struct child_process *);
*/
int run_command(struct child_process *);
-/**
- * Run a hook.
- * The first argument is a pathname to an index file, or NULL
- * if the hook uses the default index file or no index is needed.
- * The second argument is the name of the hook.
- * The further arguments correspond to the hook arguments.
- * The last argument has to be NULL to terminate the arguments list.
- * If the hook does not exist or is not executable, the return
- * value will be zero.
- * If it is executable, the hook will be executed and the exit
- * status of the hook is returned.
- * On execution, .stdout_to_stderr and .no_stdin will be set.
- */
-LAST_ARG_MUST_BE_NULL
-int run_hook_le(const char *const *env, const char *name, ...);
-
/*
* Trigger an auto-gc
*/
--
2.34.1.1146.gb52885e7c44
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (16 preceding siblings ...)
2021-12-22 3:59 ` [PATCH v6 17/17] run-command: remove old run_hook_{le,ve}() hook API Ævar Arnfjörð Bjarmason
@ 2022-01-06 18:47 ` Glen Choo
2022-01-07 21:48 ` Emily Shaffer
18 siblings, 0 replies; 115+ messages in thread
From: Glen Choo @ 2022-01-06 18:47 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason, git
Cc: Junio C Hamano, Bagas Sanjaya, Emily Shaffer, René Scharfe,
Phillip Wood, Ævar Arnfjörð Bjarmason
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
> A trivial update to v5 to rebase it past conflicts with topics that
> recently landed on "master". For v5 see:
> https://lore.kernel.org/git/cover-v5-00.17-00000000000-20211123T114206Z-avarab@gmail.com/
>
> Emily Shaffer (14):
> hook: add 'run' subcommand
> gc: use hook library for pre-auto-gc hook
> am: convert {pre,post}-applypatch to use hook.h
> rebase: convert pre-rebase to use hook.h
> am: convert applypatch-msg to use hook.h
> merge: convert post-merge to use hook.h
> hooks: convert non-worktree 'post-checkout' hook to hook library
> hooks: convert worktree 'post-checkout' hook to hook library
> send-email: use 'git hook run' for 'sendemail-validate'
> git-p4: use 'git hook' to run hooks
> commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
> read-cache: convert post-index-change to use hook.h
> receive-pack: convert push-to-checkout hook to hook.h
> run-command: remove old run_hook_{le,ve}() hook API
>
> Ævar Arnfjörð Bjarmason (3):
> hook API: add a run_hooks() wrapper
> hook API: add a run_hooks_l() wrapper
> git hook run: add an --ignore-missing flag
>
> .gitignore | 1 +
> Documentation/git-hook.txt | 45 +++++++++++++
> Documentation/githooks.txt | 4 ++
> Makefile | 1 +
> builtin.h | 1 +
> builtin/am.c | 6 +-
> builtin/checkout.c | 3 +-
> builtin/clone.c | 3 +-
> builtin/gc.c | 3 +-
> builtin/hook.c | 84 +++++++++++++++++++++++
> builtin/merge.c | 2 +-
> builtin/rebase.c | 3 +-
> builtin/receive-pack.c | 7 +-
> builtin/worktree.c | 26 +++----
> command-list.txt | 1 +
> commit.c | 15 +++--
> git-p4.py | 70 ++-----------------
> git-send-email.perl | 22 +++---
> git.c | 1 +
> hook.c | 131 ++++++++++++++++++++++++++++++++++++
> hook.h | 57 ++++++++++++++++
> read-cache.c | 3 +-
> reset.c | 3 +-
> run-command.c | 33 ---------
> run-command.h | 17 -----
> t/t1800-hook.sh | 134 +++++++++++++++++++++++++++++++++++++
> t/t9001-send-email.sh | 4 +-
> 27 files changed, 522 insertions(+), 158 deletions(-)
> create mode 100644 Documentation/git-hook.txt
> create mode 100644 builtin/hook.c
> create mode 100755 t/t1800-hook.sh
>
> Range-diff against v5:
> 1: 4ca52feebb8 = 1: ba6fd47482e hook: add 'run' subcommand
> 2: 6275b97a306 = 2: cfba5c139e7 hook API: add a run_hooks() wrapper
> 3: b5b3051b2e5 = 3: a4cca074bcb gc: use hook library for pre-auto-gc hook
> 4: c88eb5d4c25 = 4: ce57ce1adcb am: convert {pre,post}-applypatch to use hook.h
> 5: 1d8f7b7e4c1 = 5: d6162fbef80 hook API: add a run_hooks_l() wrapper
> 6: d49a1444345 = 6: 4c1a8951fc5 rebase: convert pre-rebase to use hook.h
> 7: 191fdad0165 = 7: d8aa5e8345f am: convert applypatch-msg to use hook.h
> 8: 119b92fbeae = 8: 6f8d3754b4f merge: convert post-merge to use hook.h
> 9: 359ba416e84 ! 9: d3107034806 hooks: convert non-worktree 'post-checkout' hook to hook library
> @@ builtin/checkout.c
> #include "ll-merge.h"
> #include "lockfile.h"
> #include "merge-recursive.h"
> -@@ builtin/checkout.c: struct branch_info {
> +@@ builtin/checkout.c: static void branch_info_release(struct branch_info *info)
> static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
> int changed)
> {
> 10: b7599be95a7 ! 10: bff7c1513ca hooks: convert worktree 'post-checkout' hook to hook library
> @@ builtin/worktree.c: static int add_worktree(const char *path, const char *refnam
> - const char *hook = find_hook("post-checkout");
> - if (hook) {
> - const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL };
> -- cp.git_cmd = 0;
> +- struct child_process cp = CHILD_PROCESS_INIT;
> - cp.no_stdin = 1;
> - cp.stdout_to_stderr = 1;
> - cp.dir = path;
> -- cp.env = env;
> -- cp.argv = NULL;
> +- strvec_pushv(&cp.env_array, env);
> - cp.trace2_hook_name = "post-checkout";
> - strvec_pushl(&cp.args, absolute_path(hook),
> - oid_to_hex(null_oid()),
> 11: f1c84d7f627 = 11: 7d9c0a73568 git hook run: add an --ignore-missing flag
> 12: 4e0f94d9102 = 12: 8ea3b250dff send-email: use 'git hook run' for 'sendemail-validate'
> 13: e858f332a62 = 13: a184afd1ffd git-p4: use 'git hook' to run hooks
> 14: 9a5956cc028 = 14: 1a43e50617f commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
> 15: 6fd47c4c499 = 15: 08b7e63ba5b read-cache: convert post-index-change to use hook.h
> 16: b201ea46f4b = 16: c47b36ab41a receive-pack: convert push-to-checkout hook to hook.h
> 17: 281d17b04db ! 17: 7b99a4b633c run-command: remove old run_hook_{le,ve}() hook API
> @@ run-command.c: int async_with_fork(void)
> - strvec_push(&hook.args, p);
> - while ((p = va_arg(args, const char *)))
> - strvec_push(&hook.args, p);
> -- hook.env = env;
> +- if (env)
> +- strvec_pushv(&hook.env_array, (const char **)env);
> - hook.no_stdin = 1;
> - hook.stdout_to_stderr = 1;
> - hook.trace2_hook_name = name;
> --
> 2.34.1.1146.gb52885e7c44
The Google folks picked up this series for our "review club" sessions
(which is open to the public, as you know ;)). As Junio mentioned in the
last "What's Cooking" [1], he would like serious review on the patches
you contributed, so that is where we focused most of our attention.
The code itself looks quite good, but one concern that came up was that
the motivation behind this series doesn't seem immediately obvious to
first time readers. This series has existed in some form for a very long
time; the first patches for config-based hooks I could find date back to
2019! [2]. So keeping everyone on the same page is definitely hard, but
it's worthwhile if it means that someone can pick up the series without
having to be familiar with the prior work.
With that in mind, your original cover letter [3] does a good job at
describing the "what" of the series - what it does (extend the hook API
and replace calls), what it is (an incremental restart of an ejected
topic). However, it's hard to recreate the motivation behind this series
based on the cover letter and its papertrail. Much of the Google team is
fairly familiar with the feature, but newcomers (including myself) have
a hard time piecing together the story based on this thread alone.
I found myself asking some questions when reading this cover letter, and
here are some suggestions to make this friendlier for new readers:
* Why do we want config based hooks in the first place?
Convincing us that we want this is Emily's job, not yours, but it
helps to know how this fits in with the whole thing. As a convenience,
linking to Emily's original series would save the reader a lot of
thread-following.
* How does this series contribute to config based hooks?
* Why did we need this reroll in the first place?
* How does this series meet the goals of the reroll?
These are pretty difficult to pin down without being familiar with the
original series too. Emily probably knows the anwers to these, so you
have at least one person who can review the series based on these
questions, but it's pretty challenging for others to figure this out.
This question is probably best answered in the cover letter, or at the
very least, links to suggested reading and the order in which to read
them.
* What benefit does this series bring irrespective of config based
hooks?
This is best answered in the cover letter as well, but the payoff is
way bigger than the previous set of questions. If you can sell
reviewers on the idea that this series independently mergeable, is
good for the project on its own (I think that it is!), _and_ it
contributes to config based hooks, then reviewers have a good reason
to look at it even if they aren't particularly invested in config
based hooks. I think this is even more important because we want
reviews saying "yes this series is good for the project".
TL;DR this is basically a long-winded way of saying that for a
long-running work in progress like this one, new reviewers are probably
scared off by having to recreate the context leading up to this series,
and anything we can do to lessen that burden will be greatly
appreciated :)
[1] https://lore.kernel.org/git/xmqq1r1lfwyq.fsf@gitster.g
[2] https://lore.kernel.org/git/20191210023335.49987-1-emilyshaffer@google.com/
[3] https://lore.kernel.org/git/cover-00.13-00000000000-20211012T131934Z-avarab@gmail.com/
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion
2021-12-22 3:59 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Ævar Arnfjörð Bjarmason
` (17 preceding siblings ...)
2022-01-06 18:47 ` [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion Glen Choo
@ 2022-01-07 21:48 ` Emily Shaffer
2022-01-07 22:01 ` Emily Shaffer
18 siblings, 1 reply; 115+ messages in thread
From: Emily Shaffer @ 2022-01-07 21:48 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason
Cc: git, Junio C Hamano, Bagas Sanjaya, René Scharfe,
Phillip Wood
On Wed, Dec 22, 2021 at 04:59:26AM +0100, Ævar Arnfjörð Bjarmason wrote:
>
> A trivial update to v5 to rebase it past conflicts with topics that
> recently landed on "master". For v5 see:
> https://lore.kernel.org/git/cover-v5-00.17-00000000000-20211123T114206Z-avarab@gmail.com/
One note, which is not so useful for this time, but might be useful in
the future:
It seems that in order to understand the purpose of this series and what
it's building for, you need to be me or be you (and therefore be aware
of the history of the series), or you need to go back through the
breadcrumbs and eventually read my huge config-based-hooks 30-patch
series (or at least the cover letter). Which sort of defeats the purpose
of splitting the series up into smaller reviewable chunks.
Next time it might be nice to add a quick summary of the whole goal,
which part of that goal this series is, and a link to the longer cover
letter/older series? But again, for this time, I think it is probably
too late, especially since this series looked pretty good to me.
Per-patch reviews to follow momentarily.
- Emily
>
> Emily Shaffer (14):
> hook: add 'run' subcommand
> gc: use hook library for pre-auto-gc hook
> am: convert {pre,post}-applypatch to use hook.h
> rebase: convert pre-rebase to use hook.h
> am: convert applypatch-msg to use hook.h
> merge: convert post-merge to use hook.h
> hooks: convert non-worktree 'post-checkout' hook to hook library
> hooks: convert worktree 'post-checkout' hook to hook library
> send-email: use 'git hook run' for 'sendemail-validate'
> git-p4: use 'git hook' to run hooks
> commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
> read-cache: convert post-index-change to use hook.h
> receive-pack: convert push-to-checkout hook to hook.h
> run-command: remove old run_hook_{le,ve}() hook API
>
> Ævar Arnfjörð Bjarmason (3):
> hook API: add a run_hooks() wrapper
> hook API: add a run_hooks_l() wrapper
> git hook run: add an --ignore-missing flag
>
> .gitignore | 1 +
> Documentation/git-hook.txt | 45 +++++++++++++
> Documentation/githooks.txt | 4 ++
> Makefile | 1 +
> builtin.h | 1 +
> builtin/am.c | 6 +-
> builtin/checkout.c | 3 +-
> builtin/clone.c | 3 +-
> builtin/gc.c | 3 +-
> builtin/hook.c | 84 +++++++++++++++++++++++
> builtin/merge.c | 2 +-
> builtin/rebase.c | 3 +-
> builtin/receive-pack.c | 7 +-
> builtin/worktree.c | 26 +++----
> command-list.txt | 1 +
> commit.c | 15 +++--
> git-p4.py | 70 ++-----------------
> git-send-email.perl | 22 +++---
> git.c | 1 +
> hook.c | 131 ++++++++++++++++++++++++++++++++++++
> hook.h | 57 ++++++++++++++++
> read-cache.c | 3 +-
> reset.c | 3 +-
> run-command.c | 33 ---------
> run-command.h | 17 -----
> t/t1800-hook.sh | 134 +++++++++++++++++++++++++++++++++++++
> t/t9001-send-email.sh | 4 +-
> 27 files changed, 522 insertions(+), 158 deletions(-)
> create mode 100644 Documentation/git-hook.txt
> create mode 100644 builtin/hook.c
> create mode 100755 t/t1800-hook.sh
>
> Range-diff against v5:
> 1: 4ca52feebb8 = 1: ba6fd47482e hook: add 'run' subcommand
> 2: 6275b97a306 = 2: cfba5c139e7 hook API: add a run_hooks() wrapper
> 3: b5b3051b2e5 = 3: a4cca074bcb gc: use hook library for pre-auto-gc hook
> 4: c88eb5d4c25 = 4: ce57ce1adcb am: convert {pre,post}-applypatch to use hook.h
> 5: 1d8f7b7e4c1 = 5: d6162fbef80 hook API: add a run_hooks_l() wrapper
> 6: d49a1444345 = 6: 4c1a8951fc5 rebase: convert pre-rebase to use hook.h
> 7: 191fdad0165 = 7: d8aa5e8345f am: convert applypatch-msg to use hook.h
> 8: 119b92fbeae = 8: 6f8d3754b4f merge: convert post-merge to use hook.h
> 9: 359ba416e84 ! 9: d3107034806 hooks: convert non-worktree 'post-checkout' hook to hook library
> @@ builtin/checkout.c
> #include "ll-merge.h"
> #include "lockfile.h"
> #include "merge-recursive.h"
> -@@ builtin/checkout.c: struct branch_info {
> +@@ builtin/checkout.c: static void branch_info_release(struct branch_info *info)
> static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
> int changed)
> {
> 10: b7599be95a7 ! 10: bff7c1513ca hooks: convert worktree 'post-checkout' hook to hook library
> @@ builtin/worktree.c: static int add_worktree(const char *path, const char *refnam
> - const char *hook = find_hook("post-checkout");
> - if (hook) {
> - const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL };
> -- cp.git_cmd = 0;
> +- struct child_process cp = CHILD_PROCESS_INIT;
> - cp.no_stdin = 1;
> - cp.stdout_to_stderr = 1;
> - cp.dir = path;
> -- cp.env = env;
> -- cp.argv = NULL;
> +- strvec_pushv(&cp.env_array, env);
> - cp.trace2_hook_name = "post-checkout";
> - strvec_pushl(&cp.args, absolute_path(hook),
> - oid_to_hex(null_oid()),
> 11: f1c84d7f627 = 11: 7d9c0a73568 git hook run: add an --ignore-missing flag
> 12: 4e0f94d9102 = 12: 8ea3b250dff send-email: use 'git hook run' for 'sendemail-validate'
> 13: e858f332a62 = 13: a184afd1ffd git-p4: use 'git hook' to run hooks
> 14: 9a5956cc028 = 14: 1a43e50617f commit: convert {pre-commit,prepare-commit-msg} hook to hook.h
> 15: 6fd47c4c499 = 15: 08b7e63ba5b read-cache: convert post-index-change to use hook.h
> 16: b201ea46f4b = 16: c47b36ab41a receive-pack: convert push-to-checkout hook to hook.h
> 17: 281d17b04db ! 17: 7b99a4b633c run-command: remove old run_hook_{le,ve}() hook API
> @@ run-command.c: int async_with_fork(void)
> - strvec_push(&hook.args, p);
> - while ((p = va_arg(args, const char *)))
> - strvec_push(&hook.args, p);
> -- hook.env = env;
> +- if (env)
> +- strvec_pushv(&hook.env_array, (const char **)env);
> - hook.no_stdin = 1;
> - hook.stdout_to_stderr = 1;
> - hook.trace2_hook_name = name;
> --
> 2.34.1.1146.gb52885e7c44
>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v6 00/17] hook.[ch]: new library to run hooks + simple hook conversion
2022-01-07 21:48 ` Emily Shaffer
@ 2022-01-07 22:01 ` Emily Shaffer
0 siblings, 0 replies; 115+ messages in thread
From: Emily Shaffer @ 2022-01-07 22:01 UTC (permalink / raw)
To: Ævar Arnfjörð Bjarmason
Cc: git, Junio C Hamano, Bagas Sanjaya, René Scharfe,
Phillip Wood
On Fri, Jan 07, 2022 at 01:48:16PM -0800, Emily Shaffer wrote:
>
> On Wed, Dec 22, 2021 at 04:59:26AM +0100, Ævar Arnfjörð Bjarmason wrote:
> >
> > A trivial update to v5 to rebase it past conflicts with topics that
> > recently landed on "master". For v5 see:
> > https://lore.kernel.org/git/cover-v5-00.17-00000000000-20211123T114206Z-avarab@gmail.com/
>
> One note, which is not so useful for this time, but might be useful in
> the future:
>
> It seems that in order to understand the purpose of this series and what
> it's building for, you need to be me or be you (and therefore be aware
> of the history of the series), or you need to go back through the
> breadcrumbs and eventually read my huge config-based-hooks 30-patch
> series (or at least the cover letter). Which sort of defeats the purpose
> of splitting the series up into smaller reviewable chunks.
>
> Next time it might be nice to add a quick summary of the whole goal,
> which part of that goal this series is, and a link to the longer cover
> letter/older series? But again, for this time, I think it is probably
> too late, especially since this series looked pretty good to me.
>
> Per-patch reviews to follow momentarily.
Left a couple nits here and there, but it all looks fine for me. Some
comments that I thought I had turned out to be invalid once I read the
series a second time... ;)
For all patches, but especially Ævar's,
Reviewed-by: Emily Shaffer <emilyshaffer@google.com>
I think that's stronger than an ACK for mine, but either way, for my
own patches:
Acked-by: Emily Shaffer <emilyshaffer@google.com>
Thanks. I'd be excited to see this go in.
- Emily
^ permalink raw reply [flat|nested] 115+ messages in thread