Skip to content

Commit e30a6ee

Browse files
authored
Merge pull request libgit2#4160 from pks-t/pks/diff-fixes
Diff fixes
2 parents 44b3b9f + c0eba37 commit e30a6ee

File tree

5 files changed

+120
-82
lines changed

5 files changed

+120
-82
lines changed

src/diff.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,41 @@ int git_diff_get_perfdata(git_diff_perfdata *out, const git_diff *diff)
120120
return 0;
121121
}
122122

123+
int git_diff_foreach(
124+
git_diff *diff,
125+
git_diff_file_cb file_cb,
126+
git_diff_binary_cb binary_cb,
127+
git_diff_hunk_cb hunk_cb,
128+
git_diff_line_cb data_cb,
129+
void *payload)
130+
{
131+
int error = 0;
132+
git_diff_delta *delta;
133+
size_t idx;
134+
135+
assert(diff);
136+
137+
git_vector_foreach(&diff->deltas, idx, delta) {
138+
git_patch *patch;
139+
140+
/* check flags against patch status */
141+
if (git_diff_delta__should_skip(&diff->opts, delta))
142+
continue;
143+
144+
if ((error = git_patch_from_diff(&patch, diff, idx)) != 0)
145+
break;
146+
147+
error = git_patch__invoke_callbacks(patch, file_cb, binary_cb,
148+
hunk_cb, data_cb, payload);
149+
git_patch_free(patch);
150+
151+
if (error)
152+
break;
153+
}
154+
155+
return error;
156+
}
157+
123158
int git_diff_format_email__append_header_tobuf(
124159
git_buf *out,
125160
const git_oid *id,

src/diff_parse.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,16 @@ static git_diff_parsed *diff_parsed_alloc(void)
3737

3838
GIT_REFCOUNT_INC(diff);
3939
diff->base.type = GIT_DIFF_TYPE_PARSED;
40-
diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE;
4140
diff->base.strcomp = git__strcmp;
4241
diff->base.strncomp = git__strncmp;
4342
diff->base.pfxcomp = git__prefixcmp;
4443
diff->base.entrycomp = git_diff__entry_cmp;
4544
diff->base.patch_fn = git_patch_parsed_from_diff;
4645
diff->base.free_fn = diff_parsed_free;
4746

47+
git_diff_init_options(&diff->base.opts, GIT_DIFF_OPTIONS_VERSION);
48+
diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE;
49+
4850
git_pool_init(&diff->base.pool, 1);
4951

5052
if (git_vector_init(&diff->patches, 0, NULL) < 0 ||

src/patch_generate.c

Lines changed: 8 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -206,35 +206,14 @@ static int patch_generated_load(git_patch_generated *patch, git_patch_generated_
206206
((patch->nfile.flags & GIT_DIFF_FLAG__NO_DATA) != 0 ||
207207
(patch->nfile.file->flags & GIT_DIFF_FLAG_VALID_ID) != 0));
208208

209-
/* always try to load workdir content first because filtering may
210-
* need 2x data size and this minimizes peak memory footprint
211-
*/
212-
if (patch->ofile.src == GIT_ITERATOR_TYPE_WORKDIR) {
213-
if ((error = git_diff_file_content__load(
214-
&patch->ofile, &patch->base.diff_opts)) < 0 ||
215-
should_skip_binary(patch, patch->ofile.file))
216-
goto cleanup;
217-
}
218-
if (patch->nfile.src == GIT_ITERATOR_TYPE_WORKDIR) {
219-
if ((error = git_diff_file_content__load(
220-
&patch->nfile, &patch->base.diff_opts)) < 0 ||
221-
should_skip_binary(patch, patch->nfile.file))
222-
goto cleanup;
223-
}
224-
225-
/* once workdir has been tried, load other data as needed */
226-
if (patch->ofile.src != GIT_ITERATOR_TYPE_WORKDIR) {
227-
if ((error = git_diff_file_content__load(
228-
&patch->ofile, &patch->base.diff_opts)) < 0 ||
229-
should_skip_binary(patch, patch->ofile.file))
230-
goto cleanup;
231-
}
232-
if (patch->nfile.src != GIT_ITERATOR_TYPE_WORKDIR) {
233-
if ((error = git_diff_file_content__load(
234-
&patch->nfile, &patch->base.diff_opts)) < 0 ||
235-
should_skip_binary(patch, patch->nfile.file))
236-
goto cleanup;
237-
}
209+
if ((error = git_diff_file_content__load(
210+
&patch->ofile, &patch->base.diff_opts)) < 0 ||
211+
should_skip_binary(patch, patch->ofile.file))
212+
goto cleanup;
213+
if ((error = git_diff_file_content__load(
214+
&patch->nfile, &patch->base.diff_opts)) < 0 ||
215+
should_skip_binary(patch, patch->nfile.file))
216+
goto cleanup;
238217

239218
/* if previously missing an oid, and now that we have it the two sides
240219
* are the same (and not submodules), update MODIFIED -> UNMODIFIED
@@ -421,56 +400,6 @@ static int diff_required(git_diff *diff, const char *action)
421400
return -1;
422401
}
423402

424-
int git_diff_foreach(
425-
git_diff *diff,
426-
git_diff_file_cb file_cb,
427-
git_diff_binary_cb binary_cb,
428-
git_diff_hunk_cb hunk_cb,
429-
git_diff_line_cb data_cb,
430-
void *payload)
431-
{
432-
int error = 0;
433-
git_xdiff_output xo;
434-
size_t idx;
435-
git_patch_generated patch;
436-
437-
if ((error = diff_required(diff, "git_diff_foreach")) < 0)
438-
return error;
439-
440-
memset(&xo, 0, sizeof(xo));
441-
memset(&patch, 0, sizeof(patch));
442-
diff_output_init(
443-
&xo.output, &diff->opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
444-
git_xdiff_init(&xo, &diff->opts);
445-
446-
git_vector_foreach(&diff->deltas, idx, patch.base.delta) {
447-
448-
/* check flags against patch status */
449-
if (git_diff_delta__should_skip(&diff->opts, patch.base.delta))
450-
continue;
451-
452-
if (binary_cb || hunk_cb || data_cb) {
453-
if ((error = patch_generated_init(&patch, diff, idx)) != 0 ||
454-
(error = patch_generated_load(&patch, &xo.output)) != 0) {
455-
git_patch_free(&patch.base);
456-
return error;
457-
}
458-
}
459-
460-
if ((error = patch_generated_invoke_file_callback(&patch, &xo.output)) == 0) {
461-
if (binary_cb || hunk_cb || data_cb)
462-
error = patch_generated_create(&patch, &xo.output);
463-
}
464-
465-
git_patch_free(&patch.base);
466-
467-
if (error)
468-
break;
469-
}
470-
471-
return error;
472-
}
473-
474403
typedef struct {
475404
git_patch_generated patch;
476405
git_diff_delta delta;

src/patch_parse.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,8 +562,9 @@ static int parse_hunk_body(
562562
int newlines = hunk->hunk.new_lines;
563563

564564
for (;
565-
ctx->remain_len > 4 && (oldlines || newlines) &&
566-
memcmp(ctx->line, "@@ -", 4) != 0;
565+
ctx->remain_len > 1 &&
566+
(oldlines || newlines) &&
567+
(ctx->remain_len <= 4 || memcmp(ctx->line, "@@ -", 4) != 0);
567568
parse_advance_line(ctx)) {
568569

569570
int origin;

tests/diff/parse.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,74 @@ void test_diff_parse__get_patch_from_diff(void)
196196

197197
cl_git_sandbox_cleanup();
198198
}
199+
200+
static int file_cb(const git_diff_delta *delta, float progress, void *payload)
201+
{
202+
int *called = (int *) payload;
203+
GIT_UNUSED(delta);
204+
GIT_UNUSED(progress);
205+
(*called)++;
206+
return 0;
207+
}
208+
209+
void test_diff_parse__foreach_works_with_parsed_patch(void)
210+
{
211+
const char patch[] =
212+
"diff --git a/obj1 b/obj2\n"
213+
"index 1234567..7654321 10644\n"
214+
"--- a/obj1\n"
215+
"+++ b/obj2\n"
216+
"@@ -1 +1 @@\n"
217+
"-abcde\n"
218+
"+12345\n";
219+
int called = 0;
220+
git_diff *diff;
221+
222+
cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch)));
223+
cl_git_pass(git_diff_foreach(diff, file_cb, NULL, NULL, NULL, &called));
224+
cl_assert_equal_i(called, 1);
225+
226+
git_diff_free(diff);
227+
}
228+
229+
void test_diff_parse__parsing_minimal_patch_succeeds(void)
230+
{
231+
const char patch[] =
232+
"diff --git a/obj1 b/obj2\n"
233+
"index 1234567..7654321 10644\n"
234+
"--- a/obj1\n"
235+
"+++ b/obj2\n"
236+
"@@ -1 +1 @@\n"
237+
"-a\n"
238+
"+\n";
239+
git_buf buf = GIT_BUF_INIT;
240+
git_diff *diff;
241+
242+
cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch)));
243+
cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH));
244+
cl_assert_equal_s(patch, buf.ptr);
245+
246+
git_diff_free(diff);
247+
git_buf_free(&buf);
248+
}
249+
250+
void test_diff_parse__patch_roundtrip_succeeds(void)
251+
{
252+
const char buf1[] = "a\n", buf2[] = "b\n";
253+
git_buf patchbuf = GIT_BUF_INIT, diffbuf = GIT_BUF_INIT;
254+
git_patch *patch;
255+
git_diff *diff;
256+
257+
cl_git_pass(git_patch_from_buffers(&patch, buf1, strlen(buf1), "obj1", buf2, strlen(buf2), "obj2", NULL));
258+
cl_git_pass(git_patch_to_buf(&patchbuf, patch));
259+
260+
cl_git_pass(git_diff_from_buffer(&diff, patchbuf.ptr, patchbuf.size));
261+
cl_git_pass(git_diff_to_buf(&diffbuf, diff, GIT_DIFF_FORMAT_PATCH));
262+
263+
cl_assert_equal_s(patchbuf.ptr, diffbuf.ptr);
264+
265+
git_patch_free(patch);
266+
git_diff_free(diff);
267+
git_buf_free(&patchbuf);
268+
git_buf_free(&diffbuf);
269+
}

0 commit comments

Comments
 (0)