#ifndef HOOK_H #define HOOK_H #include "strvec.h" #include "run-command.h" #include "string-list.h" #include "strmap.h" struct repository; /** * Represents a hook command to be run. * Hooks can be: * 1. "traditional" (found in the hooks directory) * 2. "configured" (defined in Git's configuration via hook..event). * The 'kind' field determines which part of the union 'u' is valid. */ struct hook { enum { HOOK_TRADITIONAL, HOOK_CONFIGURED, } kind; union { struct { const char *path; } traditional; struct { const char *friendly_name; const char *command; } configured; } u; /** * Opaque data pointer used to keep internal state across callback calls. * * It can be accessed directly via the third hook callback arg: * struct ... *state = pp_task_cb; * * The caller is responsible for managing the memory for this data by * providing alloc/free callbacks to `run_hooks_opt`. * * Only useful when using `run_hooks_opt.feed_pipe`, otherwise ignore it. */ void *feed_pipe_cb_data; }; typedef void (*cb_data_free_fn)(void *data); typedef void *(*cb_data_alloc_fn)(void *init_ctx); struct run_hooks_opt { /* Environment vars to be set for each hook */ struct strvec env; /* Args to be passed to each hook */ struct strvec args; /* Emit an error if the hook is missing */ unsigned int error_if_missing:1; /** * Number of processes to parallelize across. * * If > 1, output will be buffered and de-interleaved (ungroup=0). * If == 1, output will be real-time (ungroup=1). */ unsigned int jobs; /** * An optional initial working directory for the hook, * translates to "struct child_process"'s "dir" member. */ const char *dir; /** * A pointer which if provided will be set to 1 or 0 depending * on if a hook was started, regardless of whether or not that * was successful. I.e. if the underlying start_command() was * successful this will be set to 1. * * Used for avoiding TOCTOU races in code that would otherwise * call hook_exist() after a "maybe hook run" to see if a hook * was invoked. */ int *invoked_hook; /** * Send the hook's stdout to stderr. * * This is the default behavior for all hooks except pre-push, * which has separate stdout and stderr streams for backwards * compatibility reasons. */ unsigned int stdout_to_stderr:1; /** * Path to file which should be piped to stdin for each hook. */ const char *path_to_stdin; /** * Callback used to incrementally feed a child hook stdin pipe. * * Useful especially if a hook consumes large quantities of data * (e.g. a list of all refs in a client push), so feeding it via * in-memory strings or slurping to/from files is inefficient. * While the callback allows piecemeal writing, it can also be * used for smaller inputs, where it gets called only once. * * Add hook callback initalization context to `feed_pipe_ctx`. * Add hook callback internal state to `feed_pipe_cb_data`. * */ feed_pipe_fn feed_pipe; /** * Opaque data pointer used to pass context to `feed_pipe_fn`. * * It can be accessed via the second callback arg 'pp_cb': * ((struct hook_cb_data *) pp_cb)->hook_cb->options->feed_pipe_ctx; * * The caller is responsible for managing the memory for this data. * Only useful when using `run_hooks_opt.feed_pipe`, otherwise ignore it. */ void *feed_pipe_ctx; /** * Some hooks need to create a fresh `feed_pipe_cb_data` internal state, * so they can keep track of progress without affecting one another. * * If provided, this function will be called to alloc & initialize the * `feed_pipe_cb_data` for each hook. * * The `feed_pipe_ctx` pointer can be used to pass initialization data. */ cb_data_alloc_fn feed_pipe_cb_data_alloc; /** * Called to free the memory initialized by `feed_pipe_cb_data_alloc`. * * Must always be provided when `feed_pipe_cb_data_alloc` is provided. */ cb_data_free_fn feed_pipe_cb_data_free; }; #define RUN_HOOKS_OPT_INIT { \ .env = STRVEC_INIT, \ .args = STRVEC_INIT, \ .stdout_to_stderr = 1, \ .jobs = 1, \ } struct hook_cb_data { /* rc reflects the cumulative failure state */ int rc; const char *hook_name; /** * A list of hook commands/paths to run for the 'hook_name' event. * * The 'string' member of each item holds the path (for traditional hooks) * or the unique friendly-name for hooks specified in configs. * The 'util' member of each item points to the corresponding struct hook. */ struct string_list *hook_command_list; /* Iterator/cursor for the above list, pointing to the next hook to run. */ size_t hook_to_run_index; struct run_hooks_opt *options; }; /** * Provides a list of hook commands to run for the 'hookname' event. * * This function consolidates hooks from two sources: * 1. The config-based hooks (not yet implemented). * 2. The "traditional" hook found in the repository hooks directory * (e.g., .git/hooks/pre-commit). * * The list is ordered by execution priority. * * The caller is responsible for freeing the memory of the returned list * using string_list_clear() and free(). */ struct string_list *list_hooks(struct repository *r, const char *hookname, struct run_hooks_opt *options); /** * Frees the memory allocated for the hook list, including the `struct hook` * items and their internal state. */ void hook_list_clear(struct string_list *hooks, cb_data_free_fn cb_data_free); /** * Frees the hook configuration cache stored in `struct repository`. * Called by repo_clear(). */ void hook_cache_clear(struct strmap *cache); /** * Returns the path to the hook file, or NULL if the hook is missing * or disabled. Note that this points to static storage that will be * overwritten by further calls to find_hook and run_hook_*. */ const char *find_hook(struct repository *r, const char *name); /** * A boolean version of find_hook() */ int hook_exists(struct repository *r, const char *hookname); /** * Takes a `hook_name`, resolves it to a path with find_hook(), and * runs the hook for you with the options specified in "struct * run_hooks opt". Will free memory associated with the "struct run_hooks_opt". * * Returns the status code of the run hook, or a negative value on * error(). */ int run_hooks_opt(struct repository *r, const char *hook_name, struct run_hooks_opt *options); /** * A wrapper for run_hooks_opt() which provides a dummy "struct * run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT". */ int run_hooks(struct repository *r, const char *hook_name); /** * Like run_hooks(), a wrapper for run_hooks_opt(). * * In addition to the wrapping behavior provided by run_hooks(), this * wrapper takes a list of strings terminated by a NULL * argument. These things will be used as positional arguments to the * hook. This function behaves like the old run_hook_le() API. */ LAST_ARG_MUST_BE_NULL int run_hooks_l(struct repository *r, const char *hook_name, ...); #endif