{"thread":{"id":"55950","subject":"[PATCH 0/3] Add a generated list of hooks in hook-list.h","startedAt":"2021-06-17T10:09:41Z","lastAt":"2021-07-12T20:55:40Z","messageCount":21,"participants":["Ævar Arnfjörð Bjarmason","SZEDER Gábor","Eric Sunshine","Junio C Hamano","René Scharfe","Johannes Schindelin","Emily Shaffer"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"427689","messageId":"cover-0.3-0000000000-20210617T100239Z-avarab@gmail.com","threadId":"55950","inReplyTo":null,"subject":"[PATCH 0/3] Add a generated list of hooks in hook-list.h","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-17T10:09:33Z","receivedAt":"2021-06-17T10:09:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This goes on top of my just-submitted trivial Makefile fixes[1], and\nadds a list of hooks in hook-list.h, similar to the existing\nconfig-list.h.\n\nWe can then error when a C API provides us with an unknown hook, so\nnon-type-checked things in the codebase like find_hook(\"proc-receive\")\nnow effectively have a type check of sorts (well, we'd catch a typo in\nour tests).\n\nThese changes are currently at the end of the\nab/config-based-hooks-base series[2], I'm carving them out to make\nthat topic even easier to digest. We can this without any of the \"git\nhook run\" stuff.\n\nWe also had a big but inaccurate list of hooks in builtin/help.c, as\npart of submitting a bugreport. That's now using githooks(5) as a\nsource of truth.\n\nThis also builds on Windows with cmake, unlike the outstanding [2]\n`restart of \"config-based-hooks\"` series, at least that part of the CI\nnow passes, and the change to contrib/buildsystems/CMakeLists.txt\nlooks trivially correct to me.\n\n1. https://lore.kernel.org/git/cover-0.3-0000000000-20210617T095827Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/cover-00.30-00000000000-20210614T101920Z-avarab@gmail.com/\n\nEmily Shaffer (1):\n  hook.c: add a hook_exists() wrapper and use it in bugreport.c\n\nÆvar Arnfjörð Bjarmason (2):\n  hook.[ch]: move find_hook() to this new library\n  hook-list.h: add a generated list of hooks, like config-list.h\n\n .gitignore                          |  1 +\n Makefile                            | 12 +++++-\n builtin/am.c                        |  1 +\n builtin/bugreport.c                 | 46 +++++-----------------\n builtin/commit.c                    |  1 +\n builtin/merge.c                     |  1 +\n builtin/receive-pack.c              |  1 +\n builtin/worktree.c                  |  1 +\n contrib/buildsystems/CMakeLists.txt |  7 ++++\n generate-hooklist.sh                | 24 ++++++++++++\n hook.c                              | 61 +++++++++++++++++++++++++++++\n hook.h                              | 16 ++++++++\n refs.c                              |  1 +\n run-command.c                       | 35 +----------------\n run-command.h                       |  7 ----\n sequencer.c                         |  1 +\n transport.c                         |  1 +\n 17 files changed, 138 insertions(+), 79 deletions(-)\n create mode 100755 generate-hooklist.sh\n create mode 100644 hook.c\n create mode 100644 hook.h\n\n-- \n2.32.0.576.g59759b6ca7d\n\n"},{"id":"427690","messageId":"patch-1.3-58c37e4f06-20210617T100239Z-avarab@gmail.com","threadId":"55950","inReplyTo":"cover-0.3-0000000000-20210617T100239Z-avarab@gmail.com","subject":"[PATCH 1/3] hook.[ch]: move find_hook() to this new library","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-17T10:09:34Z","receivedAt":"2021-06-17T10:09:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Move the find_hook() function from run-command.c to a new hook.c\nlibrary. This change establishes a stub library that's pretty\npointless right now, but will see much wider use with Emily Shaffer's\nupcoming \"configuration-based hooks\" series.\n\nEventually all the hook related code will live in hook.[ch]. Let's\nstart that process by moving the simple find_hook() function over\nas-is.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile               |  1 +\n builtin/am.c           |  1 +\n builtin/bugreport.c    |  2 +-\n builtin/commit.c       |  1 +\n builtin/merge.c        |  1 +\n builtin/receive-pack.c |  1 +\n builtin/worktree.c     |  1 +\n hook.c                 | 37 +++++++++++++++++++++++++++++++++++++\n hook.h                 | 11 +++++++++++\n refs.c                 |  1 +\n run-command.c          | 35 +----------------------------------\n run-command.h          |  7 -------\n sequencer.c            |  1 +\n transport.c            |  1 +\n 14 files changed, 59 insertions(+), 42 deletions(-)\n create mode 100644 hook.c\n create mode 100644 hook.h\n\ndiff --git a/Makefile b/Makefile\nindex 29a152cd4f..d155b7be21 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -903,6 +903,7 @@ LIB_OBJS += hash-lookup.o\n LIB_OBJS += hashmap.o\n LIB_OBJS += help.o\n LIB_OBJS += hex.o\n+LIB_OBJS += hook.o\n LIB_OBJS += ident.o\n LIB_OBJS += json-writer.o\n LIB_OBJS += kwset.o\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 0b2d886c81..1c8a548903 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -11,6 +11,7 @@\n #include \"parse-options.h\"\n #include \"dir.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"quote.h\"\n #include \"tempfile.h\"\n #include \"lockfile.h\"\ndiff --git a/builtin/bugreport.c b/builtin/bugreport.c\nindex 9915a5841d..596f079a7f 100644\n--- a/builtin/bugreport.c\n+++ b/builtin/bugreport.c\n@@ -3,7 +3,7 @@\n #include \"strbuf.h\"\n #include \"help.h\"\n #include \"compat/compiler.h\"\n-#include \"run-command.h\"\n+#include \"hook.h\"\n \n \n static void get_system_info(struct strbuf *sys_info)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 190d215d43..f1aafd67d4 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -19,6 +19,7 @@\n #include \"revision.h\"\n #include \"wt-status.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"refs.h\"\n #include \"log-tree.h\"\n #include \"strbuf.h\"\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex a8a843b1f5..be98d66b0a 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -13,6 +13,7 @@\n #include \"builtin.h\"\n #include \"lockfile.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"diff.h\"\n #include \"diff-merges.h\"\n #include \"refs.h\"\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex a34742513a..1e0e04c62f 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -7,6 +7,7 @@\n #include \"pkt-line.h\"\n #include \"sideband.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"exec-cmd.h\"\n #include \"commit.h\"\n #include \"object.h\"\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 976bf8ed06..b1350640fe 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -8,6 +8,7 @@\n #include \"branch.h\"\n #include \"refs.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"sigchain.h\"\n #include \"submodule.h\"\n #include \"utf8.h\"\ndiff --git a/hook.c b/hook.c\nnew file mode 100644\nindex 0000000000..c4dbef1d0e\n--- /dev/null\n+++ b/hook.c\n@@ -0,0 +1,37 @@\n+#include \"cache.h\"\n+#include \"hook.h\"\n+#include \"run-command.h\"\n+\n+const char *find_hook(const char *name)\n+{\n+\tstatic struct strbuf path = STRBUF_INIT;\n+\n+\tstrbuf_reset(&path);\n+\tstrbuf_git_path(&path, \"hooks/%s\", name);\n+\tif (access(path.buf, X_OK) < 0) {\n+\t\tint err = errno;\n+\n+#ifdef STRIP_EXTENSION\n+\t\tstrbuf_addstr(&path, STRIP_EXTENSION);\n+\t\tif (access(path.buf, X_OK) >= 0)\n+\t\t\treturn path.buf;\n+\t\tif (errno == EACCES)\n+\t\t\terr = errno;\n+#endif\n+\n+\t\tif (err == EACCES && advice_ignored_hook) {\n+\t\t\tstatic struct string_list advise_given = STRING_LIST_INIT_DUP;\n+\n+\t\t\tif (!string_list_lookup(&advise_given, name)) {\n+\t\t\t\tstring_list_insert(&advise_given, name);\n+\t\t\t\tadvise(_(\"The '%s' hook was ignored because \"\n+\t\t\t\t\t \"it's not set as executable.\\n\"\n+\t\t\t\t\t \"You can disable this warning with \"\n+\t\t\t\t\t \"`git config advice.ignoredHook false`.\"),\n+\t\t\t\t       path.buf);\n+\t\t\t}\n+\t\t}\n+\t\treturn NULL;\n+\t}\n+\treturn path.buf;\n+}\ndiff --git a/hook.h b/hook.h\nnew file mode 100644\nindex 0000000000..68624f1605\n--- /dev/null\n+++ b/hook.h\n@@ -0,0 +1,11 @@\n+#ifndef HOOK_H\n+#define HOOK_H\n+\n+/*\n+ * Returns the path to the hook file, or NULL if the hook is missing\n+ * or disabled. Note that this points to static storage that will be\n+ * overwritten by further calls to find_hook and run_hook_*.\n+ */\n+const char *find_hook(const char *name);\n+\n+#endif\ndiff --git a/refs.c b/refs.c\nindex 8c9490235e..59be29cf08 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -10,6 +10,7 @@\n #include \"refs.h\"\n #include \"refs/refs-internal.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"object-store.h\"\n #include \"object.h\"\n #include \"tag.h\"\ndiff --git a/run-command.c b/run-command.c\nindex be6bc128cd..82fdf29656 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -8,6 +8,7 @@\n #include \"string-list.h\"\n #include \"quote.h\"\n #include \"config.h\"\n+#include \"hook.h\"\n \n void child_process_init(struct child_process *child)\n {\n@@ -1320,40 +1321,6 @@ int async_with_fork(void)\n #endif\n }\n \n-const char *find_hook(const char *name)\n-{\n-\tstatic struct strbuf path = STRBUF_INIT;\n-\n-\tstrbuf_reset(&path);\n-\tstrbuf_git_path(&path, \"hooks/%s\", name);\n-\tif (access(path.buf, X_OK) < 0) {\n-\t\tint err = errno;\n-\n-#ifdef STRIP_EXTENSION\n-\t\tstrbuf_addstr(&path, STRIP_EXTENSION);\n-\t\tif (access(path.buf, X_OK) >= 0)\n-\t\t\treturn path.buf;\n-\t\tif (errno == EACCES)\n-\t\t\terr = errno;\n-#endif\n-\n-\t\tif (err == EACCES && advice_ignored_hook) {\n-\t\t\tstatic struct string_list advise_given = STRING_LIST_INIT_DUP;\n-\n-\t\t\tif (!string_list_lookup(&advise_given, name)) {\n-\t\t\t\tstring_list_insert(&advise_given, name);\n-\t\t\t\tadvise(_(\"The '%s' hook was ignored because \"\n-\t\t\t\t\t \"it's not set as executable.\\n\"\n-\t\t\t\t\t \"You can disable this warning with \"\n-\t\t\t\t\t \"`git config advice.ignoredHook false`.\"),\n-\t\t\t\t       path.buf);\n-\t\t\t}\n-\t\t}\n-\t\treturn NULL;\n-\t}\n-\treturn path.buf;\n-}\n-\n int run_hook_ve(const char *const *env, const char *name, va_list args)\n {\n \tstruct child_process hook = CHILD_PROCESS_INIT;\ndiff --git a/run-command.h b/run-command.h\nindex d08414a92e..b58531a7eb 100644\n--- a/run-command.h\n+++ b/run-command.h\n@@ -201,13 +201,6 @@ int finish_command_in_signal(struct child_process *);\n  */\n int run_command(struct child_process *);\n \n-/*\n- * Returns the path to the hook file, or NULL if the hook is missing\n- * or disabled. Note that this points to static storage that will be\n- * overwritten by further calls to find_hook and run_hook_*.\n- */\n-const char *find_hook(const char *name);\n-\n /**\n  * Run a hook.\n  * The first argument is a pathname to an index file, or NULL\ndiff --git a/sequencer.c b/sequencer.c\nindex 0bec01cf38..3de479f90e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -8,6 +8,7 @@\n #include \"sequencer.h\"\n #include \"tag.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"exec-cmd.h\"\n #include \"utf8.h\"\n #include \"cache-tree.h\"\ndiff --git a/transport.c b/transport.c\nindex 50f5830eb6..2ed270171f 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -2,6 +2,7 @@\n #include \"config.h\"\n #include \"transport.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"pkt-line.h\"\n #include \"fetch-pack.h\"\n #include \"remote.h\"\n-- \n2.32.0.576.g59759b6ca7d\n\n"},{"id":"427691","messageId":"patch-2.3-0cf7e078ef-20210617T100239Z-avarab@gmail.com","threadId":"55950","inReplyTo":"cover-0.3-0000000000-20210617T100239Z-avarab@gmail.com","subject":"[PATCH 2/3] hook.c: add a hook_exists() wrapper and use it in bugreport.c","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-17T10:09:35Z","receivedAt":"2021-06-17T10:09:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nAdd a boolean version of the find_hook() function for those callers\nwho are only interested in checking whether the hook exists, not what\nthe path to it is.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/bugreport.c | 2 +-\n hook.c              | 5 +++++\n hook.h              | 5 +++++\n 3 files changed, 11 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/bugreport.c b/builtin/bugreport.c\nindex 596f079a7f..941c8d5e27 100644\n--- a/builtin/bugreport.c\n+++ b/builtin/bugreport.c\n@@ -82,7 +82,7 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n \t}\n \n \tfor (i = 0; i < ARRAY_SIZE(hook); i++)\n-\t\tif (find_hook(hook[i]))\n+\t\tif (hook_exists(hook[i]))\n \t\t\tstrbuf_addf(hook_info, \"%s\\n\", hook[i]);\n }\n \ndiff --git a/hook.c b/hook.c\nindex c4dbef1d0e..97cd799a32 100644\n--- a/hook.c\n+++ b/hook.c\n@@ -35,3 +35,8 @@ const char *find_hook(const char *name)\n \t}\n \treturn path.buf;\n }\n+\n+int hook_exists(const char *name)\n+{\n+\treturn !!find_hook(name);\n+}\ndiff --git a/hook.h b/hook.h\nindex 68624f1605..4c547ac15e 100644\n--- a/hook.h\n+++ b/hook.h\n@@ -8,4 +8,9 @@\n  */\n const char *find_hook(const char *name);\n \n+/*\n+ * A boolean version of find_hook()\n+ */\n+int hook_exists(const char *hookname);\n+\n #endif\n-- \n2.32.0.576.g59759b6ca7d\n\n"},{"id":"427692","messageId":"patch-3.3-f343fc7ae6-20210617T100239Z-avarab@gmail.com","threadId":"55950","inReplyTo":"cover-0.3-0000000000-20210617T100239Z-avarab@gmail.com","subject":"[PATCH 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-17T10:09:36Z","receivedAt":"2021-06-17T10:09:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Make githooks(5) the source of truth for what hooks git supports, and\ndie hooks we don't know about in find_hook(). This ensures that the\ndocumentation and the C code's idea about existing hooks doesn't\ndiverge.\n\nWe still have Perl and Python code running its own hooks, but that'll\nbe addressed by Emily Shaffer's upcoming \"git hook run\" command.\n\nThis resolves a long-standing TODO item in bugreport.c of there being\nno centralized listing of hooks, and fixes a bug with the bugreport\nlisting only knowing about 1/4 of the p4 hooks. It didn't know about\nthe recent \"reference-transaction\" hook either.\n\nI have not been able to directly test the CMake change being made\nhere. Since 4c2c38e800 (ci: modification of main.yml to use cmake for\nvs-build job, 2020-06-26) some of the Windows CI has a hard dependency\non CMake, this change works there, and is to my eyes an obviously\ncorrect use of a pattern established in previous CMake changes,\nnamely:\n\n - 061c2240b1 (Introduce CMake support for configuring Git,\n    2020-06-12)\n - 709df95b78 (help: move list_config_help to builtin/help,\n    2020-04-16)\n - 976aaedca0 (msvc: add a Makefile target to pre-generate the Visual\n   Studio solution, 2019-07-29)\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n .gitignore                          |  1 +\n Makefile                            | 11 +++++++-\n builtin/bugreport.c                 | 44 ++++++-----------------------\n contrib/buildsystems/CMakeLists.txt |  7 +++++\n generate-hooklist.sh                | 24 ++++++++++++++++\n hook.c                              | 19 +++++++++++++\n 6 files changed, 69 insertions(+), 37 deletions(-)\n create mode 100755 generate-hooklist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 311841f9be..6be9de41ae 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -190,6 +190,7 @@\n /gitweb/static/gitweb.min.*\n /config-list.h\n /command-list.h\n+/hook-list.h\n *.tar.gz\n *.dsc\n *.deb\ndiff --git a/Makefile b/Makefile\nindex d155b7be21..9bd31e1ac5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -817,6 +817,8 @@ XDIFF_LIB = xdiff/lib.a\n \n GENERATED_H += command-list.h\n GENERATED_H += config-list.h\n+GENERATED_H += hook-list.h\n+\n .PHONY: generated-hdrs\n generated-hdrs: $(GENERATED_H)\n \n@@ -2208,7 +2210,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n+hook.sp hook.s hook.o: hook-list.h\n+\n+builtin/help.sp builtin/help.s builtin/help.o: config-list.h hook-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -2241,6 +2245,11 @@ command-list.h: $(wildcard Documentation/git*.txt)\n \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n \t\tcommand-list.txt >$@+ && mv $@+ $@\n \n+hook-list.h: generate-hooklist.sh\n+hook-list.h: Documentation/githooks.txt\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\ndiff --git a/builtin/bugreport.c b/builtin/bugreport.c\nindex 941c8d5e27..a7a1fcb8a7 100644\n--- a/builtin/bugreport.c\n+++ b/builtin/bugreport.c\n@@ -4,6 +4,7 @@\n #include \"help.h\"\n #include \"compat/compiler.h\"\n #include \"hook.h\"\n+#include \"hook-list.h\"\n \n \n static void get_system_info(struct strbuf *sys_info)\n@@ -41,39 +42,7 @@ static void get_system_info(struct strbuf *sys_info)\n \n static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n {\n-\t/*\n-\t * NEEDSWORK: Doesn't look like there is a list of all possible hooks;\n-\t * so below is a transcription of `git help hooks`. Later, this should\n-\t * be replaced with some programmatically generated list (generated from\n-\t * doc or else taken from some library which tells us about all the\n-\t * hooks)\n-\t */\n-\tstatic const char *hook[] = {\n-\t\t\"applypatch-msg\",\n-\t\t\"pre-applypatch\",\n-\t\t\"post-applypatch\",\n-\t\t\"pre-commit\",\n-\t\t\"pre-merge-commit\",\n-\t\t\"prepare-commit-msg\",\n-\t\t\"commit-msg\",\n-\t\t\"post-commit\",\n-\t\t\"pre-rebase\",\n-\t\t\"post-checkout\",\n-\t\t\"post-merge\",\n-\t\t\"pre-push\",\n-\t\t\"pre-receive\",\n-\t\t\"update\",\n-\t\t\"post-receive\",\n-\t\t\"post-update\",\n-\t\t\"push-to-checkout\",\n-\t\t\"pre-auto-gc\",\n-\t\t\"post-rewrite\",\n-\t\t\"sendemail-validate\",\n-\t\t\"fsmonitor-watchman\",\n-\t\t\"p4-pre-submit\",\n-\t\t\"post-index-change\",\n-\t};\n-\tint i;\n+\tconst char **p;\n \n \tif (nongit) {\n \t\tstrbuf_addstr(hook_info,\n@@ -81,9 +50,12 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n \t\treturn;\n \t}\n \n-\tfor (i = 0; i < ARRAY_SIZE(hook); i++)\n-\t\tif (hook_exists(hook[i]))\n-\t\t\tstrbuf_addf(hook_info, \"%s\\n\", hook[i]);\n+\tfor (p = hook_name_list; *p; p++) {\n+\t\tconst char *hook = *p;\n+\n+\t\tif (hook_exists(hook))\n+\t\t\tstrbuf_addf(hook_info, \"%s\\n\", hook);\n+\t}\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt\nindex a87841340e..c216940945 100644\n--- a/contrib/buildsystems/CMakeLists.txt\n+++ b/contrib/buildsystems/CMakeLists.txt\n@@ -602,6 +602,13 @@ if(NOT EXISTS ${CMAKE_BINARY_DIR}/config-list.h)\n \t\t\tOUTPUT_FILE ${CMAKE_BINARY_DIR}/config-list.h)\n endif()\n \n+if(NOT EXISTS ${CMAKE_BINARY_DIR}/hook-list.h)\n+\tmessage(\"Generating hook-list.h\")\n+\texecute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-hooklist.sh\n+\t\t\tWORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n+\t\t\tOUTPUT_FILE ${CMAKE_BINARY_DIR}/hook-list.h)\n+endif()\n+\n include_directories(${CMAKE_BINARY_DIR})\n \n #build\ndiff --git a/generate-hooklist.sh b/generate-hooklist.sh\nnew file mode 100755\nindex 0000000000..5a3f7f849c\n--- /dev/null\n+++ b/generate-hooklist.sh\n@@ -0,0 +1,24 @@\n+#!/bin/sh\n+\n+echo \"/* Automatically generated by generate-hooklist.sh */\"\n+\n+print_hook_list () {\n+\tcat <<EOF\n+static const char *hook_name_list[] = {\n+EOF\n+\tperl -ne '\n+\t\tchomp;\n+\t\t@l[$.] = $_;\n+\t\tpush @h => $l[$. - 1] if /^~~~+$/s;\n+\t\tEND {\n+\t\t\tprint qq[\\t\"$_\",\\n] for sort @h;\n+\t\t}\n+\t' <Documentation/githooks.txt\n+\tcat <<EOF\n+\tNULL,\n+};\n+EOF\n+}\n+\n+echo\n+print_hook_list\ndiff --git a/hook.c b/hook.c\nindex 97cd799a32..1f1db1ec9b 100644\n--- a/hook.c\n+++ b/hook.c\n@@ -1,11 +1,30 @@\n #include \"cache.h\"\n #include \"hook.h\"\n #include \"run-command.h\"\n+#include \"hook-list.h\"\n+\n+static int known_hook(const char *name)\n+{\n+\tconst char **p;\n+\tsize_t len = strlen(name);\n+\tfor (p = hook_name_list; *p; p++) {\n+\t\tconst char *hook = *p;\n+\n+\t\tif (!strncmp(name, hook, len) && hook[len] == '\\0')\n+\t\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n \n const char *find_hook(const char *name)\n {\n \tstatic struct strbuf path = STRBUF_INIT;\n \n+\tif (!known_hook(name))\n+\t\tdie(_(\"the hook '%s' is not known to git, should be in hook-list.h via githooks(5)\"),\n+\t\t    name);\n+\n \tstrbuf_reset(&path);\n \tstrbuf_git_path(&path, \"hooks/%s\", name);\n \tif (access(path.buf, X_OK) < 0) {\n-- \n2.32.0.576.g59759b6ca7d\n\n"},{"id":"427842","messageId":"20210618170550.GE6312@szeder.dev","threadId":"55950","inReplyTo":"patch-3.3-f343fc7ae6-20210617T100239Z-avarab@gmail.com","subject":"Re: [PATCH 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2021-06-18T17:05:50Z","receivedAt":"2021-06-18T17:05:56Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Thu, Jun 17, 2021 at 12:09:36PM +0200, Ævar Arnfjörð Bjarmason wrote:\n> diff --git a/generate-hooklist.sh b/generate-hooklist.sh\n> new file mode 100755\n> index 0000000000..5a3f7f849c\n> --- /dev/null\n> +++ b/generate-hooklist.sh\n> @@ -0,0 +1,24 @@\n> +#!/bin/sh\n> +\n> +echo \"/* Automatically generated by generate-hooklist.sh */\"\n> +\n> +print_hook_list () {\n> +\tcat <<EOF\n> +static const char *hook_name_list[] = {\n> +EOF\n> +\tperl -ne '\n\nWhy Perl?\n\nAt the moment I can run 'make' and get a functioning git even when\nPerl is not installed.  With this patch that wouldn't work anymore.\n\nBoth 'generate-cmdlist.sh' and 'generate-configlist.sh' can process\nthe documentation into a header file with a long list in it without\nresorting to Perl; I'm sure that hooks could be processed without Perl\nas well.\n\n> +\t\tchomp;\n> +\t\t@l[$.] = $_;\n> +\t\tpush @h => $l[$. - 1] if /^~~~+$/s;\n> +\t\tEND {\n> +\t\t\tprint qq[\\t\"$_\",\\n] for sort @h;\n> +\t\t}\n> +\t' <Documentation/githooks.txt\n> +\tcat <<EOF\n> +\tNULL,\n> +};\n> +EOF\n> +}\n> +\n> +echo\n> +print_hook_list\n"},{"id":"427843","messageId":"CAPig+cQvn+_56iuZmvHVDFSVYto-FMX2vp5aaEGrdr8L8+NY0w@mail.gmail.com","threadId":"55950","inReplyTo":"20210618170550.GE6312@szeder.dev","subject":"Re: [PATCH 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2021-06-18T17:50:44Z","receivedAt":"2021-06-18T17:51:03Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Jun 18, 2021 at 1:06 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> On Thu, Jun 17, 2021 at 12:09:36PM +0200, Ævar Arnfjörð Bjarmason wrote:\n> > diff --git a/generate-hooklist.sh b/generate-hooklist.sh\n> > @@ -0,0 +1,24 @@\n> > +#!/bin/sh\n> > +\n> > +echo \"/* Automatically generated by generate-hooklist.sh */\"\n> > +\n> > +print_hook_list () {\n> > +     cat <<EOF\n> > +static const char *hook_name_list[] = {\n> > +EOF\n> > +     perl -ne '\n>\n> Why Perl?\n>\n> At the moment I can run 'make' and get a functioning git even when\n> Perl is not installed.  With this patch that wouldn't work anymore.\n>\n> Both 'generate-cmdlist.sh' and 'generate-configlist.sh' can process\n> the documentation into a header file with a long list in it without\n> resorting to Perl; I'm sure that hooks could be processed without Perl\n> as well.\n\nThat's a good point and not an idle question. It wasn't all that long\nago that I rewrote `generate-cmdlist` in Perl and got a complaint that\nthe Git project was no longer buildable on FreeBSD[1], with the result\nthat I ended up re-implementing it (again) in shell[2].\n\n[1]: https://lore.kernel.org/git/loom.20150814T171757-901@post.gmane.org/\n[2]: https://lore.kernel.org/git/1440365469-9928-1-git-send-email-sunshine@sunshineco.com/\n"},{"id":"427939","messageId":"xmqqlf76l765.fsf@gitster.g","threadId":"55950","inReplyTo":"CAPig+cQvn+_56iuZmvHVDFSVYto-FMX2vp5aaEGrdr8L8+NY0w@mail.gmail.com","subject":"Re: [PATCH 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-06-19T06:06:42Z","receivedAt":"2021-06-19T06:06:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> That's a good point and not an idle question. It wasn't all that long\n> ago that I rewrote `generate-cmdlist` in Perl and got a complaint that\n> the Git project was no longer buildable on FreeBSD[1], with the result\n> that I ended up re-implementing it (again) in shell[2].\n>\n> [1]: https://lore.kernel.org/git/loom.20150814T171757-901@post.gmane.org/\n> [2]: https://lore.kernel.org/git/1440365469-9928-1-git-send-email-sunshine@sunshineco.com/\n\nIf it works without Perl, I would not complain too much, but NO_PERL\nis purely about the execution environment (i.e. do not build and/or\ninstall what requires Perl at runtime), so the old complaint [1]\nmisses the point, I would have to say.  We do expect a working Perl\nin test enviroment to run test suite, for example.\n\n\n"},{"id":"427972","messageId":"648321ed-bda9-d7fc-73e1-7ccf48addf9c@web.de","threadId":"55950","inReplyTo":"20210618170550.GE6312@szeder.dev","subject":"Re: [PATCH 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2021-06-20T12:53:10Z","receivedAt":"2021-06-20T12:54:37Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 18.06.21 um 19:05 schrieb SZEDER Gábor:\n> On Thu, Jun 17, 2021 at 12:09:36PM +0200, Ævar Arnfjörð Bjarmason wrote:\n>> diff --git a/generate-hooklist.sh b/generate-hooklist.sh\n>> new file mode 100755\n>> index 0000000000..5a3f7f849c\n>> --- /dev/null\n>> +++ b/generate-hooklist.sh\n>> @@ -0,0 +1,24 @@\n>> +#!/bin/sh\n>> +\n>> +echo \"/* Automatically generated by generate-hooklist.sh */\"\n>> +\n>> +print_hook_list () {\n>> +\tcat <<EOF\n>> +static const char *hook_name_list[] = {\n>> +EOF\n>> +\tperl -ne '\n>\n> Why Perl?\n>\n> At the moment I can run 'make' and get a functioning git even when\n> Perl is not installed.  With this patch that wouldn't work anymore.\n>\n> Both 'generate-cmdlist.sh' and 'generate-configlist.sh' can process\n> the documentation into a header file with a long list in it without\n> resorting to Perl; I'm sure that hooks could be processed without Perl\n> as well.\n>\n>> +\t\tchomp;\n>> +\t\t@l[$.] = $_;\n>> +\t\tpush @h => $l[$. - 1] if /^~~~+$/s;\n>> +\t\tEND {\n>> +\t\t\tprint qq[\\t\"$_\",\\n] for sort @h;\n>> +\t\t}\n>> +\t' <Documentation/githooks.txt\n\nHow about something like this?\n\n\tsed -n '/^~~~~*$/ {x; p;}; x' Documentation/githooks.txt |\n\tsort |\n\tsed 's/^.*$/\t\"&\",/'\n\nsed is already used by generate-configlist.sh.\n\n>> +\tcat <<EOF\n>> +\tNULL,\n>> +};\n>> +EOF\n>> +}\n>> +\n>> +echo\n>> +print_hook_list\n\n"},{"id":"427974","messageId":"87lf744oyk.fsf@evledraar.gmail.com","threadId":"55950","inReplyTo":"CAPig+cQvn+_56iuZmvHVDFSVYto-FMX2vp5aaEGrdr8L8+NY0w@mail.gmail.com","subject":"Re: [PATCH 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-20T13:53:35Z","receivedAt":"2021-06-20T13:59:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Jun 18 2021, Eric Sunshine wrote:\n\n> On Fri, Jun 18, 2021 at 1:06 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n>> On Thu, Jun 17, 2021 at 12:09:36PM +0200, Ævar Arnfjörð Bjarmason wrote:\n>> > diff --git a/generate-hooklist.sh b/generate-hooklist.sh\n>> > @@ -0,0 +1,24 @@\n>> > +#!/bin/sh\n>> > +\n>> > +echo \"/* Automatically generated by generate-hooklist.sh */\"\n>> > +\n>> > +print_hook_list () {\n>> > +     cat <<EOF\n>> > +static const char *hook_name_list[] = {\n>> > +EOF\n>> > +     perl -ne '\n>>\n>> Why Perl?\n>>\n>> At the moment I can run 'make' and get a functioning git even when\n>> Perl is not installed.  With this patch that wouldn't work anymore.\n>>\n>> Both 'generate-cmdlist.sh' and 'generate-configlist.sh' can process\n>> the documentation into a header file with a long list in it without\n>> resorting to Perl; I'm sure that hooks could be processed without Perl\n>> as well.\n>\n> That's a good point and not an idle question. It wasn't all that long\n> ago that I rewrote `generate-cmdlist` in Perl and got a complaint that\n> the Git project was no longer buildable on FreeBSD[1], with the result\n> that I ended up re-implementing it (again) in shell[2].\n>\n> [1]: https://lore.kernel.org/git/loom.20150814T171757-901@post.gmane.org/\n> [2]: https://lore.kernel.org/git/1440365469-9928-1-git-send-email-sunshine@sunshineco.com/\n\nI'm sympathetic to changing this from Perl, as can be seen from the \"v1\"\n(as part of another series) I intially used an unportable grep flag for\nit. I'll test and probably convert it to René's few-liner.\n\nThe [1] link is not it not being buildable on FreeBSD though, it's\nsomeone understandably not understanding what NO_PERL=Y means, because\nwe really should call it PERL_ONLY_FOR_BUILDING_AND_TESTING or\nsomething.\n\nAside from this series it would be useful to clarify that point, what do\nwe really think it means? I was under the impression that it meant that,\nand I really shouldn't be giving it a second thought if we introduced a\nperl dependency during the build or testing.\n"},{"id":"428235","messageId":"nycvar.QRO.7.76.6.2106221642560.57@tvgsbejvaqbjf.bet","threadId":"55950","inReplyTo":"648321ed-bda9-d7fc-73e1-7ccf48addf9c@web.de","subject":"Re: [PATCH 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2021-06-22T22:32:43Z","receivedAt":"2021-06-22T22:32:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi René,\n\nOn Sun, 20 Jun 2021, René Scharfe wrote:\n\n> Am 18.06.21 um 19:05 schrieb SZEDER Gábor:\n> > On Thu, Jun 17, 2021 at 12:09:36PM +0200, Ævar Arnfjörð Bjarmason wrote:\n> >> diff --git a/generate-hooklist.sh b/generate-hooklist.sh\n> >> new file mode 100755\n> >> index 0000000000..5a3f7f849c\n> >> --- /dev/null\n> >> +++ b/generate-hooklist.sh\n> >> @@ -0,0 +1,24 @@\n> >> +#!/bin/sh\n> >> +\n> >> +echo \"/* Automatically generated by generate-hooklist.sh */\"\n> >> +\n> >> +print_hook_list () {\n> >> +\tcat <<EOF\n> >> +static const char *hook_name_list[] = {\n> >> +EOF\n> >> +\tperl -ne '\n> >\n> > Why Perl?\n> >\n> > At the moment I can run 'make' and get a functioning git even when\n> > Perl is not installed.  With this patch that wouldn't work anymore.\n> >\n> > Both 'generate-cmdlist.sh' and 'generate-configlist.sh' can process\n> > the documentation into a header file with a long list in it without\n> > resorting to Perl; I'm sure that hooks could be processed without Perl\n> > as well.\n> >\n> >> +\t\tchomp;\n> >> +\t\t@l[$.] = $_;\n> >> +\t\tpush @h => $l[$. - 1] if /^~~~+$/s;\n> >> +\t\tEND {\n> >> +\t\t\tprint qq[\\t\"$_\",\\n] for sort @h;\n> >> +\t\t}\n> >> +\t' <Documentation/githooks.txt\n>\n> How about something like this?\n>\n> \tsed -n '/^~~~~*$/ {x; p;}; x' Documentation/githooks.txt |\n> \tsort |\n> \tsed 's/^.*$/\t\"&\",/'\n>\n> sed is already used by generate-configlist.sh.\n\nI do like me a good sed script.\n\nThanks,\nDscho\n\n>\n> >> +\tcat <<EOF\n> >> +\tNULL,\n> >> +};\n> >> +EOF\n> >> +}\n> >> +\n> >> +echo\n> >> +print_hook_list\n>\n>\n"},{"id":"428652","messageId":"xmqqv95x4ijd.fsf@gitster.g","threadId":"55950","inReplyTo":"nycvar.QRO.7.76.6.2106221642560.57@tvgsbejvaqbjf.bet","subject":"Re: [PATCH 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-06-29T00:32:38Z","receivedAt":"2021-06-29T00:32:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> On Sun, 20 Jun 2021, René Scharfe wrote:\n>\n>> How about something like this?\n>>\n>> \tsed -n '/^~~~~*$/ {x; p;}; x' Documentation/githooks.txt |\n>> \tsort |\n>> \tsed 's/^.*$/\t\"&\",/'\n>>\n>> sed is already used by generate-configlist.sh.\n>\n> I do like me a good sed script.\n>\n> Thanks,\n> Dscho\n\nYup.  \n\nThis is buried below the 27-patch series, so the whole thing cannot\nadvance until this gets sorted out.\n\nThanks.\n"},{"id":"428758","messageId":"20b1bfb6-8881-2a21-1753-0e2e508a7861@web.de","threadId":"55950","inReplyTo":"xmqqv95x4ijd.fsf@gitster.g","subject":"Re: [PATCH 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2021-06-29T17:53:55Z","receivedAt":"2021-06-29T17:54:07Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 29.06.21 um 02:32 schrieb Junio C Hamano:\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>\n>> On Sun, 20 Jun 2021, René Scharfe wrote:\n>>\n>>> How about something like this?\n>>>\n>>> \tsed -n '/^~~~~*$/ {x; p;}; x' Documentation/githooks.txt |\n>>> \tsort |\n>>> \tsed 's/^.*$/\t\"&\",/'\n>>>\n>>> sed is already used by generate-configlist.sh.\n>>\n>> I do like me a good sed script.\n>>\n>> Thanks,\n>> Dscho\n>\n> Yup.\n>\n> This is buried below the 27-patch series, so the whole thing cannot\n> advance until this gets sorted out.\n\nIf it helps: You can add the patch below as number 28 or squash\nit in.\n\n--- >8 ---\nSubject: [PATCH] generate-hooklist.sh: use sed instead of Perl\n\nAllow hooklist.h to be built without Perl by finding, sorting and\nformatting hook names using two short sed(1) scripts and sort(1).\n\nSigned-off-by: René Scharfe <l.s.r@web.de>\n---\n generate-hooklist.sh | 11 +++--------\n 1 file changed, 3 insertions(+), 8 deletions(-)\n\ndiff --git a/generate-hooklist.sh b/generate-hooklist.sh\nindex 5a3f7f849c..6f3de0a2ec 100755\n--- a/generate-hooklist.sh\n+++ b/generate-hooklist.sh\n@@ -6,14 +6,9 @@ print_hook_list () {\n \tcat <<EOF\n static const char *hook_name_list[] = {\n EOF\n-\tperl -ne '\n-\t\tchomp;\n-\t\t@l[$.] = $_;\n-\t\tpush @h => $l[$. - 1] if /^~~~+$/s;\n-\t\tEND {\n-\t\t\tprint qq[\\t\"$_\",\\n] for sort @h;\n-\t\t}\n-\t' <Documentation/githooks.txt\n+\tsed -n '/^~~~~*$/ {x; p;}; x' Documentation/githooks.txt |\n+\tsort |\n+\tsed 's/^.*$/\t\"&\",/'\n \tcat <<EOF\n \tNULL,\n };\n--\n2.32.0\n"},{"id":"428761","messageId":"cover-0.3-0000000000-20210629T183325Z-avarab@gmail.com","threadId":"55950","inReplyTo":"cover-0.3-0000000000-20210617T100239Z-avarab@gmail.com","subject":"[PATCH v2 0/3] Add a generated list of hooks in hook-list.h","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-29T18:53:59Z","receivedAt":"2021-06-29T18:54:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A re-roll of this v1[1] to stop hardcoding the hook list, and instead generate it.\n\nThe v1 used a Perl script to generate the hook-list.h, it's now a\nshellscsript that uses \"sed\" instead.\n\nThe sed script is an adaptation of René's in [2]. I fixed a regression\nin it vis-a-vis the Perl version, we need to set LC_ALL so we don't\nsort the list at build-time with the locale of the user performing the\nbuild.\n\nI also turned the two sed commands into one, with a trick that's\nperhaps too clever, but which has worked in my cross-platform testing\nso far.\n\n1. http://lore.kernel.org/git/cover-0.3-0000000000-20210617T100239Z-avarab@gmail.com\n2. https://lore.kernel.org/git/648321ed-bda9-d7fc-73e1-7ccf48addf9c@web.de/\n\nEmily Shaffer (1):\n  hook.c: add a hook_exists() wrapper and use it in bugreport.c\n\nÆvar Arnfjörð Bjarmason (2):\n  hook.[ch]: move find_hook() to this new library\n  hook-list.h: add a generated list of hooks, like config-list.h\n\n .gitignore                          |  1 +\n Makefile                            | 11 +++++-\n builtin/am.c                        |  1 +\n builtin/bugreport.c                 | 46 +++++-----------------\n builtin/commit.c                    |  1 +\n builtin/merge.c                     |  1 +\n builtin/receive-pack.c              |  1 +\n builtin/worktree.c                  |  1 +\n contrib/buildsystems/CMakeLists.txt |  7 ++++\n generate-hooklist.sh                | 18 +++++++++\n hook.c                              | 61 +++++++++++++++++++++++++++++\n hook.h                              | 16 ++++++++\n refs.c                              |  1 +\n run-command.c                       | 35 +----------------\n run-command.h                       |  7 ----\n sequencer.c                         |  1 +\n transport.c                         |  1 +\n 17 files changed, 131 insertions(+), 79 deletions(-)\n create mode 100755 generate-hooklist.sh\n create mode 100644 hook.c\n create mode 100644 hook.h\n\nRange-diff against v1:\n-:  ---------- > 1:  58c37e4f06 hook.[ch]: move find_hook() to this new library\n-:  ---------- > 2:  0cf7e078ef hook.c: add a hook_exists() wrapper and use it in bugreport.c\n1:  f343fc7ae6 ! 3:  ba7f01f4f6 hook-list.h: add a generated list of hooks, like config-list.h\n    @@ Commit message\n          - 976aaedca0 (msvc: add a Makefile target to pre-generate the Visual\n            Studio solution, 2019-07-29)\n     \n    +    The LC_ALL=C is needed because at least in my locale the dash (\"-\") is\n    +    ignored for the purposes of sorting, which results in a different\n    +    order. I'm not aware of anything in git that has a hard dependency on\n    +    the order, but e.g. the bugreport output would end up using whatever\n    +    locale was in effect when git was compiled.\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n    +    Signed-off-by: René Scharfe <l.s.r@web.de>\n     \n      ## .gitignore ##\n     @@\n    @@ Makefile: command-list.h: $(wildcard Documentation/git*.txt)\n      \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n      \t\tcommand-list.txt >$@+ && mv $@+ $@\n      \n    -+hook-list.h: generate-hooklist.sh\n    -+hook-list.h: Documentation/githooks.txt\n    ++hook-list.h: generate-hooklist.sh Documentation/githooks.txt\n     +\t$(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh \\\n     +\t\t>$@+ && mv $@+ $@\n     +\n    @@ contrib/buildsystems/CMakeLists.txt: if(NOT EXISTS ${CMAKE_BINARY_DIR}/config-li\n      ## generate-hooklist.sh (new) ##\n     @@\n     +#!/bin/sh\n    ++#\n    ++# Usage: ./generate-hooklist.sh >hook-list.h\n     +\n    -+echo \"/* Automatically generated by generate-hooklist.sh */\"\n    ++cat <<EOF\n    ++/* Automatically generated by generate-hooklist.sh */\n     +\n    -+print_hook_list () {\n    -+\tcat <<EOF\n     +static const char *hook_name_list[] = {\n     +EOF\n    -+\tperl -ne '\n    -+\t\tchomp;\n    -+\t\t@l[$.] = $_;\n    -+\t\tpush @h => $l[$. - 1] if /^~~~+$/s;\n    -+\t\tEND {\n    -+\t\t\tprint qq[\\t\"$_\",\\n] for sort @h;\n    -+\t\t}\n    -+\t' <Documentation/githooks.txt\n    -+\tcat <<EOF\n    ++\n    ++sed -n -e '/^~~~~*$/ {x; s/^.*$/\t\"&\",/; p;}; x' \\\n    ++\t<Documentation/githooks.txt |\n    ++\tLC_ALL=C sort\n    ++\n    ++cat <<EOF\n     +\tNULL,\n     +};\n     +EOF\n    -+}\n    -+\n    -+echo\n    -+print_hook_list\n     \n      ## hook.c ##\n     @@\n-- \n2.32.0.615.g90fb4d7369\n\n"},{"id":"428762","messageId":"patch-1.3-58c37e4f06-20210629T183325Z-avarab@gmail.com","threadId":"55950","inReplyTo":"cover-0.3-0000000000-20210629T183325Z-avarab@gmail.com","subject":"[PATCH v2 1/3] hook.[ch]: move find_hook() to this new library","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-29T18:54:00Z","receivedAt":"2021-06-29T18:54:30Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Move the find_hook() function from run-command.c to a new hook.c\nlibrary. This change establishes a stub library that's pretty\npointless right now, but will see much wider use with Emily Shaffer's\nupcoming \"configuration-based hooks\" series.\n\nEventually all the hook related code will live in hook.[ch]. Let's\nstart that process by moving the simple find_hook() function over\nas-is.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Makefile               |  1 +\n builtin/am.c           |  1 +\n builtin/bugreport.c    |  2 +-\n builtin/commit.c       |  1 +\n builtin/merge.c        |  1 +\n builtin/receive-pack.c |  1 +\n builtin/worktree.c     |  1 +\n hook.c                 | 37 +++++++++++++++++++++++++++++++++++++\n hook.h                 | 11 +++++++++++\n refs.c                 |  1 +\n run-command.c          | 35 +----------------------------------\n run-command.h          |  7 -------\n sequencer.c            |  1 +\n transport.c            |  1 +\n 14 files changed, 59 insertions(+), 42 deletions(-)\n create mode 100644 hook.c\n create mode 100644 hook.h\n\ndiff --git a/Makefile b/Makefile\nindex 29a152cd4f..d155b7be21 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -903,6 +903,7 @@ LIB_OBJS += hash-lookup.o\n LIB_OBJS += hashmap.o\n LIB_OBJS += help.o\n LIB_OBJS += hex.o\n+LIB_OBJS += hook.o\n LIB_OBJS += ident.o\n LIB_OBJS += json-writer.o\n LIB_OBJS += kwset.o\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 0b2d886c81..1c8a548903 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -11,6 +11,7 @@\n #include \"parse-options.h\"\n #include \"dir.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"quote.h\"\n #include \"tempfile.h\"\n #include \"lockfile.h\"\ndiff --git a/builtin/bugreport.c b/builtin/bugreport.c\nindex 9915a5841d..596f079a7f 100644\n--- a/builtin/bugreport.c\n+++ b/builtin/bugreport.c\n@@ -3,7 +3,7 @@\n #include \"strbuf.h\"\n #include \"help.h\"\n #include \"compat/compiler.h\"\n-#include \"run-command.h\"\n+#include \"hook.h\"\n \n \n static void get_system_info(struct strbuf *sys_info)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 190d215d43..f1aafd67d4 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -19,6 +19,7 @@\n #include \"revision.h\"\n #include \"wt-status.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"refs.h\"\n #include \"log-tree.h\"\n #include \"strbuf.h\"\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex a8a843b1f5..be98d66b0a 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -13,6 +13,7 @@\n #include \"builtin.h\"\n #include \"lockfile.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"diff.h\"\n #include \"diff-merges.h\"\n #include \"refs.h\"\ndiff --git a/builtin/receive-pack.c b/builtin/receive-pack.c\nindex a34742513a..1e0e04c62f 100644\n--- a/builtin/receive-pack.c\n+++ b/builtin/receive-pack.c\n@@ -7,6 +7,7 @@\n #include \"pkt-line.h\"\n #include \"sideband.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"exec-cmd.h\"\n #include \"commit.h\"\n #include \"object.h\"\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 976bf8ed06..b1350640fe 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -8,6 +8,7 @@\n #include \"branch.h\"\n #include \"refs.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"sigchain.h\"\n #include \"submodule.h\"\n #include \"utf8.h\"\ndiff --git a/hook.c b/hook.c\nnew file mode 100644\nindex 0000000000..c4dbef1d0e\n--- /dev/null\n+++ b/hook.c\n@@ -0,0 +1,37 @@\n+#include \"cache.h\"\n+#include \"hook.h\"\n+#include \"run-command.h\"\n+\n+const char *find_hook(const char *name)\n+{\n+\tstatic struct strbuf path = STRBUF_INIT;\n+\n+\tstrbuf_reset(&path);\n+\tstrbuf_git_path(&path, \"hooks/%s\", name);\n+\tif (access(path.buf, X_OK) < 0) {\n+\t\tint err = errno;\n+\n+#ifdef STRIP_EXTENSION\n+\t\tstrbuf_addstr(&path, STRIP_EXTENSION);\n+\t\tif (access(path.buf, X_OK) >= 0)\n+\t\t\treturn path.buf;\n+\t\tif (errno == EACCES)\n+\t\t\terr = errno;\n+#endif\n+\n+\t\tif (err == EACCES && advice_ignored_hook) {\n+\t\t\tstatic struct string_list advise_given = STRING_LIST_INIT_DUP;\n+\n+\t\t\tif (!string_list_lookup(&advise_given, name)) {\n+\t\t\t\tstring_list_insert(&advise_given, name);\n+\t\t\t\tadvise(_(\"The '%s' hook was ignored because \"\n+\t\t\t\t\t \"it's not set as executable.\\n\"\n+\t\t\t\t\t \"You can disable this warning with \"\n+\t\t\t\t\t \"`git config advice.ignoredHook false`.\"),\n+\t\t\t\t       path.buf);\n+\t\t\t}\n+\t\t}\n+\t\treturn NULL;\n+\t}\n+\treturn path.buf;\n+}\ndiff --git a/hook.h b/hook.h\nnew file mode 100644\nindex 0000000000..68624f1605\n--- /dev/null\n+++ b/hook.h\n@@ -0,0 +1,11 @@\n+#ifndef HOOK_H\n+#define HOOK_H\n+\n+/*\n+ * Returns the path to the hook file, or NULL if the hook is missing\n+ * or disabled. Note that this points to static storage that will be\n+ * overwritten by further calls to find_hook and run_hook_*.\n+ */\n+const char *find_hook(const char *name);\n+\n+#endif\ndiff --git a/refs.c b/refs.c\nindex 8c9490235e..59be29cf08 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -10,6 +10,7 @@\n #include \"refs.h\"\n #include \"refs/refs-internal.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"object-store.h\"\n #include \"object.h\"\n #include \"tag.h\"\ndiff --git a/run-command.c b/run-command.c\nindex be6bc128cd..82fdf29656 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -8,6 +8,7 @@\n #include \"string-list.h\"\n #include \"quote.h\"\n #include \"config.h\"\n+#include \"hook.h\"\n \n void child_process_init(struct child_process *child)\n {\n@@ -1320,40 +1321,6 @@ int async_with_fork(void)\n #endif\n }\n \n-const char *find_hook(const char *name)\n-{\n-\tstatic struct strbuf path = STRBUF_INIT;\n-\n-\tstrbuf_reset(&path);\n-\tstrbuf_git_path(&path, \"hooks/%s\", name);\n-\tif (access(path.buf, X_OK) < 0) {\n-\t\tint err = errno;\n-\n-#ifdef STRIP_EXTENSION\n-\t\tstrbuf_addstr(&path, STRIP_EXTENSION);\n-\t\tif (access(path.buf, X_OK) >= 0)\n-\t\t\treturn path.buf;\n-\t\tif (errno == EACCES)\n-\t\t\terr = errno;\n-#endif\n-\n-\t\tif (err == EACCES && advice_ignored_hook) {\n-\t\t\tstatic struct string_list advise_given = STRING_LIST_INIT_DUP;\n-\n-\t\t\tif (!string_list_lookup(&advise_given, name)) {\n-\t\t\t\tstring_list_insert(&advise_given, name);\n-\t\t\t\tadvise(_(\"The '%s' hook was ignored because \"\n-\t\t\t\t\t \"it's not set as executable.\\n\"\n-\t\t\t\t\t \"You can disable this warning with \"\n-\t\t\t\t\t \"`git config advice.ignoredHook false`.\"),\n-\t\t\t\t       path.buf);\n-\t\t\t}\n-\t\t}\n-\t\treturn NULL;\n-\t}\n-\treturn path.buf;\n-}\n-\n int run_hook_ve(const char *const *env, const char *name, va_list args)\n {\n \tstruct child_process hook = CHILD_PROCESS_INIT;\ndiff --git a/run-command.h b/run-command.h\nindex d08414a92e..b58531a7eb 100644\n--- a/run-command.h\n+++ b/run-command.h\n@@ -201,13 +201,6 @@ int finish_command_in_signal(struct child_process *);\n  */\n int run_command(struct child_process *);\n \n-/*\n- * Returns the path to the hook file, or NULL if the hook is missing\n- * or disabled. Note that this points to static storage that will be\n- * overwritten by further calls to find_hook and run_hook_*.\n- */\n-const char *find_hook(const char *name);\n-\n /**\n  * Run a hook.\n  * The first argument is a pathname to an index file, or NULL\ndiff --git a/sequencer.c b/sequencer.c\nindex 0bec01cf38..3de479f90e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -8,6 +8,7 @@\n #include \"sequencer.h\"\n #include \"tag.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"exec-cmd.h\"\n #include \"utf8.h\"\n #include \"cache-tree.h\"\ndiff --git a/transport.c b/transport.c\nindex 50f5830eb6..2ed270171f 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -2,6 +2,7 @@\n #include \"config.h\"\n #include \"transport.h\"\n #include \"run-command.h\"\n+#include \"hook.h\"\n #include \"pkt-line.h\"\n #include \"fetch-pack.h\"\n #include \"remote.h\"\n-- \n2.32.0.615.g90fb4d7369\n\n"},{"id":"428763","messageId":"patch-3.3-ba7f01f4f6-20210629T183325Z-avarab@gmail.com","threadId":"55950","inReplyTo":"cover-0.3-0000000000-20210629T183325Z-avarab@gmail.com","subject":"[PATCH v2 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-29T18:54:02Z","receivedAt":"2021-06-29T18:54:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Make githooks(5) the source of truth for what hooks git supports, and\ndie hooks we don't know about in find_hook(). This ensures that the\ndocumentation and the C code's idea about existing hooks doesn't\ndiverge.\n\nWe still have Perl and Python code running its own hooks, but that'll\nbe addressed by Emily Shaffer's upcoming \"git hook run\" command.\n\nThis resolves a long-standing TODO item in bugreport.c of there being\nno centralized listing of hooks, and fixes a bug with the bugreport\nlisting only knowing about 1/4 of the p4 hooks. It didn't know about\nthe recent \"reference-transaction\" hook either.\n\nI have not been able to directly test the CMake change being made\nhere. Since 4c2c38e800 (ci: modification of main.yml to use cmake for\nvs-build job, 2020-06-26) some of the Windows CI has a hard dependency\non CMake, this change works there, and is to my eyes an obviously\ncorrect use of a pattern established in previous CMake changes,\nnamely:\n\n - 061c2240b1 (Introduce CMake support for configuring Git,\n    2020-06-12)\n - 709df95b78 (help: move list_config_help to builtin/help,\n    2020-04-16)\n - 976aaedca0 (msvc: add a Makefile target to pre-generate the Visual\n   Studio solution, 2019-07-29)\n\nThe LC_ALL=C is needed because at least in my locale the dash (\"-\") is\nignored for the purposes of sorting, which results in a different\norder. I'm not aware of anything in git that has a hard dependency on\nthe order, but e.g. the bugreport output would end up using whatever\nlocale was in effect when git was compiled.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: René Scharfe <l.s.r@web.de>\n---\n .gitignore                          |  1 +\n Makefile                            | 10 ++++++-\n builtin/bugreport.c                 | 44 ++++++-----------------------\n contrib/buildsystems/CMakeLists.txt |  7 +++++\n generate-hooklist.sh                | 18 ++++++++++++\n hook.c                              | 19 +++++++++++++\n 6 files changed, 62 insertions(+), 37 deletions(-)\n create mode 100755 generate-hooklist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 311841f9be..6be9de41ae 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -190,6 +190,7 @@\n /gitweb/static/gitweb.min.*\n /config-list.h\n /command-list.h\n+/hook-list.h\n *.tar.gz\n *.dsc\n *.deb\ndiff --git a/Makefile b/Makefile\nindex d155b7be21..9b811d3548 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -817,6 +817,8 @@ XDIFF_LIB = xdiff/lib.a\n \n GENERATED_H += command-list.h\n GENERATED_H += config-list.h\n+GENERATED_H += hook-list.h\n+\n .PHONY: generated-hdrs\n generated-hdrs: $(GENERATED_H)\n \n@@ -2208,7 +2210,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n+hook.sp hook.s hook.o: hook-list.h\n+\n+builtin/help.sp builtin/help.s builtin/help.o: config-list.h hook-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -2241,6 +2245,10 @@ command-list.h: $(wildcard Documentation/git*.txt)\n \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n \t\tcommand-list.txt >$@+ && mv $@+ $@\n \n+hook-list.h: generate-hooklist.sh Documentation/githooks.txt\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\ndiff --git a/builtin/bugreport.c b/builtin/bugreport.c\nindex 941c8d5e27..a7a1fcb8a7 100644\n--- a/builtin/bugreport.c\n+++ b/builtin/bugreport.c\n@@ -4,6 +4,7 @@\n #include \"help.h\"\n #include \"compat/compiler.h\"\n #include \"hook.h\"\n+#include \"hook-list.h\"\n \n \n static void get_system_info(struct strbuf *sys_info)\n@@ -41,39 +42,7 @@ static void get_system_info(struct strbuf *sys_info)\n \n static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n {\n-\t/*\n-\t * NEEDSWORK: Doesn't look like there is a list of all possible hooks;\n-\t * so below is a transcription of `git help hooks`. Later, this should\n-\t * be replaced with some programmatically generated list (generated from\n-\t * doc or else taken from some library which tells us about all the\n-\t * hooks)\n-\t */\n-\tstatic const char *hook[] = {\n-\t\t\"applypatch-msg\",\n-\t\t\"pre-applypatch\",\n-\t\t\"post-applypatch\",\n-\t\t\"pre-commit\",\n-\t\t\"pre-merge-commit\",\n-\t\t\"prepare-commit-msg\",\n-\t\t\"commit-msg\",\n-\t\t\"post-commit\",\n-\t\t\"pre-rebase\",\n-\t\t\"post-checkout\",\n-\t\t\"post-merge\",\n-\t\t\"pre-push\",\n-\t\t\"pre-receive\",\n-\t\t\"update\",\n-\t\t\"post-receive\",\n-\t\t\"post-update\",\n-\t\t\"push-to-checkout\",\n-\t\t\"pre-auto-gc\",\n-\t\t\"post-rewrite\",\n-\t\t\"sendemail-validate\",\n-\t\t\"fsmonitor-watchman\",\n-\t\t\"p4-pre-submit\",\n-\t\t\"post-index-change\",\n-\t};\n-\tint i;\n+\tconst char **p;\n \n \tif (nongit) {\n \t\tstrbuf_addstr(hook_info,\n@@ -81,9 +50,12 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n \t\treturn;\n \t}\n \n-\tfor (i = 0; i < ARRAY_SIZE(hook); i++)\n-\t\tif (hook_exists(hook[i]))\n-\t\t\tstrbuf_addf(hook_info, \"%s\\n\", hook[i]);\n+\tfor (p = hook_name_list; *p; p++) {\n+\t\tconst char *hook = *p;\n+\n+\t\tif (hook_exists(hook))\n+\t\t\tstrbuf_addf(hook_info, \"%s\\n\", hook);\n+\t}\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt\nindex a87841340e..c216940945 100644\n--- a/contrib/buildsystems/CMakeLists.txt\n+++ b/contrib/buildsystems/CMakeLists.txt\n@@ -602,6 +602,13 @@ if(NOT EXISTS ${CMAKE_BINARY_DIR}/config-list.h)\n \t\t\tOUTPUT_FILE ${CMAKE_BINARY_DIR}/config-list.h)\n endif()\n \n+if(NOT EXISTS ${CMAKE_BINARY_DIR}/hook-list.h)\n+\tmessage(\"Generating hook-list.h\")\n+\texecute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-hooklist.sh\n+\t\t\tWORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n+\t\t\tOUTPUT_FILE ${CMAKE_BINARY_DIR}/hook-list.h)\n+endif()\n+\n include_directories(${CMAKE_BINARY_DIR})\n \n #build\ndiff --git a/generate-hooklist.sh b/generate-hooklist.sh\nnew file mode 100755\nindex 0000000000..6d4e56d1a3\n--- /dev/null\n+++ b/generate-hooklist.sh\n@@ -0,0 +1,18 @@\n+#!/bin/sh\n+#\n+# Usage: ./generate-hooklist.sh >hook-list.h\n+\n+cat <<EOF\n+/* Automatically generated by generate-hooklist.sh */\n+\n+static const char *hook_name_list[] = {\n+EOF\n+\n+sed -n -e '/^~~~~*$/ {x; s/^.*$/\t\"&\",/; p;}; x' \\\n+\t<Documentation/githooks.txt |\n+\tLC_ALL=C sort\n+\n+cat <<EOF\n+\tNULL,\n+};\n+EOF\ndiff --git a/hook.c b/hook.c\nindex 97cd799a32..1f1db1ec9b 100644\n--- a/hook.c\n+++ b/hook.c\n@@ -1,11 +1,30 @@\n #include \"cache.h\"\n #include \"hook.h\"\n #include \"run-command.h\"\n+#include \"hook-list.h\"\n+\n+static int known_hook(const char *name)\n+{\n+\tconst char **p;\n+\tsize_t len = strlen(name);\n+\tfor (p = hook_name_list; *p; p++) {\n+\t\tconst char *hook = *p;\n+\n+\t\tif (!strncmp(name, hook, len) && hook[len] == '\\0')\n+\t\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n \n const char *find_hook(const char *name)\n {\n \tstatic struct strbuf path = STRBUF_INIT;\n \n+\tif (!known_hook(name))\n+\t\tdie(_(\"the hook '%s' is not known to git, should be in hook-list.h via githooks(5)\"),\n+\t\t    name);\n+\n \tstrbuf_reset(&path);\n \tstrbuf_git_path(&path, \"hooks/%s\", name);\n \tif (access(path.buf, X_OK) < 0) {\n-- \n2.32.0.615.g90fb4d7369\n\n"},{"id":"428764","messageId":"patch-2.3-0cf7e078ef-20210629T183325Z-avarab@gmail.com","threadId":"55950","inReplyTo":"cover-0.3-0000000000-20210629T183325Z-avarab@gmail.com","subject":"[PATCH v2 2/3] hook.c: add a hook_exists() wrapper and use it in bugreport.c","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-29T18:54:01Z","receivedAt":"2021-06-29T18:54:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Emily Shaffer <emilyshaffer@google.com>\n\nAdd a boolean version of the find_hook() function for those callers\nwho are only interested in checking whether the hook exists, not what\nthe path to it is.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/bugreport.c | 2 +-\n hook.c              | 5 +++++\n hook.h              | 5 +++++\n 3 files changed, 11 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/bugreport.c b/builtin/bugreport.c\nindex 596f079a7f..941c8d5e27 100644\n--- a/builtin/bugreport.c\n+++ b/builtin/bugreport.c\n@@ -82,7 +82,7 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n \t}\n \n \tfor (i = 0; i < ARRAY_SIZE(hook); i++)\n-\t\tif (find_hook(hook[i]))\n+\t\tif (hook_exists(hook[i]))\n \t\t\tstrbuf_addf(hook_info, \"%s\\n\", hook[i]);\n }\n \ndiff --git a/hook.c b/hook.c\nindex c4dbef1d0e..97cd799a32 100644\n--- a/hook.c\n+++ b/hook.c\n@@ -35,3 +35,8 @@ const char *find_hook(const char *name)\n \t}\n \treturn path.buf;\n }\n+\n+int hook_exists(const char *name)\n+{\n+\treturn !!find_hook(name);\n+}\ndiff --git a/hook.h b/hook.h\nindex 68624f1605..4c547ac15e 100644\n--- a/hook.h\n+++ b/hook.h\n@@ -8,4 +8,9 @@\n  */\n const char *find_hook(const char *name);\n \n+/*\n+ * A boolean version of find_hook()\n+ */\n+int hook_exists(const char *hookname);\n+\n #endif\n-- \n2.32.0.615.g90fb4d7369\n\n"},{"id":"428772","messageId":"76bd9738-65e8-3696-7934-8090b5912427@web.de","threadId":"55950","inReplyTo":"patch-3.3-ba7f01f4f6-20210629T183325Z-avarab@gmail.com","subject":"Re: [PATCH v2 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2021-06-29T19:45:53Z","receivedAt":"2021-06-29T19:46:12Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 29.06.21 um 20:54 schrieb Ævar Arnfjörð Bjarmason:\n> Make githooks(5) the source of truth for what hooks git supports, and\n> die hooks we don't know about in find_hook(). This ensures that the\n> documentation and the C code's idea about existing hooks doesn't\n> diverge.\n>\n> We still have Perl and Python code running its own hooks, but that'll\n> be addressed by Emily Shaffer's upcoming \"git hook run\" command.\n>\n> This resolves a long-standing TODO item in bugreport.c of there being\n> no centralized listing of hooks, and fixes a bug with the bugreport\n> listing only knowing about 1/4 of the p4 hooks. It didn't know about\n> the recent \"reference-transaction\" hook either.\n>\n> I have not been able to directly test the CMake change being made\n> here. Since 4c2c38e800 (ci: modification of main.yml to use cmake for\n> vs-build job, 2020-06-26) some of the Windows CI has a hard dependency\n> on CMake, this change works there, and is to my eyes an obviously\n> correct use of a pattern established in previous CMake changes,\n> namely:\n>\n>  - 061c2240b1 (Introduce CMake support for configuring Git,\n>     2020-06-12)\n>  - 709df95b78 (help: move list_config_help to builtin/help,\n>     2020-04-16)\n>  - 976aaedca0 (msvc: add a Makefile target to pre-generate the Visual\n>    Studio solution, 2019-07-29)\n>\n> The LC_ALL=C is needed because at least in my locale the dash (\"-\") is\n> ignored for the purposes of sorting, which results in a different\n> order. I'm not aware of anything in git that has a hard dependency on\n> the order, but e.g. the bugreport output would end up using whatever\n> locale was in effect when git was compiled.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> Signed-off-by: René Scharfe <l.s.r@web.de>\n\nPlease remove my sign-off line.  The code looks OK, but there are\nbasically only trivial traces of my suggestion left.  That's fine, but\nit makes my sign-off unnecessary, and I cannot certify the origin of the\nrest of the patch.  You could turn it into a Helped-by or\nContributions-by if you like.\n\n> ---\n>  .gitignore                          |  1 +\n>  Makefile                            | 10 ++++++-\n>  builtin/bugreport.c                 | 44 ++++++-----------------------\n>  contrib/buildsystems/CMakeLists.txt |  7 +++++\n>  generate-hooklist.sh                | 18 ++++++++++++\n>  hook.c                              | 19 +++++++++++++\n>  6 files changed, 62 insertions(+), 37 deletions(-)\n>  create mode 100755 generate-hooklist.sh\n>\n> diff --git a/.gitignore b/.gitignore\n> index 311841f9be..6be9de41ae 100644\n> --- a/.gitignore\n> +++ b/.gitignore\n> @@ -190,6 +190,7 @@\n>  /gitweb/static/gitweb.min.*\n>  /config-list.h\n>  /command-list.h\n> +/hook-list.h\n>  *.tar.gz\n>  *.dsc\n>  *.deb\n> diff --git a/Makefile b/Makefile\n> index d155b7be21..9b811d3548 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -817,6 +817,8 @@ XDIFF_LIB = xdiff/lib.a\n>\n>  GENERATED_H += command-list.h\n>  GENERATED_H += config-list.h\n> +GENERATED_H += hook-list.h\n> +\n>  .PHONY: generated-hdrs\n>  generated-hdrs: $(GENERATED_H)\n>\n> @@ -2208,7 +2210,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n>\n>  help.sp help.s help.o: command-list.h\n>\n> -builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n> +hook.sp hook.s hook.o: hook-list.h\n> +\n> +builtin/help.sp builtin/help.s builtin/help.o: config-list.h hook-list.h GIT-PREFIX\n>  builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n>  \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n>  \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n> @@ -2241,6 +2245,10 @@ command-list.h: $(wildcard Documentation/git*.txt)\n>  \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n>  \t\tcommand-list.txt >$@+ && mv $@+ $@\n>\n> +hook-list.h: generate-hooklist.sh Documentation/githooks.txt\n> +\t$(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh \\\n> +\t\t>$@+ && mv $@+ $@\n> +\n>  SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n>  \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n>  \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\n> diff --git a/builtin/bugreport.c b/builtin/bugreport.c\n> index 941c8d5e27..a7a1fcb8a7 100644\n> --- a/builtin/bugreport.c\n> +++ b/builtin/bugreport.c\n> @@ -4,6 +4,7 @@\n>  #include \"help.h\"\n>  #include \"compat/compiler.h\"\n>  #include \"hook.h\"\n> +#include \"hook-list.h\"\n>\n>\n>  static void get_system_info(struct strbuf *sys_info)\n> @@ -41,39 +42,7 @@ static void get_system_info(struct strbuf *sys_info)\n>\n>  static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n>  {\n> -\t/*\n> -\t * NEEDSWORK: Doesn't look like there is a list of all possible hooks;\n> -\t * so below is a transcription of `git help hooks`. Later, this should\n> -\t * be replaced with some programmatically generated list (generated from\n> -\t * doc or else taken from some library which tells us about all the\n> -\t * hooks)\n> -\t */\n> -\tstatic const char *hook[] = {\n> -\t\t\"applypatch-msg\",\n> -\t\t\"pre-applypatch\",\n> -\t\t\"post-applypatch\",\n> -\t\t\"pre-commit\",\n> -\t\t\"pre-merge-commit\",\n> -\t\t\"prepare-commit-msg\",\n> -\t\t\"commit-msg\",\n> -\t\t\"post-commit\",\n> -\t\t\"pre-rebase\",\n> -\t\t\"post-checkout\",\n> -\t\t\"post-merge\",\n> -\t\t\"pre-push\",\n> -\t\t\"pre-receive\",\n> -\t\t\"update\",\n> -\t\t\"post-receive\",\n> -\t\t\"post-update\",\n> -\t\t\"push-to-checkout\",\n> -\t\t\"pre-auto-gc\",\n> -\t\t\"post-rewrite\",\n> -\t\t\"sendemail-validate\",\n> -\t\t\"fsmonitor-watchman\",\n> -\t\t\"p4-pre-submit\",\n> -\t\t\"post-index-change\",\n> -\t};\n> -\tint i;\n> +\tconst char **p;\n>\n>  \tif (nongit) {\n>  \t\tstrbuf_addstr(hook_info,\n> @@ -81,9 +50,12 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n>  \t\treturn;\n>  \t}\n>\n> -\tfor (i = 0; i < ARRAY_SIZE(hook); i++)\n> -\t\tif (hook_exists(hook[i]))\n> -\t\t\tstrbuf_addf(hook_info, \"%s\\n\", hook[i]);\n> +\tfor (p = hook_name_list; *p; p++) {\n> +\t\tconst char *hook = *p;\n> +\n> +\t\tif (hook_exists(hook))\n> +\t\t\tstrbuf_addf(hook_info, \"%s\\n\", hook);\n> +\t}\n>  }\n>\n>  static const char * const bugreport_usage[] = {\n> diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt\n> index a87841340e..c216940945 100644\n> --- a/contrib/buildsystems/CMakeLists.txt\n> +++ b/contrib/buildsystems/CMakeLists.txt\n> @@ -602,6 +602,13 @@ if(NOT EXISTS ${CMAKE_BINARY_DIR}/config-list.h)\n>  \t\t\tOUTPUT_FILE ${CMAKE_BINARY_DIR}/config-list.h)\n>  endif()\n>\n> +if(NOT EXISTS ${CMAKE_BINARY_DIR}/hook-list.h)\n> +\tmessage(\"Generating hook-list.h\")\n> +\texecute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-hooklist.sh\n> +\t\t\tWORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n> +\t\t\tOUTPUT_FILE ${CMAKE_BINARY_DIR}/hook-list.h)\n> +endif()\n> +\n>  include_directories(${CMAKE_BINARY_DIR})\n>\n>  #build\n> diff --git a/generate-hooklist.sh b/generate-hooklist.sh\n> new file mode 100755\n> index 0000000000..6d4e56d1a3\n> --- /dev/null\n> +++ b/generate-hooklist.sh\n> @@ -0,0 +1,18 @@\n> +#!/bin/sh\n> +#\n> +# Usage: ./generate-hooklist.sh >hook-list.h\n> +\n> +cat <<EOF\n> +/* Automatically generated by generate-hooklist.sh */\n> +\n> +static const char *hook_name_list[] = {\n> +EOF\n> +\n> +sed -n -e '/^~~~~*$/ {x; s/^.*$/\t\"&\",/; p;}; x' \\\n> +\t<Documentation/githooks.txt |\n> +\tLC_ALL=C sort\n> +\n> +cat <<EOF\n> +\tNULL,\n> +};\n> +EOF\n> diff --git a/hook.c b/hook.c\n> index 97cd799a32..1f1db1ec9b 100644\n> --- a/hook.c\n> +++ b/hook.c\n> @@ -1,11 +1,30 @@\n>  #include \"cache.h\"\n>  #include \"hook.h\"\n>  #include \"run-command.h\"\n> +#include \"hook-list.h\"\n> +\n> +static int known_hook(const char *name)\n> +{\n> +\tconst char **p;\n> +\tsize_t len = strlen(name);\n> +\tfor (p = hook_name_list; *p; p++) {\n> +\t\tconst char *hook = *p;\n> +\n> +\t\tif (!strncmp(name, hook, len) && hook[len] == '\\0')\n> +\t\t\treturn 1;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n>\n>  const char *find_hook(const char *name)\n>  {\n>  \tstatic struct strbuf path = STRBUF_INIT;\n>\n> +\tif (!known_hook(name))\n> +\t\tdie(_(\"the hook '%s' is not known to git, should be in hook-list.h via githooks(5)\"),\n> +\t\t    name);\n> +\n>  \tstrbuf_reset(&path);\n>  \tstrbuf_git_path(&path, \"hooks/%s\", name);\n>  \tif (access(path.buf, X_OK) < 0) {\n>\n"},{"id":"428784","messageId":"87fsx0fhjb.fsf@evledraar.gmail.com","threadId":"55950","inReplyTo":"76bd9738-65e8-3696-7934-8090b5912427@web.de","subject":"Re: [PATCH v2 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-06-29T22:09:26Z","receivedAt":"2021-06-29T22:11:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Jun 29 2021, René Scharfe wrote:\n\n> Am 29.06.21 um 20:54 schrieb Ævar Arnfjörð Bjarmason:\n>> Make githooks(5) the source of truth for what hooks git supports, and\n>> die hooks we don't know about in find_hook(). This ensures that the\n>> documentation and the C code's idea about existing hooks doesn't\n>> diverge.\n>>\n>> We still have Perl and Python code running its own hooks, but that'll\n>> be addressed by Emily Shaffer's upcoming \"git hook run\" command.\n>>\n>> This resolves a long-standing TODO item in bugreport.c of there being\n>> no centralized listing of hooks, and fixes a bug with the bugreport\n>> listing only knowing about 1/4 of the p4 hooks. It didn't know about\n>> the recent \"reference-transaction\" hook either.\n>>\n>> I have not been able to directly test the CMake change being made\n>> here. Since 4c2c38e800 (ci: modification of main.yml to use cmake for\n>> vs-build job, 2020-06-26) some of the Windows CI has a hard dependency\n>> on CMake, this change works there, and is to my eyes an obviously\n>> correct use of a pattern established in previous CMake changes,\n>> namely:\n>>\n>>  - 061c2240b1 (Introduce CMake support for configuring Git,\n>>     2020-06-12)\n>>  - 709df95b78 (help: move list_config_help to builtin/help,\n>>     2020-04-16)\n>>  - 976aaedca0 (msvc: add a Makefile target to pre-generate the Visual\n>>    Studio solution, 2019-07-29)\n>>\n>> The LC_ALL=C is needed because at least in my locale the dash (\"-\") is\n>> ignored for the purposes of sorting, which results in a different\n>> order. I'm not aware of anything in git that has a hard dependency on\n>> the order, but e.g. the bugreport output would end up using whatever\n>> locale was in effect when git was compiled.\n>>\n>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> Signed-off-by: René Scharfe <l.s.r@web.de>\n>\n> Please remove my sign-off line.  The code looks OK, but there are\n> basically only trivial traces of my suggestion left.  That's fine, but\n> it makes my sign-off unnecessary, and I cannot certify the origin of the\n> rest of the patch.  You could turn it into a Helped-by or\n> Contributions-by if you like.\n\nIsn't that what the SOB is for though? I.e. a copyright audit trail, I\nwouldn't have come up with that sed code myself, it's copied & adjusted\nfrom your version.\n\nI can re-roll with a Helped-by if you/Junio think that's appropriate, I\njust thought this was /the/ use-case for SOB.\n"},{"id":"429583","messageId":"YOixxZQDVDKIM8bo@google.com","threadId":"55950","inReplyTo":"patch-3.3-ba7f01f4f6-20210629T183325Z-avarab@gmail.com","subject":"Re: [PATCH v2 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2021-07-09T20:29:57Z","receivedAt":"2021-07-09T20:30:07Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Jun 29, 2021 at 08:54:02PM +0200, Ævar Arnfjörð Bjarmason wrote:\n> \n> Make githooks(5) the source of truth for what hooks git supports, and\n> die hooks we don't know about in find_hook(). This ensures that the\n> documentation and the C code's idea about existing hooks doesn't\n> diverge.\n> \n> We still have Perl and Python code running its own hooks, but that'll\n> be addressed by Emily Shaffer's upcoming \"git hook run\" command.\n> \n> This resolves a long-standing TODO item in bugreport.c of there being\n> no centralized listing of hooks, and fixes a bug with the bugreport\n> listing only knowing about 1/4 of the p4 hooks. It didn't know about\n> the recent \"reference-transaction\" hook either.\n> \n> I have not been able to directly test the CMake change being made\n> here. Since 4c2c38e800 (ci: modification of main.yml to use cmake for\n> vs-build job, 2020-06-26) some of the Windows CI has a hard dependency\n> on CMake, this change works there, and is to my eyes an obviously\n> correct use of a pattern established in previous CMake changes,\n> namely:\n> \n>  - 061c2240b1 (Introduce CMake support for configuring Git,\n>     2020-06-12)\n>  - 709df95b78 (help: move list_config_help to builtin/help,\n>     2020-04-16)\n>  - 976aaedca0 (msvc: add a Makefile target to pre-generate the Visual\n>    Studio solution, 2019-07-29)\n> \n> The LC_ALL=C is needed because at least in my locale the dash (\"-\") is\n> ignored for the purposes of sorting, which results in a different\n> order. I'm not aware of anything in git that has a hard dependency on\n> the order, but e.g. the bugreport output would end up using whatever\n> locale was in effect when git was compiled.\n> \n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> Signed-off-by: René Scharfe <l.s.r@web.de>\n> ---\n>  .gitignore                          |  1 +\n>  Makefile                            | 10 ++++++-\n>  builtin/bugreport.c                 | 44 ++++++-----------------------\n>  contrib/buildsystems/CMakeLists.txt |  7 +++++\n>  generate-hooklist.sh                | 18 ++++++++++++\n>  hook.c                              | 19 +++++++++++++\n>  6 files changed, 62 insertions(+), 37 deletions(-)\n>  create mode 100755 generate-hooklist.sh\n> \n> diff --git a/.gitignore b/.gitignore\n> index 311841f9be..6be9de41ae 100644\n> --- a/.gitignore\n> +++ b/.gitignore\n> @@ -190,6 +190,7 @@\n>  /gitweb/static/gitweb.min.*\n>  /config-list.h\n>  /command-list.h\n> +/hook-list.h\n>  *.tar.gz\n>  *.dsc\n>  *.deb\n> diff --git a/Makefile b/Makefile\n> index d155b7be21..9b811d3548 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -817,6 +817,8 @@ XDIFF_LIB = xdiff/lib.a\n>  \n>  GENERATED_H += command-list.h\n>  GENERATED_H += config-list.h\n> +GENERATED_H += hook-list.h\n> +\n>  .PHONY: generated-hdrs\n>  generated-hdrs: $(GENERATED_H)\n>  \n> @@ -2208,7 +2210,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n>  \n>  help.sp help.s help.o: command-list.h\n>  \n> -builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n> +hook.sp hook.s hook.o: hook-list.h\n> +\n> +builtin/help.sp builtin/help.s builtin/help.o: config-list.h hook-list.h GIT-PREFIX\n>  builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n>  \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n>  \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n> @@ -2241,6 +2245,10 @@ command-list.h: $(wildcard Documentation/git*.txt)\n>  \t\t$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \\\n>  \t\tcommand-list.txt >$@+ && mv $@+ $@\n>  \n> +hook-list.h: generate-hooklist.sh Documentation/githooks.txt\n> +\t$(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh \\\n> +\t\t>$@+ && mv $@+ $@\n> +\n>  SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n>  \t$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\\\n>  \t$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\\\n> diff --git a/builtin/bugreport.c b/builtin/bugreport.c\n> index 941c8d5e27..a7a1fcb8a7 100644\n> --- a/builtin/bugreport.c\n> +++ b/builtin/bugreport.c\n> @@ -4,6 +4,7 @@\n>  #include \"help.h\"\n>  #include \"compat/compiler.h\"\n>  #include \"hook.h\"\n> +#include \"hook-list.h\"\n>  \n>  \n>  static void get_system_info(struct strbuf *sys_info)\n> @@ -41,39 +42,7 @@ static void get_system_info(struct strbuf *sys_info)\n>  \n>  static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n>  {\n> -\t/*\n> -\t * NEEDSWORK: Doesn't look like there is a list of all possible hooks;\n> -\t * so below is a transcription of `git help hooks`. Later, this should\n> -\t * be replaced with some programmatically generated list (generated from\n> -\t * doc or else taken from some library which tells us about all the\n> -\t * hooks)\n> -\t */\n> -\tstatic const char *hook[] = {\n> -\t\t\"applypatch-msg\",\n> -\t\t\"pre-applypatch\",\n> -\t\t\"post-applypatch\",\n> -\t\t\"pre-commit\",\n> -\t\t\"pre-merge-commit\",\n> -\t\t\"prepare-commit-msg\",\n> -\t\t\"commit-msg\",\n> -\t\t\"post-commit\",\n> -\t\t\"pre-rebase\",\n> -\t\t\"post-checkout\",\n> -\t\t\"post-merge\",\n> -\t\t\"pre-push\",\n> -\t\t\"pre-receive\",\n> -\t\t\"update\",\n> -\t\t\"post-receive\",\n> -\t\t\"post-update\",\n> -\t\t\"push-to-checkout\",\n> -\t\t\"pre-auto-gc\",\n> -\t\t\"post-rewrite\",\n> -\t\t\"sendemail-validate\",\n> -\t\t\"fsmonitor-watchman\",\n> -\t\t\"p4-pre-submit\",\n> -\t\t\"post-index-change\",\n> -\t};\n> -\tint i;\n> +\tconst char **p;\n>  \n>  \tif (nongit) {\n>  \t\tstrbuf_addstr(hook_info,\n> @@ -81,9 +50,12 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)\n>  \t\treturn;\n>  \t}\n>  \n> -\tfor (i = 0; i < ARRAY_SIZE(hook); i++)\n> -\t\tif (hook_exists(hook[i]))\n> -\t\t\tstrbuf_addf(hook_info, \"%s\\n\", hook[i]);\n> +\tfor (p = hook_name_list; *p; p++) {\n> +\t\tconst char *hook = *p;\n> +\n> +\t\tif (hook_exists(hook))\n> +\t\t\tstrbuf_addf(hook_info, \"%s\\n\", hook);\n> +\t}\n>  }\n>  \n>  static const char * const bugreport_usage[] = {\n> diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt\n> index a87841340e..c216940945 100644\n> --- a/contrib/buildsystems/CMakeLists.txt\n> +++ b/contrib/buildsystems/CMakeLists.txt\n> @@ -602,6 +602,13 @@ if(NOT EXISTS ${CMAKE_BINARY_DIR}/config-list.h)\n>  \t\t\tOUTPUT_FILE ${CMAKE_BINARY_DIR}/config-list.h)\n>  endif()\n>  \n> +if(NOT EXISTS ${CMAKE_BINARY_DIR}/hook-list.h)\n> +\tmessage(\"Generating hook-list.h\")\n> +\texecute_process(COMMAND ${SH_EXE} ${CMAKE_SOURCE_DIR}/generate-hooklist.sh\n> +\t\t\tWORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n> +\t\t\tOUTPUT_FILE ${CMAKE_BINARY_DIR}/hook-list.h)\n> +endif()\n> +\n>  include_directories(${CMAKE_BINARY_DIR})\n>  \n>  #build\n> diff --git a/generate-hooklist.sh b/generate-hooklist.sh\n> new file mode 100755\n> index 0000000000..6d4e56d1a3\n> --- /dev/null\n> +++ b/generate-hooklist.sh\n> @@ -0,0 +1,18 @@\n> +#!/bin/sh\n> +#\n> +# Usage: ./generate-hooklist.sh >hook-list.h\n> +\n> +cat <<EOF\n> +/* Automatically generated by generate-hooklist.sh */\n> +\n> +static const char *hook_name_list[] = {\n> +EOF\n> +\n> +sed -n -e '/^~~~~*$/ {x; s/^.*$/\t\"&\",/; p;}; x' \\\n> +\t<Documentation/githooks.txt |\n> +\tLC_ALL=C sort\n> +\n> +cat <<EOF\n> +\tNULL,\n> +};\n> +EOF\n> diff --git a/hook.c b/hook.c\n> index 97cd799a32..1f1db1ec9b 100644\n> --- a/hook.c\n> +++ b/hook.c\n> @@ -1,11 +1,30 @@\n>  #include \"cache.h\"\n>  #include \"hook.h\"\n>  #include \"run-command.h\"\n> +#include \"hook-list.h\"\n> +\n> +static int known_hook(const char *name)\n> +{\n> +\tconst char **p;\n> +\tsize_t len = strlen(name);\n> +\tfor (p = hook_name_list; *p; p++) {\n> +\t\tconst char *hook = *p;\n> +\n> +\t\tif (!strncmp(name, hook, len) && hook[len] == '\\0')\n> +\t\t\treturn 1;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n>  \n>  const char *find_hook(const char *name)\n>  {\n>  \tstatic struct strbuf path = STRBUF_INIT;\n>  \n> +\tif (!known_hook(name))\n> +\t\tdie(_(\"the hook '%s' is not known to git, should be in hook-list.h via githooks(5)\"),\n> +\t\t    name);\n> +\n\nI'm not sure that it's necessary to require this, to be honest. I see a\nuse case for wrappers to want to store and run hooks in an idiomatic\nway, and doing so by instructing their users to stick in\n.git/hooks/wrapper-clone (for example) and then calling 'git hook run\nwrapper-clone'. That's doubly compelling in a later config-based-hooks\nworld where 'git hook run' gets you free multihook features like\nordering and parallelism. I will likely want to remove this when\nrebasing my config-based hooks work on top of your restart.\n\n>  \tstrbuf_reset(&path);\n>  \tstrbuf_git_path(&path, \"hooks/%s\", name);\n>  \tif (access(path.buf, X_OK) < 0) {\n> -- \n> 2.32.0.615.g90fb4d7369\n> \n"},{"id":"429604","messageId":"87wnpy4jyb.fsf@evledraar.gmail.com","threadId":"55950","inReplyTo":"YOixxZQDVDKIM8bo@google.com","subject":"Re: [PATCH v2 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-07-10T09:03:50Z","receivedAt":"2021-07-10T09:06:10Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Jul 09 2021, Emily Shaffer wrote:\n\n> On Tue, Jun 29, 2021 at 08:54:02PM +0200, Ævar Arnfjörð Bjarmason wrote:\n>>  const char *find_hook(const char *name)\n>>  {\n>>  \tstatic struct strbuf path = STRBUF_INIT;\n>>  \n>> +\tif (!known_hook(name))\n>> +\t\tdie(_(\"the hook '%s' is not known to git, should be in hook-list.h via githooks(5)\"),\n>> +\t\t    name);\n>> +\n>\n> I'm not sure that it's necessary to require this, to be honest. I see a\n> use case for wrappers to want to store and run hooks in an idiomatic\n> way, and doing so by instructing their users to stick in\n> .git/hooks/wrapper-clone (for example) and then calling 'git hook run\n> wrapper-clone'. That's doubly compelling in a later config-based-hooks\n> world where 'git hook run' gets you free multihook features like\n> ordering and parallelism. I will likely want to remove this when\n> rebasing my config-based hooks work on top of your restart.\n\nIndeed, FWIW this was part of my general approach of narrowly supporting\nexisting git behavior only with 'git hook run', i.e. there's no general\n\"run this thing like a hook for me\" now, so we're not losing anything by\nnot having it support that.\n\nBut yes, I can see how \"run this script for me as if though it were a\nhook\" would be useful, will be trivial to support it & still somehow\nassert typos/that hook-list.h / githooks.txt is a source of truth about\nour known hooks.\n"},{"id":"429835","messageId":"YOysQ7ewkpLZMP2I@google.com","threadId":"55950","inReplyTo":"87wnpy4jyb.fsf@evledraar.gmail.com","subject":"Re: [PATCH v2 3/3] hook-list.h: add a generated list of hooks, like config-list.h","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2021-07-12T20:55:31Z","receivedAt":"2021-07-12T20:55:40Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Sat, Jul 10, 2021 at 11:03:50AM +0200, Ævar Arnfjörð Bjarmason wrote:\n> \n> \n> On Fri, Jul 09 2021, Emily Shaffer wrote:\n> \n> > On Tue, Jun 29, 2021 at 08:54:02PM +0200, Ævar Arnfjörð Bjarmason wrote:\n> >>  const char *find_hook(const char *name)\n> >>  {\n> >>  \tstatic struct strbuf path = STRBUF_INIT;\n> >>  \n> >> +\tif (!known_hook(name))\n> >> +\t\tdie(_(\"the hook '%s' is not known to git, should be in hook-list.h via githooks(5)\"),\n> >> +\t\t    name);\n> >> +\n> >\n> > I'm not sure that it's necessary to require this, to be honest. I see a\n> > use case for wrappers to want to store and run hooks in an idiomatic\n> > way, and doing so by instructing their users to stick in\n> > .git/hooks/wrapper-clone (for example) and then calling 'git hook run\n> > wrapper-clone'. That's doubly compelling in a later config-based-hooks\n> > world where 'git hook run' gets you free multihook features like\n> > ordering and parallelism. I will likely want to remove this when\n> > rebasing my config-based hooks work on top of your restart.\n> \n> Indeed, FWIW this was part of my general approach of narrowly supporting\n> existing git behavior only with 'git hook run', i.e. there's no general\n> \"run this thing like a hook for me\" now, so we're not losing anything by\n> not having it support that.\n> \n> But yes, I can see how \"run this script for me as if though it were a\n> hook\" would be useful, will be trivial to support it & still somehow\n> assert typos/that hook-list.h / githooks.txt is a source of truth about\n> our known hooks.\n\nHm, I see - you're using the BUG() to gently remind people that they\nshould go and update githooks.txt if they call find_hook(\"new-hook\").\nOk, I'll add a flag or a wrapper or something in my own rebase - so 'git\nhook run' doesn't check but internal calls do.\n\nThanks for explaining the intent better.\n - Emily\n"}]}