diff options
Diffstat (limited to 'range-diff.c')
-rw-r--r-- | range-diff.c | 178 |
1 files changed, 107 insertions, 71 deletions
diff --git a/range-diff.c b/range-diff.c index 40af086281..1a4471fe4c 100644 --- a/range-diff.c +++ b/range-diff.c @@ -2,7 +2,7 @@ #include "range-diff.h" #include "string-list.h" #include "run-command.h" -#include "argv-array.h" +#include "strvec.h" #include "hashmap.h" #include "xdiff-interface.h" #include "linear-assignment.h" @@ -11,6 +11,7 @@ #include "pretty.h" #include "userdiff.h" #include "apply.h" +#include "revision.h" struct patch_util { /* For the search for an exact match */ @@ -41,7 +42,7 @@ static size_t find_end_of_line(char *buffer, unsigned long size) * as struct object_id (will need to be free()d). */ static int read_patches(const char *range, struct string_list *list, - const struct argv_array *other_arg) + const struct strvec *other_arg) { struct child_process cp = CHILD_PROCESS_INIT; struct strbuf buf = STRBUF_INIT, contents = STRBUF_INIT; @@ -51,24 +52,24 @@ static int read_patches(const char *range, struct string_list *list, int offset, len; size_t size; - argv_array_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges", - "--reverse", "--date-order", "--decorate=no", - "--no-prefix", - /* - * Choose indicators that are not used anywhere - * else in diffs, but still look reasonable - * (e.g. will not be confusing when debugging) - */ - "--output-indicator-new=>", - "--output-indicator-old=<", - "--output-indicator-context=#", - "--no-abbrev-commit", - "--pretty=medium", - "--notes", - NULL); + strvec_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges", + "--reverse", "--date-order", "--decorate=no", + "--no-prefix", + /* + * Choose indicators that are not used anywhere + * else in diffs, but still look reasonable + * (e.g. will not be confusing when debugging) + */ + "--output-indicator-new=>", + "--output-indicator-old=<", + "--output-indicator-context=#", + "--no-abbrev-commit", + "--pretty=medium", + "--notes", + NULL); if (other_arg) - argv_array_pushv(&cp.args, other_arg->argv); - argv_array_push(&cp.args, range); + strvec_pushv(&cp.args, other_arg->v); + strvec_push(&cp.args, range); cp.out = -1; cp.no_stdin = 1; cp.git_cmd = 1; @@ -80,6 +81,8 @@ static int read_patches(const char *range, struct string_list *list, finish_command(&cp); return -1; } + if (finish_command(&cp)) + return -1; line = contents.buf; size = contents.len; @@ -93,14 +96,14 @@ static int read_patches(const char *range, struct string_list *list, string_list_append(list, buf.buf)->util = util; strbuf_reset(&buf); } - util = xcalloc(sizeof(*util), 1); + CALLOC_ARRAY(util, 1); if (get_oid(p, &util->oid)) { error(_("could not parse commit '%s'"), p); free(util); + free(current_filename); string_list_clear(list, 1); strbuf_release(&buf); strbuf_release(&contents); - finish_command(&cp); return -1; } util->matching = -1; @@ -112,10 +115,10 @@ static int read_patches(const char *range, struct string_list *list, error(_("could not parse first line of `log` output: " "did not start with 'commit ': '%s'"), line); + free(current_filename); string_list_clear(list, 1); strbuf_release(&buf); strbuf_release(&contents); - finish_command(&cp); return -1; } @@ -133,9 +136,16 @@ static int read_patches(const char *range, struct string_list *list, orig_len = len; len = parse_git_diff_header(&root, &linenr, 0, line, len, size, &patch); - if (len < 0) - die(_("could not parse git header '%.*s'"), - orig_len, line); + if (len < 0) { + error(_("could not parse git header '%.*s'"), + orig_len, line); + free(util); + free(current_filename); + string_list_clear(list, 1); + strbuf_release(&buf); + strbuf_release(&contents); + return -1; + } strbuf_addstr(&buf, " ## "); if (patch.is_new > 0) strbuf_addf(&buf, "%s (new)", patch.new_name); @@ -218,9 +228,6 @@ static int read_patches(const char *range, struct string_list *list, strbuf_release(&buf); free(current_filename); - if (finish_command(&cp)) - return -1; - return 0; } @@ -232,11 +239,9 @@ static int patch_util_cmp(const void *dummy, const struct patch_util *a, static void find_exact_matches(struct string_list *a, struct string_list *b) { - struct hashmap map; + struct hashmap map = HASHMAP_INIT((hashmap_cmp_fn)patch_util_cmp, NULL); int i; - hashmap_init(&map, (hashmap_cmp_fn)patch_util_cmp, NULL, 0); - /* First, add the patches of a to a hash map */ for (i = 0; i < a->nr; i++) { struct patch_util *util = a->items[i].util; @@ -266,7 +271,7 @@ static void find_exact_matches(struct string_list *a, struct string_list *b) } } - hashmap_free(&map); + hashmap_clear(&map); } static void diffsize_consume(void *data, char *line, unsigned long len) @@ -440,7 +445,7 @@ static struct diff_filespec *get_filespec(const char *name, const char *p) { struct diff_filespec *spec = alloc_filespec(name); - fill_filespec(spec, &null_oid, 0, 0100644); + fill_filespec(spec, null_oid(), 0, 0100644); spec->data = (char *)p; spec->size = strlen(p); spec->should_munmap = 0; @@ -460,12 +465,35 @@ static void patch_diff(const char *a, const char *b, diff_flush(diffopt); } +static struct strbuf *output_prefix_cb(struct diff_options *opt, void *data) +{ + return data; +} + static void output(struct string_list *a, struct string_list *b, - struct diff_options *diffopt) + struct range_diff_options *range_diff_opts) { struct strbuf buf = STRBUF_INIT, dashes = STRBUF_INIT; int patch_no_width = decimal_width(1 + (a->nr > b->nr ? a->nr : b->nr)); int i = 0, j = 0; + struct diff_options opts; + struct strbuf indent = STRBUF_INIT; + + if (range_diff_opts->diffopt) + memcpy(&opts, range_diff_opts->diffopt, sizeof(opts)); + else + diff_setup(&opts); + + if (!opts.output_format) + opts.output_format = DIFF_FORMAT_PATCH; + opts.flags.suppress_diff_headers = 1; + opts.flags.dual_color_diffed_diffs = + range_diff_opts->dual_color; + opts.flags.suppress_hunk_header_line_count = 1; + opts.output_prefix = output_prefix_cb; + strbuf_addstr(&indent, " "); + opts.output_prefix_data = &indent; + diff_setup_done(&opts); /* * We assume the user is really more interested in the second argument @@ -486,7 +514,8 @@ static void output(struct string_list *a, struct string_list *b, /* Show unmatched LHS commit whose predecessors were shown. */ if (i < a->nr && a_util->matching < 0) { - output_pair_header(diffopt, patch_no_width, + if (!range_diff_opts->right_only) + output_pair_header(&opts, patch_no_width, &buf, &dashes, a_util, NULL); i++; continue; @@ -494,7 +523,8 @@ static void output(struct string_list *a, struct string_list *b, /* Show unmatched RHS commits. */ while (j < b->nr && b_util->matching < 0) { - output_pair_header(diffopt, patch_no_width, + if (!range_diff_opts->left_only) + output_pair_header(&opts, patch_no_width, &buf, &dashes, NULL, b_util); b_util = ++j < b->nr ? b->items[j].util : NULL; } @@ -502,63 +532,41 @@ static void output(struct string_list *a, struct string_list *b, /* Show matching LHS/RHS pair. */ if (j < b->nr) { a_util = a->items[b_util->matching].util; - output_pair_header(diffopt, patch_no_width, + output_pair_header(&opts, patch_no_width, &buf, &dashes, a_util, b_util); - if (!(diffopt->output_format & DIFF_FORMAT_NO_OUTPUT)) + if (!(opts.output_format & DIFF_FORMAT_NO_OUTPUT)) patch_diff(a->items[b_util->matching].string, - b->items[j].string, diffopt); + b->items[j].string, &opts); a_util->shown = 1; j++; } } strbuf_release(&buf); strbuf_release(&dashes); -} - -static struct strbuf *output_prefix_cb(struct diff_options *opt, void *data) -{ - return data; + strbuf_release(&indent); } int show_range_diff(const char *range1, const char *range2, - int creation_factor, int dual_color, - const struct diff_options *diffopt, - const struct argv_array *other_arg) + struct range_diff_options *range_diff_opts) { int res = 0; struct string_list branch1 = STRING_LIST_INIT_DUP; struct string_list branch2 = STRING_LIST_INIT_DUP; - if (read_patches(range1, &branch1, other_arg)) + if (range_diff_opts->left_only && range_diff_opts->right_only) + res = error(_("--left-only and --right-only are mutually exclusive")); + + if (!res && read_patches(range1, &branch1, range_diff_opts->other_arg)) res = error(_("could not parse log for '%s'"), range1); - if (!res && read_patches(range2, &branch2, other_arg)) + if (!res && read_patches(range2, &branch2, range_diff_opts->other_arg)) res = error(_("could not parse log for '%s'"), range2); if (!res) { - struct diff_options opts; - struct strbuf indent = STRBUF_INIT; - - if (diffopt) - memcpy(&opts, diffopt, sizeof(opts)); - else - diff_setup(&opts); - - if (!opts.output_format) - opts.output_format = DIFF_FORMAT_PATCH; - opts.flags.suppress_diff_headers = 1; - opts.flags.dual_color_diffed_diffs = dual_color; - opts.flags.suppress_hunk_header_line_count = 1; - opts.output_prefix = output_prefix_cb; - strbuf_addstr(&indent, " "); - opts.output_prefix_data = &indent; - diff_setup_done(&opts); - find_exact_matches(&branch1, &branch2); - get_correspondences(&branch1, &branch2, creation_factor); - output(&branch1, &branch2, &opts); - - strbuf_release(&indent); + get_correspondences(&branch1, &branch2, + range_diff_opts->creation_factor); + output(&branch1, &branch2, range_diff_opts); } string_list_clear(&branch1, 1); @@ -566,3 +574,31 @@ int show_range_diff(const char *range1, const char *range2, return res; } + +int is_range_diff_range(const char *arg) +{ + char *copy = xstrdup(arg); /* setup_revisions() modifies it */ + const char *argv[] = { "", copy, "--", NULL }; + int i, positive = 0, negative = 0; + struct rev_info revs; + + init_revisions(&revs, NULL); + if (setup_revisions(3, argv, &revs, NULL) == 1) { + for (i = 0; i < revs.pending.nr; i++) + if (revs.pending.objects[i].item->flags & UNINTERESTING) + negative++; + else + positive++; + for (i = 0; i < revs.pending.nr; i++) { + struct object *obj = revs.pending.objects[i].item; + + if (obj->type == OBJ_COMMIT) + clear_commit_marks((struct commit *)obj, + ALL_REV_FLAGS); + } + } + + free(copy); + object_array_clear(&revs.pending); + return negative > 0 && positive > 0; +} |