From 8824689884a5673f803d77cda499f83b84145a06 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 20 May 2006 23:43:13 +0200 Subject: diff family: add --check option Actually, it is a diff option now, so you can say git diff --check to ask if what you are about to commit is a good patch. [jc: this also would work for fmt-patch, but the point is that the check is done before making a commit. format-patch is run from an already created commit, and that is too late to catch whitespace damaged change.] Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- diff.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index e16e0bfc0a..af5db0ec12 100644 --- a/diff.c +++ b/diff.c @@ -397,6 +397,46 @@ static void show_stats(struct diffstat_t* data) total_files, adds, dels); } +struct checkdiff_t { + struct xdiff_emit_state xm; + const char *filename; + int lineno; +}; + +static void checkdiff_consume(void *priv, char *line, unsigned long len) +{ + struct checkdiff_t *data = priv; + + if (line[0] == '+') { + int i, spaces = 0; + + data->lineno++; + + /* check space before tab */ + for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++) + if (line[i] == ' ') + spaces++; + if (line[i - 1] == '\t' && spaces) + printf("%s:%d: space before tab:%.*s\n", + data->filename, data->lineno, (int)len, line); + + /* check white space at line end */ + if (line[len - 1] == '\n') + len--; + if (isspace(line[len - 1])) + printf("%s:%d: white space at end: %.*s\n", + data->filename, data->lineno, (int)len, line); + } else if (line[0] == ' ') + data->lineno++; + else if (line[0] == '@') { + char *plus = strchr(line, '+'); + if (plus) + data->lineno = strtol(plus, line + len, 10); + else + die("invalid diff"); + } +} + static unsigned char *deflate_it(char *data, unsigned long size, unsigned long *result_size) @@ -624,6 +664,41 @@ static void builtin_diffstat(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) +{ + mmfile_t mf1, mf2; + struct checkdiff_t data; + + if (!two) + return; + + memset(&data, 0, sizeof(data)); + data.xm.consume = checkdiff_consume; + data.filename = name_b ? name_b : name_a; + data.lineno = 0; + + if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) + die("unable to read files to diff"); + + if (mmfile_is_binary(&mf2)) + return; + else { + /* Crazy xdl interfaces.. */ + xpparam_t xpp; + xdemitconf_t xecfg; + xdemitcb_t ecb; + + xpp.flags = XDF_NEED_MINIMAL; + xecfg.ctxlen = 0; + xecfg.flags = 0; + ecb.outf = xdiff_outf; + ecb.priv = &data; + xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + } +} + struct diff_filespec *alloc_filespec(const char *path) { int namelen = strlen(path); @@ -1180,6 +1255,25 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o, builtin_diffstat(name, other, p->one, p->two, diffstat, complete_rewrite); } +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; + } + + name = p->one->path; + other = (strcmp(name, p->two->path) ? p->two->path : NULL); + + diff_fill_sha1_info(p->one); + diff_fill_sha1_info(p->two); + + builtin_checkdiff(name, other, p->one, p->two); +} + void diff_setup(struct diff_options *options) { memset(options, 0, sizeof(*options)); @@ -1205,7 +1299,8 @@ int diff_setup_done(struct diff_options *options) * recursive bits for other formats here. */ if ((options->output_format == DIFF_FORMAT_PATCH) || - (options->output_format == DIFF_FORMAT_DIFFSTAT)) + (options->output_format == DIFF_FORMAT_DIFFSTAT) || + (options->output_format == DIFF_FORMAT_CHECKDIFF)) options->recursive = 1; if (options->detect_rename && options->rename_limit < 0) @@ -1288,6 +1383,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) } else if (!strcmp(arg, "--stat")) options->output_format = DIFF_FORMAT_DIFFSTAT; + else if (!strcmp(arg, "--check")) + options->output_format = DIFF_FORMAT_CHECKDIFF; else if (!strcmp(arg, "--summary")) options->summary = 1; else if (!strcmp(arg, "--patch-with-stat")) { @@ -1610,6 +1707,19 @@ 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, + struct diff_options *o) +{ + if (diff_unmodified_pair(p)) + return; + + 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 */ + + run_checkdiff(p, o); +} + int diff_queue_is_empty(void) { struct diff_queue_struct *q = &diff_queued_diff; @@ -1740,6 +1850,9 @@ static void flush_one_pair(struct diff_filepair *p, case DIFF_FORMAT_DIFFSTAT: diff_flush_stat(p, options, diffstat); break; + case DIFF_FORMAT_CHECKDIFF: + diff_flush_checkdiff(p, options); + break; case DIFF_FORMAT_PATCH: diff_flush_patch(p, options); break; -- cgit v1.3 From 698ce6f87e0d6db380f7306e190e8586da184577 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 20 May 2006 15:40:29 +0200 Subject: fmt-patch: Support --attach This patch touches a couple of files, because it adds options to print a custom text just after the subject of a commit, and just after the diffstat. [jc: made "many dashes" used as the boundary leader into a single variable, to reduce the possibility of later tweaks to miscount the number of dashes to break it.] Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-log.c | 17 ++++++++++++++--- builtin-rev-list.c | 2 +- commit.c | 10 +++++++++- commit.h | 2 +- diff.c | 6 +++++- diff.h | 3 +++ log-tree.c | 37 +++++++++++++++++++++++++++++++++---- revision.h | 1 + show-branch.c | 2 +- 9 files changed, 68 insertions(+), 12 deletions(-) (limited to 'diff.c') diff --git a/builtin-log.c b/builtin-log.c index 12a6d19203..c8feb0f795 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -183,7 +183,12 @@ int cmd_format_patch(int argc, const char **argv, char **envp) argv[i + 1]); output_directory = strdup(argv[i + 1]); i++; - } else + } + else if (!strcmp(argv[i], "--attach")) + rev.mime_boundary = git_version_string; + else if (!strncmp(argv[i], "--attach=", 9)) + rev.mime_boundary = argv[i] + 9; + else argv[j++] = argv[i]; } argc = j; @@ -224,8 +229,14 @@ int cmd_format_patch(int argc, const char **argv, char **envp) shown = log_tree_commit(&rev, commit); free(commit->buffer); commit->buffer = NULL; - if (shown) - printf("-- \n%s\n\n", git_version_string); + if (shown) { + if (rev.mime_boundary) + printf("\n--%s%s--\n\n\n", + mime_boundary_leader, + rev.mime_boundary); + else + printf("-- \n%s\n\n", git_version_string); + } if (!use_stdout) fclose(stdout); } diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 7942297d13..f11dbd65c1 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -85,7 +85,7 @@ static void show_commit(struct commit *commit) static char pretty_header[16384]; pretty_print_commit(revs.commit_format, commit, ~0, pretty_header, sizeof(pretty_header), - revs.abbrev, NULL); + revs.abbrev, NULL, NULL); printf("%s%c", pretty_header, hdr_termination); } fflush(stdout); diff --git a/commit.c b/commit.c index 84558bac29..0b163d4857 100644 --- a/commit.c +++ b/commit.c @@ -498,7 +498,7 @@ static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *com return offset; } -unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject) +unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject) { int hdr = 1, body = 0; unsigned long offset = 0; @@ -591,6 +591,14 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit buf[offset++] = '\n'; if (fmt == CMIT_FMT_ONELINE) break; + if (after_subject) { + int slen = strlen(after_subject); + if (slen > space - offset - 1) + slen = space - offset - 1; + memcpy(buf + offset, after_subject, slen); + offset += slen; + after_subject = NULL; + } subject = NULL; } while (offset && isspace(buf[offset-1])) diff --git a/commit.h b/commit.h index 8d7514cd00..c9de1677e9 100644 --- a/commit.h +++ b/commit.h @@ -51,7 +51,7 @@ enum cmit_fmt { }; extern enum cmit_fmt get_commit_format(const char *arg); -extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject); +extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject); /** Removes the first commit from a list sorted by date, and adds all * of its parents. diff --git a/diff.c b/diff.c index af5db0ec12..be459cac69 100644 --- a/diff.c +++ b/diff.c @@ -299,6 +299,7 @@ static void diffstat_consume(void *priv, char *line, unsigned long len) static const char pluses[] = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; static const char minuses[]= "----------------------------------------------------------------------"; +const char mime_boundary_leader[] = "------------"; static void show_stats(struct diffstat_t* data) { @@ -1980,7 +1981,10 @@ void diff_flush(struct diff_options *options) show_stats(diffstat); free(diffstat); diffstat = NULL; - putchar(options->line_termination); + if (options->stat_sep) + fputs(options->stat_sep, stdout); + else + putchar(options->line_termination); } for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; diff --git a/diff.h b/diff.h index c672277df2..4fc597c594 100644 --- a/diff.h +++ b/diff.h @@ -44,6 +44,7 @@ struct diff_options { int rename_limit; int setup; int abbrev; + const char *stat_sep; int nr_paths; const char **paths; @@ -52,6 +53,8 @@ struct diff_options { add_remove_fn_t add_remove; }; +extern const char mime_boundary_leader[]; + extern void diff_tree_setup_paths(const char **paths, struct diff_options *); extern void diff_tree_release_paths(struct diff_options *); extern int diff_tree(struct tree_desc *t1, struct tree_desc *t2, diff --git a/log-tree.c b/log-tree.c index 526d578e98..7e23e42788 100644 --- a/log-tree.c +++ b/log-tree.c @@ -20,7 +20,7 @@ void show_log(struct rev_info *opt, struct log_info *log, const char *sep) int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40; const char *extra; int len; - char* subject = NULL; + char *subject = NULL, *after_subject = NULL; opt->loginfo = NULL; if (!opt->verbose_header) { @@ -52,6 +52,7 @@ void show_log(struct rev_info *opt, struct log_info *log, const char *sep) */ if (opt->commit_format == CMIT_FMT_EMAIL) { + char *sha1 = sha1_to_hex(commit->object.sha1); if (opt->total > 0) { static char buffer[64]; snprintf(buffer, sizeof(buffer), @@ -63,8 +64,36 @@ void show_log(struct rev_info *opt, struct log_info *log, const char *sep) else subject = "Subject: "; - printf("From %s Thu Apr 7 15:13:13 2005\n", - sha1_to_hex(commit->object.sha1)); + printf("From %s Mon Sep 17 00:00:00 2001\n", sha1); + if (opt->mime_boundary) { + static char subject_buffer[1024]; + static char buffer[1024]; + snprintf(subject_buffer, sizeof(subject_buffer) - 1, + "MIME-Version: 1.0\n" + "Content-Type: multipart/mixed;\n" + " boundary=\"%s%s\"\n" + "\n" + "This is a multi-part message in MIME " + "format.\n" + "--%s%s\n" + "Content-Type: text/plain; " + "charset=UTF-8; format=fixed\n" + "Content-Transfer-Encoding: 8bit\n\n", + mime_boundary_leader, opt->mime_boundary, + mime_boundary_leader, opt->mime_boundary); + after_subject = subject_buffer; + + snprintf(buffer, sizeof(buffer) - 1, + "--%s%s\n" + "Content-Type: text/x-patch;\n" + " name=\"%s.diff\"\n" + "Content-Transfer-Encoding: 8bit\n" + "Content-Disposition: inline;\n" + " filename=\"%s.diff\"\n\n", + mime_boundary_leader, opt->mime_boundary, + sha1, sha1); + opt->diffopt.stat_sep = buffer; + } } else { printf("%s%s", opt->commit_format == CMIT_FMT_ONELINE ? "" : "commit ", @@ -81,7 +110,7 @@ void show_log(struct rev_info *opt, struct log_info *log, const char *sep) /* * And then the pretty-printed message itself */ - len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header, sizeof(this_header), abbrev, subject); + len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header, sizeof(this_header), abbrev, subject, after_subject); printf("%s%s%s", this_header, extra, sep); } diff --git a/revision.h b/revision.h index 62759f7bc0..bdbdd235d8 100644 --- a/revision.h +++ b/revision.h @@ -59,6 +59,7 @@ struct rev_info { enum cmit_fmt commit_format; struct log_info *loginfo; int nr, total; + const char *mime_boundary; /* special limits */ int max_count; diff --git a/show-branch.c b/show-branch.c index bbe26c2e7a..684ffd187c 100644 --- a/show-branch.c +++ b/show-branch.c @@ -259,7 +259,7 @@ static void show_one_commit(struct commit *commit, int no_name) struct commit_name *name = commit->object.util; if (commit->object.parsed) pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, - pretty, sizeof(pretty), 0, NULL); + pretty, sizeof(pretty), 0, NULL, NULL); else strcpy(pretty, "(unavailable)"); if (!strncmp(pretty, "[PATCH] ", 8)) -- cgit v1.3 From 9e848163eda686093f689c25cfa9937ed2a9fdf8 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 21 May 2006 03:01:59 -0700 Subject: checkdiff_consume: strtol parameter fix. The second parameter is not the end of string input; it is the optional return value to retrieve where the parser stopped. Signed-off-by: Junio C Hamano --- diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index af5db0ec12..d3bb10e009 100644 --- a/diff.c +++ b/diff.c @@ -431,7 +431,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) else if (line[0] == '@') { char *plus = strchr(line, '+'); if (plus) - data->lineno = strtol(plus, line + len, 10); + data->lineno = strtol(plus, NULL, 10); else die("invalid diff"); } -- cgit v1.3 From 5e363541d0431b640e4bbbafb2941d1c64fa13c4 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 22 May 2006 00:31:02 -0700 Subject: diff: minor option combination fix. output_format == DIFFSTAT and with_stat == true does not make sense, and the way the code is structured it causes trouble. Avoid it. Signed-off-by: Junio C Hamano --- diff.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'diff.c') diff --git a/diff.c b/diff.c index d3bb10e009..1601783679 100644 --- a/diff.c +++ b/diff.c @@ -1303,6 +1303,14 @@ int diff_setup_done(struct diff_options *options) (options->output_format == DIFF_FORMAT_CHECKDIFF)) options->recursive = 1; + /* + * These combinations do not make sense. + */ + if (options->output_format == DIFF_FORMAT_RAW) + options->with_raw = 0; + if (options->output_format == DIFF_FORMAT_DIFFSTAT) + options->with_stat = 0; + if (options->detect_rename && options->rename_limit < 0) options->rename_limit = diff_rename_limit_default; if (options->setup & DIFF_SETUP_USE_CACHE) { -- cgit v1.3 From e3008464e70d25b4926b97b1f86951d7a3cb938d Mon Sep 17 00:00:00 2001 From: Sean Date: Mon, 22 May 2006 20:36:34 -0400 Subject: Avoid segfault in diff --stat rename output. Signed-off-by: Sean Estabrooks Signed-off-by: Junio C Hamano --- diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 1601783679..3a2a175c7e 100644 --- a/diff.c +++ b/diff.c @@ -237,7 +237,7 @@ static char *pprint_rename(const char *a, const char *b) if (a_midlen < 0) a_midlen = 0; if (b_midlen < 0) b_midlen = 0; - name = xmalloc(len_a + len_b - pfx_length - sfx_length + 7); + name = xmalloc(pfx_length + a_midlen + b_midlen + sfx_length + 7); sprintf(name, "%.*s{%.*s => %.*s}%s", pfx_length, a, a_midlen, a + pfx_length, -- cgit v1.3 From fad70686b25c414b6224406d42a4dfb7c4136e85 Mon Sep 17 00:00:00 2001 From: Sean Date: Tue, 23 May 2006 05:34:23 -0400 Subject: --summary output should print immediately after stats. Currently the summary is displayed after the patch. Fix this so that the output order is stat-summary-patch. As a consequence of the way this is coded, the --summary option will only actually display summary data if combined with either the --stat or --patch-with-stat option. Signed-off-by: Sean Estabrooks Signed-off-by: Junio C Hamano --- diff.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 3a2a175c7e..77c09a87b0 100644 --- a/diff.c +++ b/diff.c @@ -1988,6 +1988,9 @@ void diff_flush(struct diff_options *options) show_stats(diffstat); free(diffstat); diffstat = NULL; + if (options->summary) + for (i = 0; i < q->nr; i++) + diff_summary(q->queue[i]); putchar(options->line_termination); } for (i = 0; i < q->nr; i++) { @@ -2001,7 +2004,7 @@ void diff_flush(struct diff_options *options) } for (i = 0; i < q->nr; i++) { - if (options->summary) + if (diffstat && options->summary) diff_summary(q->queue[i]); diff_free_filepair(q->queue[i]); } -- cgit v1.3