Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/diff_patch.c')
-rw-r--r--src/diff_patch.c304
1 files changed, 142 insertions, 162 deletions
diff --git a/src/diff_patch.c b/src/diff_patch.c
index cc49d68eb..38d5f4257 100644
--- a/src/diff_patch.c
+++ b/src/diff_patch.c
@@ -5,6 +5,7 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "common.h"
+#include "git2/blob.h"
#include "diff.h"
#include "diff_file.h"
#include "diff_driver.h"
@@ -133,9 +134,9 @@ static int diff_patch_load(git_patch *patch, git_diff_output *output)
incomplete_data =
(((patch->ofile.flags & GIT_DIFF_FLAG__NO_DATA) != 0 ||
- (patch->ofile.file->flags & GIT_DIFF_FLAG_VALID_OID) != 0) &&
+ (patch->ofile.file->flags & GIT_DIFF_FLAG_VALID_ID) != 0) &&
((patch->nfile.flags & GIT_DIFF_FLAG__NO_DATA) != 0 ||
- (patch->nfile.file->flags & GIT_DIFF_FLAG_VALID_OID) != 0));
+ (patch->nfile.file->flags & GIT_DIFF_FLAG_VALID_ID) != 0));
/* always try to load workdir content first because filtering may
* need 2x data size and this minimizes peak memory footprint
@@ -169,7 +170,7 @@ static int diff_patch_load(git_patch *patch, git_diff_output *output)
if (incomplete_data &&
patch->ofile.file->mode == patch->nfile.file->mode &&
patch->ofile.file->mode != GIT_FILEMODE_COMMIT &&
- git_oid_equal(&patch->ofile.file->oid, &patch->nfile.file->oid) &&
+ git_oid_equal(&patch->ofile.file->id, &patch->nfile.file->id) &&
patch->delta->status == GIT_DELTA_MODIFIED) /* not RENAMED/COPIED! */
patch->delta->status = GIT_DELTA_UNMODIFIED;
@@ -184,7 +185,7 @@ cleanup:
patch->delta->status != GIT_DELTA_UNMODIFIED &&
(patch->ofile.map.len || patch->nfile.map.len) &&
(patch->ofile.map.len != patch->nfile.map.len ||
- !git_oid_equal(&patch->ofile.file->oid, &patch->nfile.file->oid)))
+ !git_oid_equal(&patch->ofile.file->id, &patch->nfile.file->id)))
patch->flags |= GIT_DIFF_PATCH_DIFFABLE;
patch->flags |= GIT_DIFF_PATCH_LOADED;
@@ -193,21 +194,18 @@ cleanup:
return error;
}
-static int diff_patch_file_callback(
+static int diff_patch_invoke_file_callback(
git_patch *patch, git_diff_output *output)
{
- float progress;
+ float progress = patch->diff ?
+ ((float)patch->delta_index / patch->diff->deltas.length) : 1.0f;
if (!output->file_cb)
return 0;
- progress = patch->diff ?
- ((float)patch->delta_index / patch->diff->deltas.length) : 1.0f;
-
- if (output->file_cb(patch->delta, progress, output->payload) != 0)
- output->error = GIT_EUSER;
-
- return output->error;
+ return giterr_set_after_callback_function(
+ output->file_cb(patch->delta, progress, output->payload),
+ "git_patch");
}
static int diff_patch_generate(git_patch *patch, git_diff_output *output)
@@ -229,7 +227,7 @@ static int diff_patch_generate(git_patch *patch, git_diff_output *output)
return 0;
if (output->diff_cb != NULL &&
- !(error = output->diff_cb(output, patch)))
+ (error = output->diff_cb(output, patch)) < 0)
patch->flags |= GIT_DIFF_PATCH_DIFFED;
return error;
@@ -272,9 +270,10 @@ int git_diff_foreach(
size_t idx;
git_patch patch;
- if (diff_required(diff, "git_diff_foreach") < 0)
- return -1;
+ if ((error = diff_required(diff, "git_diff_foreach")) < 0)
+ return error;
+ memset(&xo, 0, sizeof(xo));
diff_output_init(
&xo.output, &diff->opts, file_cb, hunk_cb, data_cb, payload);
git_xdiff_init(&xo, &diff->opts);
@@ -285,22 +284,18 @@ int git_diff_foreach(
if (git_diff_delta__should_skip(&diff->opts, patch.delta))
continue;
- if (!(error = diff_patch_init_from_diff(&patch, diff, idx))) {
-
- error = diff_patch_file_callback(&patch, &xo.output);
+ if ((error = diff_patch_init_from_diff(&patch, diff, idx)) < 0)
+ break;
- if (!error)
- error = diff_patch_generate(&patch, &xo.output);
+ if (!(error = diff_patch_invoke_file_callback(&patch, &xo.output)))
+ error = diff_patch_generate(&patch, &xo.output);
- git_patch_free(&patch);
- }
+ git_patch_free(&patch);
- if (error < 0)
+ if (error)
break;
}
- if (error == GIT_EUSER)
- giterr_clear(); /* don't leave error message set invalidly */
return error;
}
@@ -321,7 +316,7 @@ static int diff_single_generate(diff_patch_with_delta *pd, git_xdiff_output *xo)
(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))
+ if (git_oid_equal(&patch->nfile.file->id, &patch->ofile.file->id))
pd->delta.status = GIT_DELTA_UNMODIFIED;
patch->delta = &pd->delta;
@@ -332,49 +327,53 @@ static int diff_single_generate(diff_patch_with_delta *pd, git_xdiff_output *xo)
!(patch->ofile.opts_flags & GIT_DIFF_INCLUDE_UNMODIFIED))
return error;
- error = diff_patch_file_callback(patch, (git_diff_output *)xo);
+ error = diff_patch_invoke_file_callback(patch, (git_diff_output *)xo);
if (!error)
error = diff_patch_generate(patch, (git_diff_output *)xo);
- if (error == GIT_EUSER)
- giterr_clear(); /* don't leave error message set invalidly */
-
return error;
}
-static int diff_patch_from_blobs(
+static int diff_patch_from_sources(
diff_patch_with_delta *pd,
git_xdiff_output *xo,
- const git_blob *old_blob,
- const char *old_path,
- const git_blob *new_blob,
- const char *new_path,
+ git_diff_file_content_src *oldsrc,
+ git_diff_file_content_src *newsrc,
const git_diff_options *opts)
{
int error = 0;
git_repository *repo =
- new_blob ? git_object_owner((const git_object *)new_blob) :
- old_blob ? git_object_owner((const git_object *)old_blob) : NULL;
+ oldsrc->blob ? git_blob_owner(oldsrc->blob) :
+ newsrc->blob ? git_blob_owner(newsrc->blob) : NULL;
+ git_diff_file *lfile = &pd->delta.old_file, *rfile = &pd->delta.new_file;
+ git_diff_file_content *ldata = &pd->patch.ofile, *rdata = &pd->patch.nfile;
GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options");
if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) {
- const git_blob *tmp_blob;
- const char *tmp_path;
- tmp_blob = old_blob; old_blob = new_blob; new_blob = tmp_blob;
- tmp_path = old_path; old_path = new_path; new_path = tmp_path;
+ void *tmp = lfile; lfile = rfile; rfile = tmp;
+ tmp = ldata; ldata = rdata; rdata = tmp;
}
pd->patch.delta = &pd->delta;
- pd->delta.old_file.path = old_path;
- pd->delta.new_file.path = new_path;
+ if (!oldsrc->as_path) {
+ if (newsrc->as_path)
+ oldsrc->as_path = newsrc->as_path;
+ else
+ oldsrc->as_path = newsrc->as_path = "file";
+ }
+ else if (!newsrc->as_path)
+ newsrc->as_path = oldsrc->as_path;
+
+ lfile->path = oldsrc->as_path;
+ rfile->path = newsrc->as_path;
- if ((error = git_diff_file_content__init_from_blob(
- &pd->patch.ofile, repo, opts, old_blob, &pd->delta.old_file)) < 0 ||
- (error = git_diff_file_content__init_from_blob(
- &pd->patch.nfile, repo, opts, new_blob, &pd->delta.new_file)) < 0)
+ if ((error = git_diff_file_content__init_from_src(
+ ldata, repo, opts, oldsrc, lfile)) < 0 ||
+ (error = git_diff_file_content__init_from_src(
+ rdata, repo, opts, newsrc, rfile)) < 0)
return error;
return diff_single_generate(pd, xo);
@@ -409,11 +408,9 @@ static int diff_patch_with_delta_alloc(
return 0;
}
-int git_diff_blobs(
- const git_blob *old_blob,
- const char *old_path,
- const git_blob *new_blob,
- const char *new_path,
+static int diff_from_sources(
+ git_diff_file_content_src *oldsrc,
+ git_diff_file_content_src *newsrc,
const git_diff_options *opts,
git_diff_file_cb file_cb,
git_diff_hunk_cb hunk_cb,
@@ -424,32 +421,24 @@ int git_diff_blobs(
diff_patch_with_delta pd;
git_xdiff_output xo;
- memset(&pd, 0, sizeof(pd));
memset(&xo, 0, sizeof(xo));
-
diff_output_init(
&xo.output, opts, file_cb, hunk_cb, data_cb, payload);
git_xdiff_init(&xo, opts);
- if (!old_path && new_path)
- old_path = new_path;
- else if (!new_path && old_path)
- new_path = old_path;
+ memset(&pd, 0, sizeof(pd));
- error = diff_patch_from_blobs(
- &pd, &xo, old_blob, old_path, new_blob, new_path, opts);
+ error = diff_patch_from_sources(&pd, &xo, oldsrc, newsrc, opts);
git_patch_free(&pd.patch);
return error;
}
-int git_patch_from_blobs(
+static int patch_from_sources(
git_patch **out,
- const git_blob *old_blob,
- const char *old_path,
- const git_blob *new_blob,
- const char *new_path,
+ git_diff_file_content_src *oldsrc,
+ git_diff_file_content_src *newsrc,
const git_diff_options *opts)
{
int error = 0;
@@ -459,18 +448,15 @@ int git_patch_from_blobs(
assert(out);
*out = NULL;
- if (diff_patch_with_delta_alloc(&pd, &old_path, &new_path) < 0)
- return -1;
+ if ((error = diff_patch_with_delta_alloc(
+ &pd, &oldsrc->as_path, &newsrc->as_path)) < 0)
+ return error;
memset(&xo, 0, sizeof(xo));
-
diff_output_to_patch(&xo.output, &pd->patch);
git_xdiff_init(&xo, opts);
- error = diff_patch_from_blobs(
- pd, &xo, old_blob, old_path, new_blob, new_path, opts);
-
- if (!error)
+ if (!(error = diff_patch_from_sources(pd, &xo, oldsrc, newsrc, opts)))
*out = (git_patch *)pd;
else
git_patch_free((git_patch *)pd);
@@ -478,46 +464,38 @@ int git_patch_from_blobs(
return error;
}
-static int diff_patch_from_blob_and_buffer(
- diff_patch_with_delta *pd,
- git_xdiff_output *xo,
+int git_diff_blobs(
const git_blob *old_blob,
const char *old_path,
- const char *buf,
- size_t buflen,
- const char *buf_path,
- const git_diff_options *opts)
+ const git_blob *new_blob,
+ const char *new_path,
+ const git_diff_options *opts,
+ git_diff_file_cb file_cb,
+ git_diff_hunk_cb hunk_cb,
+ git_diff_line_cb data_cb,
+ void *payload)
{
- int error = 0;
- 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");
-
- pd->patch.delta = &pd->delta;
-
- if (opts && (opts->flags & GIT_DIFF_REVERSE) != 0) {
- pd->delta.old_file.path = buf_path;
- pd->delta.new_file.path = old_path;
-
- if (!(error = git_diff_file_content__init_from_raw(
- &pd->patch.ofile, repo, opts, buf, buflen, &pd->delta.old_file)))
- error = git_diff_file_content__init_from_blob(
- &pd->patch.nfile, repo, opts, old_blob, &pd->delta.new_file);
- } else {
- pd->delta.old_file.path = old_path;
- pd->delta.new_file.path = buf_path;
-
- if (!(error = git_diff_file_content__init_from_blob(
- &pd->patch.ofile, repo, opts, old_blob, &pd->delta.old_file)))
- error = git_diff_file_content__init_from_raw(
- &pd->patch.nfile, repo, opts, buf, buflen, &pd->delta.new_file);
- }
-
- if (error < 0)
- return error;
+ git_diff_file_content_src osrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BLOB(old_blob, old_path);
+ git_diff_file_content_src nsrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BLOB(new_blob, new_path);
+ return diff_from_sources(
+ &osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
+}
- return diff_single_generate(pd, xo);
+int git_patch_from_blobs(
+ git_patch **out,
+ const git_blob *old_blob,
+ const char *old_path,
+ const git_blob *new_blob,
+ const char *new_path,
+ const git_diff_options *opts)
+{
+ git_diff_file_content_src osrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BLOB(old_blob, old_path);
+ git_diff_file_content_src nsrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BLOB(new_blob, new_path);
+ return patch_from_sources(out, &osrc, &nsrc, opts);
}
int git_diff_blob_to_buffer(
@@ -532,28 +510,12 @@ int git_diff_blob_to_buffer(
git_diff_line_cb data_cb,
void *payload)
{
- int error = 0;
- diff_patch_with_delta pd;
- git_xdiff_output xo;
-
- memset(&pd, 0, sizeof(pd));
- memset(&xo, 0, sizeof(xo));
-
- diff_output_init(
- &xo.output, opts, file_cb, hunk_cb, data_cb, payload);
- git_xdiff_init(&xo, opts);
-
- if (!old_path && buf_path)
- old_path = buf_path;
- else if (!buf_path && old_path)
- buf_path = old_path;
-
- error = diff_patch_from_blob_and_buffer(
- &pd, &xo, old_blob, old_path, buf, buflen, buf_path, opts);
-
- git_patch_free(&pd.patch);
-
- return error;
+ git_diff_file_content_src osrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BLOB(old_blob, old_path);
+ git_diff_file_content_src nsrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BUF(buf, buflen, buf_path);
+ return diff_from_sources(
+ &osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
}
int git_patch_from_blob_and_buffer(
@@ -565,30 +527,49 @@ int git_patch_from_blob_and_buffer(
const char *buf_path,
const git_diff_options *opts)
{
- int error = 0;
- diff_patch_with_delta *pd;
- git_xdiff_output xo;
-
- assert(out);
- *out = NULL;
-
- if (diff_patch_with_delta_alloc(&pd, &old_path, &buf_path) < 0)
- return -1;
-
- memset(&xo, 0, sizeof(xo));
-
- diff_output_to_patch(&xo.output, &pd->patch);
- git_xdiff_init(&xo, opts);
-
- error = diff_patch_from_blob_and_buffer(
- pd, &xo, old_blob, old_path, buf, buflen, buf_path, opts);
+ git_diff_file_content_src osrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BLOB(old_blob, old_path);
+ git_diff_file_content_src nsrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BUF(buf, buflen, buf_path);
+ return patch_from_sources(out, &osrc, &nsrc, opts);
+}
- if (!error)
- *out = (git_patch *)pd;
- else
- git_patch_free((git_patch *)pd);
+int git_diff_buffers(
+ const void *old_buf,
+ size_t old_len,
+ const char *old_path,
+ const void *new_buf,
+ size_t new_len,
+ const char *new_path,
+ const git_diff_options *opts,
+ git_diff_file_cb file_cb,
+ git_diff_hunk_cb hunk_cb,
+ git_diff_line_cb data_cb,
+ void *payload)
+{
+ git_diff_file_content_src osrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BUF(old_buf, old_len, old_path);
+ git_diff_file_content_src nsrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BUF(new_buf, new_len, new_path);
+ return diff_from_sources(
+ &osrc, &nsrc, opts, file_cb, hunk_cb, data_cb, payload);
+}
- return error;
+int git_patch_from_buffers(
+ git_patch **out,
+ const void *old_buf,
+ size_t old_len,
+ const char *old_path,
+ const char *new_buf,
+ size_t new_len,
+ const char *new_path,
+ const git_diff_options *opts)
+{
+ git_diff_file_content_src osrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BUF(old_buf, old_len, old_path);
+ git_diff_file_content_src nsrc =
+ GIT_DIFF_FILE_CONTENT_SRC__BUF(new_buf, new_len, new_path);
+ return patch_from_sources(out, &osrc, &nsrc, opts);
}
int git_patch_from_diff(
@@ -622,17 +603,18 @@ int git_patch_from_diff(
if ((error = diff_patch_alloc_from_diff(&patch, diff, idx)) < 0)
return error;
+ memset(&xo, 0, sizeof(xo));
diff_output_to_patch(&xo.output, patch);
git_xdiff_init(&xo, &diff->opts);
- error = diff_patch_file_callback(patch, &xo.output);
+ error = diff_patch_invoke_file_callback(patch, &xo.output);
if (!error)
error = diff_patch_generate(patch, &xo.output);
if (!error) {
- /* if cumulative diff size is < 0.5 total size, flatten the patch */
- /* unload the file content */
+ /* TODO: if cumulative diff size is < 0.5 total size, flatten patch */
+ /* TODO: and unload the file content */
}
if (error || !patch_ptr)
@@ -640,8 +622,6 @@ int git_patch_from_diff(
else
*patch_ptr = patch;
- if (error == GIT_EUSER)
- giterr_clear(); /* don't leave error message set invalidly */
return error;
}
@@ -651,13 +631,13 @@ void git_patch_free(git_patch *patch)
GIT_REFCOUNT_DEC(patch, diff_patch_free);
}
-const git_diff_delta *git_patch_get_delta(git_patch *patch)
+const git_diff_delta *git_patch_get_delta(const git_patch *patch)
{
assert(patch);
return patch->delta;
}
-size_t git_patch_num_hunks(git_patch *patch)
+size_t git_patch_num_hunks(const git_patch *patch)
{
assert(patch);
return git_array_size(patch->hunks);
@@ -728,7 +708,7 @@ int git_patch_get_hunk(
return 0;
}
-int git_patch_num_lines_in_hunk(git_patch *patch, size_t hunk_idx)
+int git_patch_num_lines_in_hunk(const git_patch *patch, size_t hunk_idx)
{
diff_patch_hunk *hunk;
assert(patch);
@@ -905,7 +885,7 @@ static int diff_patch_line_cb(
GIT_UNUSED(hunk_);
hunk = git_array_last(patch->hunks);
- GITERR_CHECK_ALLOC(hunk);
+ assert(hunk); /* programmer error if no hunk is available */
line = git_array_alloc(patch->lines);
GITERR_CHECK_ALLOC(line);