>From 0f435feee87dc96b2e4890a5a5de7b1d0c0befe1 Mon Sep 17 00:00:00 2001 From: magisterRab <sv_91@xxxxxxxx> Date: Tue, 1 Apr 2014 17:02:10 +0400 Subject: [PATCH] hook for git status Signed-off-by: Ivan Suvorov <sv_91@xxxxxxxx> --- hook for git status allows you to display additional fields when you run git status. For example, for a hook with a content of STATUS_FILE=$1 NEW_SCOPE=$2 cat > "$STATUS_FILE" <<EOF Binary files add --binary lib.lib lib.a lib.o $NEW_SCOPE Other files add --other dll.lib dll.a dll.o EOF here's how it will look conclusion Binary files: (use "git add --binary <file>..." to include in what will be committed) lib.a lib.lib lib.o Other files: (use "git add --other <file>..." to include in what will be committed) dll.a dll.lib dll.o Documentation/git-status.txt | 10 +++ Documentation/githooks.txt | 9 +++ builtin/commit.c | 7 +++ t/t7513-status-hook.sh | 137 +++++++++++++++++++++++++++++++++++++++++ templates/hooks--status.sample | 36 +++++++++++ wt-status.c | 88 ++++++++++++++++++++++++++ wt-status.h | 1 + 7 files changed, 288 insertions(+) create mode 100644 t/t7513-status-hook.sh create mode 100755 templates/hooks--status.sample diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index def635f..6c81323 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -94,6 +94,10 @@ configuration variable documented in linkgit:git-config[1]. respectively. +--no-run-hook:: + This option bypasses the status hooks. + See also linkgit:githooks[5]. + OUTPUT ------ The output from this command is designed to be used as a commit @@ -218,9 +222,15 @@ ignored submodules you can either use the --ignore-submodules=dirty command line option or the 'git submodule summary' command, which shows a similar output but does not honor these settings. +HOOKS +----- +This command can run `status` hooks. See linkgit:githooks[5] for more +information. + SEE ALSO -------- linkgit:gitignore[5] +linkgit:githooks[5] GIT --- diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index d954bf6..e3e3206 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -381,6 +381,15 @@ rebase:: The commits are guaranteed to be listed in the order that they were processed by rebase. +status +~~~~~~~~~~~ + +This hook is invoked by 'git status', and can be bypassed +with `--no-run-hook` option. Exiting with non-zero status from this script +causes the 'git status' to abort. + +The default 'status' hook, when enabled, adds to the output +of the command 'git status' several files names. GIT --- diff --git a/builtin/commit.c b/builtin/commit.c index 9cfef6c..16c430f 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -122,6 +122,7 @@ static enum commit_whence whence; static int sequencer_in_use; static int use_editor = 1, include_status = 1; static int show_ignored_in_status, have_option_m; +static int no_run_hook = 0; static const char *only_include_assumed; static struct strbuf message = STRBUF_INIT; @@ -1276,6 +1277,8 @@ int cmd_status(int argc, const char **argv, const char *prefix) N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")), + OPT_BOOL(0, "no-run-hook", &no_run_hook, + N_("bypass status hook")), OPT_END(), }; @@ -1296,6 +1299,10 @@ int cmd_status(int argc, const char **argv, const char *prefix) PATHSPEC_PREFER_FULL, prefix, argv); + if (no_run_hook) + s.run_hook = 0; + else + s.run_hook = 1; read_cache_preload(&s.pathspec); refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL); diff --git a/t/t7513-status-hook.sh b/t/t7513-status-hook.sh new file mode 100644 index 0000000..584137e --- /dev/null +++ b/t/t7513-status-hook.sh @@ -0,0 +1,137 @@ +#!/bin/sh + +test_description='status hook' + +. ./test-lib.sh + +test_expect_success 'with no hook' ' + + echo "foo" > file && + git status + +' + +test_expect_success '--no-run-hook with no hook' ' + + echo "bar" > file && + git status --no-run-hook + +' + +test_expect_success 'with no hook short' ' + + echo "foo" > file && + git status -s + +' + +test_expect_success '--no-run-hook with no hook short' ' + + echo "bar" > file && + git status --no-run-hook -s + +' + +# now install hook that always succeeds +HOOKDIR="$(git rev-parse --git-dir)/hooks" +HOOK="$HOOKDIR/status" +mkdir -p "$HOOKDIR" +cat > "$HOOK" <<EOF +#!/bin/sh +exit 0 +EOF +chmod +x "$HOOK" + +test_expect_success 'with succeeding hook' ' + + echo "more" >> file && + git status + +' + +test_expect_success '--no-run-hook with succeeding hook' ' + + echo "even more" >> file && + git status --no-run-hook + +' + +test_expect_success 'with succeeding hook short' ' + + echo "more" >> file && + git status -s + +' + +test_expect_success '--no-run-hook with succeeding hook short' ' + + echo "even more" >> file && + git status --no-run-hook -s + +' + +# now a hook that fails +cat > "$HOOK" <<EOF +#!/bin/sh +exit 1 +EOF + +test_expect_success 'with failing hook' ' + + echo "another" >> file && + test_must_fail git status + +' + +test_expect_success '--no-run-hook with failing hook' ' + + echo "stuff" >> file && + git status --no-run-hook + +' + +test_expect_success 'with failing hook short' ' + + echo "another" >> file && + test_must_fail git status -s + +' + +test_expect_success '--no-run-hook with failing hook short' ' + + echo "stuff" >> file && + git status --no-run-hook -s + +' + +chmod -x "$HOOK" +test_expect_success POSIXPERM 'with non-executable hook' ' + + echo "content" >> file && + git status + +' + +test_expect_success POSIXPERM '--no-run-hook with non-executable hook' ' + + echo "more content" >> file && + git status --no-run-hook + +' + +test_expect_success POSIXPERM 'with non-executable hook short' ' + + echo "content" >> file && + git status -s + +' + +test_expect_success POSIXPERM '--no-run-hook with non-executable hook short' ' + + echo "more content" >> file && + git status --no-run-hook -s + +' +chmod +x "$HOOK" + +test_done diff --git a/templates/hooks--status.sample b/templates/hooks--status.sample new file mode 100755 index 0000000..8739b44 --- /dev/null +++ b/templates/hooks--status.sample @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be status. +# Called by "git status" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the status. +# +# To enable this hook, rename this file to "status". +# +# This hook is called with the following parameters: +# +# $1 -- Name and path of the file, from which it will take additional information for hook status +# $2 -- line separating the blocks of information +# +# Information in the file must be contained in the blocks, the blocks +# must be separated by a line separating. The first line of the block +# must contain the type of files in the block, the second line should +# contain a command to include in what will be committed, continue +# until the end of the block or file files names, one file name per line. + +STATUS_FILE=$1 +NEW_SCOPE=$2 + +cat > "$STATUS_FILE" <<EOF +Binary files +add --binary +lib.lib +lib.a +lib.o +$NEW_SCOPE +Other files +add --other +dll.lib +dll.a +dll.o +EOF diff --git a/wt-status.c b/wt-status.c index ec7344e..f5d5f72 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1406,6 +1406,60 @@ void wt_status_print(struct wt_status *s) } else printf(_("nothing to commit, working directory clean\n")); } + + if (s->run_hook) { + const char *NEW_SCOPE = "==================="; + + const char *path_to_status_file = git_path("STATUS-MSG"); + fclose(fopen(path_to_status_file, "w")); + + if (run_hook_le(NULL, "status", path_to_status_file, NEW_SCOPE, NULL) != 0) + die(_("hook status has error")); + + FILE *f = fopen(path_to_status_file, "rt"); + struct strbuf buf; + strbuf_init(&buf, 0); + + struct string_list other_files; + struct strbuf description_files; + strbuf_init(&description_files, 0); + struct strbuf operation_files; + strbuf_init(&operation_files, 0); + int scope_line_number = 0; + + while (strbuf_getline(&buf, f, '\n') != EOF) { + if (strcmp(buf.buf, NEW_SCOPE) == 0) { + scope_line_number = 0; + wt_status_print_other(s, &other_files, + _(description_files.buf), operation_files.buf); + + strbuf_release(&description_files); + strbuf_release(&operation_files); + string_list_clear(&other_files, 1); + } else { + if (scope_line_number == 0) { + strbuf_init(&description_files, 0); + strbuf_addbuf(&description_files, &buf); + } else if (scope_line_number == 1) { + strbuf_init(&operation_files, 0); + strbuf_addbuf(&operation_files, &buf); + } else { + size_t size_buf; + const char *line = strbuf_detach(&buf, &size_buf); + string_list_insert(&other_files, line); + } + scope_line_number++; + } + } + wt_status_print_other(s, &other_files, + _(description_files.buf), operation_files.buf); + strbuf_release(&buf); + strbuf_release(&description_files); + strbuf_release(&operation_files); + string_list_clear(&other_files, 1); + + fclose(f); + } } static void wt_shortstatus_unmerged(struct string_list_item *it, @@ -1599,6 +1653,40 @@ void wt_shortstatus_print(struct wt_status *s) it = &(s->ignored.items[i]); wt_shortstatus_other(it, s, "!!"); } + + if (s->run_hook) { + const char *NEW_SCOPE = "==================="; + + const char *path_to_status_file = git_path("STATUS-MSG"); + fclose(fopen(path_to_status_file, "w")); + + if (run_hook_le(NULL, "status", path_to_status_file, NEW_SCOPE, NULL) != 0) + die(_("hook status has error")); + + FILE *f = fopen(path_to_status_file, "rt"); + struct strbuf buf; + strbuf_init(&buf, 0); + + int scope_line_number = 0; + + while (strbuf_getline(&buf, f, '\n') != EOF) { + if (strcmp(buf.buf, NEW_SCOPE) == 0) { + scope_line_number = 0; + } else { + if (scope_line_number == 0) { + } else if (scope_line_number == 1) { + } else { + struct string_list_item it; + it.string = buf.buf; + wt_shortstatus_other(&it, s, "::"); + } + scope_line_number++; + } + } + strbuf_release(&buf); + + fclose(f); + } } void wt_porcelain_print(struct wt_status *s) diff --git a/wt-status.h b/wt-status.h index 283a9fe..ff94b22 100644 --- a/wt-status.h +++ b/wt-status.h @@ -55,6 +55,7 @@ struct wt_status { int relative_paths; int submodule_summary; int show_ignored_files; + int run_hook; enum untracked_status_type show_untracked_files; const char *ignore_submodule_arg; char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN]; -- 1.8.5.2.msysgit.0��.n��������+%������w��{.n��������n�r������&��z�ޗ�zf���h���~����������_��+v���)ߣ�