Unverified Commit fb439c97 by Patrick Steinhardt Committed by GitHub

Merge pull request #5306 from herrerog/patchid

diff: complete support for git patchid
parents 61176a9b ece5bb5e
...@@ -1093,6 +1093,7 @@ typedef enum { ...@@ -1093,6 +1093,7 @@ typedef enum {
GIT_DIFF_FORMAT_RAW = 3u, /**< like git diff --raw */ GIT_DIFF_FORMAT_RAW = 3u, /**< like git diff --raw */
GIT_DIFF_FORMAT_NAME_ONLY = 4u, /**< like git diff --name-only */ 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_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; } git_diff_format_t;
/** /**
......
...@@ -426,81 +426,38 @@ static void strip_spaces(git_buf *buf) ...@@ -426,81 +426,38 @@ static void strip_spaces(git_buf *buf)
git_buf_truncate(buf, len); git_buf_truncate(buf, len);
} }
static int file_cb( int git_diff_patchid_print_callback__to_buf(
const git_diff_delta *delta, const git_diff_delta *delta,
float progress, const git_diff_hunk *hunk,
const git_diff_line *line,
void *payload) void *payload)
{ {
struct patch_id_args *args = (struct patch_id_args *) payload; struct patch_id_args *args = (struct patch_id_args *) payload;
git_buf buf = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT;
int error; int error = 0;
GIT_UNUSED(progress);
if (!args->first_file && if (line->origin == GIT_DIFF_LINE_CONTEXT_EOFNL ||
(error = flush_hunk(&args->result, &args->ctx)) < 0) line->origin == GIT_DIFF_LINE_ADD_EOFNL ||
goto out; line->origin == GIT_DIFF_LINE_DEL_EOFNL)
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)
goto out; goto out;
strip_spaces(&buf); if ((error = git_diff_print_callback__to_buf(delta, hunk,
line, &buf)) < 0)
if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0)
goto out; 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); 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) if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0)
goto out; goto out;
if (line->origin == GIT_DIFF_LINE_FILE_HDR && args->first_file)
args->first_file = 0;
out: out:
git_buf_dispose(&buf); git_buf_dispose(&buf);
return error; return error;
...@@ -526,7 +483,10 @@ int git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opt ...@@ -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) if ((error = git_hash_ctx_init(&args.ctx)) < 0)
goto out; 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; goto out;
if ((error = (flush_hunk(&args.result, &args.ctx))) < 0) if ((error = (flush_hunk(&args.result, &args.ctx))) < 0)
......
...@@ -57,7 +57,8 @@ extern int git_diff_delta__format_file_header( ...@@ -57,7 +57,8 @@ extern int git_diff_delta__format_file_header(
const git_diff_delta *delta, const git_diff_delta *delta,
const char *oldpfx, const char *oldpfx,
const char *newpfx, 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__cmp(const void *a, const void *b);
extern int git_diff_delta__casecmp(const void *a, const void *b); extern int git_diff_delta__casecmp(const void *a, const void *b);
......
...@@ -269,7 +269,8 @@ static int diff_print_modes( ...@@ -269,7 +269,8 @@ static int diff_print_modes(
} }
static int diff_print_oid_range( 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]; char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
...@@ -293,8 +294,9 @@ static int diff_print_oid_range( ...@@ -293,8 +294,9 @@ static int diff_print_oid_range(
git_oid_tostr(end_oid, id_strlen + 1, &delta->new_file.id); git_oid_tostr(end_oid, id_strlen + 1, &delta->new_file.id);
if (delta->old_file.mode == delta->new_file.mode) { if (delta->old_file.mode == delta->new_file.mode) {
git_buf_printf(out, "index %s..%s %o\n", if (print_index)
start_oid, end_oid, delta->old_file.mode); git_buf_printf(out, "index %s..%s %o\n",
start_oid, end_oid, delta->old_file.mode);
} else { } else {
if (delta->old_file.mode == 0) if (delta->old_file.mode == 0)
git_buf_printf(out, "new file mode %o\n", delta->new_file.mode); git_buf_printf(out, "new file mode %o\n", delta->new_file.mode);
...@@ -303,7 +305,8 @@ static int diff_print_oid_range( ...@@ -303,7 +305,8 @@ static int diff_print_oid_range(
else else
diff_print_modes(out, delta); 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; return git_buf_oom(out) ? -1 : 0;
...@@ -400,7 +403,8 @@ int git_diff_delta__format_file_header( ...@@ -400,7 +403,8 @@ int git_diff_delta__format_file_header(
const git_diff_delta *delta, const git_diff_delta *delta,
const char *oldpfx, const char *oldpfx,
const char *newpfx, const char *newpfx,
int id_strlen) int id_strlen,
bool print_index)
{ {
git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT; git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT;
bool unchanged = delta_is_unchanged(delta); bool unchanged = delta_is_unchanged(delta);
...@@ -431,7 +435,8 @@ int git_diff_delta__format_file_header( ...@@ -431,7 +435,8 @@ int git_diff_delta__format_file_header(
} }
if (!unchanged) { 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; goto done;
if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0)
...@@ -566,6 +571,7 @@ static int diff_print_patch_file( ...@@ -566,6 +571,7 @@ static int diff_print_patch_file(
(pi->flags & GIT_DIFF_FORCE_BINARY); (pi->flags & GIT_DIFF_FORCE_BINARY);
bool show_binary = !!(pi->flags & GIT_DIFF_SHOW_BINARY); bool show_binary = !!(pi->flags & GIT_DIFF_SHOW_BINARY);
int id_strlen = pi->id_strlen; int id_strlen = pi->id_strlen;
bool print_index = (pi->format != GIT_DIFF_FORMAT_PATCH_ID);
if (binary && show_binary) if (binary && show_binary)
id_strlen = delta->old_file.id_abbrev ? delta->old_file.id_abbrev : id_strlen = delta->old_file.id_abbrev ? delta->old_file.id_abbrev :
...@@ -582,7 +588,8 @@ static int diff_print_patch_file( ...@@ -582,7 +588,8 @@ static int diff_print_patch_file(
return 0; return 0;
if ((error = git_diff_delta__format_file_header( 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; return error;
pi->line.origin = GIT_DIFF_LINE_FILE_HDR; pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
...@@ -670,6 +677,11 @@ int git_diff_print( ...@@ -670,6 +677,11 @@ int git_diff_print(
print_hunk = diff_print_patch_hunk; print_hunk = diff_print_patch_hunk;
print_line = diff_print_patch_line; print_line = diff_print_patch_line;
break; 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: case GIT_DIFF_FORMAT_PATCH_HEADER:
print_file = diff_print_patch_file; print_file = diff_print_patch_file;
break; break;
......
...@@ -79,7 +79,7 @@ size_t git_patch_size( ...@@ -79,7 +79,7 @@ size_t git_patch_size(
git_buf file_header = GIT_BUF_INIT; git_buf file_header = GIT_BUF_INIT;
if (git_diff_delta__format_file_header( 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(); git_error_clear();
else else
out += git_buf_len(&file_header); out += git_buf_len(&file_header);
......
...@@ -231,9 +231,9 @@ static int parse_header_git_deletedfilemode( ...@@ -231,9 +231,9 @@ static int parse_header_git_deletedfilemode(
git_patch_parsed *patch, git_patch_parsed *patch,
git_patch_parse_ctx *ctx) 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->status = GIT_DELTA_DELETED;
patch->base.delta->nfiles = 1; patch->base.delta->nfiles = 1;
...@@ -244,9 +244,9 @@ static int parse_header_git_newfilemode( ...@@ -244,9 +244,9 @@ static int parse_header_git_newfilemode(
git_patch_parsed *patch, git_patch_parsed *patch,
git_patch_parse_ctx *ctx) 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->status = GIT_DELTA_ADDED;
patch->base.delta->nfiles = 1; patch->base.delta->nfiles = 1;
...@@ -884,6 +884,11 @@ static int parse_patch_binary_nodata( ...@@ -884,6 +884,11 @@ static int parse_patch_binary_nodata(
if (!old || !new) if (!old || !new)
return git_parse_err("corrupt binary data without paths at line %"PRIuZ, ctx->parse_ctx.line_num); 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 || 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, old) < 0 ||
git_parse_advance_expected_str(&ctx->parse_ctx, " and ") < 0 || git_parse_advance_expected_str(&ctx->parse_ctx, " and ") < 0 ||
......
...@@ -20,6 +20,39 @@ void test_diff_patchid__simple_commit(void) ...@@ -20,6 +20,39 @@ void test_diff_patchid__simple_commit(void)
verify_patch_id(PATCH_SIMPLE_COMMIT, "06094b1948b878b7d9ff7560b4eae672a014b0ec"); 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) void test_diff_patchid__filename_with_spaces(void)
{ {
verify_patch_id(PATCH_APPEND_NO_NL, "f0ba05413beaef743b630e796153839462ee477a"); verify_patch_id(PATCH_APPEND_NO_NL, "f0ba05413beaef743b630e796153839462ee477a");
......
...@@ -385,6 +385,38 @@ ...@@ -385,6 +385,38 @@
"@@ -9,0 +10 @@ below it!\n" \ "@@ -9,0 +10 @@ below it!\n" \
"+insert at end\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 \ #define PATCH_SIMPLE_COMMIT \
"commit 15e119375018fba121cf58e02a9f17fe22df0df8\n" \ "commit 15e119375018fba121cf58e02a9f17fe22df0df8\n" \
"Author: Edward Thomson <ethomson@edwardthomson.com>\n" \ "Author: Edward Thomson <ethomson@edwardthomson.com>\n" \
...@@ -878,6 +910,12 @@ ...@@ -878,6 +910,12 @@
"index 27184d9..7c94f9e 100644\n" \ "index 27184d9..7c94f9e 100644\n" \
"Binary files a/binary.bin and b/binary.bin differ\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 \ #define PATCH_ORIGINAL_NEW_FILE_WITH_SPACE \
"diff --git a/sp ace.txt b/sp ace.txt\n" \ "diff --git a/sp ace.txt b/sp ace.txt\n" \
"new file mode 100644\n" \ "new file mode 100644\n" \
......
...@@ -172,3 +172,9 @@ void test_patch_print__binary_not_shown(void) ...@@ -172,3 +172,9 @@ void test_patch_print__binary_not_shown(void)
patch_print_from_patchfile(PATCH_BINARY_NOT_PRINTED, patch_print_from_patchfile(PATCH_BINARY_NOT_PRINTED,
strlen(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));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment