* [PATCH 0/5] "diff --check" and whitespace enhancements @ 2007-12-13 13:32 Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 1/5] "diff --check" should affect exit status Wincent Colaiuta 0 siblings, 1 reply; 24+ messages in thread From: Wincent Colaiuta @ 2007-12-13 13:32 UTC (permalink / raw) To: git; +Cc: gitster This is a repost of the topic I posted yesterday, rebased on top of master and omitting the changes already applied to it. Of the series the most interesting is [3/5], where I implement Junio's suggestion of further refactoring to get rid of emit_line_with_ws(). [1/5] "diff --check" should affect exit status [2/5] New version of pre-commit hook [3/5] Unify whitespace checking [4/5] Make "diff --check" output match "git apply" [5/5] Add tests for "git diff --check" with core.whitespace options I think there are still some opportunities for further refactoring and clean-up, but this is a good start. Overall the refactoring saves duplication and reduces the line count (apart from the tests, of course, where line count goes unequivocally up). Documentation/diff-options.txt | 4 +- builtin-apply.c | 56 +++---------- builtin-diff-files.c | 2 + builtin-diff-index.c | 2 + builtin-diff-tree.c | 28 +++--- builtin-diff.c | 3 +- cache.h | 4 + diff.c | 172 +++++++++--------------------------- diff.h | 1 + t/t4015-diff-whitespace.sh | 189 +++++++++++++++++++++++++++++++++++++++- templates/hooks--pre-commit | 67 ++------------- ws.c | 105 ++++++++++++++++++++++ 12 files changed, 379 insertions(+), 254 deletions(-) Cheers, Wincent ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 1/5] "diff --check" should affect exit status 2007-12-13 13:32 [PATCH 0/5] "diff --check" and whitespace enhancements Wincent Colaiuta @ 2007-12-13 13:32 ` Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 2/5] New version of pre-commit hook Wincent Colaiuta ` (2 more replies) 0 siblings, 3 replies; 24+ messages in thread From: Wincent Colaiuta @ 2007-12-13 13:32 UTC (permalink / raw) To: git; +Cc: gitster, Wincent Colaiuta "git diff" has a --check option that can be used to check for whitespace problems but it only reported by printing warnings to the console. Now when the --check option is used we give a non-zero exit status, making "git diff --check" nicer to use in scripts and hooks. Signed-off-by: Wincent Colaiuta <win@wincent.com> --- Documentation/diff-options.txt | 4 +- builtin-diff-files.c | 2 + builtin-diff-index.c | 2 + builtin-diff-tree.c | 28 ++++---- builtin-diff.c | 3 +- diff.c | 37 +++++++---- diff.h | 1 + t/t4015-diff-whitespace.sh | 137 +++++++++++++++++++++++++++++++++++++++- 8 files changed, 184 insertions(+), 30 deletions(-) diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 5d22b7b..9ecc1d7 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -93,7 +93,9 @@ endif::git-format-patch[] --check:: Warn if changes introduce trailing whitespace - or an indent that uses a space before a tab. + or an indent that uses a space before a tab. Exits with + non-zero status if problems are found. Not compatible with + --exit-code. --full-index:: Instead of the first handful characters, show full diff --git a/builtin-diff-files.c b/builtin-diff-files.c index 046b7e3..4afc872 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -33,5 +33,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) result = run_diff_files_cmd(&rev, argc, argv); if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; + if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) + return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; return result; } diff --git a/builtin-diff-index.c b/builtin-diff-index.c index 556c506..532b284 100644 --- a/builtin-diff-index.c +++ b/builtin-diff-index.c @@ -46,5 +46,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) result = run_diff_index(&rev, cached); if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; + if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) + return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; return result; } diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 2e13716..9ab90cb 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -117,23 +117,23 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) break; } - if (!read_stdin) - return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS) - && DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES); + if (read_stdin) { + if (opt->diffopt.detect_rename) + opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE | + DIFF_SETUP_USE_CACHE); + while (fgets(line, sizeof(line), stdin)) { + unsigned char sha1[20]; - if (opt->diffopt.detect_rename) - opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE | - DIFF_SETUP_USE_CACHE); - while (fgets(line, sizeof(line), stdin)) { - unsigned char sha1[20]; - - if (get_sha1_hex(line, sha1)) { - fputs(line, stdout); - fflush(stdout); + if (get_sha1_hex(line, sha1)) { + fputs(line, stdout); + fflush(stdout); + } + else + diff_tree_stdin(line); } - else - diff_tree_stdin(line); } + if (opt->diffopt.output_format & DIFF_FORMAT_CHECKDIFF) + return DIFF_OPT_TST(&opt->diffopt, CHECK_FAILED) != 0; return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS) && DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES); } diff --git a/builtin-diff.c b/builtin-diff.c index 55fb84c..86d01a3 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -353,7 +353,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix) ent, ents); if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) result = DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; - + if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) + return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; if (1 < rev.diffopt.skip_stat_unmatch) refresh_index_quietly(); return result; diff --git a/diff.c b/diff.c index 9c79ee2..39109a6 100644 --- a/diff.c +++ b/diff.c @@ -1031,6 +1031,7 @@ struct checkdiff_t { const char *filename; int lineno, color_diff; unsigned ws_rule; + unsigned status; }; static void checkdiff_consume(void *priv, char *line, unsigned long len) @@ -1064,6 +1065,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) white_space_at_end = 1; if (space_before_tab || white_space_at_end) { + data->status = 1; printf("%s:%d: %s", data->filename, data->lineno, ws); if (space_before_tab) { printf("space before tab"); @@ -1454,7 +1456,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b, diff_free_filespec_data(two); } -static void builtin_checkdiff(const char *name_a, const char *name_b, +static int builtin_checkdiff(const char *name_a, const char *name_b, struct diff_filespec *one, struct diff_filespec *two, struct diff_options *o) { @@ -1462,7 +1464,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, struct checkdiff_t data; if (!two) - return; + return 0; memset(&data, 0, sizeof(data)); data.xm.consume = checkdiff_consume; @@ -1491,6 +1493,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, free_and_return: diff_free_filespec_data(one); diff_free_filespec_data(two); + return data.status; } struct diff_filespec *alloc_filespec(const char *path) @@ -2075,14 +2078,14 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o, builtin_diffstat(name, other, p->one, p->two, diffstat, o, complete_rewrite); } -static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) +static int run_checkdiff(struct diff_filepair *p, struct diff_options *o) { const char *name; const char *other; if (DIFF_PAIR_UNMERGED(p)) { /* unmerged */ - return; + return 0; } name = p->one->path; @@ -2091,7 +2094,7 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) diff_fill_sha1_info(p->one); diff_fill_sha1_info(p->two); - builtin_checkdiff(name, other, p->one, p->two, o); + return builtin_checkdiff(name, other, p->one, p->two, o); } void diff_setup(struct diff_options *options) @@ -2121,7 +2124,12 @@ int diff_setup_done(struct diff_options *options) if (options->output_format & DIFF_FORMAT_NAME_STATUS) count++; if (options->output_format & DIFF_FORMAT_CHECKDIFF) + { count++; + if (DIFF_OPT_TST(options, QUIET) || + DIFF_OPT_TST(options, EXIT_WITH_STATUS)) + die("--check may not be used with --quiet or --exit-code"); + } if (options->output_format & DIFF_FORMAT_NO_OUTPUT) count++; if (count > 1) @@ -2588,17 +2596,17 @@ static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o, run_diffstat(p, o, diffstat); } -static void diff_flush_checkdiff(struct diff_filepair *p, +static int diff_flush_checkdiff(struct diff_filepair *p, struct diff_options *o) { if (diff_unmodified_pair(p)) - return; + return 0; if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) || (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode))) - return; /* no tree diffs in patch format */ + return 0; /* no tree diffs in patch format */ - run_checkdiff(p, o); + return run_checkdiff(p, o); } int diff_queue_is_empty(void) @@ -2717,16 +2725,19 @@ static int check_pair_status(struct diff_filepair *p) } } -static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt) +static int flush_one_pair(struct diff_filepair *p, struct diff_options *opt) { int fmt = opt->output_format; if (fmt & DIFF_FORMAT_CHECKDIFF) - diff_flush_checkdiff(p, opt); + return diff_flush_checkdiff(p, opt); else if (fmt & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS)) diff_flush_raw(p, opt); else if (fmt & DIFF_FORMAT_NAME) write_name_quoted(p->two->path, stdout, opt->line_termination); + + /* return value only matters with DIFF_FORMAT_CHECKDIFF */ + return 0; } static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs) @@ -2965,8 +2976,8 @@ void diff_flush(struct diff_options *options) DIFF_FORMAT_CHECKDIFF)) { for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - if (check_pair_status(p)) - flush_one_pair(p, options); + if (check_pair_status(p) && flush_one_pair(p, options)) + DIFF_OPT_SET(options, CHECK_FAILED); } separator++; } diff --git a/diff.h b/diff.h index a52496a..5d50d93 100644 --- a/diff.h +++ b/diff.h @@ -59,6 +59,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_ALLOW_EXTERNAL (1 << 13) #define DIFF_OPT_EXIT_WITH_STATUS (1 << 14) #define DIFF_OPT_REVERSE_DIFF (1 << 15) +#define DIFF_OPT_CHECK_FAILED (1 << 16) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 6adf9d1..dc538b3 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -117,7 +117,6 @@ EOF git diff -b > out test_expect_success 'another test, with -b' 'git diff expect out' - test_expect_success 'check mixed spaces and tabs in indent' ' # This is indented with SP HT SP. @@ -126,4 +125,140 @@ test_expect_success 'check mixed spaces and tabs in indent' ' ' +test_expect_success 'check with no whitespace errors' ' + + git commit -m "snapshot" && + echo "foo();" > x && + git diff --check + +' + +test_expect_failure 'check with trailing whitespace' ' + + echo "foo(); " > x && + git diff --check + +' + +test_expect_failure 'check with space before tab in indent' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git diff --check + +' + +test_expect_failure '--check and --exit-code are exclusive' ' + + git checkout x && + git diff --check --exit-code + +' + +test_expect_failure '--check and --quiet are exclusive' ' + + git diff --check --quiet + +' + +test_expect_success 'check staged with no whitespace errors' ' + + echo "foo();" > x && + git add x && + git diff --cached --check + +' + +test_expect_failure 'check staged with trailing whitespace' ' + + echo "foo(); " > x && + git add x && + git diff --cached --check + +' + +test_expect_failure 'check staged with space before tab in indent' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + git diff --cached --check + +' + +test_expect_success 'check with no whitespace errors (diff-index)' ' + + echo "foo();" > x && + git add x && + git diff-index --check HEAD + +' + +test_expect_failure 'check with trailing whitespace (diff-index)' ' + + echo "foo(); " > x && + git add x && + git diff-index --check HEAD + +' + +test_expect_failure 'check with space before tab in indent (diff-index)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + git diff-index --check HEAD + +' + +test_expect_success 'check staged with no whitespace errors (diff-index)' ' + + echo "foo();" > x && + git add x && + git diff-index --cached --check HEAD + +' + +test_expect_failure 'check staged with trailing whitespace (diff-index)' ' + + echo "foo(); " > x && + git add x && + git diff-index --cached --check HEAD + +' + +test_expect_failure 'check staged with space before tab in indent (diff-index)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + git diff-index --cached --check HEAD + +' + +test_expect_success 'check with no whitespace errors (diff-tree)' ' + + echo "foo();" > x && + git commit -m "new commit" x && + git diff-tree --check HEAD^ HEAD + +' + +test_expect_failure 'check with trailing whitespace (diff-tree)' ' + + echo "foo(); " > x && + git commit -m "another commit" x && + git diff-tree --check HEAD^ HEAD + +' + +test_expect_failure 'check with space before tab in indent (diff-tree)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git commit -m "yet another" x && + git diff-tree --check HEAD^ HEAD + +' + test_done -- 1.5.4.rc0.4.g50348 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 2/5] New version of pre-commit hook 2007-12-13 13:32 ` [PATCH 1/5] "diff --check" should affect exit status Wincent Colaiuta @ 2007-12-13 13:32 ` Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 3/5] Unify whitespace checking Wincent Colaiuta 2007-12-14 0:17 ` [PATCH 2/5] New version of pre-commit hook Jakub Narebski 2007-12-13 19:45 ` [PATCH] Don't use the pager when running "git diff --check" Wincent Colaiuta 2007-12-13 23:51 ` [PATCH 1/5] "diff --check" should affect exit status Junio C Hamano 2 siblings, 2 replies; 24+ messages in thread From: Wincent Colaiuta @ 2007-12-13 13:32 UTC (permalink / raw) To: git; +Cc: gitster, Wincent Colaiuta Now that "git diff --check" indicates problems with its exit code the pre-commit hook becomes a trivial one-liner. A side effect of this is that when "git diff --check" learns to detect problems according to core.whitespace in the future, the hook's behaviour will evolve to match without any changes required. Signed-off-by: Wincent Colaiuta <win@wincent.com> --- templates/hooks--pre-commit | 67 ++++-------------------------------------- 1 files changed, 7 insertions(+), 60 deletions(-) diff --git a/templates/hooks--pre-commit b/templates/hooks--pre-commit index 7092bae..f8c7be7 100644 --- a/templates/hooks--pre-commit +++ b/templates/hooks--pre-commit @@ -7,64 +7,11 @@ # # To enable this hook, make this file executable. -# This is slightly modified from Andrew Morton's Perfect Patch. -# Lines you introduce should not have trailing whitespace. -# Also check for an indentation that has SP before a TAB. +git-diff-index -M --cached --check HEAD -- && exit 0 -if git-rev-parse --verify HEAD 2>/dev/null -then - git-diff-index -p -M --cached HEAD -- -else - # NEEDSWORK: we should produce a diff with an empty tree here - # if we want to do the same verification for the initial import. - : -fi | -perl -e ' - my $found_bad = 0; - my $filename; - my $reported_filename = ""; - my $lineno; - sub bad_line { - my ($why, $line) = @_; - if (!$found_bad) { - print STDERR "*\n"; - print STDERR "* You have some suspicious patch lines:\n"; - print STDERR "*\n"; - $found_bad = 1; - } - if ($reported_filename ne $filename) { - print STDERR "* In $filename\n"; - $reported_filename = $filename; - } - print STDERR "* $why (line $lineno)\n"; - print STDERR "$filename:$lineno:$line\n"; - } - while (<>) { - if (m|^diff --git a/(.*) b/\1$|) { - $filename = $1; - next; - } - if (/^@@ -\S+ \+(\d+)/) { - $lineno = $1 - 1; - next; - } - if (/^ /) { - $lineno++; - next; - } - if (s/^\+//) { - $lineno++; - chomp; - if (/\s$/) { - bad_line("trailing whitespace", $_); - } - if (/^\s* \t/) { - bad_line("indent SP followed by a TAB", $_); - } - if (/^(?:[<>=]){7}/) { - bad_line("unresolved merge conflict", $_); - } - } - } - exit($found_bad); -' +cat >&2 <<EOF +fatal: commit aborted due to whitespace problems +specify --no-verify to bypass these checks and commit anyway +EOF + +exit 1 -- 1.5.4.rc0.4.g50348 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 3/5] Unify whitespace checking 2007-12-13 13:32 ` [PATCH 2/5] New version of pre-commit hook Wincent Colaiuta @ 2007-12-13 13:32 ` Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 4/5] Make "diff --check" output match "git apply" Wincent Colaiuta ` (2 more replies) 2007-12-14 0:17 ` [PATCH 2/5] New version of pre-commit hook Jakub Narebski 1 sibling, 3 replies; 24+ messages in thread From: Wincent Colaiuta @ 2007-12-13 13:32 UTC (permalink / raw) To: git; +Cc: gitster, Wincent Colaiuta This commit unifies three separate places where whitespace checking was performed: - the whitespace checking previously done in builtin-apply.c is extracted into a function in ws.c - the equivalent logic in "git diff" is removed - the emit_line_with_ws() function is also removed because that also rechecks the shitespace, and its functionality is rolled into ws.c The new function is called check_and_emit_line() and it does two things: checks a line for whitespace errors and optionally emits it. The checking is based on lines of content rather than patch lines (in other words, the caller must strip the leading "+" or "-"); this was suggested by Junio on the mailing list to allow for a future extension to "git show" to display whitespace errors in blobs. At the same time we teach it to report all classes of whitespace errors found for a given line rather than reporting only the first found error. Signed-off-by: Wincent Colaiuta <win@wincent.com> --- builtin-apply.c | 54 +++-------------- cache.h | 4 + diff.c | 138 ++++++-------------------------------------- t/t4015-diff-whitespace.sh | 2 +- ws.c | 105 +++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 164 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index f2e9a33..ab393f3 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -900,56 +900,22 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc static void check_whitespace(const char *line, int len, unsigned ws_rule) { - const char *err = "Adds trailing whitespace"; - int seen_space = 0; - int i; - - /* - * We know len is at least two, since we have a '+' and we - * checked that the last character was a '\n' before calling - * this function. That is, an addition of an empty line would - * check the '+' here. Sneaky... - */ - if ((ws_rule & WS_TRAILING_SPACE) && isspace(line[len-2])) - goto error; - - /* - * Make sure that there is no space followed by a tab in - * indentation. - */ - if (ws_rule & WS_SPACE_BEFORE_TAB) { - err = "Space in indent is followed by a tab"; - for (i = 1; i < len; i++) { - if (line[i] == '\t') { - if (seen_space) - goto error; - } - else if (line[i] == ' ') - seen_space = 1; - else - break; - } - } - - /* - * Make sure that the indentation does not contain more than - * 8 spaces. - */ - if ((ws_rule & WS_INDENT_WITH_NON_TAB) && - (8 < len) && !strncmp("+ ", line, 9)) { - err = "Indent more than 8 places with spaces"; - goto error; - } - return; + char *err; + unsigned result = check_and_emit_line(line + 1, len - 1, ws_rule, + NULL, NULL, NULL, NULL); + if (!result) + return; - error: whitespace_error++; if (squelch_whitespace_errors && squelch_whitespace_errors < whitespace_error) ; - else + else { + err = whitespace_error_string(result); fprintf(stderr, "%s.\n%s:%d:%.*s\n", - err, patch_input_file, linenr, len-2, line+1); + err, patch_input_file, linenr, len - 2, line + 1); + free(err); + } } /* diff --git a/cache.h b/cache.h index 27d90fe..39331c2 100644 --- a/cache.h +++ b/cache.h @@ -655,6 +655,10 @@ void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, i extern unsigned whitespace_rule_cfg; extern unsigned whitespace_rule(const char *); extern unsigned parse_whitespace_rule(const char *); +extern unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, + FILE *stream, const char *set, + const char *reset, const char *ws); +extern char *whitespace_error_string(unsigned ws); /* ls-files */ int pathspec_match(const char **spec, char *matched, const char *filename, int skiplen); diff --git a/diff.c b/diff.c index 39109a6..d96a4ac 100644 --- a/diff.c +++ b/diff.c @@ -486,88 +486,9 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix) static void emit_line(const char *set, const char *reset, const char *line, int len) { - if (len > 0 && line[len-1] == '\n') - len--; fputs(set, stdout); fwrite(line, len, 1, stdout); - puts(reset); -} - -static void emit_line_with_ws(int nparents, - const char *set, const char *reset, const char *ws, - const char *line, int len, unsigned ws_rule) -{ - int col0 = nparents; - int last_tab_in_indent = -1; - int last_space_in_indent = -1; - int i; - int tail = len; - int need_highlight_leading_space = 0; - /* - * The line is a newly added line. Does it have funny leading - * whitespaces? In indent, SP should never precede a TAB. In - * addition, under "indent with non tab" rule, there should not - * be more than 8 consecutive spaces. - */ - for (i = col0; i < len; i++) { - if (line[i] == '\t') { - last_tab_in_indent = i; - if ((ws_rule & WS_SPACE_BEFORE_TAB) && - 0 <= last_space_in_indent) - need_highlight_leading_space = 1; - } - else if (line[i] == ' ') - last_space_in_indent = i; - else - break; - } - if ((ws_rule & WS_INDENT_WITH_NON_TAB) && - 0 <= last_space_in_indent && - last_tab_in_indent < 0 && - 8 <= (i - col0)) { - last_tab_in_indent = i; - need_highlight_leading_space = 1; - } - fputs(set, stdout); - fwrite(line, col0, 1, stdout); fputs(reset, stdout); - if (((i == len) || line[i] == '\n') && i != col0) { - /* The whole line was indent */ - emit_line(ws, reset, line + col0, len - col0); - return; - } - i = col0; - if (need_highlight_leading_space) { - while (i < last_tab_in_indent) { - if (line[i] == ' ') { - fputs(ws, stdout); - putchar(' '); - fputs(reset, stdout); - } - else - putchar(line[i]); - i++; - } - } - tail = len - 1; - if (line[tail] == '\n' && i < tail) - tail--; - if (ws_rule & WS_TRAILING_SPACE) { - while (i < tail) { - if (!isspace(line[tail])) - break; - tail--; - } - } - if ((i < tail && line[tail + 1] != '\n')) { - /* This has whitespace between tail+1..len */ - fputs(set, stdout); - fwrite(line + i, tail - i + 1, 1, stdout); - fputs(reset, stdout); - emit_line(ws, reset, line + tail + 1, len - tail - 1); - } - else - emit_line(set, reset, line + i, len - i); } static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len) @@ -577,9 +498,13 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons if (!*ws) emit_line(set, reset, line, len); - else - emit_line_with_ws(ecbdata->nparents, set, reset, ws, - line, len, ecbdata->ws_rule); + else { + /* Emit just the prefix, then the rest. */ + emit_line(set, reset, line, ecbdata->nparents); + (void)check_and_emit_line(line + ecbdata->nparents, + len - ecbdata->nparents, ecbdata->ws_rule, + stdout, set, reset, ws); + } } static void fn_out_consume(void *priv, char *line, unsigned long len) @@ -1040,45 +965,20 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) const char *ws = diff_get_color(data->color_diff, DIFF_WHITESPACE); const char *reset = diff_get_color(data->color_diff, DIFF_RESET); const char *set = diff_get_color(data->color_diff, DIFF_FILE_NEW); + char *err; if (line[0] == '+') { - int i, spaces = 0, space_before_tab = 0, white_space_at_end = 0; - - /* check space before tab */ - for (i = 1; i < len; i++) { - if (line[i] == ' ') - spaces++; - else if (line[i] == '\t') { - if (spaces) { - space_before_tab = 1; - break; - } - } - else - break; - } - - /* check whitespace at line end */ - if (line[len - 1] == '\n') - len--; - if (isspace(line[len - 1])) - white_space_at_end = 1; - - if (space_before_tab || white_space_at_end) { - data->status = 1; - printf("%s:%d: %s", data->filename, data->lineno, ws); - if (space_before_tab) { - printf("space before tab"); - if (white_space_at_end) - putchar(','); - } - if (white_space_at_end) - printf("whitespace at end"); - printf(":%s ", reset); - emit_line_with_ws(1, set, reset, ws, line, len, - data->ws_rule); - } - + data->status = check_and_emit_line(line + 1, len - 1, + data->ws_rule, NULL, NULL, NULL, NULL); + if (!data->status) + return; + err = whitespace_error_string(data->status); + printf("%s:%d: %s%s:%s ", data->filename, data->lineno, + ws, err, reset); + free(err); + emit_line(set, reset, line, 1); + (void)check_and_emit_line(line + 1, len - 1, data->ws_rule, + stdout, set, reset, ws); data->lineno++; } else if (line[0] == ' ') data->lineno++; diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index dc538b3..a0a47dd 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -121,7 +121,7 @@ test_expect_success 'check mixed spaces and tabs in indent' ' # This is indented with SP HT SP. echo " foo();" > x && - git diff --check | grep "space before tab" + git diff --check | grep "Space in indent is followed by a tab" ' diff --git a/ws.c b/ws.c index 52c10ca..a0ce860 100644 --- a/ws.c +++ b/ws.c @@ -94,3 +94,108 @@ unsigned whitespace_rule(const char *pathname) return whitespace_rule_cfg; } } + +/* The returned string should be freed by the caller. */ +char *whitespace_error_string(unsigned ws) +{ + struct strbuf err; + strbuf_init(&err, 0); + if (ws & WS_TRAILING_SPACE) + strbuf_addstr(&err, "Adds trailing whitespace"); + if (ws & WS_SPACE_BEFORE_TAB) { + if (err.len) + strbuf_addstr(&err, ", "); + strbuf_addstr(&err, "Space in indent is followed by a tab"); + } + if (ws & WS_INDENT_WITH_NON_TAB) { + if (err.len) + strbuf_addstr(&err, ", "); + strbuf_addstr(&err, "Indent more than 8 places with spaces"); + } + return strbuf_detach(&err, NULL); +} + +/* If stream is non-NULL, emits the line after checking. */ +unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, + FILE *stream, const char *set, + const char *reset, const char *ws) +{ + unsigned result = 0; + int leading_space = -1; + int trailing_whitespace = -1; + int trailing_newline = 0; + int i; + + /* Logic is simpler if we temporarily ignore the trailing newline. */ + if (len > 0 && line[len - 1] == '\n') { + trailing_newline = 1; + len--; + } + + /* Check for trailing whitespace. */ + if (ws_rule & WS_TRAILING_SPACE) { + for (i = len - 1; i >= 0; i--) { + if (isspace(line[i])) { + trailing_whitespace = i; + result |= WS_TRAILING_SPACE; + } + else + break; + } + } + + /* Check for space before tab in initial indent. */ + for (i = 0; i < len; i++) { + if (line[i] == '\t') { + if ((ws_rule & WS_SPACE_BEFORE_TAB) && + (leading_space != -1)) + result |= WS_SPACE_BEFORE_TAB; + break; + } + else if (line[i] == ' ') + leading_space = i; + else + break; + } + + /* Check for indent using non-tab. */ + if ((ws_rule & WS_INDENT_WITH_NON_TAB) && leading_space >= 8) + result |= WS_INDENT_WITH_NON_TAB; + + if (stream) { + /* Highlight errors in leading whitespace. */ + if ((result & WS_SPACE_BEFORE_TAB) || + (result & WS_INDENT_WITH_NON_TAB)) { + fputs(ws, stream); + fwrite(line, leading_space + 1, 1, stream); + fputs(reset, stream); + leading_space++; + } + else + leading_space = 0; + + /* Now the rest of the line starts at leading_space. + * The non-highlighted part ends at trailing_whitespace. */ + if (trailing_whitespace == -1) + trailing_whitespace = len; + + /* Emit non-highlighted (middle) segment. */ + if (trailing_whitespace - leading_space > 0) { + fputs(set, stream); + fwrite(line + leading_space, + trailing_whitespace - leading_space, 1, stream); + fputs(reset, stream); + } + + /* Highlight errors in trailing whitespace. */ + if (trailing_whitespace != len) { + fputs(ws, stream); + fwrite(line + trailing_whitespace, + len - trailing_whitespace, 1, stream); + fputs(reset, stream); + } + if (trailing_newline) + fputc('\n', stream); + } + return result; +} -- 1.5.4.rc0.4.g50348 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 4/5] Make "diff --check" output match "git apply" 2007-12-13 13:32 ` [PATCH 3/5] Unify whitespace checking Wincent Colaiuta @ 2007-12-13 13:32 ` Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 5/5] Add tests for "git diff --check" with core.whitespace options Wincent Colaiuta 2007-12-14 0:12 ` [PATCH 4/5] Make "diff --check" output match "git apply" Junio C Hamano 2007-12-13 13:40 ` [PATCH 3/5] Unify whitespace checking Andreas Ericsson 2007-12-14 0:03 ` Junio C Hamano 2 siblings, 2 replies; 24+ messages in thread From: Wincent Colaiuta @ 2007-12-13 13:32 UTC (permalink / raw) To: git; +Cc: gitster, Wincent Colaiuta For consistency, make the two tools report whitespace errors in the same way (the output of "diff --check" has been tweaked to match that of "git apply"). Note that although the textual content is basically the same only "git diff --check" provides a colorized version of the problematic lines; making "git apply" do colorization will require more extensive changes (figuring out the diff colorization preferences of the user) and so that will be a subject for another commit. Signed-off-by: Wincent Colaiuta <win@wincent.com> --- builtin-apply.c | 4 ++-- diff.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index ab393f3..2edd83b 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -912,8 +912,8 @@ static void check_whitespace(const char *line, int len, unsigned ws_rule) ; else { err = whitespace_error_string(result); - fprintf(stderr, "%s.\n%s:%d:%.*s\n", - err, patch_input_file, linenr, len - 2, line + 1); + fprintf(stderr, "%s:%d: %s.\n%.*s\n", + patch_input_file, linenr, err, len - 2, line + 1); free(err); } } diff --git a/diff.c b/diff.c index d96a4ac..73a723d 100644 --- a/diff.c +++ b/diff.c @@ -973,8 +973,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) if (!data->status) return; err = whitespace_error_string(data->status); - printf("%s:%d: %s%s:%s ", data->filename, data->lineno, - ws, err, reset); + printf("%s:%d: %s.\n", data->filename, data->lineno, err); free(err); emit_line(set, reset, line, 1); (void)check_and_emit_line(line + 1, len - 1, data->ws_rule, -- 1.5.4.rc0.4.g50348 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH 5/5] Add tests for "git diff --check" with core.whitespace options 2007-12-13 13:32 ` [PATCH 4/5] Make "diff --check" output match "git apply" Wincent Colaiuta @ 2007-12-13 13:32 ` Wincent Colaiuta 2007-12-14 0:55 ` Junio C Hamano 2007-12-14 0:12 ` [PATCH 4/5] Make "diff --check" output match "git apply" Junio C Hamano 1 sibling, 1 reply; 24+ messages in thread From: Wincent Colaiuta @ 2007-12-13 13:32 UTC (permalink / raw) To: git; +Cc: gitster, Wincent Colaiuta Make sure that "git diff --check" does the right thing when the core.whitespace options are set. Signed-off-by: Wincent Colaiuta <win@wincent.com> --- t/t4015-diff-whitespace.sh | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 50 insertions(+), 0 deletions(-) diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index a0a47dd..cb90ee7 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -261,4 +261,54 @@ test_expect_failure 'check with space before tab in indent (diff-tree)' ' ' +test_expect_success 'check trailing whitespace (trailing-space: off)' ' + + git config core.whitespace "-trailing-space" && + echo "foo (); " > x && + git diff --check + +' + +test_expect_failure 'check trailing whitespace (trailing-space: on)' ' + + git config core.whitespace "trailing-space" && + echo "foo (); " > x && + git diff --check + +' + +test_expect_success 'check space before tab in indent (space-before-tab: off)' ' + + # indent contains space followed by HT + git config core.whitespace "-space-before-tab" && + echo " foo ();" > x && + git diff --check + +' + +test_expect_failure 'check space before tab in indent (space-before-tab: on)' ' + + # indent contains space followed by HT + git config core.whitespace "space-before-tab" && + echo " foo (); " > x && + git diff --check + +' + +test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' ' + + git config core.whitespace "-indent-with-non-tab" + echo " foo ();" > x && + git diff --check + +' + +test_expect_failure 'check spaces as indentation (indent-with-non-tab: on)' ' + + git config core.whitespace "indent-with-non-tab" && + echo " foo ();" > x && + git diff --check + +' + test_done -- 1.5.4.rc0.4.g50348 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH 5/5] Add tests for "git diff --check" with core.whitespace options 2007-12-13 13:32 ` [PATCH 5/5] Add tests for "git diff --check" with core.whitespace options Wincent Colaiuta @ 2007-12-14 0:55 ` Junio C Hamano 0 siblings, 0 replies; 24+ messages in thread From: Junio C Hamano @ 2007-12-14 0:55 UTC (permalink / raw) To: Wincent Colaiuta; +Cc: git, gitster Wincent Colaiuta <win@wincent.com> writes: > +test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' ' > + > + git config core.whitespace "-indent-with-non-tab" > + echo " foo ();" > x && > + git diff --check > + > +' > + > +test_expect_failure 'check spaces as indentation (indent-with-non-tab: on)' ' > + > + git config core.whitespace "indent-with-non-tab" && > + echo " foo ();" > x && > + git diff --check > + > +' > + > test_done It is good to check both positive and negative cases, but I would prefer avoiding test_expect_failure. You cannot tell if the "git config" before the real test failed or "git diff --check" correctly reported whitespace breakage --- both would cause the test to pass. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 4/5] Make "diff --check" output match "git apply" 2007-12-13 13:32 ` [PATCH 4/5] Make "diff --check" output match "git apply" Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 5/5] Add tests for "git diff --check" with core.whitespace options Wincent Colaiuta @ 2007-12-14 0:12 ` Junio C Hamano 1 sibling, 0 replies; 24+ messages in thread From: Junio C Hamano @ 2007-12-14 0:12 UTC (permalink / raw) To: Wincent Colaiuta; +Cc: git Nice attention to the details. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 3/5] Unify whitespace checking 2007-12-13 13:32 ` [PATCH 3/5] Unify whitespace checking Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 4/5] Make "diff --check" output match "git apply" Wincent Colaiuta @ 2007-12-13 13:40 ` Andreas Ericsson 2007-12-14 0:03 ` Junio C Hamano 2 siblings, 0 replies; 24+ messages in thread From: Andreas Ericsson @ 2007-12-13 13:40 UTC (permalink / raw) To: Wincent Colaiuta; +Cc: git, gitster Wincent Colaiuta wrote: > > - the emit_line_with_ws() function is also removed because that also > rechecks the shitespace, and its functionality is rolled into ws.c > shitespace? It's fitting though. I'd stick with it :-) -- Andreas Ericsson andreas.ericsson@op5.se OP5 AB www.op5.se Tel: +46 8-230225 Fax: +46 8-230231 ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 3/5] Unify whitespace checking 2007-12-13 13:32 ` [PATCH 3/5] Unify whitespace checking Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 4/5] Make "diff --check" output match "git apply" Wincent Colaiuta 2007-12-13 13:40 ` [PATCH 3/5] Unify whitespace checking Andreas Ericsson @ 2007-12-14 0:03 ` Junio C Hamano 2007-12-14 7:36 ` Wincent Colaiuta 2 siblings, 1 reply; 24+ messages in thread From: Junio C Hamano @ 2007-12-14 0:03 UTC (permalink / raw) To: Wincent Colaiuta; +Cc: git, gitster Wincent Colaiuta <win@wincent.com> writes: > The new function is called check_and_emit_line() and it does two things: > checks a line for whitespace errors and optionally emits it. The checking > is based on lines of content rather than patch lines (in other words, the > caller must strip the leading "+" or "-"); this was suggested by Junio on > the mailing list to allow for a future extension to "git show" to display > whitespace errors in blobs. I do not think "git show" is a realistic "future extension", by the way. But at least from the interface-cleanliness point of view, I think not passing the leading "+" to the function is a right thing to do. > diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh > index dc538b3..a0a47dd 100755 > --- a/t/t4015-diff-whitespace.sh > +++ b/t/t4015-diff-whitespace.sh > @@ -121,7 +121,7 @@ test_expect_success 'check mixed spaces and tabs in indent' ' > > # This is indented with SP HT SP. > echo " foo();" > x && > - git diff --check | grep "space before tab" > + git diff --check | grep "Space in indent is followed by a tab" > > ' Hmph. I think with the multiple detection this rewording would make the error message very long to read. Was the rewording really necessary? > +/* If stream is non-NULL, emits the line after checking. */ > +unsigned check_and_emit_line(const char *line, int len, unsigned ws_rule, > + FILE *stream, const char *set, > + const char *reset, const char *ws) > +{ Honestly, I regretted suggesting this, fearing that it might make the checking too costly, but the code is clean, readable, and does not look costly at all. Nice job. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 3/5] Unify whitespace checking 2007-12-14 0:03 ` Junio C Hamano @ 2007-12-14 7:36 ` Wincent Colaiuta 0 siblings, 0 replies; 24+ messages in thread From: Wincent Colaiuta @ 2007-12-14 7:36 UTC (permalink / raw) To: Junio C Hamano; +Cc: git El 14/12/2007, a las 1:03, Junio C Hamano escribió: >> - git diff --check | grep "space before tab" >> + git diff --check | grep "Space in indent is followed by a tab" >> > Hmph. I think with the multiple detection this rewording would make > the > error message very long to read. Was the rewording really necessary? Well, that wording came from builtin-apply.c so it wasn't really a "re- wording" but an extraction. The other string comes from "diff.c". So I had to pick one of them in unifying them and basically the one from builtin-apply.c won because it was the site where I extracted from first. So basically it was arbitrary. If I were to actually *re-word* the message I think something like this would be the compromise between clarity and conciseness: "space before tab in indent" And in the same spirit, the other two strings extracted from builtin- apply.c into the new whitespace_error_string() function: "Adds trailing whitespace" "Indent more than 8 places with spaces" Could be shortened to: "trailing whitespace" (diff.c says "white space at end") "indent using spaces" But I personally have no strong conviction about this, so I'm happy for it to be whatever you want. >> +/* If stream is non-NULL, emits the line after checking. */ >> +unsigned check_and_emit_line(const char *line, int len, unsigned >> ws_rule, >> + FILE *stream, const char *set, >> + const char *reset, const char *ws) >> +{ > > Honestly, I regretted suggesting this, fearing that it might make the > checking too costly, but the code is clean, readable, and does not > look > costly at all. Nice job. Thanks. The check_and_emit_line function itself is fairly clean internally (apart from the somewhat ugly parameter list, but that was mostly inherited from the emit_line_with_ws function which it replaces). It's the sites where check_and_emit_line is called that look a bit ugly, but those can hopefully be cleaned up at some point in the future. Cheers, Wincent ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/5] New version of pre-commit hook 2007-12-13 13:32 ` [PATCH 2/5] New version of pre-commit hook Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 3/5] Unify whitespace checking Wincent Colaiuta @ 2007-12-14 0:17 ` Jakub Narebski 2007-12-14 7:24 ` Wincent Colaiuta 1 sibling, 1 reply; 24+ messages in thread From: Jakub Narebski @ 2007-12-14 0:17 UTC (permalink / raw) To: git Wincent Colaiuta wrote: > Now that "git diff --check" indicates problems with its exit code the > pre-commit hook becomes a trivial one-liner. > - if (/^(?:[<>=]){7}/) { > - bad_line("unresolved merge conflict", $_); > - } Aren't you losing this check with rewrite? -- Jakub Narebski Warsaw, Poland ShadeHawk on #git ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/5] New version of pre-commit hook 2007-12-14 0:17 ` [PATCH 2/5] New version of pre-commit hook Jakub Narebski @ 2007-12-14 7:24 ` Wincent Colaiuta 2007-12-14 10:23 ` Jakub Narebski 0 siblings, 1 reply; 24+ messages in thread From: Wincent Colaiuta @ 2007-12-14 7:24 UTC (permalink / raw) To: Jakub Narebski; +Cc: git El 14/12/2007, a las 1:17, Jakub Narebski escribió: > Wincent Colaiuta wrote: > >> Now that "git diff --check" indicates problems with its exit code the >> pre-commit hook becomes a trivial one-liner. > >> - if (/^(?:[<>=]){7}/) { >> - bad_line("unresolved merge conflict", $_); >> - } > > Aren't you losing this check with rewrite? Yes. If that's a problem then this is definitely a "no-goer". Cheers, Wincent ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 2/5] New version of pre-commit hook 2007-12-14 7:24 ` Wincent Colaiuta @ 2007-12-14 10:23 ` Jakub Narebski 0 siblings, 0 replies; 24+ messages in thread From: Jakub Narebski @ 2007-12-14 10:23 UTC (permalink / raw) To: Wincent Colaiuta; +Cc: git Dnia piątek 14. grudnia 2007 08:24, Wincent Colaiuta napisał: > El 14/12/2007, a las 1:17, Jakub Narebski escribió: > >> Wincent Colaiuta wrote: >> >>> Now that "git diff --check" indicates problems with its exit code the >>> pre-commit hook becomes a trivial one-liner. >> >>> - if (/^(?:[<>=]){7}/) { >>> - bad_line("unresolved merge conflict", $_); >>> - } >> >> Aren't you losing this check with rewrite? > > Yes. If that's a problem then this is definitely a "no-goer". Well, this only means that it wouldn't be one-liner, but replacing all whitespace damage checks by "git diff --check" is still a good idea. Perhaps we could add 'merge conflict' check to git diff/git applyt too... -- Jakub Narebski Poland ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH] Don't use the pager when running "git diff --check" 2007-12-13 13:32 ` [PATCH 1/5] "diff --check" should affect exit status Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 2/5] New version of pre-commit hook Wincent Colaiuta @ 2007-12-13 19:45 ` Wincent Colaiuta 2007-12-14 4:51 ` Jeff King 2007-12-13 23:51 ` [PATCH 1/5] "diff --check" should affect exit status Junio C Hamano 2 siblings, 1 reply; 24+ messages in thread From: Wincent Colaiuta @ 2007-12-13 19:45 UTC (permalink / raw) To: git; +Cc: gitster, Wincent Colaiuta In 89d07f75 "git diff" learnt to not run the pager if the user passes the --exit-code switch. This commit does the same for the --check switch for the same reason: we want the user to get the exit status from "git diff", not the pager. Signed-off-by: Wincent Colaiuta <win@wincent.com> --- This really should have been part of my original patch, ([PATCH 1/5] "diff --check" should affect exit status"), but I only just discovered this now. builtin-diff.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/builtin-diff.c b/builtin-diff.c index 86d01a3..ed2d218 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -247,7 +247,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix) /* If the user asked for our exit code then don't start a * pager or we would end up reporting its exit code instead. */ - if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) + if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS) && + (!&rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)) setup_pager(); /* Do we have --cached and not have a pending object, then -- 1.5.4.rc0.5.gd201-dirty ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH] Don't use the pager when running "git diff --check" 2007-12-13 19:45 ` [PATCH] Don't use the pager when running "git diff --check" Wincent Colaiuta @ 2007-12-14 4:51 ` Jeff King 2007-12-14 5:11 ` Junio C Hamano 0 siblings, 1 reply; 24+ messages in thread From: Jeff King @ 2007-12-14 4:51 UTC (permalink / raw) To: Wincent Colaiuta; +Cc: git, gitster On Thu, Dec 13, 2007 at 08:45:38PM +0100, Wincent Colaiuta wrote: > In 89d07f75 "git diff" learnt to not run the pager if the user passes > the --exit-code switch. This commit does the same for the --check > switch for the same reason: we want the user to get the exit status > from "git diff", not the pager. But --check is also producing useful output, which might need paged. So you are sacrificing existing interactive use of --check for scriptable exit-code uses. If you really want the exit code, why not "git diff --check --exit-code"? OTOH, I am not too sad to lose the paging behavior; it would take quite a few whitespace errors to scroll off the screen. -Peff ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Don't use the pager when running "git diff --check" 2007-12-14 4:51 ` Jeff King @ 2007-12-14 5:11 ` Junio C Hamano 2007-12-14 7:33 ` Junio C Hamano 2007-12-14 7:47 ` Wincent Colaiuta 0 siblings, 2 replies; 24+ messages in thread From: Junio C Hamano @ 2007-12-14 5:11 UTC (permalink / raw) To: Jeff King; +Cc: Wincent Colaiuta, git Jeff King <peff@peff.net> writes: > On Thu, Dec 13, 2007 at 08:45:38PM +0100, Wincent Colaiuta wrote: > >> In 89d07f75 "git diff" learnt to not run the pager if the user passes >> the --exit-code switch. This commit does the same for the --check >> switch for the same reason: we want the user to get the exit status >> from "git diff", not the pager. > > But --check is also producing useful output, which might need paged. So > you are sacrificing existing interactive use of --check for scriptable > exit-code uses. If you really want the exit code, why not "git diff > --check --exit-code"? > > OTOH, I am not too sad to lose the paging behavior; it would take quite > a few whitespace errors to scroll off the screen. You are right. While I do not personally miss paging output, it is a regression not to page --check output by default. By the way, there is no reason to make --check and --exit-code mutually exclusive either. You could say with --exit-code the command will exit with status 01 or'ed in if trees are not identical, and with --check the command will exit with status 02 or'ed in. Loosely written scripted callers can continue doing: if git --no-pager diff --exit-code then they are different fi if git --no-pager diff --check then there are funky blanks fi while the ones that are aware of the new behaviour of --check can: git --no-pager diff --check --exit-code case $? in 0) all is well ;; 1) clean difference there ;; 3) dirty difference there ;; 2) cannot happen ;; *) bombed out, as die exits with 128 ;; esac ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Don't use the pager when running "git diff --check" 2007-12-14 5:11 ` Junio C Hamano @ 2007-12-14 7:33 ` Junio C Hamano 2007-12-14 7:51 ` Wincent Colaiuta 2007-12-14 7:47 ` Wincent Colaiuta 1 sibling, 1 reply; 24+ messages in thread From: Junio C Hamano @ 2007-12-14 7:33 UTC (permalink / raw) To: Wincent Colaiuta; +Cc: Jeff King, git Junio C Hamano <gitster@pobox.com> writes: > By the way, there is no reason to make --check and --exit-code mutually > exclusive either. Perhaps something like this. Regardless of the exclusivity issue, I think the "diff_result_code()" helper function is a good clean-up. --- builtin-diff-files.c | 6 +----- builtin-diff-index.c | 6 +----- builtin-diff-tree.c | 6 ++---- builtin-diff.c | 11 ++++------- diff.c | 19 ++++++++++++++----- diff.h | 2 ++ t/t4015-diff-whitespace.sh | 4 ++-- 7 files changed, 26 insertions(+), 28 deletions(-) diff --git a/builtin-diff-files.c b/builtin-diff-files.c index 4afc872..9c04111 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -31,9 +31,5 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) if (!rev.diffopt.output_format) rev.diffopt.output_format = DIFF_FORMAT_RAW; result = run_diff_files_cmd(&rev, argc, argv); - if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) - return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; - if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) - return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; - return result; + return diff_result_code(&rev.diffopt, result); } diff --git a/builtin-diff-index.c b/builtin-diff-index.c index 532b284..0f2390a 100644 --- a/builtin-diff-index.c +++ b/builtin-diff-index.c @@ -44,9 +44,5 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) return -1; } result = run_diff_index(&rev, cached); - if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) - return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; - if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) - return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; - return result; + return diff_result_code(&rev.diffopt, result); } diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 9ab90cb..ebc50ef 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -132,8 +132,6 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) diff_tree_stdin(line); } } - if (opt->diffopt.output_format & DIFF_FORMAT_CHECKDIFF) - return DIFF_OPT_TST(&opt->diffopt, CHECK_FAILED) != 0; - return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS) - && DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES); + + return diff_result_code(&opt->diffopt, 0); } diff --git a/builtin-diff.c b/builtin-diff.c index 9d878f6..29365a0 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -244,11 +244,11 @@ int cmd_diff(int argc, const char **argv, const char *prefix) DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL); DIFF_OPT_SET(&rev.diffopt, RECURSIVE); - /* If the user asked for our exit code then don't start a + /* + * If the user asked for our exit code then don't start a * pager or we would end up reporting its exit code instead. */ - if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS) && - (!(rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF))) + if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) setup_pager(); /* Do we have --cached and not have a pending object, then @@ -352,10 +352,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) else result = builtin_diff_combined(&rev, argc, argv, ent, ents); - if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) - result = DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; - if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) - return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0; + result = diff_result_code(&rev.diffopt, result); if (1 < rev.diffopt.skip_stat_unmatch) refresh_index_quietly(); return result; diff --git a/diff.c b/diff.c index 8237075..3e46ff8 100644 --- a/diff.c +++ b/diff.c @@ -2125,12 +2125,7 @@ int diff_setup_done(struct diff_options *options) if (options->output_format & DIFF_FORMAT_NAME_STATUS) count++; if (options->output_format & DIFF_FORMAT_CHECKDIFF) - { count++; - if (DIFF_OPT_TST(options, QUIET) || - DIFF_OPT_TST(options, EXIT_WITH_STATUS)) - die("--check may not be used with --quiet or --exit-code"); - } if (options->output_format & DIFF_FORMAT_NO_OUTPUT) count++; if (count > 1) @@ -3180,6 +3175,20 @@ void diffcore_std(struct diff_options *options) DIFF_OPT_CLR(options, HAS_CHANGES); } +int diff_result_code(struct diff_options *opt, int status) +{ + int result = 0; + if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) && + !(opt->output_format & DIFF_FORMAT_CHECKDIFF)) + return status; + if (DIFF_OPT_TST(opt, EXIT_WITH_STATUS) && + DIFF_OPT_TST(opt, HAS_CHANGES)) + result |= 01; + if ((opt->output_format & DIFF_FORMAT_CHECKDIFF) && + DIFF_OPT_TST(opt, CHECK_FAILED)) + result |= 02; + return result; +} void diff_addremove(struct diff_options *options, int addremove, unsigned mode, diff --git a/diff.h b/diff.h index 5d50d93..7e8000a 100644 --- a/diff.h +++ b/diff.h @@ -247,4 +247,6 @@ extern int run_diff_index(struct rev_info *revs, int cached); extern int do_diff_cache(const unsigned char *, struct diff_options *); extern int diff_flush_patch_id(struct diff_options *, unsigned char *); +extern int diff_result_code(struct diff_options *, int); + #endif /* DIFF_H */ diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index dc538b3..757a27a 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -148,14 +148,14 @@ test_expect_failure 'check with space before tab in indent' ' ' -test_expect_failure '--check and --exit-code are exclusive' ' +test_expect_success '--check and --exit-code are not exclusive' ' git checkout x && git diff --check --exit-code ' -test_expect_failure '--check and --quiet are exclusive' ' +test_expect_success '--check and --quiet are not exclusive' ' git diff --check --quiet ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH] Don't use the pager when running "git diff --check" 2007-12-14 7:33 ` Junio C Hamano @ 2007-12-14 7:51 ` Wincent Colaiuta 2007-12-14 7:57 ` Junio C Hamano 0 siblings, 1 reply; 24+ messages in thread From: Wincent Colaiuta @ 2007-12-14 7:51 UTC (permalink / raw) To: Junio C Hamano; +Cc: Jeff King, git El 14/12/2007, a las 8:33, Junio C Hamano escribió: > Junio C Hamano <gitster@pobox.com> writes: > >> By the way, there is no reason to make --check and --exit-code >> mutually >> exclusive either. > > Perhaps something like this. Regardless of the exclusivity issue, I > think the "diff_result_code()" helper function is a good clean-up. Totally agreed. It replaces some groups of very-similar lines. I'll integrate these (and the other suggestions) some time this morning and post a new version of the series that incorporates all the feedback and patch suggestions. Cheers, Wincent ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Don't use the pager when running "git diff --check" 2007-12-14 7:51 ` Wincent Colaiuta @ 2007-12-14 7:57 ` Junio C Hamano 0 siblings, 0 replies; 24+ messages in thread From: Junio C Hamano @ 2007-12-14 7:57 UTC (permalink / raw) To: Wincent Colaiuta; +Cc: Jeff King, git Wincent Colaiuta <win@wincent.com> writes: > I'll integrate these (and the other suggestions) some time this > morning and post a new version of the series that incorporates all the > feedback and patch suggestions. Heh, I am about to push out fixed-up results, so it might save both of us some time if you looked at it first and then complained on my screwups. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Don't use the pager when running "git diff --check" 2007-12-14 5:11 ` Junio C Hamano 2007-12-14 7:33 ` Junio C Hamano @ 2007-12-14 7:47 ` Wincent Colaiuta 2007-12-14 20:54 ` Junio C Hamano 1 sibling, 1 reply; 24+ messages in thread From: Wincent Colaiuta @ 2007-12-14 7:47 UTC (permalink / raw) To: Junio C Hamano; +Cc: Jeff King, git El 14/12/2007, a las 6:11, Junio C Hamano escribió: > Jeff King <peff@peff.net> writes: > >> On Thu, Dec 13, 2007 at 08:45:38PM +0100, Wincent Colaiuta wrote: >> >>> In 89d07f75 "git diff" learnt to not run the pager if the user >>> passes >>> the --exit-code switch. This commit does the same for the --check >>> switch for the same reason: we want the user to get the exit status >>> from "git diff", not the pager. >> >> But --check is also producing useful output, which might need >> paged. So >> you are sacrificing existing interactive use of --check for >> scriptable >> exit-code uses. If you really want the exit code, why not "git diff >> --check --exit-code"? >> >> OTOH, I am not too sad to lose the paging behavior; it would take >> quite >> a few whitespace errors to scroll off the screen. > > You are right. While I do not personally miss paging output, it is a > regression not to page --check output by default. I thought this was ok because "git diff --exit-code" also produces useful output and also turns off the pager. > By the way, there is no reason to make --check and --exit-code > mutually > exclusive either. You could say with --exit-code the command will > exit > with status 01 or'ed in if trees are not identical, and with --check > the > command will exit with status 02 or'ed in. Yes, this sounds fine to me. Cheers, Wincent ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Don't use the pager when running "git diff --check" 2007-12-14 7:47 ` Wincent Colaiuta @ 2007-12-14 20:54 ` Junio C Hamano 0 siblings, 0 replies; 24+ messages in thread From: Junio C Hamano @ 2007-12-14 20:54 UTC (permalink / raw) To: Wincent Colaiuta; +Cc: Jeff King, git Wincent Colaiuta <win@wincent.com> writes: > El 14/12/2007, a las 6:11, Junio C Hamano escribió: > >> You are right. While I do not personally miss paging output, it is a >> regression not to page --check output by default. > > I thought this was ok because "git diff --exit-code" also produces > useful output and also turns off the pager. It is different. --exit-code was that way from day one. The primary use of --check has been (and I suspect it will continue to be) for people to _view_ the diff, spot problems so that they can fix them up, and for that use case, exit code does not matter but pageability does. You are introducing a new behaviour and a new use case --- that does not give you a license to break other existing use cases. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/5] "diff --check" should affect exit status 2007-12-13 13:32 ` [PATCH 1/5] "diff --check" should affect exit status Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 2/5] New version of pre-commit hook Wincent Colaiuta 2007-12-13 19:45 ` [PATCH] Don't use the pager when running "git diff --check" Wincent Colaiuta @ 2007-12-13 23:51 ` Junio C Hamano 2007-12-14 2:10 ` Junio C Hamano 2 siblings, 1 reply; 24+ messages in thread From: Junio C Hamano @ 2007-12-13 23:51 UTC (permalink / raw) To: Wincent Colaiuta; +Cc: git Wincent Colaiuta <win@wincent.com> writes: > @@ -2965,8 +2976,8 @@ void diff_flush(struct diff_options *options) > DIFF_FORMAT_CHECKDIFF)) { > for (i = 0; i < q->nr; i++) { > struct diff_filepair *p = q->queue[i]; > - if (check_pair_status(p)) > - flush_one_pair(p, options); > + if (check_pair_status(p) && flush_one_pair(p, options)) > + DIFF_OPT_SET(options, CHECK_FAILED); > } > separator++; > } Isn't this wrong when check is not in effect? I think highjacking the "did we encounter problems" return value of the entire callchain for the purpose of checkdiff is very ugly and wrong to begin with, so please do not argue "but if checkdiff is not in effect, the caller does not check CHECK_FAILED". Wouldn't it be much cleaner to make diff_flush_checkdiff(), or its underlying function run_checkdiff(), set that CHECK_FAILED flag to options structure, and return success? The toplevel caller can decide to exit with non-zero when --check is in effect and CHECK_FAILED flag is set. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 1/5] "diff --check" should affect exit status 2007-12-13 23:51 ` [PATCH 1/5] "diff --check" should affect exit status Junio C Hamano @ 2007-12-14 2:10 ` Junio C Hamano 0 siblings, 0 replies; 24+ messages in thread From: Junio C Hamano @ 2007-12-14 2:10 UTC (permalink / raw) To: Wincent Colaiuta; +Cc: git Junio C Hamano <gitster@pobox.com> writes: > I think highjacking the "did we encounter problems" return value of the > entire callchain for the purpose of checkdiff is very ugly and wrong to > begin with,... How about this on top of your 1/5? It mostly is about reverting the damage to the higher level callchain. Instead, builtin_checkdiff() inspects the checkdiff data and sets the CHECK_FAILED flag to the diffopt structure. The callers are already checking that flag so there is nothing to change for them. -- diff --git a/diff.c b/diff.c index 39109a6..fc496bf 100644 --- a/diff.c +++ b/diff.c @@ -1456,7 +1456,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b, diff_free_filespec_data(two); } -static int builtin_checkdiff(const char *name_a, const char *name_b, +static void builtin_checkdiff(const char *name_a, const char *name_b, struct diff_filespec *one, struct diff_filespec *two, struct diff_options *o) { @@ -1464,7 +1464,7 @@ static int builtin_checkdiff(const char *name_a, const char *name_b, struct checkdiff_t data; if (!two) - return 0; + return; memset(&data, 0, sizeof(data)); data.xm.consume = checkdiff_consume; @@ -1493,7 +1493,8 @@ static int builtin_checkdiff(const char *name_a, const char *name_b, free_and_return: diff_free_filespec_data(one); diff_free_filespec_data(two); - return data.status; + if (data.status) + DIFF_OPT_SET(o, CHECK_FAILED); } struct diff_filespec *alloc_filespec(const char *path) @@ -2078,14 +2079,14 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o, builtin_diffstat(name, other, p->one, p->two, diffstat, o, complete_rewrite); } -static int run_checkdiff(struct diff_filepair *p, struct diff_options *o) +static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) { const char *name; const char *other; if (DIFF_PAIR_UNMERGED(p)) { /* unmerged */ - return 0; + return; } name = p->one->path; @@ -2094,7 +2095,7 @@ static int run_checkdiff(struct diff_filepair *p, struct diff_options *o) diff_fill_sha1_info(p->one); diff_fill_sha1_info(p->two); - return builtin_checkdiff(name, other, p->one, p->two, o); + builtin_checkdiff(name, other, p->one, p->two, o); } void diff_setup(struct diff_options *options) @@ -2596,17 +2597,17 @@ static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o, run_diffstat(p, o, diffstat); } -static int diff_flush_checkdiff(struct diff_filepair *p, +static void diff_flush_checkdiff(struct diff_filepair *p, struct diff_options *o) { if (diff_unmodified_pair(p)) - return 0; + return; if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) || (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode))) - return 0; /* no tree diffs in patch format */ + return; /* no tree diffs in patch format */ - return run_checkdiff(p, o); + run_checkdiff(p, o); } int diff_queue_is_empty(void) @@ -2725,19 +2726,16 @@ static int check_pair_status(struct diff_filepair *p) } } -static int flush_one_pair(struct diff_filepair *p, struct diff_options *opt) +static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt) { int fmt = opt->output_format; if (fmt & DIFF_FORMAT_CHECKDIFF) - return diff_flush_checkdiff(p, opt); + diff_flush_checkdiff(p, opt); else if (fmt & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS)) diff_flush_raw(p, opt); else if (fmt & DIFF_FORMAT_NAME) write_name_quoted(p->two->path, stdout, opt->line_termination); - - /* return value only matters with DIFF_FORMAT_CHECKDIFF */ - return 0; } static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs) @@ -2976,8 +2974,8 @@ void diff_flush(struct diff_options *options) DIFF_FORMAT_CHECKDIFF)) { for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - if (check_pair_status(p) && flush_one_pair(p, options)) - DIFF_OPT_SET(options, CHECK_FAILED); + if (check_pair_status(p)) + flush_one_pair(p, options); } separator++; } -- 1.5.4.rc0.1.g37d0 ^ permalink raw reply related [flat|nested] 24+ messages in thread
end of thread, other threads:[~2007-12-14 20:55 UTC | newest] Thread overview: 24+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-12-13 13:32 [PATCH 0/5] "diff --check" and whitespace enhancements Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 1/5] "diff --check" should affect exit status Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 2/5] New version of pre-commit hook Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 3/5] Unify whitespace checking Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 4/5] Make "diff --check" output match "git apply" Wincent Colaiuta 2007-12-13 13:32 ` [PATCH 5/5] Add tests for "git diff --check" with core.whitespace options Wincent Colaiuta 2007-12-14 0:55 ` Junio C Hamano 2007-12-14 0:12 ` [PATCH 4/5] Make "diff --check" output match "git apply" Junio C Hamano 2007-12-13 13:40 ` [PATCH 3/5] Unify whitespace checking Andreas Ericsson 2007-12-14 0:03 ` Junio C Hamano 2007-12-14 7:36 ` Wincent Colaiuta 2007-12-14 0:17 ` [PATCH 2/5] New version of pre-commit hook Jakub Narebski 2007-12-14 7:24 ` Wincent Colaiuta 2007-12-14 10:23 ` Jakub Narebski 2007-12-13 19:45 ` [PATCH] Don't use the pager when running "git diff --check" Wincent Colaiuta 2007-12-14 4:51 ` Jeff King 2007-12-14 5:11 ` Junio C Hamano 2007-12-14 7:33 ` Junio C Hamano 2007-12-14 7:51 ` Wincent Colaiuta 2007-12-14 7:57 ` Junio C Hamano 2007-12-14 7:47 ` Wincent Colaiuta 2007-12-14 20:54 ` Junio C Hamano 2007-12-13 23:51 ` [PATCH 1/5] "diff --check" should affect exit status Junio C Hamano 2007-12-14 2:10 ` Junio C Hamano
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).