mirror of
https://github.com/git/git.git
synced 2026-02-26 01:43:43 +00:00
Teach the hook.[hc] library to parse configs to populate the list of hooks to run for a given event. Multiple commands can be specified for a given hook by providing "hook.<friendly-name>.command = <path-to-hook>" and "hook.<friendly-name>.event = <hook-event>" lines. Hooks will be started in config order of the "hook.<name>.event" lines and will be run sequentially (.jobs == 1) like before. Running the hooks in parallel will be enabled in a future patch. The "traditional" hook from the hookdir is run last, if present. A strmap cache is added to struct repository to avoid re-reading the configs on each rook run. This is useful for hooks like the ref-transaction which gets executed multiple times per process. Examples: $ git config --get-regexp "^hook\." hook.bar.command=~/bar.sh hook.bar.event=pre-commit # Will run ~/bar.sh, then .git/hooks/pre-commit $ git hook run pre-commit Signed-off-by: Emily Shaffer <emilyshaffer@google.com> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
240 lines
6.9 KiB
C
240 lines
6.9 KiB
C
#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.<name>.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
|