Esempio n. 1
0
/*
 *  call-seq:
 *    patch.each_hunk { |hunk| } -> self
 *    patch.each_hunk -> enumerator
 *
 *  If given a block, yields each hunk that is part of the patch.
 *
 *  If no block is given, an enumerator is returned instead.
 */
static VALUE rb_git_diff_patch_each_hunk(VALUE self)
{
    git_patch *patch;
    const git_diff_hunk *hunk;
    size_t lines_in_hunk;
    int error = 0;
    size_t hunks_count, h;

    if (!rb_block_given_p()) {
        return rb_funcall(self, rb_intern("to_enum"), 1, CSTR2SYM("each_hunk"), self);
    }

    Data_Get_Struct(self, git_patch, patch);

    hunks_count = git_patch_num_hunks(patch);
    for (h = 0; h < hunks_count; ++h) {
        error = git_patch_get_hunk(&hunk, &lines_in_hunk, patch, h);
        if (error) break;

        rb_yield(rugged_diff_hunk_new(self, h, hunk, lines_in_hunk));
    }
    rugged_exception_check(error);

    return self;
}
Esempio n. 2
0
void test_diff_tree__larger_hunks(void)
{
	const char *a_commit = "d70d245ed97ed2aa596dd1af6536e4bfdb047b69";
	const char *b_commit = "7a9e0b02e63179929fed24f0a3e0f19168114d10";
	size_t d, num_d, h, num_h, l, num_l;
	git_patch *patch;
	const git_diff_hunk *hunk;
	const git_diff_line *line;

	g_repo = cl_git_sandbox_init("diff");

	cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
	cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);

	opts.context_lines = 1;
	opts.interhunk_lines = 0;

	cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts));

	num_d = git_diff_num_deltas(diff);
	for (d = 0; d < num_d; ++d) {
		cl_git_pass(git_patch_from_diff(&patch, diff, d));
		cl_assert(patch);

		num_h = git_patch_num_hunks(patch);
		for (h = 0; h < num_h; h++) {
			cl_git_pass(git_patch_get_hunk(&hunk, &num_l, patch, h));

			for (l = 0; l < num_l; ++l) {
				cl_git_pass(git_patch_get_line_in_hunk(&line, patch, h, l));
				cl_assert(line);
			}

			cl_git_fail(git_patch_get_line_in_hunk(&line, patch, h, num_l));
		}

		cl_git_fail(git_patch_get_hunk(&hunk, &num_l, patch, num_h));

		git_patch_free(patch);
	}

	cl_git_fail(git_patch_from_diff(&patch, diff, num_d));

	cl_assert_equal_i(2, (int)num_d);
}
Esempio n. 3
0
/**
 * ggit_patch_get_hunk:
 * @patch: a #GgitPatch
 * @idx: the hunk index.
 * @error: a #GError
 *
 * Get the @idx'th hunk in the patch.
 *
 * Returns: (transfer full): a new #GgitDiffHunk or %NULL on error.
 */
GgitDiffHunk *
ggit_patch_get_hunk (GgitPatch  *patch,
                     gsize       idx,
                     GError    **error)
{
	const git_diff_hunk *hunk;
	size_t tlines;
	gint ret;

	g_return_val_if_fail (patch != NULL, NULL);

	ret = git_patch_get_hunk (&hunk, &tlines, patch->patch, idx);

	if (ret != GIT_OK)
	{
		_ggit_error_set (error, ret);
		return NULL;
	}

	return _ggit_diff_hunk_wrap (hunk);
}
Esempio n. 4
0
PyObject *
wrap_diff_hunk(git_patch *patch, size_t idx)
{
    DiffHunk *py_hunk;
    const git_diff_hunk *hunk;
    const git_diff_line *line;
    size_t j, lines_in_hunk;
    int err;

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

    py_hunk = PyObject_New(DiffHunk, &DiffHunkType);
    if (py_hunk) {
        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->header = to_unicode_n((const char *) &hunk->header,
                hunk->header_len, NULL, NULL);

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

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

            py_line = wrap_diff_line(line);
            if (py_line == NULL)
                return NULL;

            PyList_SetItem(py_hunk->lines, j, py_line);
        }
    }

    return (PyObject *) py_hunk;
}
Esempio n. 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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
void QGit::commitDiffContent(QString first, QString second, QList<QString> files)
{
    git_commit *first_commit = nullptr, *second_commit = nullptr;
    git_object *first_obj = nullptr, *second_obj = nullptr;
    git_tree *first_tree = nullptr, *second_tree = nullptr;
    const git_diff_delta *delta = nullptr;
    git_repository *repo = nullptr;
    git_patch *patch = nullptr;
    QList<QGitDiffFile> items;
    git_diff *diff = nullptr;
    QGitError error;
    int res = 0;

    try {
        res = git_repository_open(&repo, m_path.absolutePath().toUtf8().constData());
        if (res)
        {
            throw QGitError("git_repository_open", res);
        }

        if (!first.isEmpty())
        {
            res = git_revparse_single(&first_obj, repo, first.toLatin1());
            if (res)
            {
                throw QGitError("git_revparse_single(first)", res);
            }

            res = git_commit_lookup(&first_commit, repo, git_object_id(first_obj));
            if (res)
            {
                throw QGitError("git_commit_lookup(first)", res);
            }

            res = git_commit_tree(&first_tree, first_commit);
            if (res)
            {
                throw QGitError("git_commit_tree(first)", res);
            }
        }

        if (second == "staged")
        {
            git_diff_options options;

            res = git_revparse_single(&first_obj, repo, "HEAD^{tree}");
            if (res)
            {
                throw QGitError("git_revparse_single(staged)", res);
            }

            res = git_tree_lookup(&first_tree, repo, git_object_id(first_obj));
            if (res)
            {
                throw QGitError("git_tree_lookup(staged)", res);
            }

            memset(&options, 0, sizeof(options));
            options.version = GIT_DIFF_OPTIONS_VERSION;
            options.flags = GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_SHOW_UNTRACKED_CONTENT;
            options.context_lines = 3;

            res = git_diff_tree_to_index(&diff, repo, first_tree, nullptr, &options);
            if (res)
            {
                throw QGitError("git_diff_tree_to_index(staged)", res);
            }
        }
        else if (second == "unstaged")
        {
            git_diff_options options;

            memset(&options, 0, sizeof(options));
            options.version = GIT_DIFF_OPTIONS_VERSION;
            options.flags = GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_SHOW_UNTRACKED_CONTENT;
            options.context_lines = 3;

            res = git_diff_index_to_workdir(&diff, repo, nullptr, &options);
            if (res)
            {
                throw QGitError("git_diff_index_to_workdir", res);
            }
        }
        else
        {
            res = git_revparse_single(&second_obj, repo, second.toLatin1());
            if (res)
            {
                throw QGitError("git_revparse_single(second)", res);
            }

            res = git_commit_lookup(&second_commit, repo, git_object_id(second_obj));
            if (res)
            {
                throw QGitError("git_commit_lookup(second)", res);
            }

            res = git_commit_tree(&second_tree, second_commit);
            if (res)
            {
                throw QGitError("git_commit_tree(second)", res);
            }

            res = git_diff_tree_to_tree(&diff, repo, first_tree, second_tree, nullptr);
            if (res)
            {
                throw QGitError("git_diff_tree_to_tree", res);
            }
        }

        size_t _count = git_diff_num_deltas(diff);
        for(size_t c = 0; c < _count; c++)
        {
            delta = git_diff_get_delta(diff, c);

            QGitDiffFile item(delta);

            if (files.contains(item.new_file().path()))
            {
                res = git_patch_from_diff(&patch, diff, c);
                if (res)
                {
                    throw QGitError("git_patch_from_diff", res);
                }

                size_t hunks = git_patch_num_hunks(patch);
                for(size_t  hunk_cnt = 0; hunk_cnt < hunks; hunk_cnt++) {
                    const git_diff_hunk *hunk = nullptr;
                    res = git_patch_get_hunk(&hunk, nullptr, patch, hunk_cnt);
                    if (res)
                    {
                        throw QGitError("git_patch_get_hunk", res);
                    }

                    QGitDiffHunk hunkObj(hunk);

                    const git_diff_line *line = nullptr;

                    int lines = git_patch_num_lines_in_hunk(patch, hunk_cnt);
                    if (lines > 0)
                    {
                        for(int  line_cnt = 0; line_cnt < lines; line_cnt++) {
                            res = git_patch_get_line_in_hunk(&line, patch, hunk_cnt, static_cast<size_t>(line_cnt));
                            if (res)
                            {
                                throw QGitError("git_patch_get_line_in_hunk", res);
                            }

                            hunkObj.addLine(line);
                        }
                    }

                    item.addHunk(hunkObj);
                }

                items.append(item);
            }
        }
    } catch(const QGitError &ex) {
        error = ex;
    }

    emit commitDiffContentReply(first, second, items, error);
}