Skip to content

Commit 98cd180

Browse files
Merge pull request #627 from libgit2/arthur/fix-patch-lines
Fix `Rugged::Patch#lines` and `Rugged::Patch#bytesize`
2 parents 9eeee74 + 5bed5e0 commit 98cd180

File tree

3 files changed

+90
-21
lines changed

3 files changed

+90
-21
lines changed

ext/rugged/rugged_patch.c

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,13 @@ static VALUE rb_git_diff_patch_stat(VALUE self)
173173
return rb_ary_new3(2, INT2FIX(additions), INT2FIX(deletions));
174174
}
175175

176+
enum {
177+
EXCLUDE_CONTEXT = (1u << 0),
178+
EXCLUDE_ADDITIONS = (1u << 1),
179+
EXCLUDE_DELETIONS = (1u << 2),
180+
EXCLUDE_EOFNL = (1u << 3)
181+
};
182+
176183
/*
177184
* call-seq:
178185
* patch.lines(options = {}) -> int
@@ -191,41 +198,82 @@ static VALUE rb_git_diff_patch_stat(VALUE self)
191198
* Boolean value specifying that deletion line counts should be excluded from
192199
* the returned total.
193200
*
201+
* :exclude_eofnl ::
202+
* Boolean value specifying that end-of-file newline change lines should
203+
* be excluded from the returned total.
204+
*
194205
* Returns the total number of lines in the patch, depending on the options
195206
* specified.
196207
*/
197208
static VALUE rb_git_diff_patch_lines(int argc, VALUE *argv, VALUE self)
198209
{
199210
git_patch *patch;
200-
size_t context_lines, additions, deletions;
201-
size_t total_out;
211+
size_t lines = 0;
202212
VALUE rb_options;
203213
Data_Get_Struct(self, git_patch, patch);
204214

205-
context_lines = 0;
206-
additions = 0;
207-
deletions = 0;
208-
209-
git_patch_line_stats(&context_lines, &additions, &deletions, patch);
210-
211-
total_out = context_lines + additions + deletions;
215+
int options = 0;
212216

213217
rb_scan_args(argc, argv, "0:", &rb_options);
214218
if (!NIL_P(rb_options)) {
215219
if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_context")))) {
216-
total_out -= context_lines;
220+
options |= EXCLUDE_CONTEXT;
217221
}
218222

219223
if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_additions")))) {
220-
total_out -= additions;
224+
options |= EXCLUDE_ADDITIONS;
221225
}
222226

223227
if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_deletions")))) {
224-
total_out -= deletions;
228+
options |= EXCLUDE_DELETIONS;
229+
}
230+
231+
if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_eofnl")))) {
232+
options |= EXCLUDE_EOFNL;
225233
}
226234
}
227235

228-
return INT2FIX(total_out);
236+
if (options == 0) {
237+
size_t i = 0, hunks_count = git_patch_num_hunks(patch);
238+
for (i = 0; i < hunks_count; ++i) {
239+
lines += git_patch_num_lines_in_hunk(patch, i);
240+
}
241+
} else {
242+
size_t i = 0, hunks_count = git_patch_num_hunks(patch);
243+
for (i = 0; i < hunks_count; ++i) {
244+
size_t lines_in_hunk = git_patch_num_lines_in_hunk(patch, i), l = 0;
245+
246+
for (l = 0; l < lines_in_hunk; ++l) {
247+
const git_diff_line *line;
248+
rugged_exception_check(
249+
git_patch_get_line_in_hunk(&line, patch, i, l)
250+
);
251+
252+
switch (line->origin) {
253+
case GIT_DIFF_LINE_CONTEXT:
254+
if (options & EXCLUDE_CONTEXT) continue;
255+
break;
256+
257+
case GIT_DIFF_LINE_ADDITION:
258+
if (options & EXCLUDE_ADDITIONS) continue;
259+
break;
260+
261+
case GIT_DIFF_LINE_DELETION:
262+
if (options & EXCLUDE_DELETIONS) continue;
263+
break;
264+
265+
case GIT_DIFF_LINE_ADD_EOFNL:
266+
case GIT_DIFF_LINE_DEL_EOFNL:
267+
if (options & EXCLUDE_EOFNL) continue;
268+
break;
269+
}
270+
271+
lines += 1;
272+
}
273+
}
274+
}
275+
276+
return INT2FIX(lines);
229277
}
230278
/*
231279
* call-seq:
@@ -256,21 +304,19 @@ static VALUE rb_git_diff_patch_bytesize(int argc, VALUE *argv, VALUE self)
256304
int include_context, include_hunk_headers, include_file_headers;
257305
Data_Get_Struct(self, git_patch, patch);
258306

259-
include_context = 1;
260-
include_hunk_headers = 1;
261-
include_file_headers = 1;
307+
include_context = include_hunk_headers = include_file_headers = 1;
262308

263309
rb_scan_args(argc, argv, "0:", &rb_options);
264310
if (!NIL_P(rb_options)) {
265-
if (rb_hash_aref(rb_options, CSTR2SYM("include_context")) == Qfalse) {
311+
if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_context")))) {
266312
include_context = 0;
267313
}
268314

269-
if (rb_hash_aref(rb_options, CSTR2SYM("include_hunk_headers")) == Qfalse) {
315+
if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_hunk_headers")))) {
270316
include_hunk_headers = 0;
271317
}
272318

273-
if (rb_hash_aref(rb_options, CSTR2SYM("include_file_headers")) == Qfalse) {
319+
if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_file_headers")))) {
274320
include_file_headers = 0;
275321
}
276322
}

test/diff_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def test_with_oid_string
7373
patches = diff.patches
7474
hunks = patches.map(&:hunks).flatten
7575
lines = hunks.map(&:lines).flatten
76-
bytesize = patches.inject(0) {|n, p| n += p.bytesize(include_context: false)}
76+
bytesize = patches.inject(0) {|n, p| n += p.bytesize(exclude_context: true)}
7777

7878
assert_equal 5, diff.size
7979
assert_equal 5, deltas.size
@@ -1149,7 +1149,7 @@ def test_stats
11491149
assert_equal expected_dels, actual_dels
11501150
assert_equal expected_adds + expected_dels, patch.changes
11511151

1152-
assert_equal expected_lines, patch.lines
1152+
assert_equal expected_lines, patch.lines(exclude_eofnl: true)
11531153
end
11541154
end
11551155
end

test/patch_test.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,27 @@ def test_to_s
5353
\\ No newline at end of file
5454
EOS
5555
end
56+
57+
def test_lines
58+
repo = FixtureRepo.from_libgit2("diff")
59+
repo.config['core.abbrev'] = 7
60+
61+
a = repo.lookup("d70d245ed97ed2aa596dd1af6536e4bfdb047b69")
62+
b = repo.lookup("7a9e0b02e63179929fed24f0a3e0f19168114d10")
63+
64+
diff = a.tree.diff(b.tree, :context_lines => 0)
65+
66+
patch = diff.patches[1]
67+
68+
assert_equal 12, patch.lines
69+
70+
assert_equal 12, patch.lines(exclude_context: true)
71+
assert_equal 10, patch.lines(exclude_additions: true)
72+
assert_equal 3, patch.lines(exclude_deletions: true)
73+
assert_equal 11, patch.lines(exclude_eofnl: true)
74+
75+
assert_equal 1, patch.lines(exclude_additions: true, exclude_deletions: true)
76+
77+
assert_equal 0, patch.lines(exclude_eofnl: true, exclude_additions: true, exclude_deletions: true, exclude_context: true)
78+
end
5679
end

0 commit comments

Comments
 (0)