Пример #1
0
/*
 *  call-seq:
 *    hunk.each_line { |line| } -> self
 *    hunk.each_line -> Enumerator
 *
 *  If given a block, yields each line that is part of the current hunk.
 *
 *  If no block is given, an enumerator is returned instead.
 */
static VALUE rb_git_diff_hunk_each_line(VALUE self)
{
	git_patch *patch;
	int error = 0, l, lines_count, hunk_idx;

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

	Data_Get_Struct(rugged_owner(self), git_patch, patch);

	lines_count = FIX2INT(rb_iv_get(self, "@line_count"));
	hunk_idx = FIX2INT(rb_iv_get(self, "@hunk_index"));

	for (l = 0; l < lines_count; ++l) {
		const git_diff_line *line;
		error = git_patch_get_line_in_hunk(&line, patch, hunk_idx, l);
		if (error) break;

		rb_yield(rugged_diff_line_new(line));
	}
	rugged_exception_check(error);

	return self;
}
Пример #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);
}
Пример #3
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;
}
Пример #4
0
/*
 *  call-seq:
 *    hunk.each_line { |line| } -> self
 *    hunk.each_line -> Enumerator
 *
 *  If given a block, yields each line that is part of the current hunk.
 *
 *  If no block is given, an enumerator is returned instead.
 */
static VALUE rb_git_diff_hunk_each_line(VALUE self)
{
	git_patch *patch;
	int error = 0, l, lines_count, hunk_idx;

	RETURN_ENUMERATOR(self, 0, 0);

	Data_Get_Struct(rugged_owner(self), git_patch, patch);

	lines_count = FIX2INT(rb_iv_get(self, "@line_count"));
	hunk_idx = FIX2INT(rb_iv_get(self, "@hunk_index"));

	for (l = 0; l < lines_count; ++l) {
		const git_diff_line *line;
		error = git_patch_get_line_in_hunk(&line, patch, hunk_idx, l);
		if (error) break;

		rb_yield(rugged_diff_line_new(line));
	}
	rugged_exception_check(error);

	return self;
}
Пример #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;
}
Пример #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;
}
Пример #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);
}
Пример #8
0
/*
 *  call-seq:
 *    patch.lines(options = {}) -> int
 *
 *  The following options can be passed in the +options+ Hash:
 *
 *  :exclude_context ::
 *    Boolean value specifying that context line counts should be excluded from
 *    the returned total.
 *
 *  :exclude_additions ::
 *    Boolean value specifying that addition line counts should be excluded from
 *    the returned total.
 *
 *  :exclude_deletions ::
 *    Boolean value specifying that deletion line counts should be excluded from
 *    the returned total.
 *
 *  :exclude_eofnl ::
 *    Boolean value specifying that end-of-file newline change lines should
 *    be excluded from the returned total.
 *
 *  Returns the total number of lines in the patch, depending on the options
 *  specified.
 */
static VALUE rb_git_diff_patch_lines(int argc, VALUE *argv, VALUE self)
{
    git_patch *patch;
    size_t lines = 0;
    VALUE rb_options;
    Data_Get_Struct(self, git_patch, patch);

    int options = 0;

    rb_scan_args(argc, argv, "0:", &rb_options);
    if (!NIL_P(rb_options)) {
        if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_context")))) {
            options |= EXCLUDE_CONTEXT;
        }

        if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_additions")))) {
            options |= EXCLUDE_ADDITIONS;
        }

        if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_deletions")))) {
            options |= EXCLUDE_DELETIONS;
        }

        if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_eofnl")))) {
            options |= EXCLUDE_EOFNL;
        }
    }

    if (options == 0) {
        size_t i = 0, hunks_count = git_patch_num_hunks(patch);
        for (i = 0; i < hunks_count; ++i) {
            lines += git_patch_num_lines_in_hunk(patch, i);
        }
    } else {
        size_t i = 0, hunks_count = git_patch_num_hunks(patch);
        for (i = 0; i < hunks_count; ++i) {
            size_t lines_in_hunk = git_patch_num_lines_in_hunk(patch, i), l = 0;

            for (l = 0; l < lines_in_hunk; ++l) {
                const git_diff_line *line;
                rugged_exception_check(
                    git_patch_get_line_in_hunk(&line, patch, i, l)
                );

                switch (line->origin) {
                case GIT_DIFF_LINE_CONTEXT:
                    if (options & EXCLUDE_CONTEXT) continue;
                    break;

                case GIT_DIFF_LINE_ADDITION:
                    if (options & EXCLUDE_ADDITIONS) continue;
                    break;

                case GIT_DIFF_LINE_DELETION:
                    if (options & EXCLUDE_DELETIONS) continue;
                    break;

                case GIT_DIFF_LINE_ADD_EOFNL:
                case GIT_DIFF_LINE_DEL_EOFNL:
                    if (options & EXCLUDE_EOFNL) continue;
                    break;
                }

                lines += 1;
            }
        }
    }

    return INT2FIX(lines);
}
Пример #9
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);
}