diff_helpers.c 4.59 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

Vicent Marti committed
24
int diff_file_cb(
25
	const git_diff_delta *delta,
26 27
	float progress,
	void *payload)
28
{
29
	diff_expects *e = payload;
30

31 32 33 34 35 36 37 38 39
	if (e->debug)
		fprintf(stderr, "%c %s (%.3f)\n",
			git_diff_status_char(delta->status),
			delta->old_file.path, progress);

	if (e->names)
		cl_assert_equal_s(e->names[e->files], delta->old_file.path);
	if (e->statuses)
		cl_assert_equal_i(e->statuses[e->files], (int)delta->status);
40

41 42
	e->files++;

43
	if ((delta->flags & GIT_DIFF_FLAG_BINARY) != 0)
44
		e->files_binary++;
45 46 47 48 49

	cl_assert(delta->status <= GIT_DELTA_TYPECHANGE);

	e->file_status[delta->status] += 1;

50 51 52
	return 0;
}

53 54 55 56 57 58 59 60 61 62
int diff_print_file_cb(
	const git_diff_delta *delta,
	float progress,
	void *payload)
{
	fprintf(stderr, "%c %s\n",
		git_diff_status_char(delta->status), delta->old_file.path);
	return diff_file_cb(delta, progress, payload);
}

Vicent Marti committed
63
int diff_hunk_cb(
64 65
	const git_diff_delta *delta,
	const git_diff_range *range,
66
	const char *header,
67 68
	size_t header_len,
	void *payload)
69
{
70
	diff_expects *e = payload;
71 72 73 74 75

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

76 77 78 79 80 81
	e->hunks++;
	e->hunk_old_lines += range->old_lines;
	e->hunk_new_lines += range->new_lines;
	return 0;
}

Vicent Marti committed
82
int diff_line_cb(
83 84
	const git_diff_delta *delta,
	const git_diff_range *range,
85 86
	char line_origin,
	const char *content,
87 88
	size_t content_len,
	void *payload)
89
{
90
	diff_expects *e = payload;
91 92 93 94 95 96

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

97 98 99 100 101 102 103 104
	e->lines++;
	switch (line_origin) {
	case GIT_DIFF_LINE_CONTEXT:
		e->line_ctxt++;
		break;
	case GIT_DIFF_LINE_ADDITION:
		e->line_adds++;
		break;
105
	case GIT_DIFF_LINE_ADD_EOFNL:
106 107
		/* technically not a line add, but we'll count it as such */
		e->line_adds++;
108
		break;
109
	case GIT_DIFF_LINE_DELETION:
110 111
		e->line_dels++;
		break;
112
	case GIT_DIFF_LINE_DEL_EOFNL:
113
		/* technically not a line delete, but we'll count it as such */
114 115 116 117 118 119 120
		e->line_dels++;
		break;
	default:
		break;
	}
	return 0;
}
Russell Belfer committed
121 122 123

int diff_foreach_via_iterator(
	git_diff_list *diff,
Vicent Marti committed
124 125
	git_diff_file_cb file_cb,
	git_diff_hunk_cb hunk_cb,
126 127
	git_diff_data_cb line_cb,
	void *data)
Russell Belfer committed
128
{
129
	size_t d, num_d = git_diff_num_deltas(diff);
Russell Belfer committed
130

131 132
	for (d = 0; d < num_d; ++d) {
		git_diff_patch *patch;
133
		const git_diff_delta *delta;
134
		size_t h, num_h;
Russell Belfer committed
135

136
		cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d));
137
		cl_assert(delta);
Russell Belfer committed
138 139

		/* call file_cb for this file */
140
		if (file_cb != NULL && file_cb(delta, (float)d / num_d, data) != 0) {
141
			git_diff_patch_free(patch);
Russell Belfer committed
142
			goto abort;
143
		}
Russell Belfer committed
144

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

152 153
		if (!hunk_cb && !line_cb) {
			git_diff_patch_free(patch);
Russell Belfer committed
154
			continue;
155 156 157
		}

		num_h = git_diff_patch_num_hunks(patch);
Russell Belfer committed
158

159
		for (h = 0; h < num_h; h++) {
160
			const git_diff_range *range;
161 162
			const char *hdr;
			size_t hdr_len, l, num_l;
Russell Belfer committed
163

164 165 166
			cl_git_pass(git_diff_patch_get_hunk(
				&range, &hdr, &hdr_len, &num_l, patch, h));

167
			if (hunk_cb && hunk_cb(delta, range, hdr, hdr_len, data) != 0) {
168
				git_diff_patch_free(patch);
Russell Belfer committed
169
				goto abort;
170
			}
Russell Belfer committed
171

172 173 174 175 176
			for (l = 0; l < num_l; ++l) {
				char origin;
				const char *line;
				size_t line_len;
				int old_lineno, new_lineno;
Russell Belfer committed
177

178 179 180
				cl_git_pass(git_diff_patch_get_line_in_hunk(
					&origin, &line, &line_len, &old_lineno, &new_lineno,
					patch, h, l));
Russell Belfer committed
181

182 183
				if (line_cb &&
					line_cb(delta, range, origin, line, line_len, data) != 0) {
184
					git_diff_patch_free(patch);
Russell Belfer committed
185
					goto abort;
186
				}
Russell Belfer committed
187 188 189
			}
		}

190
		git_diff_patch_free(patch);
Russell Belfer committed
191 192
	}

193
	return 0;
Russell Belfer committed
194 195 196 197 198

abort:
	giterr_clear();
	return GIT_EUSER;
}
199 200 201 202 203 204

static int diff_print_cb(
	const git_diff_delta *delta,
	const git_diff_range *range,
	char line_origin, /**< GIT_DIFF_LINE_... value from above */
	const char *content,
205 206
	size_t content_len,
	void *payload)
207
{
208
	GIT_UNUSED(payload);
209 210 211 212
	GIT_UNUSED(delta);
	GIT_UNUSED(range);
	GIT_UNUSED(line_origin);
	GIT_UNUSED(content_len);
213
	fputs(content, (FILE *)payload);
214 215 216 217 218
	return 0;
}

void diff_print(FILE *fp, git_diff_list *diff)
{
219
	cl_git_pass(git_diff_print_patch(diff, diff_print_cb, fp ? fp : stderr));
220
}