Exemple #1
0
/*
 *  call-seq:
 *    patch.delta -> delta
 *
 *  Returns the delta object associated with the patch.
 */
static VALUE rb_git_diff_patch_delta(VALUE self)
{
    git_patch *patch;
    Data_Get_Struct(self, git_patch, patch);

    return rugged_diff_delta_new(rugged_owner(self), git_patch_get_delta(patch));
}
Exemple #2
0
/**
 * ggit_patch_get_delta:
 * @patch: a #GgitPatch.
 *
 * Get the diff delta corresponding to the patch.
 *
 * Returns: (transfer full): the #GgitDiffDelta of the patch.
 */
GgitDiffDelta *
ggit_patch_get_delta (GgitPatch *patch)
{
	g_return_val_if_fail (patch != NULL, NULL);

	return _ggit_diff_delta_wrap (git_patch_get_delta (patch->patch));
}
Exemple #3
0
static void assert_patch_matches_blobs(
	git_patch *p, git_blob *a, git_blob *b,
	int hunks, int l0, int l1, int ctxt, int adds, int dels)
{
	const git_diff_delta *delta;
	size_t tc, ta, td;

	cl_assert(p != NULL);

	delta = git_patch_get_delta(p);
	cl_assert(delta != NULL);

	cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
	cl_assert_equal_oid(git_blob_id(a), &delta->old_file.id);
	cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size);
	cl_assert_equal_oid(git_blob_id(b), &delta->new_file.id);
	cl_assert_equal_sz(git_blob_rawsize(b), delta->new_file.size);

	cl_assert_equal_i(hunks, (int)git_patch_num_hunks(p));

	if (hunks > 0)
		cl_assert_equal_i(l0, git_patch_num_lines_in_hunk(p, 0));
	if (hunks > 1)
		cl_assert_equal_i(l1, git_patch_num_lines_in_hunk(p, 1));

	cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
	cl_assert_equal_i(ctxt, (int)tc);
	cl_assert_equal_i(adds, (int)ta);
	cl_assert_equal_i(dels, (int)td);
}
Exemple #4
0
void test_diff_blob__can_compare_identical_blobs_with_patch(void)
{
	git_patch *p;
	const git_diff_delta *delta;

	cl_git_pass(git_patch_from_blobs(&p, d, NULL, d, NULL, &opts));
	cl_assert(p != NULL);

	delta = git_patch_get_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status);
	cl_assert_equal_sz(delta->old_file.size, git_blob_rawsize(d));
	cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id);
	cl_assert_equal_sz(delta->new_file.size, git_blob_rawsize(d));
	cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id);

	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
	git_patch_free(p);

	cl_git_pass(git_patch_from_blobs(&p, NULL, NULL, NULL, NULL, &opts));
	cl_assert(p != NULL);

	delta = git_patch_get_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status);
	cl_assert_equal_sz(0, delta->old_file.size);
	cl_assert(git_oid_iszero(&delta->old_file.id));
	cl_assert_equal_sz(0, delta->new_file.size);
	cl_assert(git_oid_iszero(&delta->new_file.id));

	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
	git_patch_free(p);

	cl_git_pass(git_patch_from_blobs(&p, alien, NULL, alien, NULL, &opts));
	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_patch_get_delta(p)->status);
	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
	git_patch_free(p);
}
Exemple #5
0
PyObject *
wrap_patch(git_patch *patch)
{
    Patch *py_patch;

    if (!patch)
        Py_RETURN_NONE;

    py_patch = PyObject_New(Patch, &PatchType);
    if (py_patch) {
        size_t i, j, hunk_amounts, lines_in_hunk, additions, deletions;
        const git_diff_delta *delta;
        const git_diff_hunk *hunk;
        const git_diff_line *line;
        int err;

        delta = git_patch_get_delta(patch);

        py_patch->old_file_path = delta->old_file.path;
        py_patch->new_file_path = delta->new_file.path;
        py_patch->status = git_diff_status_char(delta->status);
        py_patch->similarity = delta->similarity;
        py_patch->flags = delta->flags;
        py_patch->old_id = git_oid_allocfmt(&delta->old_file.id);
        py_patch->new_id = git_oid_allocfmt(&delta->new_file.id);

        git_patch_line_stats(NULL, &additions, &deletions, patch);
        py_patch->additions = additions;
        py_patch->deletions = deletions;

        hunk_amounts = git_patch_num_hunks(patch);
        py_patch->hunks = PyList_New(hunk_amounts);
        for (i = 0; i < hunk_amounts; ++i) {
            Hunk *py_hunk = NULL;

            err = git_patch_get_hunk(&hunk, &lines_in_hunk, patch, i);
            if (err < 0)
                return Error_set(err);

            py_hunk = PyObject_New(Hunk, &HunkType);
            if (py_hunk != NULL) {
                py_hunk->old_start = hunk->old_start;
                py_hunk->old_lines = hunk->old_lines;
                py_hunk->new_start = hunk->new_start;
                py_hunk->new_lines = hunk->new_lines;

                py_hunk->lines = PyList_New(lines_in_hunk);
                for (j = 0; j < lines_in_hunk; ++j) {
                    PyObject *py_line_origin = NULL, *py_line = NULL;

                    err = git_patch_get_line_in_hunk(&line, patch, i, j);
                    if (err < 0)
                        return Error_set(err);

                    py_line_origin = to_unicode_n(&line->origin, 1,
                        NULL, NULL);
                    py_line = to_unicode_n(line->content, line->content_len,
                        NULL, NULL);
                    PyList_SetItem(py_hunk->lines, j,
                        Py_BuildValue("OO", py_line_origin, py_line));

                    Py_DECREF(py_line_origin);
                    Py_DECREF(py_line);
                }

                PyList_SetItem((PyObject*) py_patch->hunks, i,
                    (PyObject*) py_hunk);
            }
        }
    }
    git_patch_free(patch);

    return (PyObject*) py_patch;
}
int diff_foreach_via_iterator(
	git_diff *diff,
	git_diff_file_cb file_cb,
	git_diff_hunk_cb hunk_cb,
	git_diff_line_cb line_cb,
	void *data)
{
	size_t d, num_d = git_diff_num_deltas(diff);

	for (d = 0; d < num_d; ++d) {
		git_patch *patch;
		const git_diff_delta *delta;
		size_t h, num_h;

		cl_git_pass(git_patch_from_diff(&patch, diff, d));
		cl_assert((delta = git_patch_get_delta(patch)) != NULL);

		/* call file_cb for this file */
		if (file_cb != NULL && file_cb(delta, (float)d / num_d, data) != 0) {
			git_patch_free(patch);
			goto abort;
		}

		/* if there are no changes, then the patch will be NULL */
		if (!patch) {
			cl_assert(delta->status == GIT_DELTA_UNMODIFIED ||
					  (delta->flags & GIT_DIFF_FLAG_BINARY) != 0);
			continue;
		}

		if (!hunk_cb && !line_cb) {
			git_patch_free(patch);
			continue;
		}

		num_h = git_patch_num_hunks(patch);

		for (h = 0; h < num_h; h++) {
			const git_diff_hunk *hunk;
			size_t l, num_l;

			cl_git_pass(git_patch_get_hunk(&hunk, &num_l, patch, h));

			if (hunk_cb && hunk_cb(delta, hunk, data) != 0) {
				git_patch_free(patch);
				goto abort;
			}

			for (l = 0; l < num_l; ++l) {
				const git_diff_line *line;

				cl_git_pass(git_patch_get_line_in_hunk(&line, patch, h, l));

				if (line_cb &&
					line_cb(delta, hunk, line, data) != 0) {
					git_patch_free(patch);
					goto abort;
				}
			}
		}

		git_patch_free(patch);
	}

	return 0;

abort:
	giterr_clear();
	return GIT_EUSER;
}
int git_diff_get_stats(
	git_diff_stats **out,
	git_diff *diff)
{
	size_t i, deltas;
	size_t total_insertions = 0, total_deletions = 0;
	git_diff_stats *stats = NULL;
	int error = 0;

	assert(out && diff);

	stats = (git_diff_stats *) git__calloc(1, sizeof(git_diff_stats));
	GITERR_CHECK_ALLOC(stats);

	deltas = git_diff_num_deltas(diff);

	stats->filestats = (diff_file_stats *) git__calloc(deltas, sizeof(diff_file_stats));
	if (!stats->filestats) {
		git__free(stats);
		return -1;
	}

	stats->diff = diff;
	GIT_REFCOUNT_INC(diff);

	for (i = 0; i < deltas && !error; ++i) {
		git_patch *patch = NULL;
		size_t add = 0, remove = 0, namelen;
		const git_diff_delta *delta;

		if ((error = git_patch_from_diff(&patch, diff, i)) < 0)
			break;

		/* keep a count of renames because it will affect formatting */
		delta = git_patch_get_delta(patch);

		namelen = strlen(delta->new_file.path);
		if (strcmp(delta->old_file.path, delta->new_file.path) != 0) {
			namelen += strlen(delta->old_file.path);
			stats->renames++;
		}

		/* and, of course, count the line stats */
		error = git_patch_line_stats(NULL, &add, &remove, patch);

		git_patch_free(patch);

		stats->filestats[i].insertions = add;
		stats->filestats[i].deletions = remove;

		total_insertions += add;
		total_deletions += remove;

		if (stats->max_name < namelen)
			stats->max_name = namelen;
		if (stats->max_filestat < add + remove)
			stats->max_filestat = add + remove;
	}

	stats->files_changed = deltas;
	stats->insertions = total_insertions;
	stats->deletions = total_deletions;
	stats->max_digits = digits_for_value(stats->max_filestat + 1);

	if (error < 0) {
		git_diff_stats_free(stats);
		stats = NULL;
	}

	*out = stats;
	return error;
}
static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len)
{
	git_xdiff_info *info = priv;
	git_patch *patch = info->patch;
	const git_diff_delta *delta = git_patch_get_delta(patch);
	git_diff_output *output = &info->xo->output;
	git_diff_line line;

	if (len == 1) {
		output->error = git_xdiff_parse_hunk(&info->hunk, bufs[0].ptr);
		if (output->error < 0)
			return output->error;

		info->hunk.header_len = bufs[0].size;
		if (info->hunk.header_len >= sizeof(info->hunk.header))
			info->hunk.header_len = sizeof(info->hunk.header) - 1;
		memcpy(info->hunk.header, bufs[0].ptr, info->hunk.header_len);
		info->hunk.header[info->hunk.header_len] = '\0';

		if (output->hunk_cb != NULL &&
			output->hunk_cb(delta, &info->hunk, output->payload))
			output->error = GIT_EUSER;

		info->old_lineno = info->hunk.old_start;
		info->new_lineno = info->hunk.new_start;
	}

	if (len == 2 || len == 3) {
		/* expect " "/"-"/"+", then data */
		line.origin =
			(*bufs[0].ptr == '+') ? GIT_DIFF_LINE_ADDITION :
			(*bufs[0].ptr == '-') ? GIT_DIFF_LINE_DELETION :
			GIT_DIFF_LINE_CONTEXT;

		if (line.origin == GIT_DIFF_LINE_ADDITION)
			line.content_offset = bufs[1].ptr - info->xd_new_data.ptr;
		else if (line.origin == GIT_DIFF_LINE_DELETION)
			line.content_offset = bufs[1].ptr - info->xd_old_data.ptr;
		else
			line.content_offset = -1;

		output->error = diff_update_lines(
			info, &line, bufs[1].ptr, bufs[1].size);

		if (!output->error &&
			output->data_cb != NULL &&
			output->data_cb(delta, &info->hunk, &line, output->payload))
			output->error = GIT_EUSER;
	}

	if (len == 3 && !output->error) {
		/* If we have a '+' and a third buf, then we have added a line
		 * without a newline and the old code had one, so DEL_EOFNL.
		 * If we have a '-' and a third buf, then we have removed a line
		 * with out a newline but added a blank line, so ADD_EOFNL.
		 */
		line.origin =
			(*bufs[0].ptr == '+') ? GIT_DIFF_LINE_DEL_EOFNL :
			(*bufs[0].ptr == '-') ? GIT_DIFF_LINE_ADD_EOFNL :
			GIT_DIFF_LINE_CONTEXT_EOFNL;

		line.content_offset = -1;

		output->error = diff_update_lines(
			info, &line, bufs[2].ptr, bufs[2].size);

		if (!output->error &&
			output->data_cb != NULL &&
			output->data_cb(delta, &info->hunk, &line, output->payload))
			output->error = GIT_EUSER;
	}

	return output->error;
}
Exemple #9
0
void test_diff_blob__can_compare_blob_to_buffer_with_patch(void)
{
	git_patch *p;
	git_blob *a;
	git_oid a_oid;
	const char *a_content = "Hello from the root\n";
	const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n";
	size_t tc, ta, td;

	/* tests/resources/attr/root_test1 */
	cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
	cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8));

	/* diff from blob a to content of b */
	cl_git_pass(git_patch_from_blob_and_buffer(
		&p, a, NULL, b_content, strlen(b_content), NULL, &opts));

	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_MODIFIED, git_patch_get_delta(p)->status);
	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(6, git_patch_num_lines_in_hunk(p, 0));

	cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
	cl_assert_equal_i(1, (int)tc);
	cl_assert_equal_i(5, (int)ta);
	cl_assert_equal_i(0, (int)td);

	git_patch_free(p);

	/* diff from blob a to content of a */
	opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
	cl_git_pass(git_patch_from_blob_and_buffer(
		&p, a, NULL, a_content, strlen(a_content), NULL, &opts));
	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_patch_get_delta(p)->status);
	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
	git_patch_free(p);

	/* diff from NULL blob to content of a */
	cl_git_pass(git_patch_from_blob_and_buffer(
		&p, NULL, NULL, a_content, strlen(a_content), NULL, &opts));
	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_ADDED, git_patch_get_delta(p)->status);
	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
	git_patch_free(p);

	/* diff from blob a to NULL buffer */
	cl_git_pass(git_patch_from_blob_and_buffer(
		&p, a, NULL, NULL, 0, NULL, &opts));
	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_DELETED, git_patch_get_delta(p)->status);
	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
	git_patch_free(p);

	/* diff with reverse */
	opts.flags ^= GIT_DIFF_REVERSE;

	cl_git_pass(git_patch_from_blob_and_buffer(
		&p, a, NULL, NULL, 0, NULL, &opts));
	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_ADDED, git_patch_get_delta(p)->status);
	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
	git_patch_free(p);

	git_blob_free(a);
}
Exemple #10
0
void test_diff_blob__can_compare_against_null_blobs_with_patch(void)
{
	git_blob *e = NULL;
	git_patch *p;
	const git_diff_delta *delta;
	const git_diff_line *line;
	int l, max_l;

	cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts));

	cl_assert(p != NULL);

	delta = git_patch_get_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
	cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id);
	cl_assert_equal_sz(git_blob_rawsize(d), delta->old_file.size);
	cl_assert(git_oid_iszero(&delta->new_file.id));
	cl_assert_equal_sz(0, delta->new_file.size);

	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0));

	max_l = git_patch_num_lines_in_hunk(p, 0);
	for (l = 0; l < max_l; ++l) {
		cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l));
		cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)line->origin);
	}

	git_patch_free(p);

	opts.flags |= GIT_DIFF_REVERSE;

	cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts));

	cl_assert(p != NULL);

	delta = git_patch_get_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_ADDED, delta->status);
	cl_assert(git_oid_iszero(&delta->old_file.id));
	cl_assert_equal_sz(0, delta->old_file.size);
	cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id);
	cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size);

	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0));

	max_l = git_patch_num_lines_in_hunk(p, 0);
	for (l = 0; l < max_l; ++l) {
		cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l));
		cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)line->origin);
	}

	git_patch_free(p);

	opts.flags ^= GIT_DIFF_REVERSE;

	cl_git_pass(git_patch_from_blobs(&p, alien, NULL, NULL, NULL, &opts));

	cl_assert(p != NULL);

	delta = git_patch_get_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
	cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);

	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));

	git_patch_free(p);

	cl_git_pass(git_patch_from_blobs(&p, NULL, NULL, alien, NULL, &opts));

	cl_assert(p != NULL);

	delta = git_patch_get_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_ADDED, delta->status);
	cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);

	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));

	git_patch_free(p);
}