diff --git a/src/diff.h b/src/diff.h index 2c0e52ca2..5750d2a09 100644 --- a/src/diff.h +++ b/src/diff.h @@ -8,6 +8,7 @@ #define INCLUDE_diff_h__ #include "git2/diff.h" +#include "git2/patch.h" #include "git2/sys/diff.h" #include "git2/oid.h" @@ -44,6 +45,7 @@ struct git_diff { int (*pfxcomp)(const char *str, const char *pfx); int (*entrycomp)(const void *a, const void *b); + int (*patch_fn)(git_patch **out, git_diff *diff, size_t idx); void (*free_fn)(git_diff *diff); }; diff --git a/src/diff_generate.c b/src/diff_generate.c index a996bf156..06f9b19c7 100644 --- a/src/diff_generate.c +++ b/src/diff_generate.c @@ -7,6 +7,7 @@ #include "common.h" #include "diff.h" #include "diff_generate.h" +#include "patch_generate.h" #include "fileops.h" #include "config.h" #include "attr_file.h" @@ -414,6 +415,7 @@ static git_diff_generated *diff_generated_alloc( diff->base.repo = repo; diff->base.old_src = old_iter->type; diff->base.new_src = new_iter->type; + diff->base.patch_fn = git_patch_generated_from_diff; diff->base.free_fn = diff_generated_free; memcpy(&diff->base.opts, &dflt, sizeof(git_diff_options)); diff --git a/src/diff_parse.c b/src/diff_parse.c index ffdc8df88..e640063af 100644 --- a/src/diff_parse.c +++ b/src/diff_parse.c @@ -6,15 +6,10 @@ */ #include "common.h" #include "diff.h" +#include "diff_parse.h" #include "patch.h" #include "patch_parse.h" -typedef struct { - struct git_diff base; - - git_vector patches; -} git_diff_parsed; - static void diff_parsed_free(git_diff *d) { git_diff_parsed *diff = (git_diff_parsed *)d; @@ -47,6 +42,7 @@ static git_diff_parsed *diff_parsed_alloc(void) diff->base.strncomp = git__strncmp; diff->base.pfxcomp = git__prefixcmp; diff->base.entrycomp = git_diff__entry_cmp; + diff->base.patch_fn = git_patch_parsed_from_diff; diff->base.free_fn = diff_parsed_free; git_pool_init(&diff->base.pool, 1); diff --git a/src/diff_parse.h b/src/diff_parse.h new file mode 100644 index 000000000..c47d4cbc9 --- /dev/null +++ b/src/diff_parse.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_diff_parse_h__ +#define INCLUDE_diff_parse_h__ + +#include "diff.h" + +typedef struct { + struct git_diff base; + + git_vector patches; +} git_diff_parsed; + +#endif diff --git a/src/patch.c b/src/patch.c index e14ffa9c0..ad24b0714 100644 --- a/src/patch.c +++ b/src/patch.c @@ -194,6 +194,12 @@ int git_patch_get_line_in_hunk( return 0; } +int git_patch_from_diff(git_patch **out, git_diff *diff, size_t idx) +{ + assert(out && diff && diff->patch_fn); + return diff->patch_fn(out, diff, idx); +} + static void git_patch__free(git_patch *patch) { if (patch->free_fn) diff --git a/src/patch_generate.c b/src/patch_generate.c index feac4f67a..927786a43 100644 --- a/src/patch_generate.c +++ b/src/patch_generate.c @@ -746,7 +746,7 @@ int git_patch_from_buffers( return patch_from_sources(out, &osrc, &nsrc, opts); } -int git_patch_from_diff( +int git_patch_generated_from_diff( git_patch **patch_ptr, git_diff *diff, size_t idx) { int error = 0; diff --git a/src/patch_generate.h b/src/patch_generate.h index bb26a76e5..2e89b5c4d 100644 --- a/src/patch_generate.h +++ b/src/patch_generate.h @@ -42,6 +42,8 @@ extern void git_patch_generated_old_data( char **, size_t *, git_patch_generated *); extern void git_patch_generated_new_data( char **, size_t *, git_patch_generated *); +extern int git_patch_generated_from_diff( + git_patch **, git_diff *, size_t); typedef struct git_patch_generated_output git_patch_generated_output; diff --git a/src/patch_parse.c b/src/patch_parse.c index 82d2d3e2e..44bcf8f75 100644 --- a/src/patch_parse.c +++ b/src/patch_parse.c @@ -7,6 +7,7 @@ #include "git2/patch.h" #include "patch.h" #include "patch_parse.h" +#include "diff_parse.h" #include "path.h" #define parse_err(...) \ @@ -1025,6 +1026,20 @@ void git_patch_parse_ctx_free(git_patch_parse_ctx *ctx) GIT_REFCOUNT_DEC(ctx, patch_parse_ctx_free); } +int git_patch_parsed_from_diff(git_patch **out, git_diff *d, size_t idx) +{ + git_diff_parsed *diff = (git_diff_parsed *)d; + git_patch *p; + + if ((p = git_vector_get(&diff->patches, idx)) == NULL) + return -1; + + GIT_REFCOUNT_INC(p); + *out = p; + + return 0; +} + static void patch_parsed__free(git_patch *p) { git_patch_parsed *patch = (git_patch_parsed *)p; diff --git a/src/patch_parse.h b/src/patch_parse.h index da56dad7c..99eb4587b 100644 --- a/src/patch_parse.h +++ b/src/patch_parse.h @@ -51,4 +51,6 @@ extern int git_patch_parse( git_patch **out, git_patch_parse_ctx *ctx); +extern int git_patch_parsed_from_diff(git_patch **, git_diff *, size_t); + #endif diff --git a/tests/diff/parse.c b/tests/diff/parse.c index 83000a92d..a06813d1b 100644 --- a/tests/diff/parse.c +++ b/tests/diff/parse.c @@ -2,6 +2,7 @@ #include "patch.h" #include "patch_parse.h" #include "diff_helpers.h" +#include "../src/diff.h" #include "../patch/patch_common.h" @@ -151,3 +152,47 @@ void test_diff_parse__can_parse_generated_diff(void) GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED | GIT_DIFF_FIND_EXACT_MATCH_ONLY); } +void test_diff_parse__get_patch_from_diff(void) +{ + git_repository *repo; + git_diff *computed, *parsed; + git_tree *a, *b; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_buf computed_buf = GIT_BUF_INIT; + git_patch *patch_computed, *patch_parsed; + + repo = cl_git_sandbox_init("diff"); + + opts.flags = GIT_DIFF_SHOW_BINARY; + + cl_assert((a = resolve_commit_oid_to_tree(repo, + "d70d245ed97ed2aa596dd1af6536e4bfdb047b69")) != NULL); + cl_assert((b = resolve_commit_oid_to_tree(repo, + "7a9e0b02e63179929fed24f0a3e0f19168114d10")) != NULL); + + cl_git_pass(git_diff_tree_to_tree(&computed, repo, a, b, &opts)); + cl_git_pass(git_diff_to_buf(&computed_buf, + computed, GIT_DIFF_FORMAT_PATCH)); + cl_git_pass(git_patch_from_diff(&patch_computed, computed, 0)); + + cl_git_pass(git_diff_from_buffer(&parsed, + computed_buf.ptr, computed_buf.size)); + cl_git_pass(git_patch_from_diff(&patch_parsed, parsed, 0)); + + cl_assert_equal_i( + git_patch_num_hunks(patch_computed), + git_patch_num_hunks(patch_parsed)); + + git_patch_free(patch_computed); + git_patch_free(patch_parsed); + + git_tree_free(a); + git_tree_free(b); + + git_diff_free(computed); + git_diff_free(parsed); + + git_buf_free(&computed_buf); + + cl_git_sandbox_cleanup(); +}