Message ID | 20210311021037.3001235-5-emilyshaffer@google.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | config-based hooks | expand |
On Thu, Mar 11 2021, Emily Shaffer wrote: > Historically, hooks are declared by placing an executable into > $GIT_DIR/hooks/$HOOKNAME (or $HOOKDIR/$HOOKNAME). Although hooks taken > from the config are more featureful than hooks placed in the $HOOKDIR, > those hooks should not stop working for users who already have them. > Let's list them to the user, but instead of displaying a config scope > (e.g. "global: blah") we can prefix them with "hookdir:". > > Signed-off-by: Emily Shaffer <emilyshaffer@google.com> > --- > > Notes: > Since v7, fix some nits from Jonathan Tan. The largest is to move reference to > "hookdir annotation" from this commit to the next one which introduces the > hook.runHookDir option. > > builtin/hook.c | 11 +++++++++-- > hook.c | 17 +++++++++++++++++ > hook.h | 1 + > t/t1360-config-based-hooks.sh | 19 +++++++++++++++++++ > 4 files changed, 46 insertions(+), 2 deletions(-) > > diff --git a/builtin/hook.c b/builtin/hook.c > index bb64cd77ca..c8fbfbb39d 100644 > --- a/builtin/hook.c > +++ b/builtin/hook.c > @@ -40,10 +40,15 @@ static int list(int argc, const char **argv, const char *prefix) > > list_for_each(pos, head) { > struct hook *item = list_entry(pos, struct hook, list); > - if (item) > + item = list_entry(pos, struct hook, list); > + if (item) { > + /* Don't translate 'hookdir' - it matches the config */ Let's prefix comments for translators with /* TRANSLATORS: .., see the coding style doc. That's what they'll see, and this is useful to them. Better yet have a note here about the first argument being 'system', 'local' etc., which I had to source spelunge for, and translators won't have any idea about unless the magic parameter is documented. > +setup_hookdir () { > + mkdir .git/hooks > + write_script .git/hooks/pre-commit <<-EOF > + echo \"Legacy Hook\" Nit, "'s not needed, but it also seems nothing uses this, so if it's just a pass-through script either "exit 0", or actually check if it's run or something? > [...] > +test_expect_success 'git hook list shows hooks from the hookdir' ' > + setup_hookdir && > + > + cat >expected <<-EOF && > + hookdir: $(pwd)/.git/hooks/pre-commit > + EOF > + > + git hook list pre-commit >actual && > + test_cmp expected actual > +' Ah, so it's just checking if it exists...
On Fri, Mar 12, 2021 at 09:30:04AM +0100, Ævar Arnfjörð Bjarmason wrote: > > > On Thu, Mar 11 2021, Emily Shaffer wrote: > > > Historically, hooks are declared by placing an executable into > > $GIT_DIR/hooks/$HOOKNAME (or $HOOKDIR/$HOOKNAME). Although hooks taken > > from the config are more featureful than hooks placed in the $HOOKDIR, > > those hooks should not stop working for users who already have them. > > Let's list them to the user, but instead of displaying a config scope > > (e.g. "global: blah") we can prefix them with "hookdir:". > > > > Signed-off-by: Emily Shaffer <emilyshaffer@google.com> > > --- > > > > Notes: > > Since v7, fix some nits from Jonathan Tan. The largest is to move reference to > > "hookdir annotation" from this commit to the next one which introduces the > > hook.runHookDir option. > > > > builtin/hook.c | 11 +++++++++-- > > hook.c | 17 +++++++++++++++++ > > hook.h | 1 + > > t/t1360-config-based-hooks.sh | 19 +++++++++++++++++++ > > 4 files changed, 46 insertions(+), 2 deletions(-) > > > > diff --git a/builtin/hook.c b/builtin/hook.c > > index bb64cd77ca..c8fbfbb39d 100644 > > --- a/builtin/hook.c > > +++ b/builtin/hook.c > > @@ -40,10 +40,15 @@ static int list(int argc, const char **argv, const char *prefix) > > > > list_for_each(pos, head) { > > struct hook *item = list_entry(pos, struct hook, list); > > - if (item) > > + item = list_entry(pos, struct hook, list); > > + if (item) { > > + /* Don't translate 'hookdir' - it matches the config */ > > Let's prefix comments for translators with /* TRANSLATORS: .., see the > coding style doc. That's what they'll see, and this is useful to them. > > Better yet have a note here about the first argument being 'system', > 'local' etc., which I had to source spelunge for, and translators won't > have any idea about unless the magic parameter is documented. It's not a comment for translators. It's a comment for someone helpful who comes later and says "oh, none of this is marked for translation, I'd better fix that." > > > +setup_hookdir () { > > + mkdir .git/hooks > > + write_script .git/hooks/pre-commit <<-EOF > > + echo \"Legacy Hook\" > > Nit, "'s not needed, but it also seems nothing uses this, so if it's > just a pass-through script either "exit 0", or actually check if it's > run or something? The output is checked in the run tests later on. I can remove it for this commit if you want. > > > [...] > > +test_expect_success 'git hook list shows hooks from the hookdir' ' > > + setup_hookdir && > > + > > + cat >expected <<-EOF && > > + hookdir: $(pwd)/.git/hooks/pre-commit > > + EOF > > + > > + git hook list pre-commit >actual && > > + test_cmp expected actual > > +' > > Ah, so it's just checking if it exists...
Emily Shaffer <emilyshaffer@google.com> writes: >> > @@ -40,10 +40,15 @@ static int list(int argc, const char **argv, const char *prefix) >> > >> > list_for_each(pos, head) { >> > struct hook *item = list_entry(pos, struct hook, list); >> > - if (item) >> > + item = list_entry(pos, struct hook, list); >> > + if (item) { >> > + /* Don't translate 'hookdir' - it matches the config */ >> >> Let's prefix comments for translators with /* TRANSLATORS: .., see the >> coding style doc. That's what they'll see, and this is useful to them. >> >> Better yet have a note here about the first argument being 'system', >> 'local' etc., which I had to source spelunge for, and translators won't >> have any idea about unless the magic parameter is documented. > > It's not a comment for translators. It's a comment for someone helpful > who comes later and says "oh, none of this is marked for translation, > I'd better fix that." Then, it is not limited to "hookdir", is it? Resurrecting the elided part back here: Not just we do not want "hookdir" placed inside _(), printf("%s: %s\n", + (item->from_hookdir + ? "hookdir" + : config_scope_name(item->origin)), item->command.buf); we do not want the "%s: %s\n" to be placed inside _() and get munged into "%2$s: %1$s\n" for languages that want the order swapped, for example. So perhaps the comment should be about the entire output, i.e. "don't translate the output from this helper, as it is meant to be machine parseable", or something?
On Wed, Mar 24, 2021 at 3:12 PM Junio C Hamano <gitster@pobox.com> wrote: > Not just we do not want "hookdir" placed inside _(), > > printf("%s: %s\n", > + (item->from_hookdir > + ? "hookdir" > + : config_scope_name(item->origin)), > item->command.buf); > > we do not want the "%s: %s\n" to be placed inside _() and get munged > into "%2$s: %1$s\n" for languages that want the order swapped, for > example. > > So perhaps the comment should be about the entire output, i.e. > "don't translate the output from this helper, as it is meant to be > machine parseable", or something? Having the word "translate" in the comment automatically implies localization, which confuses the issue. It would be clearer to avoid that word altogether. Perhaps something along the lines of: /* machine-parseable output; do not apply _() localization */
On Wed, Mar 24, 2021 at 03:23:30PM -0400, Eric Sunshine wrote: > > On Wed, Mar 24, 2021 at 3:12 PM Junio C Hamano <gitster@pobox.com> wrote: > > Not just we do not want "hookdir" placed inside _(), > > > > printf("%s: %s\n", > > + (item->from_hookdir > > + ? "hookdir" > > + : config_scope_name(item->origin)), > > item->command.buf); > > > > we do not want the "%s: %s\n" to be placed inside _() and get munged > > into "%2$s: %1$s\n" for languages that want the order swapped, for > > example. > > > > So perhaps the comment should be about the entire output, i.e. > > "don't translate the output from this helper, as it is meant to be > > machine parseable", or something? > > Having the word "translate" in the comment automatically implies > localization, which confuses the issue. It would be clearer to avoid > that word altogether. Perhaps something along the lines of: > > /* machine-parseable output; do not apply _() localization */ After I read Ævar's comments on the next patch in this series, I decided to rework the comments and translation markers for this whole section. if (item) { if (item->from_hookdir) { /* * TRANSLATORS: do not translate 'hookdir' as * it matches the config setting. */ switch (should_run_hookdir) { case HOOKDIR_NO: printf(_("hookdir: %s (will not run)\n"), item->command.buf); break; case HOOKDIR_ERROR: printf(_("hookdir: %s (will error and not run)\n"), item->command.buf); break; case HOOKDIR_INTERACTIVE: printf(_("hookdir: %s (will prompt)\n"), item->command.buf); break; case HOOKDIR_WARN: printf(_("hookdir: %s (will warn but run)\n"), item->command.buf); break; case HOOKDIR_YES: /* * The default behavior should agree with * hook.c:configured_hookdir_opt(). HOOKDIR_UNKNOWN should just * do the default behavior. */ case HOOKDIR_UNKNOWN: default: printf(_("hookdir: %s\n"), item->command.buf); break; } } else { /* * TRANSLATORS: "<config scope>: <path>". Both fields * should be left untranslated; config scope matches the * output of 'git config --show-scope'. Marked for * translation to provide better RTL support later. */ printf(_("%s: %s\n"), config_scope_name(item->origin), item->command.buf); } }
diff --git a/builtin/hook.c b/builtin/hook.c index bb64cd77ca..c8fbfbb39d 100644 --- a/builtin/hook.c +++ b/builtin/hook.c @@ -40,10 +40,15 @@ static int list(int argc, const char **argv, const char *prefix) list_for_each(pos, head) { struct hook *item = list_entry(pos, struct hook, list); - if (item) + item = list_entry(pos, struct hook, list); + if (item) { + /* Don't translate 'hookdir' - it matches the config */ printf("%s: %s\n", - config_scope_name(item->origin), + (item->from_hookdir + ? "hookdir" + : config_scope_name(item->origin)), item->command.buf); + } } clear_hook_list(head); @@ -60,6 +65,8 @@ int cmd_hook(int argc, const char **argv, const char *prefix) if (argc < 2) usage_with_options(builtin_hook_usage, builtin_hook_options); + git_config(git_default_config, NULL); + if (!strcmp(argv[1], "list")) return list(argc - 1, argv + 1, prefix); diff --git a/hook.c b/hook.c index fede40e925..080e25696b 100644 --- a/hook.c +++ b/hook.c @@ -2,6 +2,7 @@ #include "hook.h" #include "config.h" +#include "run-command.h" void free_hook(struct hook *ptr) { @@ -35,6 +36,7 @@ static void append_or_move_hook(struct list_head *head, const char *command) to_add = xmalloc(sizeof(*to_add)); strbuf_init(&to_add->command, 0); strbuf_addstr(&to_add->command, command); + to_add->from_hookdir = 0; } /* re-set the scope so we show where an override was specified */ @@ -115,6 +117,21 @@ struct list_head* hook_list(const struct strbuf* hookname) git_config(hook_config_lookup, &cb_data); + if (have_git_dir()) { + const char *legacy_hook_path = find_hook(hookname->buf); + + /* Unconditionally add legacy hook, but annotate it. */ + if (legacy_hook_path) { + struct hook *legacy_hook; + + append_or_move_hook(hook_head, + absolute_path(legacy_hook_path)); + legacy_hook = list_entry(hook_head->prev, struct hook, + list); + legacy_hook->from_hookdir = 1; + } + } + strbuf_release(&hook_key); return hook_head; } diff --git a/hook.h b/hook.h index e48dfc6d27..a97d43670d 100644 --- a/hook.h +++ b/hook.h @@ -11,6 +11,7 @@ struct hook { enum config_scope origin; /* The literal command to run. */ struct strbuf command; + unsigned from_hookdir : 1; }; /* diff --git a/t/t1360-config-based-hooks.sh b/t/t1360-config-based-hooks.sh index 6e4a3e763f..0f12af4659 100755 --- a/t/t1360-config-based-hooks.sh +++ b/t/t1360-config-based-hooks.sh @@ -23,6 +23,14 @@ setup_hookcmd () { test_config_global hookcmd.abc.command "/path/abc" --add } +setup_hookdir () { + mkdir .git/hooks + write_script .git/hooks/pre-commit <<-EOF + echo \"Legacy Hook\" + EOF + test_when_finished rm -rf .git/hooks +} + test_expect_success 'git hook rejects commands without a mode' ' test_must_fail git hook pre-commit ' @@ -85,4 +93,15 @@ test_expect_success 'git hook list reorders on duplicate commands' ' test_cmp expected actual ' +test_expect_success 'git hook list shows hooks from the hookdir' ' + setup_hookdir && + + cat >expected <<-EOF && + hookdir: $(pwd)/.git/hooks/pre-commit + EOF + + git hook list pre-commit >actual && + test_cmp expected actual +' + test_done
Historically, hooks are declared by placing an executable into $GIT_DIR/hooks/$HOOKNAME (or $HOOKDIR/$HOOKNAME). Although hooks taken from the config are more featureful than hooks placed in the $HOOKDIR, those hooks should not stop working for users who already have them. Let's list them to the user, but instead of displaying a config scope (e.g. "global: blah") we can prefix them with "hookdir:". Signed-off-by: Emily Shaffer <emilyshaffer@google.com> --- Notes: Since v7, fix some nits from Jonathan Tan. The largest is to move reference to "hookdir annotation" from this commit to the next one which introduces the hook.runHookDir option. builtin/hook.c | 11 +++++++++-- hook.c | 17 +++++++++++++++++ hook.h | 1 + t/t1360-config-based-hooks.sh | 19 +++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-)