summaryrefslogtreecommitdiff
path: root/src/diff_tform.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/diff_tform.c')
-rw-r--r--src/diff_tform.c116
1 files changed, 58 insertions, 58 deletions
diff --git a/src/diff_tform.c b/src/diff_tform.c
index 08b0d5c38..8fd2a4fe9 100644
--- a/src/diff_tform.c
+++ b/src/diff_tform.c
@@ -414,59 +414,26 @@ typedef struct {
git_repository *repo;
git_diff_file *file;
git_buf data;
+ git_odb_object *odb_obj;
git_blob *blob;
- int loaded;
} similarity_info;
-static void similarity_init(
+static int similarity_init(
similarity_info *info, git_diff_list *diff, size_t file_idx)
{
info->idx = file_idx;
info->src = (file_idx & 1) ? diff->new_src : diff->old_src;
info->repo = diff->repo;
info->file = similarity_get_file(diff, file_idx);
+ info->odb_obj = NULL;
info->blob = NULL;
- info->loaded = 0;
git_buf_init(&info->data, 0);
-}
-
-static int similarity_load(similarity_info *info)
-{
- int error = 0;
- git_diff_file *file = info->file;
-
- if (info->src == GIT_ITERATOR_TYPE_WORKDIR) {
- error = git_buf_joinpath(
- &info->data, git_repository_workdir(info->repo), file->path);
-
- /* if path is not a regular file, just skip this item */
- if (!error && !git_path_isfile(info->data.ptr))
- git_buf_free(&info->data);
- } else if (git_blob_lookup(&info->blob, info->repo, &file->oid) < 0) {
- /* if lookup fails, just skip this item in similarity calc */
- giterr_clear();
- } else {
- if (!file->size)
- file->size = git_blob_rawsize(info->blob);
- assert(file->size == git_blob_rawsize(info->blob));
-
- info->data.size = (size_t)(git__is_sizet(file->size) ? file->size : -1);
- info->data.ptr = (char *)git_blob_rawcontent(info->blob);
- }
-
- info->loaded = 1;
- return error;
-}
-
-static void similarity_unload(similarity_info *info)
-{
- if (info->blob)
- git_blob_free(info->blob);
- else
- git_buf_free(&info->data);
+ if (info->file->size > 0)
+ return 0;
- info->loaded = 0;
+ return git_diff_file__resolve_zero_size(
+ info->file, &info->odb_obj, info->repo);
}
static int similarity_calc(
@@ -475,28 +442,59 @@ static int similarity_calc(
void **cache)
{
int error = 0;
+ git_diff_file *file = info->file;
- if (!info->loaded && (error = similarity_load(info)) < 0)
- return error;
+ if (info->src == GIT_ITERATOR_TYPE_WORKDIR) {
+ if ((error = git_buf_joinpath(
+ &info->data, git_repository_workdir(info->repo), file->path)) < 0)
+ return error;
- if (!info->data.size)
- return 0;
+ /* if path is not a regular file, just skip this item */
+ if (!git_path_isfile(info->data.ptr))
+ return 0;
- if (info->src == GIT_ITERATOR_TYPE_WORKDIR) {
/* TODO: apply wd-to-odb filters to file data if necessary */
error = opts->metric->file_signature(
&cache[info->idx], info->file,
info->data.ptr, opts->metric->payload);
} else {
- error = opts->metric->buffer_signature(
- &cache[info->idx], info->file,
- info->data.ptr, info->data.size, opts->metric->payload);
+ /* if we didn't initially know the size, we might have an odb_obj
+ * around from earlier, so convert that, otherwise load the blob now
+ */
+ if (info->odb_obj != NULL)
+ error = git_object__from_odb_object(
+ (git_object **)&info->blob, info->repo,
+ info->odb_obj, GIT_OBJ_BLOB);
+ else
+ error = git_blob_lookup(&info->blob, info->repo, &file->oid);
+
+ if (error < 0) {
+ /* if lookup fails, just skip this item in similarity calc */
+ giterr_clear();
+ } else {
+ size_t sz = (size_t)(git__is_sizet(file->size) ? file->size : -1);
+
+ error = opts->metric->buffer_signature(
+ &cache[info->idx], info->file,
+ git_blob_rawcontent(info->blob), sz, opts->metric->payload);
+ }
}
return error;
}
+static void similarity_unload(similarity_info *info)
+{
+ if (info->odb_obj)
+ git_odb_object_free(info->odb_obj);
+
+ if (info->blob)
+ git_blob_free(info->blob);
+ else
+ git_buf_free(&info->data);
+}
+
#define FLAG_SET(opts,flag_name) (((opts)->flags & flag_name) != 0)
/* - score < 0 means files cannot be compared
@@ -550,26 +548,28 @@ static int similarity_measure(
return 0;
}
- similarity_init(&a_info, diff, a_idx);
- similarity_init(&b_info, diff, b_idx);
+ memset(&a_info, 0, sizeof(a_info));
+ memset(&b_info, 0, sizeof(b_info));
- if (!a_file->size && (error = similarity_load(&a_info)) < 0)
- goto done;
- if (!b_file->size && (error = similarity_load(&b_info)) < 0)
- goto done;
+ /* set up similarity data (will try to update missing file sizes) */
+ if (!cache[a_idx] && (error = similarity_init(&a_info, diff, a_idx)) < 0)
+ return error;
+ if (!cache[b_idx] && (error = similarity_init(&b_info, diff, b_idx)) < 0)
+ goto cleanup;
/* check if file sizes are nowhere near each other */
if (a_file->size > 127 &&
b_file->size > 127 &&
(a_file->size > (b_file->size << 4) ||
b_file->size > (a_file->size << 4)))
- goto done;
+ goto cleanup;
/* update signature cache if needed */
if (!cache[a_idx] && (error = similarity_calc(&a_info, opts, cache)) < 0)
- goto done;
+ goto cleanup;
+
if (!cache[b_idx] && (error = similarity_calc(&b_info, opts, cache)) < 0)
- goto done;
+ goto cleanup;
/* calculate similarity provided that the metric choose to process
* both the a and b files (some may not if file is too big, etc).
@@ -578,7 +578,7 @@ static int similarity_measure(
error = opts->metric->similarity(
score, cache[a_idx], cache[b_idx], opts->metric->payload);
-done:
+cleanup:
similarity_unload(&a_info);
similarity_unload(&b_info);