ext/rugged/rugged_patch.c in rugged-0.25.0b6 vs ext/rugged/rugged_patch.c in rugged-0.25.0b7

- old
+ new

@@ -171,10 +171,17 @@ git_patch_line_stats(NULL, &additions, &deletions, patch); return rb_ary_new3(2, INT2FIX(additions), INT2FIX(deletions)); } +enum { + EXCLUDE_CONTEXT = (1u << 0), + EXCLUDE_ADDITIONS = (1u << 1), + EXCLUDE_DELETIONS = (1u << 2), + EXCLUDE_EOFNL = (1u << 3) +}; + /* * call-seq: * patch.lines(options = {}) -> int * * The following options can be passed in the +options+ Hash: @@ -189,46 +196,88 @@ * * :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 context_lines, additions, deletions; - size_t total_out; + size_t lines = 0; VALUE rb_options; Data_Get_Struct(self, git_patch, patch); - context_lines = 0; - additions = 0; - deletions = 0; + int options = 0; - git_patch_line_stats(&context_lines, &additions, &deletions, patch); - - total_out = context_lines + additions + deletions; - rb_scan_args(argc, argv, "0:", &rb_options); if (!NIL_P(rb_options)) { if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_context")))) { - total_out -= context_lines; + options |= EXCLUDE_CONTEXT; } if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_additions")))) { - total_out -= additions; + options |= EXCLUDE_ADDITIONS; } if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_deletions")))) { - total_out -= deletions; + options |= EXCLUDE_DELETIONS; } + + if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_eofnl")))) { + options |= EXCLUDE_EOFNL; + } } - return INT2FIX(total_out); + 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); } + /* * call-seq: * patch.bytesize(options = {}) -> int * * The following options can be passed in the +options+ Hash: @@ -254,25 +303,23 @@ size_t bytesize; VALUE rb_options; int include_context, include_hunk_headers, include_file_headers; Data_Get_Struct(self, git_patch, patch); - include_context = 1; - include_hunk_headers = 1; - include_file_headers = 1; + include_context = include_hunk_headers = include_file_headers = 1; rb_scan_args(argc, argv, "0:", &rb_options); if (!NIL_P(rb_options)) { - if (rb_hash_aref(rb_options, CSTR2SYM("include_context")) == Qfalse) { + if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_context")))) { include_context = 0; } - if (rb_hash_aref(rb_options, CSTR2SYM("include_hunk_headers")) == Qfalse) { + if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_hunk_headers")))) { include_hunk_headers = 0; } - if (rb_hash_aref(rb_options, CSTR2SYM("include_file_headers")) == Qfalse) { + if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_file_headers")))) { include_file_headers = 0; } } bytesize = git_patch_size(patch, include_context, include_hunk_headers, include_file_headers); @@ -284,41 +331,78 @@ const git_diff_delta *delta, const git_diff_hunk *hunk, const git_diff_line *line, void *payload) { - VALUE rb_str = (VALUE)payload; + VALUE rb_buffer = (VALUE)payload; switch (line->origin) { case GIT_DIFF_LINE_CONTEXT: case GIT_DIFF_LINE_ADDITION: case GIT_DIFF_LINE_DELETION: - rb_str_cat(rb_str, &line->origin, 1); + rb_ary_push(rb_buffer, rb_str_new(&line->origin, 1)); } - rb_str_cat(rb_str, line->content, line->content_len); + rb_ary_push(rb_buffer, rb_str_new(line->content, line->content_len)); return GIT_OK; } +static int patch_print_header_cb( + const git_diff_delta *delta, + const git_diff_hunk *hunk, + const git_diff_line *line, + void *payload) +{ + VALUE rb_buffer = (VALUE)payload; + + if (line->origin == GIT_DIFF_LINE_FILE_HDR) { + rb_ary_push(rb_buffer, rb_str_new(line->content, line->content_len)); + return GIT_OK; + } else { + return GIT_ITEROVER; + } +} + /* * call-seq: * patch.to_s -> str * * Returns the contents of the patch as a single diff string. */ static VALUE rb_git_diff_patch_to_s(VALUE self) { git_patch *patch; - VALUE rb_str = rb_str_new(NULL, 0); + VALUE rb_buffer = rb_ary_new(); Data_Get_Struct(self, git_patch, patch); - rugged_exception_check(git_patch_print(patch, patch_print_cb, (void*)rb_str)); + rugged_exception_check(git_patch_print(patch, patch_print_cb, (void*)rb_buffer)); - return rb_str; + return rb_ary_join(rb_buffer, Qnil); } +/* + * call-seq: + * patch.header -> str + * + * Returns only the header of the patch as a string. + */ +static VALUE rb_git_diff_patch_header(VALUE self) +{ + git_patch *patch; + int error = 0; + VALUE rb_buffer = rb_ary_new(); + Data_Get_Struct(self, git_patch, patch); + + error = git_patch_print(patch, patch_print_header_cb, (void*)rb_buffer); + if (error && error != GIT_ITEROVER) + rugged_exception_check(error); + + return rb_ary_join(rb_buffer, Qnil); +} + + void Init_rugged_patch(void) { rb_cRuggedPatch = rb_define_class_under(rb_mRugged, "Patch", rb_cObject); rb_define_singleton_method(rb_cRuggedPatch, "from_strings", rb_git_patch_from_strings, -1); @@ -327,9 +411,10 @@ rb_define_method(rb_cRuggedPatch, "lines", rb_git_diff_patch_lines, -1); rb_define_method(rb_cRuggedPatch, "bytesize", rb_git_diff_patch_bytesize, -1); rb_define_method(rb_cRuggedPatch, "delta", rb_git_diff_patch_delta, 0); + rb_define_method(rb_cRuggedPatch, "header", rb_git_diff_patch_header, 0); rb_define_method(rb_cRuggedPatch, "to_s", rb_git_diff_patch_to_s, 0); rb_define_method(rb_cRuggedPatch, "each_hunk", rb_git_diff_patch_each_hunk, 0); rb_define_method(rb_cRuggedPatch, "hunk_count", rb_git_diff_patch_hunk_count, 0); }