Class: Rosette::Core::DiffFinder

Inherits:
Object
  • Object
show all
Defined in:
lib/rosette/core/git/diff_finder.rb

Overview

Used to compute diffs between two git refs. Can also read file contents from diff entries.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(jgit_repo, rev_walker) ⇒ DiffFinder

Creates a new diff finder instance.

Parameters:

  • jgit_repo (Java::OrgEclipseJgitStorageFile::FileRepository)

    The git repository.

  • rev_walker (Java::OrgEclipseJgitRevwalk::RevWalk)

    The RevWalk instance to use.


30
31
32
33
# File 'lib/rosette/core/git/diff_finder.rb', line 30

def initialize(jgit_repo, rev_walker)
  @jgit_repo = jgit_repo
  @rev_walker = rev_walker
end

Instance Attribute Details

#jgit_repoJava::OrgEclipseJgitStorageFile::FileRepository (readonly)

Returns the git repository.

Returns:

  • (Java::OrgEclipseJgitStorageFile::FileRepository)

    the git repository.


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/rosette/core/git/diff_finder.rb', line 21

class DiffFinder
  attr_reader :jgit_repo, :rev_walker

  # Creates a new diff finder instance.
  #
  # @param [Java::OrgEclipseJgitStorageFile::FileRepository] jgit_repo
  #   The git repository.
  # @param [Java::OrgEclipseJgitRevwalk::RevWalk] rev_walker The RevWalk
  #   instance to use.
  def initialize(jgit_repo, rev_walker)
    @jgit_repo = jgit_repo
    @rev_walker = rev_walker
  end

  # Computes a diff between two revs.
  #
  # @param [Java::OrgEclipseJgitRevwalk::RevCommit] rev_parents The first
  #   commit or commits to use in the diff (the parent, i.e. the commit that
  #   occurred earlier in time).
  # @param [Java::OrgEclipseJgitRevwalk::RevCommit] rev_child The second
  #   commit to use in the diff (the child of the parent, i.e. the commit
  #   that occurred later in time).
  # @param [Array<String>] paths The paths to include in the diff. If given
  #   an empty array, this method will return a diff for all paths.
  # @return [Hash<String, Java::OrgEclipseJgitDiff::DiffEntry>] A hash of
  #   commit ids to diff entries for the diff between +rev_parents+ and
  #   +rev_child+. There will be one diff entry for each file that changed.
  def diff(rev_parents, rev_child, paths = [])
    rev_parents = Array(rev_parents)
    diff_formatter.setPathFilter(construct_filter(Array(paths)))

    rev_parents.each_with_object({}) do |rev_parent, ret|
      ret[rev_parent.getId.name] = diff_formatter.scan(
        rev_walker.parseCommit(rev_parent.getId).getTree,
        rev_child.getTree
      )
    end
  end

  # Computes a diff between a rev and its parent.
  #
  # @param [Java::OrgEclipseJgitRevwalk::RevCommit] rev The rev to use.
  # @return [Hash<String, Java::OrgEclipseJgitDiff::DiffEntry>] A hash of
  #   commit ids to diff entries for the diff between +rev+ and its parents.
  #   There will be one diff entry for each file that changed.
  def diff_with_parents(rev)
    if rev.getParentCount > 0
      rev.getParentCount.times.each_with_object({}) do |i, ret|
        parent = rev.getParent(i)

        ret[parent.getId.name] = diff_formatter.scan(
          rev_walker.parseCommit(parent.getId).getTree,
          rev.getTree
        )
      end
    else
      {
        rev.getId.name => diff_formatter.scan(
          EmptyTreeIterator.new,
          CanonicalTreeParser.new(
            nil, rev_walker.getObjectReader, rev.getTree
          )
        )
      }
    end
  end

  # Reads the "new" contents of a diff entry. Diff entries contain a
  # reference to both the new and old files. The "new" contents means
  # the contents of the changed file, not the original.
  #
  # @param [Java::OrgEclipseJgitDiff::DiffEntry] entry The diff entry
  #   to read from.
  # @param [Encoding] encoding The encoding to expect the contents
  #   to be in.
  # @return [String] The file contents, encoded in +encoding+.
  def read_new_entry(entry, encoding = Encoding::UTF_8)
    Java::JavaLang::String.new(
      object_reader.open(entry.newId.toObjectId).getBytes, encoding.to_s
    )
  end

  private

  def object_reader
    @object_reader ||= jgit_repo.newObjectReader
  end

  def construct_filter(paths)
    paths = fix_paths(paths)
    PathFilterGroup.createFromStrings(paths) if paths.size > 0
  end

  def fix_paths(paths)
    # paths can't begin with a dot or dot slash (jgit limitation)
    paths.map do |path|
      path.gsub(/\A(\.(?:\/|\z))/, '')
    end.select do |path|
      !path.strip.empty?
    end
  end

  def diff_formatter
    @diff_formatter ||= DiffFormatter.new(NullOutputStream::INSTANCE).tap do |formatter|
      formatter.setRepository(jgit_repo)
    end
  end
end

#rev_walkerJava::OrgEclipseJgitRevwalk::RevWalk (readonly)

Returns the RevWalk instance to use.

Returns:

  • (Java::OrgEclipseJgitRevwalk::RevWalk)

    the RevWalk instance to use.


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/rosette/core/git/diff_finder.rb', line 21

class DiffFinder
  attr_reader :jgit_repo, :rev_walker

  # Creates a new diff finder instance.
  #
  # @param [Java::OrgEclipseJgitStorageFile::FileRepository] jgit_repo
  #   The git repository.
  # @param [Java::OrgEclipseJgitRevwalk::RevWalk] rev_walker The RevWalk
  #   instance to use.
  def initialize(jgit_repo, rev_walker)
    @jgit_repo = jgit_repo
    @rev_walker = rev_walker
  end

  # Computes a diff between two revs.
  #
  # @param [Java::OrgEclipseJgitRevwalk::RevCommit] rev_parents The first
  #   commit or commits to use in the diff (the parent, i.e. the commit that
  #   occurred earlier in time).
  # @param [Java::OrgEclipseJgitRevwalk::RevCommit] rev_child The second
  #   commit to use in the diff (the child of the parent, i.e. the commit
  #   that occurred later in time).
  # @param [Array<String>] paths The paths to include in the diff. If given
  #   an empty array, this method will return a diff for all paths.
  # @return [Hash<String, Java::OrgEclipseJgitDiff::DiffEntry>] A hash of
  #   commit ids to diff entries for the diff between +rev_parents+ and
  #   +rev_child+. There will be one diff entry for each file that changed.
  def diff(rev_parents, rev_child, paths = [])
    rev_parents = Array(rev_parents)
    diff_formatter.setPathFilter(construct_filter(Array(paths)))

    rev_parents.each_with_object({}) do |rev_parent, ret|
      ret[rev_parent.getId.name] = diff_formatter.scan(
        rev_walker.parseCommit(rev_parent.getId).getTree,
        rev_child.getTree
      )
    end
  end

  # Computes a diff between a rev and its parent.
  #
  # @param [Java::OrgEclipseJgitRevwalk::RevCommit] rev The rev to use.
  # @return [Hash<String, Java::OrgEclipseJgitDiff::DiffEntry>] A hash of
  #   commit ids to diff entries for the diff between +rev+ and its parents.
  #   There will be one diff entry for each file that changed.
  def diff_with_parents(rev)
    if rev.getParentCount > 0
      rev.getParentCount.times.each_with_object({}) do |i, ret|
        parent = rev.getParent(i)

        ret[parent.getId.name] = diff_formatter.scan(
          rev_walker.parseCommit(parent.getId).getTree,
          rev.getTree
        )
      end
    else
      {
        rev.getId.name => diff_formatter.scan(
          EmptyTreeIterator.new,
          CanonicalTreeParser.new(
            nil, rev_walker.getObjectReader, rev.getTree
          )
        )
      }
    end
  end

  # Reads the "new" contents of a diff entry. Diff entries contain a
  # reference to both the new and old files. The "new" contents means
  # the contents of the changed file, not the original.
  #
  # @param [Java::OrgEclipseJgitDiff::DiffEntry] entry The diff entry
  #   to read from.
  # @param [Encoding] encoding The encoding to expect the contents
  #   to be in.
  # @return [String] The file contents, encoded in +encoding+.
  def read_new_entry(entry, encoding = Encoding::UTF_8)
    Java::JavaLang::String.new(
      object_reader.open(entry.newId.toObjectId).getBytes, encoding.to_s
    )
  end

  private

  def object_reader
    @object_reader ||= jgit_repo.newObjectReader
  end

  def construct_filter(paths)
    paths = fix_paths(paths)
    PathFilterGroup.createFromStrings(paths) if paths.size > 0
  end

  def fix_paths(paths)
    # paths can't begin with a dot or dot slash (jgit limitation)
    paths.map do |path|
      path.gsub(/\A(\.(?:\/|\z))/, '')
    end.select do |path|
      !path.strip.empty?
    end
  end

  def diff_formatter
    @diff_formatter ||= DiffFormatter.new(NullOutputStream::INSTANCE).tap do |formatter|
      formatter.setRepository(jgit_repo)
    end
  end
end

Instance Method Details

#diff(rev_parents, rev_child, paths = []) ⇒ Hash<String, Java::OrgEclipseJgitDiff::DiffEntry>

Computes a diff between two revs.

Parameters:

  • rev_parents (Java::OrgEclipseJgitRevwalk::RevCommit)

    The first commit or commits to use in the diff (the parent, i.e. the commit that occurred earlier in time).

  • rev_child (Java::OrgEclipseJgitRevwalk::RevCommit)

    The second commit to use in the diff (the child of the parent, i.e. the commit that occurred later in time).

  • paths (Array<String>) (defaults to: [])

    The paths to include in the diff. If given an empty array, this method will return a diff for all paths.

Returns:

  • (Hash<String, Java::OrgEclipseJgitDiff::DiffEntry>)

    A hash of commit ids to diff entries for the diff between rev_parents and rev_child. There will be one diff entry for each file that changed.


48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rosette/core/git/diff_finder.rb', line 48

def diff(rev_parents, rev_child, paths = [])
  rev_parents = Array(rev_parents)
  diff_formatter.setPathFilter(construct_filter(Array(paths)))

  rev_parents.each_with_object({}) do |rev_parent, ret|
    ret[rev_parent.getId.name] = diff_formatter.scan(
      rev_walker.parseCommit(rev_parent.getId).getTree,
      rev_child.getTree
    )
  end
end

#diff_with_parents(rev) ⇒ Hash<String, Java::OrgEclipseJgitDiff::DiffEntry>

Computes a diff between a rev and its parent.

Parameters:

  • rev (Java::OrgEclipseJgitRevwalk::RevCommit)

    The rev to use.

Returns:

  • (Hash<String, Java::OrgEclipseJgitDiff::DiffEntry>)

    A hash of commit ids to diff entries for the diff between rev and its parents. There will be one diff entry for each file that changed.


66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rosette/core/git/diff_finder.rb', line 66

def diff_with_parents(rev)
  if rev.getParentCount > 0
    rev.getParentCount.times.each_with_object({}) do |i, ret|
      parent = rev.getParent(i)

      ret[parent.getId.name] = diff_formatter.scan(
        rev_walker.parseCommit(parent.getId).getTree,
        rev.getTree
      )
    end
  else
    {
      rev.getId.name => diff_formatter.scan(
        EmptyTreeIterator.new,
        CanonicalTreeParser.new(
          nil, rev_walker.getObjectReader, rev.getTree
        )
      )
    }
  end
end

#read_new_entry(entry, encoding = Encoding::UTF_8) ⇒ String

Reads the “new” contents of a diff entry. Diff entries contain a reference to both the new and old files. The “new” contents means the contents of the changed file, not the original.

Parameters:

  • entry (Java::OrgEclipseJgitDiff::DiffEntry)

    The diff entry to read from.

  • encoding (Encoding) (defaults to: Encoding::UTF_8)

    The encoding to expect the contents to be in.

Returns:

  • (String)

    The file contents, encoded in encoding.


97
98
99
100
101
# File 'lib/rosette/core/git/diff_finder.rb', line 97

def read_new_entry(entry, encoding = Encoding::UTF_8)
  Java::JavaLang::String.new(
    object_reader.open(entry.newId.toObjectId).getBytes, encoding.to_s
  )
end