From: Bert Wesarg <bert.wesarg@googlemail.com>
To: Emily Shaffer <emilyshaffer@google.com>
Cc: Git Mailing List <git@vger.kernel.org>
Subject: Re: [PATCH 3/6] hook: add --list mode
Date: Thu, 12 Dec 2019 10:38:55 +0100 [thread overview]
Message-ID: <CAKPyHN04hEK7PKZQvF7LkGPkbBnV2jccBAxJSiukrXb=4g4g_Q@mail.gmail.com> (raw)
In-Reply-To: <20191210023335.49987-4-emilyshaffer@google.com>
On Tue, Dec 10, 2019 at 3:34 AM Emily Shaffer <emilyshaffer@google.com> wrote:
>
> Teach 'git hook --list <hookname>', which checks the known configs in
> order to create an ordered list of hooks to run on a given hook event.
>
> The hook config format is "hook.<hookname> = <order>:<path-to-hook>".
> This paves the way for multiple hook support; hooks should be run in the
> order specified by the user in the config, and in the case of an order
> number collision, configuration order should be used (e.g. global hook
> 004 will run before repo hook 004).
>
> For example:
>
> $ grep -A2 "\[hook\]" ~/.gitconfig
> [hook]
> pre-commit = 001:~/test.sh
> pre-commit = 999:~/baz.sh
>
> $ grep -A1 "\[hook\]" ~/git/.git/config
> [hook]
> pre-commit = 900:~/bar.sh
>
> $ ./bin-wrappers/git hook --list pre-commit
> 001 global ~/test.sh
> 900 repo ~/bar.sh
> 999 global ~/baz.sh
>
> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
> ---
> Documentation/git-hook.txt | 17 +++++++-
> Makefile | 1 +
> builtin/hook.c | 54 ++++++++++++++++++++++-
> hook.c | 81 +++++++++++++++++++++++++++++++++++
> hook.h | 14 ++++++
> t/t1360-config-based-hooks.sh | 43 ++++++++++++++++++-
> 6 files changed, 206 insertions(+), 4 deletions(-)
> create mode 100644 hook.c
> create mode 100644 hook.h
>
> diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
> index 2d50c414cc..a141884239 100644
> --- a/Documentation/git-hook.txt
> +++ b/Documentation/git-hook.txt
> @@ -8,12 +8,27 @@ git-hook - Manage configured hooks
> SYNOPSIS
> --------
> [verse]
> -'git hook'
> +'git hook' -l | --list <hook-name>
>
> DESCRIPTION
> -----------
> You can list, add, and modify hooks with this command.
>
> +This command parses the default configuration files for lines which look like
> +"hook.<hook-name> = <order number>:<hook command>", e.g. "hook.pre-commit =
> +010:/path/to/script.sh". In this way, multiple scripts can be run during a
> +single hook. Hooks are sorted in ascending order by order number; in the event
> +of an order number conflict, they are sorted in configuration order.
> +
> +OPTIONS
> +-------
> +
> +-l::
> +--list::
> + List the hooks which have been configured for <hook-name>. Hooks appear
> + in the order they should be run. Output of this command follows the
> + format '<order number> <origin config> <hook command>'.
> +
> GIT
> ---
> Part of the linkgit:git[1] suite
> diff --git a/Makefile b/Makefile
> index 83263505c0..21b3a82208 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -892,6 +892,7 @@ LIB_OBJS += hashmap.o
> LIB_OBJS += linear-assignment.o
> LIB_OBJS += help.o
> LIB_OBJS += hex.o
> +LIB_OBJS += hook.o
> LIB_OBJS += ident.o
> LIB_OBJS += interdiff.o
> LIB_OBJS += json-writer.o
> diff --git a/builtin/hook.c b/builtin/hook.c
> index b2bbc84d4d..8261302b27 100644
> --- a/builtin/hook.c
> +++ b/builtin/hook.c
> @@ -1,21 +1,73 @@
> #include "cache.h"
>
> #include "builtin.h"
> +#include "config.h"
> +#include "hook.h"
> #include "parse-options.h"
> +#include "strbuf.h"
>
> static const char * const builtin_hook_usage[] = {
> - N_("git hook"),
> + N_("git hook --list <hookname>"),
Its "<hook-name>" in Documentation/git-hook.txt
> NULL
> };
>
> +enum hook_command {
> + HOOK_NO_COMMAND = 0,
> + HOOK_LIST,
> +};
> +
> +static int print_hook_list(const struct strbuf *hookname)
> +{
> + struct list_head *head, *pos;
> + struct hook *item;
> +
> + head = hook_list(hookname);
> +
> + list_for_each(pos, head) {
> + item = list_entry(pos, struct hook, list);
> + if (item)
> + printf("%.3d\t%s\t%s\n", item->order,
> + config_scope_to_string(item->origin),
> + item->command.buf);
> + }
> +
> + return 0;
> +}
> +
> int cmd_hook(int argc, const char **argv, const char *prefix)
> {
> + enum hook_command command = 0;
> + struct strbuf hookname = STRBUF_INIT;
> +
> struct option builtin_hook_options[] = {
> + OPT_CMDMODE('l', "list", &command,
> + N_("list scripts which will be run for <hookname>"),
Its "<hook-name>" in Documentation/git-hook.txt
> + HOOK_LIST),
> OPT_END(),
> };
>
> argc = parse_options(argc, argv, prefix, builtin_hook_options,
> builtin_hook_usage, 0);
>
> + if (argc < 1) {
> + usage_msg_opt("a hookname must be provided to operate on.",
> + builtin_hook_usage, builtin_hook_options);
> + }
> +
> + strbuf_addstr(&hookname, "hook.");
> + strbuf_addstr(&hookname, argv[0]);
The arg is never checked, if this is a valid/known hook.
Bert
> +
> + switch(command) {
> + case HOOK_LIST:
> + return print_hook_list(&hookname);
> + break;
> + default:
> + usage_msg_opt("no command given.", builtin_hook_usage,
> + builtin_hook_options);
> + }
> +
> + clear_hook_list();
> + strbuf_release(&hookname);
> +
> return 0;
> }
> diff --git a/hook.c b/hook.c
> new file mode 100644
> index 0000000000..f8d1109084
> --- /dev/null
> +++ b/hook.c
> @@ -0,0 +1,81 @@
> +#include "cache.h"
> +
> +#include "hook.h"
> +#include "config.h"
> +
> +static LIST_HEAD(hook_head);
> +
> +void free_hook(struct hook *ptr)
> +{
> + if (ptr) {
> + strbuf_release(&ptr->command);
> + free(ptr);
> + }
> +}
> +
> +static void emplace_hook(struct list_head *pos, int order, const char *command)
> +{
> + struct hook *to_add = malloc(sizeof(struct hook));
> + to_add->order = order;
> + to_add->origin = current_config_scope();
> + strbuf_init(&to_add->command, 0);
> + strbuf_addstr(&to_add->command, command);
> +
> + list_add_tail(&to_add->list, pos);
> +}
> +
> +static void remove_hook(struct list_head *to_remove)
> +{
> + struct hook *hook_to_remove = list_entry(to_remove, struct hook, list);
> + list_del(to_remove);
> + free_hook(hook_to_remove);
> +}
> +
> +void clear_hook_list()
> +{
> + struct list_head *pos, *tmp;
> + list_for_each_safe(pos, tmp, &hook_head)
> + remove_hook(pos);
> +}
> +
> +static int check_config_for_hooks(const char *var, const char *value, void *hookname)
> +{
> + struct list_head *pos, *p;
> + struct hook *item;
> + const struct strbuf *hookname_strbuf = hookname;
> +
> + if (!strcmp(var, hookname_strbuf->buf)) {
> + int order = 0;
> + // TODO this is bad - open to overflows
> + char command[256];
> + int added = 0;
> + if (!sscanf(value, "%d:%s", &order, command))
> + die(_("hook config '%s' doesn't match expected format"),
> + value);
> +
> + list_for_each_safe(pos, p, &hook_head) {
> + item = list_entry(pos, struct hook, list);
> +
> + /*
> + * the new entry should go just before the first entry
> + * which has a higher order number than it.
> + */
> + if (item->order > order && !added) {
> + emplace_hook(pos, order, command);
> + added = 1;
> + }
> + }
> +
> + if (!added)
> + emplace_hook(pos, order, command);
> + }
> +
> + return 0;
> +}
> +
> +struct list_head* hook_list(const struct strbuf* hookname)
> +{
> + git_config(check_config_for_hooks, (void*)hookname);
> +
> + return &hook_head;
> +}
> diff --git a/hook.h b/hook.h
> new file mode 100644
> index 0000000000..104df4c088
> --- /dev/null
> +++ b/hook.h
> @@ -0,0 +1,14 @@
> +#include "config.h"
> +
> +struct hook
> +{
> + struct list_head list;
> + int order;
> + enum config_scope origin;
> + struct strbuf command;
> +};
> +
> +struct list_head* hook_list(const struct strbuf *hookname);
> +
> +void free_hook(struct hook *ptr);
> +void clear_hook_list();
> diff --git a/t/t1360-config-based-hooks.sh b/t/t1360-config-based-hooks.sh
> index 34b0df5216..1434051db3 100755
> --- a/t/t1360-config-based-hooks.sh
> +++ b/t/t1360-config-based-hooks.sh
> @@ -4,8 +4,47 @@ test_description='config-managed multihooks, including git-hook command'
>
> . ./test-lib.sh
>
> -test_expect_success 'git hook command does not crash' '
> - git hook
> +test_expect_success 'git hook rejects commands without a mode' '
> + test_must_fail git hook pre-commit
> +'
> +
> +
> +test_expect_success 'git hook rejects commands without a hookname' '
> + test_must_fail git hook --list
> +'
> +
> +test_expect_success 'setup hooks in system, global, and local' '
> + git config --add --global hook.pre-commit "010:/path/def" &&
> + git config --add --global hook.pre-commit "999:/path/uvw" &&
> +
> + git config --add --local hook.pre-commit "100:/path/ghi" &&
> + git config --add --local hook.pre-commit "990:/path/rst"
> +'
> +
> +test_expect_success 'git hook --list orders by order number' '
> + cat >expected <<-\EOF &&
> + 010 global /path/def
> + 100 repo /path/ghi
> + 990 repo /path/rst
> + 999 global /path/uvw
> + EOF
> +
> + git hook --list pre-commit >actual &&
> + test_cmp expected actual
> +'
> +
> +test_expect_success 'order number collisions resolved in config order' '
> + cat >expected <<-\EOF &&
> + 010 global /path/def
> + 010 repo /path/abc
> + 100 repo /path/ghi
> + 990 repo /path/rst
> + 999 global /path/uvw
> + EOF
> +
> + git config --add --local hook.pre-commit "010:/path/abc" &&
> + git hook --list pre-commit >actual &&
> + test_cmp expected actual
> '
>
> test_done
> --
> 2.24.0.393.g34dc348eaf-goog
>
next prev parent reply other threads:[~2019-12-12 9:39 UTC|newest]
Thread overview: 125+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-10 2:33 [PATCH 0/6] configuration-based hook management Emily Shaffer
2019-12-10 2:33 ` [PATCH 1/6] hook: scaffolding for git-hook subcommand Emily Shaffer
2019-12-12 9:41 ` Bert Wesarg
2019-12-12 10:47 ` SZEDER Gábor
2019-12-10 2:33 ` [PATCH 2/6] config: add string mapping for enum config_scope Emily Shaffer
2019-12-10 11:16 ` Philip Oakley
2019-12-10 17:21 ` Philip Oakley
2019-12-10 2:33 ` [PATCH 3/6] hook: add --list mode Emily Shaffer
2019-12-12 9:38 ` Bert Wesarg [this message]
2019-12-12 10:58 ` SZEDER Gábor
2019-12-10 2:33 ` [PATCH 4/6] hook: support reordering of hook list Emily Shaffer
2019-12-11 19:21 ` Junio C Hamano
2019-12-10 2:33 ` [PATCH 5/6] hook: remove prior hook with '---' Emily Shaffer
2019-12-10 2:33 ` [PATCH 6/6] hook: teach --porcelain mode Emily Shaffer
2019-12-11 19:33 ` Junio C Hamano
2019-12-11 22:00 ` Emily Shaffer
2019-12-11 22:07 ` Junio C Hamano
2019-12-11 23:15 ` Emily Shaffer
2019-12-11 22:42 ` [PATCH 0/6] configuration-based hook management Junio C Hamano
-- strict thread matches above, loose matches on Subject: below --
2020-03-12 3:55 Notes from Git Contributor Summit, Los Angeles (April 5, 2020) James Ramsay
2020-03-12 3:56 ` [TOPIC 1/17] Reftable James Ramsay
2020-03-12 3:56 ` [TOPIC 2/17] Hooks in the future James Ramsay
2020-03-12 14:16 ` Emily Shaffer
2020-03-13 17:56 ` Junio C Hamano
2020-04-07 23:01 ` Emily Shaffer
2020-04-07 23:51 ` Emily Shaffer
2020-04-08 0:40 ` Junio C Hamano
2020-04-08 1:09 ` Emily Shaffer
2020-04-10 21:31 ` Jeff King
2020-04-13 19:15 ` Emily Shaffer
2020-04-13 21:52 ` Jeff King
2020-04-14 0:54 ` [RFC PATCH v2 0/2] configuration-based hook management (was: [TOPIC 2/17] Hooks in the future) Emily Shaffer
2020-04-14 0:54 ` [RFC PATCH v2 1/2] hook: scaffolding for git-hook subcommand Emily Shaffer
2020-04-14 0:54 ` [RFC PATCH v2 2/2] hook: add --list mode Emily Shaffer
2020-04-14 15:15 ` [RFC PATCH v2 0/2] configuration-based hook management Phillip Wood
2020-04-14 19:24 ` Emily Shaffer
2020-04-14 20:27 ` Jeff King
2020-04-15 10:01 ` Phillip Wood
2020-04-14 20:03 ` Josh Steadmon
2020-04-15 10:08 ` Phillip Wood
2020-04-14 20:32 ` Jeff King
2020-04-15 10:01 ` Phillip Wood
2020-04-15 14:51 ` Junio C Hamano
2020-04-15 20:30 ` Emily Shaffer
2020-04-15 22:19 ` Junio C Hamano
2020-04-15 3:45 ` [TOPIC 2/17] Hooks in the future Jonathan Nieder
2020-04-15 20:59 ` Emily Shaffer
2020-04-20 23:53 ` [PATCH] doc: propose hooks managed by the config Emily Shaffer
2020-04-21 0:22 ` Emily Shaffer
2020-04-21 1:20 ` Junio C Hamano
2020-04-24 23:14 ` Emily Shaffer
2020-04-25 20:57 ` brian m. carlson
2020-05-06 21:33 ` Emily Shaffer
2020-05-06 23:13 ` brian m. carlson
2020-05-19 20:10 ` Emily Shaffer
2020-04-15 22:42 ` [TOPIC 2/17] Hooks in the future Jeff King
2020-04-15 22:48 ` Emily Shaffer
2020-04-15 22:57 ` Jeff King
2020-03-12 3:57 ` [TOPIC 3/17] Obliterate James Ramsay
2020-03-12 18:06 ` Konstantin Ryabitsev
2020-03-15 22:19 ` Damien Robert
2020-03-16 12:55 ` Konstantin Tokarev
2020-03-26 22:27 ` Damien Robert
2020-03-16 16:32 ` Elijah Newren
2020-03-26 22:30 ` Damien Robert
2020-03-16 18:32 ` Phillip Susi
2020-03-26 22:37 ` Damien Robert
2020-03-16 20:01 ` Philip Oakley
2020-05-16 2:21 ` nbelakovski
2020-03-12 3:58 ` [TOPIC 4/17] Sparse checkout James Ramsay
2020-03-12 4:00 ` [TOPIC 5/17] Partial Clone James Ramsay
2020-03-17 7:38 ` Allowing only blob filtering was: " Christian Couder
2020-03-17 20:39 ` [RFC PATCH 0/2] upload-pack.c: limit allowed filter choices Taylor Blau
2020-03-17 20:39 ` [RFC PATCH 1/2] list_objects_filter_options: introduce 'list_object_filter_config_name' Taylor Blau
2020-03-17 20:53 ` Eric Sunshine
2020-03-18 10:03 ` Jeff King
2020-03-18 19:40 ` Junio C Hamano
2020-03-18 22:38 ` Eric Sunshine
2020-03-19 17:15 ` Jeff King
2020-03-18 21:05 ` Taylor Blau
2020-03-17 20:39 ` [RFC PATCH 2/2] upload-pack.c: allow banning certain object filter(s) Taylor Blau
2020-03-17 21:11 ` Eric Sunshine
2020-03-18 21:18 ` Taylor Blau
2020-03-18 11:18 ` Philip Oakley
2020-03-18 21:20 ` Taylor Blau
2020-03-18 10:18 ` [RFC PATCH 0/2] upload-pack.c: limit allowed filter choices Jeff King
2020-03-18 18:26 ` Re*: " Junio C Hamano
2020-03-19 17:03 ` Jeff King
2020-03-18 21:28 ` Taylor Blau
2020-03-18 22:41 ` Junio C Hamano
2020-03-19 17:10 ` Jeff King
2020-03-19 17:09 ` Jeff King
2020-04-17 9:41 ` Christian Couder
2020-04-17 17:40 ` Taylor Blau
2020-04-17 18:06 ` Jeff King
2020-04-21 12:34 ` Christian Couder
2020-04-22 20:41 ` Taylor Blau
2020-04-22 20:42 ` Taylor Blau
2020-04-21 12:17 ` Christian Couder
2020-03-12 4:01 ` [TOPIC 6/17] GC strategies James Ramsay
2020-03-12 4:02 ` [TOPIC 7/17] Background operations/maintenance James Ramsay
2020-03-12 4:03 ` [TOPIC 8/17] Push performance James Ramsay
2020-03-12 4:04 ` [TOPIC 9/17] Obsolescence markers and evolve James Ramsay
2020-05-09 21:31 ` Noam Soloveichik
2020-05-15 22:26 ` Jeff King
2020-03-12 4:05 ` [TOPIC 10/17] Expel ‘git shell’? James Ramsay
2020-03-12 4:07 ` [TOPIC 11/17] GPL enforcement James Ramsay
2020-03-12 4:08 ` [TOPIC 12/17] Test harness improvements James Ramsay
2020-03-12 4:09 ` [TOPIC 13/17] Cross implementation test suite James Ramsay
2020-03-12 4:11 ` [TOPIC 14/17] Aspects of merge-ort: cool, or crimes against humanity? James Ramsay
2020-03-12 4:13 ` [TOPIC 15/17] Reachability checks James Ramsay
2020-03-12 4:14 ` [TOPIC 16/17] “I want a reviewer” James Ramsay
2020-03-12 13:31 ` Emily Shaffer
2020-03-12 17:31 ` Konstantin Ryabitsev
2020-03-12 17:42 ` Jonathan Nieder
2020-03-12 18:00 ` Konstantin Ryabitsev
2020-03-17 0:43 ` Philippe Blain
2020-03-13 21:25 ` Eric Wong
2020-03-14 17:27 ` Jeff King
2020-03-15 0:36 ` inbox indexing wishlist [was: [TOPIC 16/17] “I want a reviewer”] Eric Wong
2020-03-12 4:16 ` [TOPIC 17/17] Security James Ramsay
2020-03-12 14:38 ` Notes from Git Contributor Summit, Los Angeles (April 5, 2020) Derrick Stolee
2020-03-13 20:47 ` Jeff King
2020-03-15 18:42 ` Jakub Narebski
2020-03-16 19:31 ` Jeff King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAKPyHN04hEK7PKZQvF7LkGPkbBnV2jccBAxJSiukrXb=4g4g_Q@mail.gmail.com' \
--to=bert.wesarg@googlemail.com \
--cc=emilyshaffer@google.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).