diff options
author | Patrick Steinhardt <ps@pks.im> | 2019-11-28 14:41:58 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-11-28 14:41:58 +0100 |
commit | fb439c975a2de33f5b0c317f3fdea49dc94b27dc (patch) | |
tree | ae22d26f1bc5d91f947577c291309cb57c2ebd77 | |
parent | 61176a9b363b1274c101d82f36cbf9cb71a10f74 (diff) | |
parent | ece5bb5e7d6e35e50096bac3d7bf17342daaec77 (diff) | |
download | libgit2-fb439c975a2de33f5b0c317f3fdea49dc94b27dc.tar.gz |
Merge pull request #5306 from herrerog/patchid
diff: complete support for git patchid
-rw-r--r-- | include/git2/diff.h | 1 | ||||
-rw-r--r-- | src/diff.c | 82 | ||||
-rw-r--r-- | src/diff.h | 3 | ||||
-rw-r--r-- | src/diff_print.c | 26 | ||||
-rw-r--r-- | src/patch.c | 2 | ||||
-rw-r--r-- | src/patch_parse.c | 13 | ||||
-rw-r--r-- | tests/diff/patchid.c | 33 | ||||
-rw-r--r-- | tests/patch/patch_common.h | 38 | ||||
-rw-r--r-- | tests/patch/print.c | 6 |
9 files changed, 130 insertions, 74 deletions
diff --git a/include/git2/diff.h b/include/git2/diff.h index 490b40605..3976ab1b9 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -1093,6 +1093,7 @@ typedef enum { GIT_DIFF_FORMAT_RAW = 3u, /**< like git diff --raw */ GIT_DIFF_FORMAT_NAME_ONLY = 4u, /**< like git diff --name-only */ GIT_DIFF_FORMAT_NAME_STATUS = 5u, /**< like git diff --name-status */ + GIT_DIFF_FORMAT_PATCH_ID = 6u, /**< git diff as used by git patch-id */ } git_diff_format_t; /** diff --git a/src/diff.c b/src/diff.c index 15a32ed48..47f49d949 100644 --- a/src/diff.c +++ b/src/diff.c @@ -426,81 +426,38 @@ static void strip_spaces(git_buf *buf) git_buf_truncate(buf, len); } -static int file_cb( +int git_diff_patchid_print_callback__to_buf( const git_diff_delta *delta, - float progress, + const git_diff_hunk *hunk, + const git_diff_line *line, void *payload) { struct patch_id_args *args = (struct patch_id_args *) payload; git_buf buf = GIT_BUF_INIT; - int error; - - GIT_UNUSED(progress); + int error = 0; - if (!args->first_file && - (error = flush_hunk(&args->result, &args->ctx)) < 0) - goto out; - args->first_file = 0; - - if ((error = git_buf_printf(&buf, - "diff--gita/%sb/%s---a/%s+++b/%s", - delta->old_file.path, - delta->new_file.path, - delta->old_file.path, - delta->new_file.path)) < 0) + if (line->origin == GIT_DIFF_LINE_CONTEXT_EOFNL || + line->origin == GIT_DIFF_LINE_ADD_EOFNL || + line->origin == GIT_DIFF_LINE_DEL_EOFNL) goto out; - strip_spaces(&buf); - - if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0) + if ((error = git_diff_print_callback__to_buf(delta, hunk, + line, &buf)) < 0) goto out; -out: - git_buf_dispose(&buf); - return error; -} - -static int patchid_line_cb( - const git_diff_delta *delta, - const git_diff_hunk *hunk, - const git_diff_line *line, - void *payload) -{ - struct patch_id_args *args = (struct patch_id_args *) payload; - git_buf buf = GIT_BUF_INIT; - int error; - - GIT_UNUSED(delta); - GIT_UNUSED(hunk); - - switch (line->origin) { - case GIT_DIFF_LINE_ADDITION: - git_buf_putc(&buf, '+'); - break; - case GIT_DIFF_LINE_DELETION: - git_buf_putc(&buf, '-'); - break; - case GIT_DIFF_LINE_CONTEXT: - break; - case GIT_DIFF_LINE_CONTEXT_EOFNL: - case GIT_DIFF_LINE_ADD_EOFNL: - case GIT_DIFF_LINE_DEL_EOFNL: - /* - * Ignore EOF without newlines for patch IDs as whitespace is - * not supposed to be significant. - */ - return 0; - default: - git_error_set(GIT_ERROR_PATCH, "invalid line origin for patch"); - return -1; - } - - git_buf_put(&buf, line->content, line->content_len); strip_spaces(&buf); + if (line->origin == GIT_DIFF_LINE_FILE_HDR && + !args->first_file && + (error = flush_hunk(&args->result, &args->ctx) < 0)) + goto out; + if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0) goto out; + if (line->origin == GIT_DIFF_LINE_FILE_HDR && args->first_file) + args->first_file = 0; + out: git_buf_dispose(&buf); return error; @@ -526,7 +483,10 @@ int git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opt if ((error = git_hash_ctx_init(&args.ctx)) < 0) goto out; - if ((error = git_diff_foreach(diff, file_cb, NULL, NULL, patchid_line_cb, &args)) < 0) + if ((error = git_diff_print(diff, + GIT_DIFF_FORMAT_PATCH_ID, + git_diff_patchid_print_callback__to_buf, + &args)) < 0) goto out; if ((error = (flush_hunk(&args.result, &args.ctx))) < 0) diff --git a/src/diff.h b/src/diff.h index 93374b96e..1a4ee47e0 100644 --- a/src/diff.h +++ b/src/diff.h @@ -57,7 +57,8 @@ extern int git_diff_delta__format_file_header( const git_diff_delta *delta, const char *oldpfx, const char *newpfx, - int oid_strlen); + int oid_strlen, + bool print_index); extern int git_diff_delta__cmp(const void *a, const void *b); extern int git_diff_delta__casecmp(const void *a, const void *b); diff --git a/src/diff_print.c b/src/diff_print.c index f1aac5eb0..369e5c1e6 100644 --- a/src/diff_print.c +++ b/src/diff_print.c @@ -269,7 +269,8 @@ static int diff_print_modes( } static int diff_print_oid_range( - git_buf *out, const git_diff_delta *delta, int id_strlen) + git_buf *out, const git_diff_delta *delta, int id_strlen, + bool print_index) { char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; @@ -293,8 +294,9 @@ static int diff_print_oid_range( git_oid_tostr(end_oid, id_strlen + 1, &delta->new_file.id); if (delta->old_file.mode == delta->new_file.mode) { - git_buf_printf(out, "index %s..%s %o\n", - start_oid, end_oid, delta->old_file.mode); + if (print_index) + git_buf_printf(out, "index %s..%s %o\n", + start_oid, end_oid, delta->old_file.mode); } else { if (delta->old_file.mode == 0) git_buf_printf(out, "new file mode %o\n", delta->new_file.mode); @@ -303,7 +305,8 @@ static int diff_print_oid_range( else diff_print_modes(out, delta); - git_buf_printf(out, "index %s..%s\n", start_oid, end_oid); + if (print_index) + git_buf_printf(out, "index %s..%s\n", start_oid, end_oid); } return git_buf_oom(out) ? -1 : 0; @@ -400,7 +403,8 @@ int git_diff_delta__format_file_header( const git_diff_delta *delta, const char *oldpfx, const char *newpfx, - int id_strlen) + int id_strlen, + bool print_index) { git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT; bool unchanged = delta_is_unchanged(delta); @@ -431,7 +435,8 @@ int git_diff_delta__format_file_header( } if (!unchanged) { - if ((error = diff_print_oid_range(out, delta, id_strlen)) < 0) + if ((error = diff_print_oid_range(out, delta, + id_strlen, print_index)) < 0) goto done; if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) @@ -566,6 +571,7 @@ static int diff_print_patch_file( (pi->flags & GIT_DIFF_FORCE_BINARY); bool show_binary = !!(pi->flags & GIT_DIFF_SHOW_BINARY); int id_strlen = pi->id_strlen; + bool print_index = (pi->format != GIT_DIFF_FORMAT_PATCH_ID); if (binary && show_binary) id_strlen = delta->old_file.id_abbrev ? delta->old_file.id_abbrev : @@ -582,7 +588,8 @@ static int diff_print_patch_file( return 0; if ((error = git_diff_delta__format_file_header( - pi->buf, delta, oldpfx, newpfx, id_strlen)) < 0) + pi->buf, delta, oldpfx, newpfx, + id_strlen, print_index)) < 0) return error; pi->line.origin = GIT_DIFF_LINE_FILE_HDR; @@ -670,6 +677,11 @@ int git_diff_print( print_hunk = diff_print_patch_hunk; print_line = diff_print_patch_line; break; + case GIT_DIFF_FORMAT_PATCH_ID: + print_file = diff_print_patch_file; + print_binary = diff_print_patch_binary; + print_line = diff_print_patch_line; + break; case GIT_DIFF_FORMAT_PATCH_HEADER: print_file = diff_print_patch_file; break; diff --git a/src/patch.c b/src/patch.c index d19e6833e..82181bb3d 100644 --- a/src/patch.c +++ b/src/patch.c @@ -79,7 +79,7 @@ size_t git_patch_size( git_buf file_header = GIT_BUF_INIT; if (git_diff_delta__format_file_header( - &file_header, patch->delta, NULL, NULL, 0) < 0) + &file_header, patch->delta, NULL, NULL, 0, true) < 0) git_error_clear(); else out += git_buf_len(&file_header); diff --git a/src/patch_parse.c b/src/patch_parse.c index 35fd65a0d..dad1813fa 100644 --- a/src/patch_parse.c +++ b/src/patch_parse.c @@ -231,9 +231,9 @@ static int parse_header_git_deletedfilemode( git_patch_parsed *patch, git_patch_parse_ctx *ctx) { - git__free((char *)patch->base.delta->old_file.path); + git__free((char *)patch->base.delta->new_file.path); - patch->base.delta->old_file.path = NULL; + patch->base.delta->new_file.path = NULL; patch->base.delta->status = GIT_DELTA_DELETED; patch->base.delta->nfiles = 1; @@ -244,9 +244,9 @@ static int parse_header_git_newfilemode( git_patch_parsed *patch, git_patch_parse_ctx *ctx) { - git__free((char *)patch->base.delta->new_file.path); + git__free((char *)patch->base.delta->old_file.path); - patch->base.delta->new_file.path = NULL; + patch->base.delta->old_file.path = NULL; patch->base.delta->status = GIT_DELTA_ADDED; patch->base.delta->nfiles = 1; @@ -884,6 +884,11 @@ static int parse_patch_binary_nodata( if (!old || !new) return git_parse_err("corrupt binary data without paths at line %"PRIuZ, ctx->parse_ctx.line_num); + if (patch->base.delta->status == GIT_DELTA_ADDED) + old = "/dev/null"; + else if (patch->base.delta->status == GIT_DELTA_DELETED) + new = "/dev/null"; + if (git_parse_advance_expected_str(&ctx->parse_ctx, "Binary files ") < 0 || git_parse_advance_expected_str(&ctx->parse_ctx, old) < 0 || git_parse_advance_expected_str(&ctx->parse_ctx, " and ") < 0 || diff --git a/tests/diff/patchid.c b/tests/diff/patchid.c index 75a2aa814..621a720f7 100644 --- a/tests/diff/patchid.c +++ b/tests/diff/patchid.c @@ -20,6 +20,39 @@ void test_diff_patchid__simple_commit(void) verify_patch_id(PATCH_SIMPLE_COMMIT, "06094b1948b878b7d9ff7560b4eae672a014b0ec"); } +void test_diff_patchid__deleted_file(void) +{ + verify_patch_id(PATCH_DELETE_ORIGINAL, "d18507fe189f49c028b32c8c34e1ad98dd6a1aad"); + verify_patch_id(PATCH_DELETED_FILE_2_HUNKS, "f31412498a17e6c3fbc635f2c5f9aa3ef4c1a9b7"); +} + +void test_diff_patchid__created_file(void) +{ + verify_patch_id(PATCH_ADD_ORIGINAL, "a7d39379308021465ae2ce65e338c048a3110db6"); +} + +void test_diff_patchid__binary_file(void) +{ + verify_patch_id(PATCH_ADD_BINARY_NOT_PRINTED, "2b31236b485faa30cf4dd33e4d6539829996739f"); +} + +void test_diff_patchid__renamed_file(void) +{ + verify_patch_id(PATCH_RENAME_EXACT, "4666d50cea4976f6f727448046d43461912058fd"); + verify_patch_id(PATCH_RENAME_SIMILAR, "a795087575fcb940227be524488bedd6b3d3f438"); +} + +void test_diff_patchid__modechange(void) +{ + verify_patch_id(PATCH_MODECHANGE_UNCHANGED, "dbf3423ee98375ef1c72a79fbd29a049a2bae771"); + verify_patch_id(PATCH_MODECHANGE_MODIFIED, "93aba696e1bbd2bbb73e3e3e62ed71f232137657"); +} + +void test_diff_patchid__shuffle_hunks(void) +{ + verify_patch_id(PATCH_DELETED_FILE_2_HUNKS_SHUFFLED, "f31412498a17e6c3fbc635f2c5f9aa3ef4c1a9b7"); +} + void test_diff_patchid__filename_with_spaces(void) { verify_patch_id(PATCH_APPEND_NO_NL, "f0ba05413beaef743b630e796153839462ee477a"); diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h index 92ab7692e..660168551 100644 --- a/tests/patch/patch_common.h +++ b/tests/patch/patch_common.h @@ -385,6 +385,38 @@ "@@ -9,0 +10 @@ below it!\n" \ "+insert at end\n" +#define PATCH_DELETED_FILE_2_HUNKS \ + "diff --git a/a b/a\n" \ + "index 7f129fd..af431f2 100644\n" \ + "--- a/a\n" \ + "+++ b/a\n" \ + "@@ -1 +1 @@\n" \ + "-a contents 2\n" \ + "+a contents\n" \ + "diff --git a/c/d b/c/d\n" \ + "deleted file mode 100644\n" \ + "index 297efb8..0000000\n" \ + "--- a/c/d\n" \ + "+++ /dev/null\n" \ + "@@ -1 +0,0 @@\n" \ + "-c/d contents\n" + +#define PATCH_DELETED_FILE_2_HUNKS_SHUFFLED \ + "diff --git a/c/d b/c/d\n" \ + "deleted file mode 100644\n" \ + "index 297efb8..0000000\n" \ + "--- a/c/d\n" \ + "+++ /dev/null\n" \ + "@@ -1 +0,0 @@\n" \ + "-c/d contents\n" \ + "diff --git a/a b/a\n" \ + "index 7f129fd..af431f2 100644\n" \ + "--- a/a\n" \ + "+++ b/a\n" \ + "@@ -1 +1 @@\n" \ + "-a contents 2\n" \ + "+a contents\n" + #define PATCH_SIMPLE_COMMIT \ "commit 15e119375018fba121cf58e02a9f17fe22df0df8\n" \ "Author: Edward Thomson <ethomson@edwardthomson.com>\n" \ @@ -878,6 +910,12 @@ "index 27184d9..7c94f9e 100644\n" \ "Binary files a/binary.bin and b/binary.bin differ\n" +#define PATCH_ADD_BINARY_NOT_PRINTED \ + "diff --git a/test.bin b/test.bin\n" \ + "new file mode 100644\n" \ + "index 0000000..9e0f96a\n" \ + "Binary files /dev/null and b/test.bin differ\n" + #define PATCH_ORIGINAL_NEW_FILE_WITH_SPACE \ "diff --git a/sp ace.txt b/sp ace.txt\n" \ "new file mode 100644\n" \ diff --git a/tests/patch/print.c b/tests/patch/print.c index 4703c1d51..c4ff479e9 100644 --- a/tests/patch/print.c +++ b/tests/patch/print.c @@ -172,3 +172,9 @@ void test_patch_print__binary_not_shown(void) patch_print_from_patchfile(PATCH_BINARY_NOT_PRINTED, strlen(PATCH_BINARY_NOT_PRINTED)); } + +void test_patch_print__binary_add_not_shown(void) +{ + patch_print_from_patchfile(PATCH_ADD_BINARY_NOT_PRINTED, + strlen(PATCH_ADD_BINARY_NOT_PRINTED)); +} |