hook: add --porcelain to list command

Teach 'git hook list --porcelain <hookname>', which prints simply the
commands to be run in the order suggested by the config. This option is
intended for use by user scripts, wrappers, or out-of-process Git
commands which still want to execute hooks. For example, the following
snippet might be added to git-send-email.perl to introduce a
`pre-send-email` hook:

  sub pre_send_email {
    open(my $fh, 'git hook list --porcelain pre-send-email |');
    chomp(my @hooks = <$fh>);
    close($fh);

    foreach $hook (@hooks) {
            system $hook
    }

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Emily Shaffer
2020-05-21 11:54:14 -07:00
committed by Junio C Hamano
parent 933f1b2e0c
commit 09b4d75c01
3 changed files with 35 additions and 6 deletions

View File

@ -8,7 +8,7 @@ git-hook - Manage configured hooks
SYNOPSIS SYNOPSIS
-------- --------
[verse] [verse]
'git hook' list <hook-name> 'git hook' list [--porcelain] <hook-name>
DESCRIPTION DESCRIPTION
----------- -----------
@ -43,11 +43,20 @@ Local config
COMMANDS COMMANDS
-------- --------
list <hook-name>:: list [--porcelain] <hook-name>::
List the hooks which have been configured for <hook-name>. Hooks appear List the hooks which have been configured for <hook-name>. Hooks appear
in the order they should be run, and note the config scope where the relevant in the order they should be run, and note the config scope where the relevant
`hook.<hook-name>.command` was specified, not the `hookcmd` (if applicable). `hook.<hook-name>.command` was specified, not the `hookcmd` (if applicable).
+
If `--porcelain` is specified, instead print the commands alone, separated by
newlines, for easy parsing by a script.
OPTIONS
-------
--porcelain::
With `list`, print the commands in the order they should be run,
separated by newlines, for easy parsing by a script.
GIT GIT
--- ---

View File

@ -16,8 +16,11 @@ static int list(int argc, const char **argv, const char *prefix)
struct list_head *head, *pos; struct list_head *head, *pos;
struct hook *item; struct hook *item;
struct strbuf hookname = STRBUF_INIT; struct strbuf hookname = STRBUF_INIT;
int porcelain = 0;
struct option list_options[] = { struct option list_options[] = {
OPT_BOOL(0, "porcelain", &porcelain,
"format for execution by a script"),
OPT_END(), OPT_END(),
}; };
@ -29,6 +32,8 @@ static int list(int argc, const char **argv, const char *prefix)
builtin_hook_usage, list_options); builtin_hook_usage, list_options);
} }
strbuf_addstr(&hookname, argv[0]); strbuf_addstr(&hookname, argv[0]);
head = hook_list(&hookname); head = hook_list(&hookname);
@ -41,10 +46,14 @@ static int list(int argc, const char **argv, const char *prefix)
list_for_each(pos, head) { list_for_each(pos, head) {
item = list_entry(pos, struct hook, list); item = list_entry(pos, struct hook, list);
if (item) if (item) {
printf("%s:\t%s\n", if (porcelain)
config_scope_name(item->origin), printf("%s\n", item->command.buf);
item->command.buf); else
printf("%s:\t%s\n",
config_scope_name(item->origin),
item->command.buf);
}
} }
clear_hook_list(); clear_hook_list();

View File

@ -55,4 +55,15 @@ test_expect_success 'git hook list reorders on duplicate commands' '
test_cmp expected actual test_cmp expected actual
' '
test_expect_success 'git hook list --porcelain prints just the command' '
cat >expected <<-\EOF &&
/path/ghi
/path/abc
/path/def
EOF
git hook list --porcelain pre-commit >actual &&
test_cmp expected actual
'
test_done test_done