115
struct hook_config_cache_entry {
116
char *command;
117
enum config_scope scope;
118
+ bool disabled;
119
};
120
121
/*
214
* every item's string is the hook's friendly-name and its util pointer is
215
* the corresponding command string. Both strings are owned by the map.
216
*
216
- * Disabled hooks and hooks missing a command are already filtered out at
217
- * parse time, so callers can iterate the list directly.
217
+ * Disabled hooks are kept in the cache with entry->disabled set, so that
218
+ * "git hook list" can display them. A non-disabled hook missing a command
219
+ * is fatal; a disabled hook missing a command emits a warning and is kept
220
+ * in the cache with entry->command = NULL.
221
*/
222
void hook_cache_clear(struct strmap *cache)
223
{
266
struct hook_config_cache_entry *entry;
267
char *command;
268
266
- /* filter out disabled hooks */
267
- if (unsorted_string_list_lookup(&cb_data.disabled_hooks,
268
- hname))
269
- continue;
269
+ bool is_disabled =
270
+ !!unsorted_string_list_lookup(
271
+ &cb_data.disabled_hooks, hname);
272
273
command = strmap_get(&cb_data.commands, hname);
272
- if (!command)
273
- die(_("'hook.%s.command' must be configured or "
274
- "'hook.%s.event' must be removed;"
275
- " aborting."), hname, hname);
274
+ if (!command) {
275
+ if (is_disabled)
276
+ warning(_("disabled hook '%s' has no "
277
+ "command configured"), hname);
278
+ else
279
+ die(_("'hook.%s.command' must be configured or "
280
+ "'hook.%s.event' must be removed;"
281
+ " aborting."), hname, hname);
282
+ }
283
284
/* util stores a cache entry; owned by the cache. */
285
CALLOC_ARRAY(entry, 1);
279
- entry->command = xstrdup(command);
286
+ entry->command = xstrdup_or_null(command);
287
entry->scope = scope;
288
+ entry->disabled = is_disabled;
289
string_list_append(hooks, hname)->util = entry;
290
}
291
366
367
hook->kind = HOOK_CONFIGURED;
368
hook->u.configured.friendly_name = xstrdup(friendly_name);
361
- hook->u.configured.command = xstrdup(entry->command);
369
+ hook->u.configured.command =
370
+ entry->command ? xstrdup(entry->command) : NULL;
371
hook->u.configured.scope = entry->scope;
372
+ hook->u.configured.disabled = entry->disabled;
373
374
string_list_append(list, friendly_name)->util = hook;
375
}
407
int hook_exists(struct repository *r, const char *name)
408
{
409
struct string_list *hooks = list_hooks(r, name, NULL);
400
- int exists = hooks->nr > 0;
410
+ int exists = 0;
411
+
412
+ for (size_t i = 0; i < hooks->nr; i++) {
413
+ struct hook *h = hooks->items[i].util;
414
+ if (h->kind == HOOK_TRADITIONAL ||
415
+ !h->u.configured.disabled) {
416
+ exists = 1;
417
+ break;
418
+ }
419
+ }
420
string_list_clear_func(hooks, hook_free);
421
free(hooks);
422
return exists;
431
struct string_list *hook_list = hook_cb->hook_command_list;
432
struct hook *h;
433
415
- if (hook_cb->hook_to_run_index >= hook_list->nr)
416
- return 0;
417
-
418
- h = hook_list->items[hook_cb->hook_to_run_index++].util;
434
+ do {
435
+ if (hook_cb->hook_to_run_index >= hook_list->nr)
436
+ return 0;
437
+ h = hook_list->items[hook_cb->hook_to_run_index++].util;
438
+ } while (h->kind == HOOK_CONFIGURED && h->u.configured.disabled);
439
440
cp->no_stdin = 1;
441
strvec_pushv(&cp->env, hook_cb->options->env.v);