Re: [PATCH v2 6/7] config: allow configuration of multiple hook error behavior
- From
Duy Nguyen <pclouds@gmail.com>
- Date
- May 14, 2019, 13:20 UTC
- Message-ID
- <CACsJy8BN32Jm62MQPLsRwKST8DDNZ7NxnJbsqBO3PJ0K2qU-Ng@mail.gmail.com>
- In-Reply-To
- <20190514002332.121089-8-sandals@crustytoothpaste.net>
On Tue, May 14, 2019 at 7:24 AM brian m. carlson <sandals@crustytoothpaste.net> wrote:
> > There are a variety of situations in which a user may want an error > behavior for multiple hooks other than the default. Add a config option, > hook.<name>.errorBehavior to allow users to customize this behavior on a
An alternative name is onError, probably more often used for event callbacks. But I don't know, maybe errorBehavior is actually better.
> per-hook basis. Provide options for the default behavior (exiting
should we fall back to hook.errorBehavior? That allows people to set global policy, then customize just a small set of weird hooks.
Show 36 quoted lines
> early), executing all hooks and succeeding if all hooks succeed, or
> executing all hooks and succeeding if any hook succeeds.
> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
> ---
> config.c | 27 +++++++++++++
> run-command.c | 42 +++++++++++++++++---
> run-command.h | 5 +++
> t/lib-hooks.sh | 106 ++++++++++++++++++++++++++++++++++++++++++++++++-
> 4 files changed, 173 insertions(+), 7 deletions(-)
>
> diff --git a/config.c b/config.c
> index c2846df3f1..9cba4061a9 100644
> --- a/config.c
> +++ b/config.c
> @@ -19,6 +19,7 @@
> #include "utf8.h"
> #include "dir.h"
> #include "color.h"
> +#include "run-command.h"
>
> struct config_source {
> struct config_source *prev;
> @@ -1093,6 +1094,29 @@ int git_config_color(char *dest, const char *var, const char *value)
> return 0;
> }
>
> +static int git_default_hook_config(const char *key, const char *value)
> +{
> + const char *hook;
> + size_t key_len;
> + uintptr_t behavior;
> +
> + key += strlen("hook.");
> + if (strip_suffix(key, ".errorbehavior", &key_len)) {
> + hook = xmemdupz(key, key_len);
> + if (!strcmp(value, "stop-on-first"))maybe stop-on-first-error (or if you go with the "onError" name, I think "stop" is enough). I know "stop on/after first hook" does not really make any sense when you think about it. Maybe stop-on-first is sufficient.
I was going to suggest strcasecmp. But core.whitespace (also has multiple-word-values) already sets a precedent on strcmp. I think we're good. Or mostly good, I don't know, we still accept False, false and FALSE.
> + behavior = HOOK_ERROR_STOP_ON_FIRST;
This is basically the logical "and" behavior in a C expression. Which makes me think if anybody's crazy enough to need the "or" counterpart (i.e. run hooks, expect failure, keep going until the first success).
I guess it's a crazy mode. We should not care about until a real use case shows up.
> + else if (!strcmp(value, "report-any-error"))
I couldn't guess based on this name alone, whether we continue or stop after the reporting part. The 7/7 document makes it clear though. So all good.
Show 9 quoted lines
> diff --git a/run-command.c b/run-command.c > index 191d6f6f7e..70fb19a55b 100644 > --- a/run-command.c > +++ b/run-command.c > @@ -1308,6 +1308,8 @@ int async_with_fork(void) > #endif > } > > +struct string_list hook_error_behavior = STRING_LIST_INIT_NODUP;
Maybe stick this in 'struct repository'. I know most config variables are still global. But I think we have to move/reorganize them at some point. Most may end up in 'struct repository'.
Show 44 quoted lines
> @@ -1401,18 +1403,48 @@ int for_each_hook(const char *name,
> void *data)
> {
> struct string_list paths = STRING_LIST_INIT_DUP;
> - int i, ret = 0;
> + int i, hret = 0;
> + uintptr_t behavior = HOOK_ERROR_STOP_ON_FIRST;
> + struct string_list_item *item;
> + /* Use -2 as sentinel because failure to exec is -1. */
> + int ret = -2;
> +
> + item = string_list_lookup(&hook_error_behavior, name);
> + if (item)
> + behavior = (uintptr_t)item->util;
>
> find_hooks(name, &paths);
> for (i = 0; i < paths.nr; i++) {
> const char *p = paths.items[i].string;
>
> - ret = handler(name, p, data);
> - if (ret)
> - break;
> + hret = handler(name, p, data);
> + switch (behavior) {
> + case HOOK_ERROR_STOP_ON_FIRST:
> + if (hret) {
> + ret = hret;
> + goto out;
> + }
> + break;
> + case HOOK_ERROR_REPORT_ANY_SUCCESS:
> + if (ret == -2)
> + ret = 1;
> + if (!hret)
> + ret = 0;
> + break;
> + case HOOK_ERROR_REPORT_ANY_ERROR:
> + if (ret == -2)
> + ret = 0;
> + if (hret)
> + ret = hret;
> + break;
> + default:
> + BUG("unknown hook error behavior");maybe BUG(".. behavior %d", behavior);Show 10 quoted lines
> + } > } > - > +out: > string_list_clear(&paths, 0); > + if (ret == -2) > + return 0; > return ret; > } >
-- Duy