diff_helpers.c 3.82 KB
Newer Older
1 2 3 4 5 6 7
#include "clar_libgit2.h"
#include "diff_helpers.h"

git_tree *resolve_commit_oid_to_tree(
	git_repository *repo,
	const char *partial_oid)
{
8
	size_t len = strlen(partial_oid);
9
	git_oid oid;
10 11
	git_object *obj = NULL;
	git_tree *tree = NULL;
12 13 14 15 16 17 18 19 20 21 22

	if (git_oid_fromstrn(&oid, partial_oid, len) == 0)
		git_object_lookup_prefix(&obj, repo, &oid, len, GIT_OBJ_ANY);
	cl_assert(obj);
	if (git_object_type(obj) == GIT_OBJ_TREE)
		return (git_tree *)obj;
	cl_assert(git_object_type(obj) == GIT_OBJ_COMMIT);
	cl_git_pass(git_commit_tree(&tree, (git_commit *)obj));
	git_object_free(obj);
	return tree;
}
23 24 25

int diff_file_fn(
	void *cb_data,
26
	const git_diff_delta *delta,
27 28 29
	float progress)
{
	diff_expects *e = cb_data;
30 31 32

	GIT_UNUSED(progress);

33 34
	if (delta->binary)
		e->at_least_one_of_them_is_binary = true;
35

36
	e->files++;
37
	switch (delta->status) {
38 39 40 41 42
	case GIT_DELTA_ADDED: e->file_adds++; break;
	case GIT_DELTA_DELETED: e->file_dels++; break;
	case GIT_DELTA_MODIFIED: e->file_mods++; break;
	case GIT_DELTA_IGNORED: e->file_ignored++; break;
	case GIT_DELTA_UNTRACKED: e->file_untracked++; break;
43
	case GIT_DELTA_UNMODIFIED: e->file_unmodified++; break;
44 45
	default: break;
	}
46 47 48 49 50
	return 0;
}

int diff_hunk_fn(
	void *cb_data,
51 52
	const git_diff_delta *delta,
	const git_diff_range *range,
53 54 55 56
	const char *header,
	size_t header_len)
{
	diff_expects *e = cb_data;
57 58 59 60 61

	GIT_UNUSED(delta);
	GIT_UNUSED(header);
	GIT_UNUSED(header_len);

62 63 64 65 66 67 68 69
	e->hunks++;
	e->hunk_old_lines += range->old_lines;
	e->hunk_new_lines += range->new_lines;
	return 0;
}

int diff_line_fn(
	void *cb_data,
70 71
	const git_diff_delta *delta,
	const git_diff_range *range,
72 73 74 75 76
	char line_origin,
	const char *content,
	size_t content_len)
{
	diff_expects *e = cb_data;
77 78 79 80 81 82

	GIT_UNUSED(delta);
	GIT_UNUSED(range);
	GIT_UNUSED(content);
	GIT_UNUSED(content_len);

83 84 85 86 87 88 89 90
	e->lines++;
	switch (line_origin) {
	case GIT_DIFF_LINE_CONTEXT:
		e->line_ctxt++;
		break;
	case GIT_DIFF_LINE_ADDITION:
		e->line_adds++;
		break;
91
	case GIT_DIFF_LINE_ADD_EOFNL:
92 93
		/* technically not a line add, but we'll count it as such */
		e->line_adds++;
94
		break;
95
	case GIT_DIFF_LINE_DELETION:
96 97
		e->line_dels++;
		break;
98
	case GIT_DIFF_LINE_DEL_EOFNL:
99
		/* technically not a line delete, but we'll count it as such */
100 101 102 103 104 105 106
		e->line_dels++;
		break;
	default:
		break;
	}
	return 0;
}
Russell Belfer committed
107 108 109 110 111 112 113 114

int diff_foreach_via_iterator(
	git_diff_list *diff,
	void *data,
	git_diff_file_fn file_cb,
	git_diff_hunk_fn hunk_cb,
	git_diff_data_fn line_cb)
{
115
	size_t d, num_d = git_diff_num_deltas(diff);
Russell Belfer committed
116

117 118
	for (d = 0; d < num_d; ++d) {
		git_diff_patch *patch;
119
		const git_diff_delta *delta;
120
		size_t h, num_h;
Russell Belfer committed
121

122
		cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d));
123
		cl_assert(delta);
Russell Belfer committed
124 125

		/* call file_cb for this file */
126 127
		if (file_cb != NULL && file_cb(data, delta, (float)d / num_d) != 0) {
			git_diff_patch_free(patch);
Russell Belfer committed
128
			goto abort;
129
		}
Russell Belfer committed
130

131 132 133 134 135 136
		/* if there are no changes, then the patch will be NULL */
		if (!patch) {
			cl_assert(delta->status == GIT_DELTA_UNMODIFIED || delta->binary == 1);
			continue;
		}

137 138
		if (!hunk_cb && !line_cb) {
			git_diff_patch_free(patch);
Russell Belfer committed
139
			continue;
140 141 142
		}

		num_h = git_diff_patch_num_hunks(patch);
Russell Belfer committed
143

144
		for (h = 0; h < num_h; h++) {
145
			const git_diff_range *range;
146 147
			const char *hdr;
			size_t hdr_len, l, num_l;
Russell Belfer committed
148

149 150 151 152 153
			cl_git_pass(git_diff_patch_get_hunk(
				&range, &hdr, &hdr_len, &num_l, patch, h));

			if (hunk_cb && hunk_cb(data, delta, range, hdr, hdr_len) != 0) {
				git_diff_patch_free(patch);
Russell Belfer committed
154
				goto abort;
155
			}
Russell Belfer committed
156

157 158 159 160 161
			for (l = 0; l < num_l; ++l) {
				char origin;
				const char *line;
				size_t line_len;
				int old_lineno, new_lineno;
Russell Belfer committed
162

163 164 165
				cl_git_pass(git_diff_patch_get_line_in_hunk(
					&origin, &line, &line_len, &old_lineno, &new_lineno,
					patch, h, l));
Russell Belfer committed
166

167 168
				if (line_cb(data, delta, range, origin, line, line_len) != 0) {
					git_diff_patch_free(patch);
Russell Belfer committed
169
					goto abort;
170
				}
Russell Belfer committed
171 172 173
			}
		}

174
		git_diff_patch_free(patch);
Russell Belfer committed
175 176
	}

177
	return 0;
Russell Belfer committed
178 179 180 181 182

abort:
	giterr_clear();
	return GIT_EUSER;
}