[PATCH 00/27] Base for "config-based-hooks"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This v3 of the "Base for 'config-based-hooks'" topic is >95% a
slimmed-down versio nof Emily Schaffer's work to introduce a mechanism
to drive hooks via config.

This topic doesn't do that, but moves all hook execution (C libary and
Perl|Python script) to either the new hook.[ch] library code, or the
"git hook run" utility.

See previous iterations for more details:

 v0 (Emily's): http://lore.kernel.org/git/20210527000856.695702-1-emilyshaffer@xxxxxxxxxx
 v1: https://lore.kernel.org/git/cover-00.31-00000000000-20210528T110515Z-avarab@xxxxxxxxx/
 v2: http://lore.kernel.org/git/cover-00.30-00000000000-20210614T101920Z-avarab@xxxxxxxxx

This series gained two new dependencies since v2, my just-submitted
preparatory topics:

    https://lore.kernel.org/git/cover-0.3-0000000000-20210617T095827Z-avarab@xxxxxxxxx/
    https://lore.kernel.org/git/cover-0.3-0000000000-20210617T100239Z-avarab@xxxxxxxxx/

And hopefully addreses all the feedback on v2, mainly/entirely from
Emily at https://lore.kernel.org/git/YMfLO9CT+iIDR3OA@xxxxxxxxxx

I'd normally have waited longer for a v3, but as discussed in the
small hook.[ch] topic that precedes this one building the new
hook-list.h had an error on Windows CI due to a missing CMake change,
that's now fixed.

Other changes can be seen in the range-diff, all rather trivial fixes
like comment fixes, trimming off "argc/argv" before we pass things to
"git hook run", removing a redundant test setup etc.

I also added a GIT_TEST_FAKE_HOOKS=true for use in the test suite to
make us support a "test-hook" and a "does-not-exist" hook, we'd
previously accept those outside the test environment.

Emily Shaffer (25):
  hook: add 'run' subcommand
  gc: use hook library for pre-auto-gc hook
  rebase: teach pre-rebase to use hook.h
  am: convert applypatch hooks to use config
  hooks: convert 'post-checkout' hook to hook library
  merge: use config-based hooks for post-merge hook
  send-email: use 'git hook run' for 'sendemail-validate'
  git-p4: use 'git hook' to run hooks
  commit: use hook.h to execute hooks
  read-cache: convert post-index-change hook to use config
  receive-pack: convert push-to-checkout hook to hook.h
  run-command: remove old run_hook_{le,ve}() hook API
  run-command: allow stdin for run_processes_parallel
  hook: support passing stdin to hooks
  am: convert 'post-rewrite' hook to hook.h
  run-command: add stdin callback for parallelization
  hook: provide stdin by string_list or callback
  hook: convert 'post-rewrite' hook in sequencer.c to hook.h
  transport: convert pre-push hook to use config
  reference-transaction: use hook.h to run hooks
  run-command: allow capturing of collated output
  hooks: allow callers to capture output
  receive-pack: convert 'update' hook to hook.h
  post-update: use hook.h library
  receive-pack: convert receive hooks to hook.h

Ævar Arnfjörð Bjarmason (2):
  git hook run: add an --ignore-missing flag
  hooks: fix a TOCTOU in "did we run a hook?" heuristic

 .gitignore                  |   1 +
 Documentation/git-hook.txt  |  51 ++++++
 Documentation/githooks.txt  |   4 +
 Makefile                    |   1 +
 builtin.h                   |   1 +
 builtin/am.c                |  33 ++--
 builtin/checkout.c          |  17 +-
 builtin/clone.c             |   7 +-
 builtin/commit.c            |  18 ++-
 builtin/fetch.c             |   1 +
 builtin/gc.c                |   8 +-
 builtin/hook.c              |  90 +++++++++++
 builtin/merge.c             |  21 ++-
 builtin/rebase.c            |   9 +-
 builtin/receive-pack.c      | 298 ++++++++++++++++++------------------
 builtin/submodule--helper.c |   2 +-
 builtin/worktree.c          |  30 ++--
 command-list.txt            |   1 +
 commit.c                    |  17 +-
 commit.h                    |   3 +-
 git-p4.py                   |  72 +--------
 git-send-email.perl         |  20 ++-
 git.c                       |   1 +
 hook.c                      | 170 ++++++++++++++++++++
 hook.h                      | 109 +++++++++++++
 read-cache.c                |  12 +-
 refs.c                      |  42 ++---
 reset.c                     |  15 +-
 run-command.c               | 122 ++++++++++-----
 run-command.h               |  48 ++++--
 sequencer.c                 |  87 +++++------
 submodule.c                 |   1 +
 t/helper/test-run-command.c |  46 +++++-
 t/t0061-run-command.sh      |  37 +++++
 t/t1800-hook.sh             | 154 +++++++++++++++++++
 t/t9001-send-email.sh       |   4 +-
 transport.c                 |  57 ++-----
 37 files changed, 1136 insertions(+), 474 deletions(-)
 create mode 100644 Documentation/git-hook.txt
 create mode 100644 builtin/hook.c
 create mode 100755 t/t1800-hook.sh

Range-diff:
 1:  447d349c73 !  1:  cf4b06bfdf hook: add 'run' subcommand
    @@ Documentation/git-hook.txt (new)
     +-----------
     +
     +run::
    -+
    -+	Run the `<hook-name>` hook. Any positional arguments to the
    -+	hook should be passed after an optional "--" (or
    -+	"--end-of-options"). See "OPTIONS" below for the arguments
    -+	this accepts.
    ++	Run the `<hook-name>` hook. See linkgit:githooks[5] for
    ++	the hook names we support.
    +++
    ++Any positional arguments to the hook should be passed after an
    ++optional `--` (or `--end-of-options`, see linkgit:gitcli[7]). The
    ++arguments (if any) differ by hook name, see linkgit:githooks[5] for
    ++what those are.
     +
     +SEE ALSO
     +--------
    @@ Documentation/githooks.txt: and "0" meaning they were not.
      Part of the linkgit:git[1] suite
     
      ## Makefile ##
    -@@ Makefile: LIB_OBJS += hash-lookup.o
    - LIB_OBJS += hashmap.o
    - LIB_OBJS += help.o
    - LIB_OBJS += hex.o
    -+LIB_OBJS += hook.o
    - LIB_OBJS += ident.o
    - LIB_OBJS += json-writer.o
    - LIB_OBJS += kwset.o
     @@ Makefile: BUILTIN_OBJS += builtin/get-tar-commit-id.o
      BUILTIN_OBJS += builtin/grep.o
      BUILTIN_OBJS += builtin/hash-object.o
    @@ builtin/hook.c (new)
     +#include "strvec.h"
     +
     +static const char * const builtin_hook_usage[] = {
    ++	N_("git hook <command> [...]"),
    ++	N_("git hook run <hook-name> [-- <hook-args>]"),
    ++	NULL
    ++};
    ++
    ++static const char * const builtin_hook_run_usage[] = {
     +	N_("git hook run <hook-name> [-- <hook-args>]"),
     +	NULL
     +};
    @@ builtin/hook.c (new)
     +	};
     +
     +	argc = parse_options(argc, argv, prefix, run_options,
    -+			     builtin_hook_usage, PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
    ++			     builtin_hook_run_usage,
    ++			     PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
     +
    -+	if (argc > 2) {
    -+		if (strcmp(argv[2], "--") &&
    -+		    strcmp(argv[2], "--end-of-options"))
    ++	if (argc > 1) {
    ++		if (strcmp(argv[1], "--") &&
    ++		    strcmp(argv[1], "--end-of-options"))
     +			/* Having a -- for "run" is mandatory */
     +			usage_with_options(builtin_hook_usage, run_options);
     +		/* Add our arguments, start after -- */
    -+		for (i = 3 ; i < argc; i++)
    ++		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[1];
    ++	/*
    ++	 * We are not using run_hooks() because we'd like to detect
    ++	 * missing hooks. Let's find it ourselves and call
    ++	 * run_found_hooks() instead.
    ++	 */
    ++	hook_name = argv[0];
     +	hook_path = find_hook(hook_name);
     +	if (!hook_path) {
     +		error("cannot find a hook named %s", hook_name);
    @@ builtin/hook.c (new)
     +	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)
    ++		usage_with_options(builtin_hook_usage, builtin_hook_options);
     +
    -+	if (!strcmp(argv[1], "run"))
    ++	if (!strcmp(argv[0], "run"))
     +		return run(argc, argv, prefix);
    -+	usage_with_options(builtin_hook_usage, builtin_hook_options);
    -+	return 1;
    ++	else
    ++		usage_with_options(builtin_hook_usage, builtin_hook_options);
     +}
     
      ## command-list.txt ##
    @@ git.c: static struct cmd_struct commands[] = {
      	{ "init", cmd_init_db },
      	{ "init-db", cmd_init_db },
     
    - ## hook.c (new) ##
    + ## hook.c ##
     @@
    -+#include "cache.h"
    -+#include "hook.h"
    -+#include "run-command.h"
    + #include "hook.h"
    + #include "run-command.h"
    + #include "hook-list.h"
    ++#include "config.h"
    + 
    + static int known_hook(const char *name)
    + {
    + 	const char **p;
    + 	size_t len = strlen(name);
    ++	static int test_hooks_ok = -1;
    ++
    + 	for (p = hook_name_list; *p; p++) {
    + 		const char *hook = *p;
    + 
    +@@ hook.c: static int known_hook(const char *name)
    + 			return 1;
    + 	}
    + 
    ++	if (test_hooks_ok == -1)
    ++		test_hooks_ok = git_env_bool("GIT_TEST_FAKE_HOOKS", 0);
    ++
    ++	if (test_hooks_ok &&
    ++	    (!strcmp(name, "test-hook") ||
    ++	     !strcmp(name, "does-not-exist")))
    ++		return 1;
    ++
    + 	return 0;
    + }
    + 
    +@@ hook.c: int hook_exists(const char *name)
    + {
    + 	return !!find_hook(name);
    + }
     +
     +void run_hooks_opt_clear(struct run_hooks_opt *o)
     +{
    @@ hook.c (new)
     +	struct hook_cb_data *hook_cb = pp_cb;
     +	struct hook *run_me = hook_cb->run_me;
     +
    -+	if (!run_me)
    -+		BUG("did we not return 1 in notify_hook_finished?");
    -+
     +	cp->no_stdin = 1;
     +	cp->env = hook_cb->options->env.v;
     +	cp->stdout_to_stderr = 1;
    @@ hook.c (new)
     +	struct hook_cb_data *hook_cb = pp_cb;
     +	struct hook *attempted = pp_task_cp;
     +
    -+	/* |= rc in cb */
     +	hook_cb->rc |= 1;
     +
     +	strbuf_addf(out, _("Couldn't start hook '%s'\n"),
    @@ hook.c (new)
     +{
     +	struct hook_cb_data *hook_cb = pp_cb;
     +
    -+	/* |= rc in cb */
     +	hook_cb->rc |= result;
     +
     +	return 1;
     +}
     +
    -+
     +int run_found_hooks(const char *hook_name, const char *hook_path,
     +		    struct run_hooks_opt *options)
     +{
    @@ hook.c (new)
     +
     +	hook_path = find_hook(hook_name);
     +
    -+	/* Care about nonexistence? Use run_found_hooks() */
    ++	/*
    ++	 * If you need to act on a missing hook, use run_found_hooks()
    ++	 * instead
    ++	 */
     +	if (!hook_path)
     +		return 0;
     +
    @@ hook.c (new)
     +	return ret;
     +}
     
    - ## hook.h (new) ##
    + ## hook.h ##
     @@
    -+#ifndef HOOK_H
    -+#define HOOK_H
    + #ifndef HOOK_H
    + #define HOOK_H
     +#include "strbuf.h"
     +#include "strvec.h"
     +#include "run-command.h"
    -+
    + 
    + /*
    +  * Returns the path to the hook file, or NULL if the hook is missing
    +@@ hook.h: const char *find_hook(const char *name);
    +  */
    + int hook_exists(const char *hookname);
    + 
     +struct hook {
     +	/* The path to the hook */
     +	const char *hook_path;
    @@ hook.h (new)
     +	/* Args to be passed to each hook */
     +	struct strvec args;
     +
    -+	/* Number of threads to parallelize across */
    ++	/*
    ++	 * Number of threads to parallelize across, currently a stub,
    ++	 * we use the parallel API for future-proofing, but we always
    ++	 * have one hook of a given name, so this is always an
    ++	 * implicit 1 for now.
    ++	 */
     +	int jobs;
     +};
     +
    @@ hook.h (new)
     +	.args = STRVEC_INIT, \
     +}
     +
    -+/*
    -+ * Callback provided to feed_pipe_fn and consume_sideband_fn.
    -+ */
     +struct hook_cb_data {
    ++	/* rc reflects the cumulative failure state */
     +	int rc;
     +	const char *hook_name;
     +	struct hook *run_me;
    @@ hook.h (new)
     + */
     +int run_found_hooks(const char *hookname, const char *hook_path,
     +		    struct run_hooks_opt *options);
    -+#endif
    + #endif
     
      ## t/t1800-hook.sh (new) ##
     @@
    @@ t/t1800-hook.sh (new)
     +
     +. ./test-lib.sh
     +
    -+test_expect_success 'git hook run -- nonexistent hook' '
    ++test_expect_success 'git hook usage' '
    ++	test_expect_code 129 git hook &&
    ++	test_expect_code 129 git hook -h &&
    ++	test_expect_code 129 git hook run -h
    ++'
    ++
    ++test_expect_success 'setup GIT_TEST_FAKE_HOOKS=true to permit "test-hook" and "does-not-exist" names"' '
    ++	GIT_TEST_FAKE_HOOKS=true &&
    ++	export GIT_TEST_FAKE_HOOKS
    ++'
    ++
    ++test_expect_success 'git hook run: nonexistent hook' '
     +	cat >stderr.expect <<-\EOF &&
    -+	error: cannot find a hook named does-not-exist
    ++	error: cannot find a hook named test-hook
     +	EOF
    -+	test_expect_code 1 git hook run does-not-exist 2>stderr.actual &&
    ++	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' '
    ++test_expect_success 'git hook run: basic' '
     +	write_script .git/hooks/test-hook <<-EOF &&
     +	echo Test hook
     +	EOF
    @@ t/t1800-hook.sh (new)
     +	test_cmp expect actual
     +'
     +
    -+test_expect_success 'git hook run -- stdout and stderr handling' '
    ++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
    @@ t/t1800-hook.sh (new)
     +	test_must_be_empty stdout.actual
     +'
     +
    -+test_expect_success 'git hook run -- exit codes are passed along' '
    ++test_expect_success 'git hook run: exit codes are passed along' '
     +	write_script .git/hooks/test-hook <<-EOF &&
     +	exit 1
     +	EOF
    @@ t/t1800-hook.sh (new)
     +
     +test_expect_success 'git -c core.hooksPath=<PATH> hook run' '
     +	mkdir my-hooks &&
    -+	write_script my-hooks/test-hook <<-EOF &&
    -+	echo Hook ran >>actual
    ++	write_script my-hooks/test-hook <<-\EOF &&
    ++	echo Hook ran $1 >>actual
     +	EOF
     +
     +	cat >expect <<-\EOF &&
     +	Test hook
    -+	Hook ran
    -+	Hook ran
    -+	Hook ran
    -+	Hook ran
    ++	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 2>>actual &&
    -+	git -c core.hooksPath=my-hooks hook run test-hook 2>>actual &&
    -+	git -c core.hooksPath=my-hooks/ hook run test-hook 2>>actual &&
    -+	git -c core.hooksPath="$PWD/my-hooks" hook run test-hook 2>>actual &&
    -+	git -c core.hooksPath="$PWD/my-hooks/" hook run test-hook 2>>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_expect_success 'set up a pre-commit hook in core.hooksPath' '
    -+	>actual &&
    -+	mkdir -p .git/custom-hooks .git/hooks &&
    -+	write_script .git/custom-hooks/pre-commit <<-\EOF &&
    -+	echo CUSTOM >>actual
    -+	EOF
    -+	write_script .git/hooks/pre-commit <<-\EOF
    -+	echo NORMAL >>actual
    -+	EOF
    -+'
    -+
     +test_done
 2:  85195a78cf <  -:  ---------- run-command.h: move find_hook() to hook.h
 3:  eb5bdd993c <  -:  ---------- hook.c: add a hook_exists() wrapper and use it in bugreport.c
 4:  da2763192a =  2:  7209f73f28 gc: use hook library for pre-auto-gc hook
 5:  51e6e72f23 =  3:  e9a1e7cf61 rebase: teach pre-rebase to use hook.h
 6:  d2f3b26d46 =  4:  1d08726930 am: convert applypatch hooks to use config
 7:  d884465aab !  5:  32eec5dc2f hooks: convert 'post-checkout' hook to hook library
    @@ hook.c: int run_found_hooks(const char *hook_name, const char *hook_path,
     
      ## hook.h ##
     @@ hook.h: struct run_hooks_opt
    - 
    - 	/* Number of threads to parallelize across */
    + 	 * implicit 1 for now.
    + 	 */
      	int jobs;
     +
     +	/* Resolve and run the "absolute_path(hook)" instead of
 8:  ad6e750784 =  6:  e9fa3f6759 merge: use config-based hooks for post-merge hook
 9:  8d8b2d2645 !  7:  12347d901b git hook run: add an --ignore-missing flag
    @@ Documentation/git-hook.txt: git-hook - run git hooks
      
      DESCRIPTION
      -----------
    -@@ Documentation/git-hook.txt: run::
    - 	"--end-of-options"). See "OPTIONS" below for the arguments
    - 	this accepts.
    +@@ Documentation/git-hook.txt: optional `--` (or `--end-of-options`, see linkgit:gitcli[7]). The
    + arguments (if any) differ by hook name, see linkgit:githooks[5] for
    + what those are.
      
     +OPTIONS
     +-------
    @@ builtin/hook.c: static int run(int argc, const char **argv, const char *prefix)
      	};
      
     @@ builtin/hook.c: static int run(int argc, const char **argv, const char *prefix)
    - 	hook_name = argv[1];
    + 	/*
    + 	 * We are not using run_hooks() because we'd like to detect
    + 	 * missing hooks. Let's find it ourselves and call
    +-	 * run_found_hooks() instead.
    ++	 * run_found_hooks() instead...
    + 	 */
    + 	hook_name = argv[0];
      	hook_path = find_hook(hook_name);
      	if (!hook_path) {
    ++		/* ... act like run_hooks() under --ignore-missing */
     +		if (ignore_missing)
     +			return 0;
      		error("cannot find a hook named %s", hook_name);
    @@ builtin/hook.c: static int run(int argc, const char **argv, const char *prefix)
      	}
     
      ## t/t1800-hook.sh ##
    -@@ t/t1800-hook.sh: test_expect_success 'git hook run -- nonexistent hook' '
    +@@ t/t1800-hook.sh: 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' '
    +-test_expect_success 'git hook run: basic' '
    ++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' '
    ++test_expect_success 'git hook run -- basic' '
      	write_script .git/hooks/test-hook <<-EOF &&
      	echo Test hook
    + 	EOF
10:  1953326d1d =  8:  71d209b407 send-email: use 'git hook run' for 'sendemail-validate'
11:  aa970a8175 !  9:  246a82b55b git-p4: use 'git hook' to run hooks
    @@ Commit message
         Python, we can directly call 'git hook run'. We emulate the existence
         check with the --ignore-missing flag.
     
    +    As this is the last hook execution in git.git to not go through "git
    +    hook run" or the hook.[ch] library we can now be absolutely sure that
    +    our assertion in hook.c that only hooks known by the generated (from
    +    githooks(5)) hook-list.h are permitted.
    +
         Signed-off-by: Emily Shaffer <emilyshaffer@xxxxxxxxxx>
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx>
     
12:  7756f10aac = 10:  e3f8482d80 commit: use hook.h to execute hooks
13:  0300607a9b = 11:  6ed61071c5 read-cache: convert post-index-change hook to use config
14:  ec4ad437f8 = 12:  e4ef3f4548 receive-pack: convert push-to-checkout hook to hook.h
15:  477eb2245c = 13:  e3dda367ec run-command: remove old run_hook_{le,ve}() hook API
16:  53a3877a47 = 14:  477d75bf57 run-command: allow stdin for run_processes_parallel
17:  c4f60db606 ! 15:  b7c0ee9719 hook: support passing stdin to hooks
    @@ Documentation/git-hook.txt: git-hook - run git hooks
      
      DESCRIPTION
      -----------
    -@@ Documentation/git-hook.txt: run::
    +@@ Documentation/git-hook.txt: what those are.
      OPTIONS
      -------
      
    @@ Documentation/git-hook.txt: run::
     
      ## builtin/hook.c ##
     @@
    - #include "strvec.h"
      
      static const char * const builtin_hook_usage[] = {
    + 	N_("git hook <command> [...]"),
     -	N_("git hook run <hook-name> [-- <hook-args>]"),
    ++	N_("git hook run [<args>] <hook-name> [-- <hook-args>]"),
    + 	NULL
    + };
    + 
    + static const char * const builtin_hook_run_usage[] = {
    + 	N_("git hook run <hook-name> [-- <hook-args>]"),
     +	N_("git hook run [--to-stdin=<path>] <hook-name> [-- <hook-args>]"),
      	NULL
      };
    @@ builtin/hook.c: static int run(int argc, const char **argv, const char *prefix)
     
      ## hook.c ##
     @@ hook.c: static int pick_next_hook(struct child_process *cp,
    - 	if (!run_me)
    - 		BUG("did we not return 1 in notify_hook_finished?");
    + 	struct hook_cb_data *hook_cb = pp_cb;
    + 	struct hook *run_me = hook_cb->run_me;
      
     -	cp->no_stdin = 1;
    ++
     +	/* reopen the file for stdin; run_command closes it. */
     +	if (hook_cb->options->path_to_stdin) {
     +		cp->no_stdin = 0;
    @@ hook.h: struct run_hooks_opt
      #define RUN_HOOKS_OPT_INIT { \
     
      ## t/t1800-hook.sh ##
    -@@ t/t1800-hook.sh: test_expect_success 'set up a pre-commit hook in core.hooksPath' '
    - 	EOF
    +@@ t/t1800-hook.sh: test_expect_success 'git -c core.hooksPath=<PATH> hook run' '
    + 	test_cmp expect actual
      '
      
     +test_expect_success 'stdin to hooks' '
18:  febf05ef23 = 16:  4035069a98 am: convert 'post-rewrite' hook to hook.h
19:  7baf2469d5 = 17:  c847a19581 run-command: add stdin callback for parallelization
20:  2edf9dea41 ! 18:  da46c859c1 hook: provide stdin by string_list or callback
    @@ hook.c: static int pick_next_hook(struct child_process *cp,
      	} else {
      		cp->no_stdin = 1;
      	}
    -@@ hook.c: static int notify_hook_finished(int result,
    - 	return 1;
    - }
    - 
    --
    - int run_found_hooks(const char *hook_name, const char *hook_path,
    - 		    struct run_hooks_opt *options)
    - {
     @@ hook.c: int run_found_hooks(const char *hook_name, const char *hook_path,
      	run_processes_parallel_tr2(options->jobs,
      				   pick_next_hook,
    @@ hook.c: int run_hooks(const char *hook_name, struct run_hooks_opt *options)
     +
      	hook_path = find_hook(hook_name);
      
    - 	/* Care about nonexistence? Use run_found_hooks() */
    + 	/*
     
      ## hook.h ##
    -@@
    +@@ hook.h: int hook_exists(const char *hookname);
      struct hook {
      	/* The path to the hook */
      	const char *hook_path;
    @@ hook.h: struct run_hooks_opt
     + */
     +int pipe_from_string_list(struct strbuf *pipe, void *pp_cb, void *pp_task_cb);
     +
    - /*
    -  * Callback provided to feed_pipe_fn and consume_sideband_fn.
    -  */
    + struct hook_cb_data {
    + 	/* rc reflects the cumulative failure state */
    + 	int rc;
21:  303b31ee62 = 19:  7343be28ef hook: convert 'post-rewrite' hook in sequencer.c to hook.h
22:  62eecafb3f = 20:  85bf13a083 transport: convert pre-push hook to use config
23:  6049b1cdc7 = 21:  331014bad1 reference-transaction: use hook.h to run hooks
24:  26ebbe4c54 = 22:  f7f56d0a3b run-command: allow capturing of collated output
25:  251085b752 = 23:  7f7fcc0688 hooks: allow callers to capture output
26:  e11a8f6007 = 24:  e74d49e559 receive-pack: convert 'update' hook to hook.h
27:  ecaedd13b8 = 25:  0bdc4878ac post-update: use hook.h library
28:  bb9d57f809 = 26:  db70b59b3b receive-pack: convert receive hooks to hook.h
29:  793f112f7a ! 27:  d86fedf041 hooks: fix a TOCTOU in "did we run a hook?" heuristic
    @@ commit.h: int compare_commits_by_commit_date(const void *a_, const void *b_, voi
     
      ## hook.c ##
     @@ hook.c: static int notify_hook_finished(int result,
    - 	/* |= rc in cb */
    + 
      	hook_cb->rc |= result;
      
     +	if (hook_cb->invoked_hook)
    @@ hook.h: struct hook_cb_data {
     +	int *invoked_hook;
      };
      
    - /*
    + void run_hooks_opt_clear(struct run_hooks_opt *o);
     
      ## sequencer.c ##
     @@ sequencer.c: static int run_prepare_commit_msg_hook(struct repository *r,
30:  bc086454d6 <  -:  ---------- hook-list.h: add a generated list of hooks, like config-list.h
-- 
2.32.0.576.g59759b6ca7d




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux