Skip to content

Commit

Permalink
Merge branch 'wc/diff'
Browse files Browse the repository at this point in the history
* wc/diff:
  Test interaction between diff --check and --exit-code
  Use shorter error messages for whitespace problems
  Add tests for "git diff --check" with core.whitespace options
  Make "diff --check" output match "git apply"
  Unify whitespace checking
  diff --check: minor fixups
  "diff --check" should affect exit status
  • Loading branch information
Junio C Hamano committed Dec 15, 2007
2 parents d7e9280 + 5973a07 commit dfaf75b
Show file tree
Hide file tree
Showing 12 changed files with 396 additions and 192 deletions.
4 changes: 3 additions & 1 deletion Documentation/diff-options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
56 changes: 11 additions & 45 deletions builtin-apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
fprintf(stderr, "%s.\n%s:%d:%.*s\n",
err, patch_input_file, linenr, len-2, line+1);
else {
err = whitespace_error_string(result);
fprintf(stderr, "%s:%d: %s.\n%.*s\n",
patch_input_file, linenr, err, len - 2, line + 1);
free(err);
}
}

/*
Expand Down
4 changes: 1 addition & 3 deletions builtin-diff-files.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +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;
return result;
return diff_result_code(&rev.diffopt, result);
}
4 changes: 1 addition & 3 deletions builtin-diff-index.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +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;
return result;
return diff_result_code(&rev.diffopt, result);
}
30 changes: 14 additions & 16 deletions builtin-diff-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,23 +117,21 @@ 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);
}
return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS)
&& DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES);

return diff_result_code(&opt->diffopt, 0);
}
7 changes: 3 additions & 4 deletions builtin-diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ 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))
Expand Down Expand Up @@ -351,9 +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;

result = diff_result_code(&rev.diffopt, result);
if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly();
return result;
Expand Down
4 changes: 4 additions & 0 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
153 changes: 35 additions & 118 deletions diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -1031,6 +956,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)
Expand All @@ -1039,44 +965,19 @@ 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) {
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.\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,
stdout, set, reset, ws);
data->lineno++;
} else if (line[0] == ' ')
data->lineno++;
Expand Down Expand Up @@ -1491,6 +1392,8 @@ 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);
if (data.status)
DIFF_OPT_SET(o, CHECK_FAILED);
}

struct diff_filespec *alloc_filespec(const char *path)
Expand Down Expand Up @@ -3171,6 +3074,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,
Expand Down
3 changes: 3 additions & 0 deletions diff.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -246,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 */
Loading

0 comments on commit dfaf75b

Please sign in to comment.