Skip to content

Commit e514359

Browse files
authored
Merge pull request #642 from tenderlove/ruby-diff
Move Rugged::Index#diff to Ruby
2 parents 88ebd5d + f11e1a4 commit e514359

File tree

2 files changed

+149
-128
lines changed

2 files changed

+149
-128
lines changed

ext/rugged/rugged_index.c

Lines changed: 34 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -691,146 +691,51 @@ static VALUE rb_git_index_readtree(VALUE self, VALUE rb_tree)
691691
return Qnil;
692692
}
693693

694-
/*
695-
* call-seq:
696-
* index.diff([options]) -> diff
697-
* index.diff(diffable[, options]) -> diff
698-
*
699-
* The first form returns a diff between the index and the current working
700-
* directory.
701-
*
702-
* The second form returns a diff between the index and the given diffable object.
703-
* +diffable+ can either be a +Rugged::Commit+ or a +Rugged::Tree+.
704-
*
705-
* The index will be used as the "old file" side of the diff, while the working
706-
* directory or the +diffable+ will be used for the "new file" side.
707-
*
708-
* The following options can be passed in the +options+ Hash:
709-
*
710-
* :paths ::
711-
* An array of paths / fnmatch patterns to constrain the diff to a specific
712-
* set of files. Also see +:disable_pathspec_match+.
713-
*
714-
* :max_size ::
715-
* An integer specifying the maximum byte size of a file before a it will
716-
* be treated as binary. The default value is 512MB.
717-
*
718-
* :context_lines ::
719-
* The number of unchanged lines that define the boundary of a hunk (and
720-
* to display before and after the actual changes). The default is 3.
721-
*
722-
* :interhunk_lines ::
723-
* The maximum number of unchanged lines between hunk boundaries before the hunks
724-
* will be merged into a one. The default is 0.
725-
*
726-
* :reverse ::
727-
* If true, the sides of the diff will be reversed.
728-
*
729-
* :force_text ::
730-
* If true, all files will be treated as text, disabling binary attributes & detection.
731-
*
732-
* :ignore_whitespace ::
733-
* If true, all whitespace will be ignored.
734-
*
735-
* :ignore_whitespace_change ::
736-
* If true, changes in amount of whitespace will be ignored.
737-
*
738-
* :ignore_whitespace_eol ::
739-
* If true, whitespace at end of line will be ignored.
740-
*
741-
* :ignore_submodules ::
742-
* if true, submodules will be excluded from the diff completely.
743-
*
744-
* :patience ::
745-
* If true, the "patience diff" algorithm will be used (currenlty unimplemented).
746-
*
747-
* :include_ignored ::
748-
* If true, ignored files will be included in the diff.
749-
*
750-
* :include_untracked ::
751-
* If true, untracked files will be included in the diff.
752-
*
753-
* :include_unmodified ::
754-
* If true, unmodified files will be included in the diff.
755-
*
756-
* :recurse_untracked_dirs ::
757-
* Even if +:include_untracked+ is true, untracked directories will only be
758-
* marked with a single entry in the diff. If this flag is set to true,
759-
* all files under ignored directories will be included in the diff, too.
760-
*
761-
* :disable_pathspec_match ::
762-
* If true, the given +:paths+ will be applied as exact matches, instead of
763-
* as fnmatch patterns.
764-
*
765-
* :deltas_are_icase ::
766-
* If true, filename comparisons will be made with case-insensitivity.
767-
*
768-
* :include_untracked_content ::
769-
* if true, untracked content will be contained in the the diff patch text.
770-
*
771-
* :skip_binary_check ::
772-
* If true, diff deltas will be generated without spending time on binary
773-
* detection. This is useful to improve performance in cases where the actual
774-
* file content difference is not needed.
775-
*
776-
* :include_typechange ::
777-
* If true, type changes for files will not be interpreted as deletion of
778-
* the "old file" and addition of the "new file", but will generate
779-
* typechange records.
780-
*
781-
* :include_typechange_trees ::
782-
* Even if +:include_typechange+ is true, blob -> tree changes will still
783-
* usually be handled as a deletion of the blob. If this flag is set to true,
784-
* blob -> tree changes will be marked as typechanges.
785-
*
786-
* :ignore_filemode ::
787-
* If true, file mode changes will be ignored.
788-
*
789-
* :recurse_ignored_dirs ::
790-
* Even if +:include_ignored+ is true, ignored directories will only be
791-
* marked with a single entry in the diff. If this flag is set to true,
792-
* all files under ignored directories will be included in the diff, too.
793-
*/
794-
static VALUE rb_git_index_diff(int argc, VALUE *argv, VALUE self)
694+
static VALUE rb_git_diff_tree_to_index(VALUE self, VALUE rb_other, VALUE rb_options)
795695
{
796696
git_index *index;
797697
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
798698
git_repository *repo;
799699
git_diff *diff = NULL;
800-
VALUE owner, rb_other, rb_options;
700+
VALUE owner;
801701
int error;
702+
git_tree *other_tree;
802703

803-
rb_scan_args(argc, argv, "01:", &rb_other, &rb_options);
804704
rugged_parse_diff_options(&opts, rb_options);
805705

806706
Data_Get_Struct(self, git_index, index);
807707
owner = rugged_owner(self);
808708
Data_Get_Struct(owner, git_repository, repo);
809709

810-
if (NIL_P(rb_other)) {
811-
error = git_diff_index_to_workdir(&diff, repo, index, &opts);
812-
} else {
813-
// Need to flip the reverse option, so that the index is by default
814-
// the "old file" side of the diff.
815-
opts.flags ^= GIT_DIFF_REVERSE;
816-
817-
if (rb_obj_is_kind_of(rb_other, rb_cRuggedCommit)) {
818-
git_tree *other_tree;
819-
git_commit *commit;
820-
Data_Get_Struct(rb_other, git_commit, commit);
821-
error = git_commit_tree(&other_tree, commit);
822-
823-
if (!error)
824-
error = git_diff_tree_to_index(&diff, repo, other_tree, index, &opts);
825-
} else if (rb_obj_is_kind_of(rb_other, rb_cRuggedTree)) {
826-
git_tree *other_tree;
827-
Data_Get_Struct(rb_other, git_tree, other_tree);
828-
error = git_diff_tree_to_index(&diff, repo, other_tree, index, &opts);
829-
} else {
830-
xfree(opts.pathspec.strings);
831-
rb_raise(rb_eTypeError, "A Rugged::Commit or Rugged::Tree instance is required");
832-
}
833-
}
710+
// Need to flip the reverse option, so that the index is by default
711+
// the "old file" side of the diff.
712+
opts.flags ^= GIT_DIFF_REVERSE;
713+
714+
Data_Get_Struct(rb_other, git_tree, other_tree);
715+
error = git_diff_tree_to_index(&diff, repo, other_tree, index, &opts);
716+
717+
xfree(opts.pathspec.strings);
718+
rugged_exception_check(error);
719+
720+
return rugged_diff_new(rb_cRuggedDiff, owner, diff);
721+
}
722+
723+
static VALUE rb_git_diff_index_to_workdir(VALUE self, VALUE rb_options)
724+
{
725+
git_index *index;
726+
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
727+
git_repository *repo;
728+
git_diff *diff = NULL;
729+
VALUE owner;
730+
int error;
731+
732+
rugged_parse_diff_options(&opts, rb_options);
733+
734+
Data_Get_Struct(self, git_index, index);
735+
owner = rugged_owner(self);
736+
Data_Get_Struct(owner, git_repository, repo);
737+
738+
error = git_diff_index_to_workdir(&diff, repo, index, &opts);
834739

835740
xfree(opts.pathspec.strings);
836741
rugged_exception_check(error);
@@ -1152,7 +1057,8 @@ void Init_rugged_index(void)
11521057
rb_define_method(rb_cRuggedIndex, "get", rb_git_index_get, -1);
11531058
rb_define_method(rb_cRuggedIndex, "[]", rb_git_index_get, -1);
11541059
rb_define_method(rb_cRuggedIndex, "each", rb_git_index_each, 0);
1155-
rb_define_method(rb_cRuggedIndex, "diff", rb_git_index_diff, -1);
1060+
rb_define_private_method(rb_cRuggedIndex, "diff_tree_to_index", rb_git_diff_tree_to_index, 2);
1061+
rb_define_private_method(rb_cRuggedIndex, "diff_index_to_workdir", rb_git_diff_index_to_workdir, 1);
11561062

11571063
rb_define_method(rb_cRuggedIndex, "conflicts?", rb_git_index_conflicts_p, 0);
11581064
rb_define_method(rb_cRuggedIndex, "conflicts", rb_git_index_conflicts, 0);

lib/rugged/index.rb

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,121 @@ module Rugged
22
class Index
33
include Enumerable
44

5+
6+
# call-seq:
7+
# index.diff([options]) -> diff
8+
# index.diff(diffable[, options]) -> diff
9+
#
10+
# The first form returns a diff between the index and the current working
11+
# directory.
12+
#
13+
# The second form returns a diff between the index and the given diffable object.
14+
# +diffable+ can either be a +Rugged::Commit+ or a +Rugged::Tree+.
15+
#
16+
# The index will be used as the "old file" side of the diff, while the working
17+
# directory or the +diffable+ will be used for the "new file" side.
18+
#
19+
# The following options can be passed in the +options+ Hash:
20+
#
21+
# :paths ::
22+
# An array of paths / fnmatch patterns to constrain the diff to a specific
23+
# set of files. Also see +:disable_pathspec_match+.
24+
#
25+
# :max_size ::
26+
# An integer specifying the maximum byte size of a file before a it will
27+
# be treated as binary. The default value is 512MB.
28+
#
29+
# :context_lines ::
30+
# The number of unchanged lines that define the boundary of a hunk (and
31+
# to display before and after the actual changes). The default is 3.
32+
#
33+
# :interhunk_lines ::
34+
# The maximum number of unchanged lines between hunk boundaries before the hunks
35+
# will be merged into a one. The default is 0.
36+
#
37+
# :reverse ::
38+
# If true, the sides of the diff will be reversed.
39+
#
40+
# :force_text ::
41+
# If true, all files will be treated as text, disabling binary attributes & detection.
42+
#
43+
# :ignore_whitespace ::
44+
# If true, all whitespace will be ignored.
45+
#
46+
# :ignore_whitespace_change ::
47+
# If true, changes in amount of whitespace will be ignored.
48+
#
49+
# :ignore_whitespace_eol ::
50+
# If true, whitespace at end of line will be ignored.
51+
#
52+
# :ignore_submodules ::
53+
# if true, submodules will be excluded from the diff completely.
54+
#
55+
# :patience ::
56+
# If true, the "patience diff" algorithm will be used (currenlty unimplemented).
57+
#
58+
# :include_ignored ::
59+
# If true, ignored files will be included in the diff.
60+
#
61+
# :include_untracked ::
62+
# If true, untracked files will be included in the diff.
63+
#
64+
# :include_unmodified ::
65+
# If true, unmodified files will be included in the diff.
66+
#
67+
# :recurse_untracked_dirs ::
68+
# Even if +:include_untracked+ is true, untracked directories will only be
69+
# marked with a single entry in the diff. If this flag is set to true,
70+
# all files under ignored directories will be included in the diff, too.
71+
#
72+
# :disable_pathspec_match ::
73+
# If true, the given +:paths+ will be applied as exact matches, instead of
74+
# as fnmatch patterns.
75+
#
76+
# :deltas_are_icase ::
77+
# If true, filename comparisons will be made with case-insensitivity.
78+
#
79+
# :include_untracked_content ::
80+
# if true, untracked content will be contained in the the diff patch text.
81+
#
82+
# :skip_binary_check ::
83+
# If true, diff deltas will be generated without spending time on binary
84+
# detection. This is useful to improve performance in cases where the actual
85+
# file content difference is not needed.
86+
#
87+
# :include_typechange ::
88+
# If true, type changes for files will not be interpreted as deletion of
89+
# the "old file" and addition of the "new file", but will generate
90+
# typechange records.
91+
#
92+
# :include_typechange_trees ::
93+
# Even if +:include_typechange+ is true, blob -> tree changes will still
94+
# usually be handled as a deletion of the blob. If this flag is set to true,
95+
# blob -> tree changes will be marked as typechanges.
96+
#
97+
# :ignore_filemode ::
98+
# If true, file mode changes will be ignored.
99+
#
100+
# :recurse_ignored_dirs ::
101+
# Even if +:include_ignored+ is true, ignored directories will only be
102+
# marked with a single entry in the diff. If this flag is set to true,
103+
# all files under ignored directories will be included in the diff, too.
104+
def diff(*args)
105+
options = args.last.is_a?(Hash) ? args.pop : {}
106+
other = args.shift
107+
108+
case other
109+
when nil
110+
diff_index_to_workdir options
111+
when ::Rugged::Commit
112+
diff_tree_to_index other.tree, options
113+
when ::Rugged::Tree
114+
diff_tree_to_index other, options
115+
else
116+
raise TypeError, "A Rugged::Commit or Rugged::Tree instance is required"
117+
end
118+
end
119+
5120
def to_s
6121
s = "#<Rugged::Index\n"
7122
self.each do |entry|

0 commit comments

Comments
 (0)