diff options
author | Russell Belfer <rb@github.com> | 2013-06-12 22:55:27 +0400 |
---|---|---|
committer | Russell Belfer <rb@github.com> | 2013-06-12 22:55:27 +0400 |
commit | f9c824c592d7a23f7cc385c25c95a5d0c5c8687e (patch) | |
tree | a9041574778f0bb2341d97c56357d280ed71f06c /src/diff_patch.c | |
parent | 54faddd299ccb6187a9747c1d3ee18d33e5edf7a (diff) |
Add patch from blobs API
This adds two new public APIs: git_diff_patch_from_blobs and
git_diff_patch_from_blob_and_buffer, plus it refactors the code
for git_diff_blobs and git_diff_blob_to_buffer so that they code
is almost entirely shared between these APIs, and adds tests for
the new APIs.
Diffstat (limited to 'src/diff_patch.c')
-rw-r--r-- | src/diff_patch.c | 195 |
1 files changed, 145 insertions, 50 deletions
diff --git a/src/diff_patch.c b/src/diff_patch.c index fe22d678c..4c0b9a70c 100644 --- a/src/diff_patch.c +++ b/src/diff_patch.c @@ -265,33 +265,32 @@ int git_diff_foreach( } typedef struct { - git_xdiff_output xo; git_diff_patch patch; git_diff_delta delta; -} diff_single_info; +} diff_patch_with_delta; -static int diff_single_generate(diff_single_info *info) +static int diff_single_generate(diff_patch_with_delta *pd, git_xdiff_output *xo) { int error = 0; - git_diff_patch *patch = &info->patch; + git_diff_patch *patch = &pd->patch; bool has_old = ((patch->ofile.file.flags & GIT_DIFF_FLAG__NO_DATA) == 0); bool has_new = ((patch->nfile.file.flags & GIT_DIFF_FLAG__NO_DATA) == 0); - info->delta.status = has_new ? + pd->delta.status = has_new ? (has_old ? GIT_DELTA_MODIFIED : GIT_DELTA_ADDED) : (has_old ? GIT_DELTA_DELETED : GIT_DELTA_UNTRACKED); if (git_oid_equal(&patch->nfile.file.oid, &patch->ofile.file.oid)) - info->delta.status = GIT_DELTA_UNMODIFIED; + pd->delta.status = GIT_DELTA_UNMODIFIED; - patch->delta = &info->delta; + patch->delta = &pd->delta; diff_patch_init_common(patch); - error = diff_patch_file_callback(patch, (git_diff_output *)&info->xo); + error = diff_patch_file_callback(patch, (git_diff_output *)xo); if (!error) - error = diff_patch_generate(patch, (git_diff_output *)&info->xo); + error = diff_patch_generate(patch, (git_diff_output *)xo); if (error == GIT_EUSER) giterr_clear(); /* don't leave error message set invalidly */ @@ -299,24 +298,23 @@ static int diff_single_generate(diff_single_info *info) return error; } -int git_diff_blobs( +static int diff_patch_from_blobs( + diff_patch_with_delta *pd, + git_xdiff_output *xo, const git_blob *old_blob, const git_blob *new_blob, - const git_diff_options *opts, - git_diff_file_cb file_cb, - git_diff_hunk_cb hunk_cb, - git_diff_data_cb data_cb, - void *payload) + const git_diff_options *opts) { int error = 0; - diff_single_info info; git_repository *repo = new_blob ? git_object_owner((const git_object *)new_blob) : old_blob ? git_object_owner((const git_object *)old_blob) : NULL; GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); - if (!repo) /* Hmm, given two NULL blobs, silently do no callbacks? */ + pd->patch.delta = &pd->delta; + + if (!repo) /* return two NULL items as UNMODIFIED delta */ return 0; if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) { @@ -325,64 +323,163 @@ int git_diff_blobs( new_blob = swap; } - memset(&info, 0, sizeof(info)); + if ((error = diff_file_content_init_from_blob( + &pd->patch.ofile, repo, opts, old_blob)) < 0 || + (error = diff_file_content_init_from_blob( + &pd->patch.nfile, repo, opts, new_blob)) < 0) + return error; - diff_output_init((git_diff_output *)&info.xo, - opts, file_cb, hunk_cb, data_cb, payload); - git_xdiff_init(&info.xo, opts); + return diff_single_generate(pd, xo); +} - if (!(error = diff_file_content_init_from_blob( - &info.patch.ofile, repo, opts, old_blob)) && - !(error = diff_file_content_init_from_blob( - &info.patch.nfile, repo, opts, new_blob))) - error = diff_single_generate(&info); +int git_diff_blobs( + const git_blob *old_blob, + const git_blob *new_blob, + const git_diff_options *opts, + git_diff_file_cb file_cb, + git_diff_hunk_cb hunk_cb, + git_diff_data_cb data_cb, + void *payload) +{ + int error = 0; + diff_patch_with_delta pd; + git_xdiff_output xo; - git_diff_patch_free(&info.patch); + memset(&pd, 0, sizeof(pd)); + memset(&xo, 0, sizeof(xo)); + + diff_output_init( + (git_diff_output *)&xo, opts, file_cb, hunk_cb, data_cb, payload); + git_xdiff_init(&xo, opts); + + error = diff_patch_from_blobs(&pd, &xo, old_blob, new_blob, opts); + + git_diff_patch_free((git_diff_patch *)&pd); return error; } -int git_diff_blob_to_buffer( +int git_diff_patch_from_blobs( + git_diff_patch **out, + const git_blob *old_blob, + const git_blob *new_blob, + const git_diff_options *opts) +{ + int error = 0; + diff_patch_with_delta *pd; + git_xdiff_output xo; + + assert(out); + *out = NULL; + + pd = git__calloc(1, sizeof(*pd)); + GITERR_CHECK_ALLOC(pd); + pd->patch.flags = GIT_DIFF_PATCH_ALLOCATED; + + memset(&xo, 0, sizeof(xo)); + + diff_output_to_patch((git_diff_output *)&xo, &pd->patch); + git_xdiff_init(&xo, opts); + + if (!(error = diff_patch_from_blobs(pd, &xo, old_blob, new_blob, opts))) + *out = (git_diff_patch *)pd; + else + git_diff_patch_free((git_diff_patch *)pd); + + return error; +} + +static int diff_patch_from_blob_and_buffer( + diff_patch_with_delta *pd, + git_xdiff_output *xo, const git_blob *old_blob, const char *buf, size_t buflen, - const git_diff_options *opts, - git_diff_file_cb file_cb, - git_diff_hunk_cb hunk_cb, - git_diff_data_cb data_cb, - void *payload) + const git_diff_options *opts) { int error = 0; - diff_single_info info; git_repository *repo = old_blob ? git_object_owner((const git_object *)old_blob) : NULL; GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); - if (!repo && !buf) /* Hmm, given NULLs, silently do no callbacks? */ - return 0; - - memset(&info, 0, sizeof(info)); + pd->patch.delta = &pd->delta; - diff_output_init((git_diff_output *)&info.xo, - opts, file_cb, hunk_cb, data_cb, payload); - git_xdiff_init(&info.xo, opts); + if (!repo && !buf) /* return two NULL items as UNMODIFIED delta */ + return 0; if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) { if (!(error = diff_file_content_init_from_raw( - &info.patch.ofile, repo, opts, buf, buflen))) + &pd->patch.ofile, repo, opts, buf, buflen))) error = diff_file_content_init_from_blob( - &info.patch.nfile, repo, opts, old_blob); + &pd->patch.nfile, repo, opts, old_blob); } else { if (!(error = diff_file_content_init_from_blob( - &info.patch.ofile, repo, opts, old_blob))) + &pd->patch.ofile, repo, opts, old_blob))) error = diff_file_content_init_from_raw( - &info.patch.nfile, repo, opts, buf, buflen); + &pd->patch.nfile, repo, opts, buf, buflen); } - error = diff_single_generate(&info); + return diff_single_generate(pd, xo); +} + +int git_diff_blob_to_buffer( + const git_blob *old_blob, + const char *buf, + size_t buflen, + const git_diff_options *opts, + git_diff_file_cb file_cb, + git_diff_hunk_cb hunk_cb, + git_diff_data_cb data_cb, + void *payload) +{ + int error = 0; + diff_patch_with_delta pd; + git_xdiff_output xo; - git_diff_patch_free(&info.patch); + memset(&pd, 0, sizeof(pd)); + memset(&xo, 0, sizeof(xo)); + + diff_output_init( + (git_diff_output *)&xo, opts, file_cb, hunk_cb, data_cb, payload); + git_xdiff_init(&xo, opts); + + error = diff_patch_from_blob_and_buffer( + &pd, &xo, old_blob, buf, buflen, opts); + + git_diff_patch_free((git_diff_patch *)&pd); + + return error; +} + +int git_diff_patch_from_blob_and_buffer( + git_diff_patch **out, + const git_blob *old_blob, + const char *buf, + size_t buflen, + const git_diff_options *opts) +{ + int error = 0; + diff_patch_with_delta *pd; + git_xdiff_output xo; + + assert(out); + *out = NULL; + + pd = git__calloc(1, sizeof(*pd)); + GITERR_CHECK_ALLOC(pd); + pd->patch.flags = GIT_DIFF_PATCH_ALLOCATED; + + memset(&xo, 0, sizeof(xo)); + + diff_output_to_patch((git_diff_output *)&xo, &pd->patch); + git_xdiff_init(&xo, opts); + + if (!(error = diff_patch_from_blob_and_buffer( + pd, &xo, old_blob, buf, buflen, opts))) + *out = (git_diff_patch *)pd; + else + git_diff_patch_free((git_diff_patch *)pd); return error; } @@ -599,9 +696,7 @@ static int diff_patch_file_cb( float progress, void *payload) { - GIT_UNUSED(delta); - GIT_UNUSED(progress); - GIT_UNUSED(payload); + GIT_UNUSED(delta); GIT_UNUSED(progress); GIT_UNUSED(payload); return 0; } |