file.rb 4.3 KB
Newer Older
D
Dmitriy Zaporozhets 已提交
1 2 3
module Gitlab
  module Diff
    class File
4
      attr_reader :diff, :repository, :diff_refs, :fallback_diff_refs
D
Dmitriy Zaporozhets 已提交
5

6 7
      delegate :new_file?, :deleted_file?, :renamed_file?,
        :old_path, :new_path, :a_mode, :b_mode, :mode_changed?,
8
        :submodule?, :too_large?, :collapsed?, to: :diff, prefix: false
D
Dmitriy Zaporozhets 已提交
9

10
      def initialize(diff, repository:, diff_refs: nil, fallback_diff_refs: nil)
D
Dmitriy Zaporozhets 已提交
11
        @diff = diff
12
        @repository = repository
13
        @diff_refs = diff_refs
14
        @fallback_diff_refs = fallback_diff_refs
15 16
      end

D
Douwe Maan 已提交
17 18 19 20 21 22 23 24
      def position(line)
        return unless diff_refs

        Position.new(
          old_path: old_path,
          new_path: new_path,
          old_line: line.old_line,
          new_line: line.new_line,
25
          diff_refs: diff_refs
D
Douwe Maan 已提交
26 27 28
        )
      end

29 30 31 32 33 34 35 36 37 38
      def line_code(line)
        return if line.meta?

        Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
      end

      def line_for_line_code(code)
        diff_lines.find { |line| line_code(line) == code }
      end

D
Douwe Maan 已提交
39 40 41 42 43 44 45 46 47 48 49 50 51 52
      def line_for_position(pos)
        diff_lines.find { |line| position(line) == pos }
      end

      def position_for_line_code(code)
        line = line_for_line_code(code)
        position(line) if line
      end

      def line_code_for_position(pos)
        line = line_for_position(pos)
        line_code(line) if line
      end

53 54 55 56 57 58 59 60
      def old_sha
        diff_refs&.base_sha
      end

      def new_sha
        diff_refs&.head_sha
      end

61 62 63
      def new_content_sha
        return if deleted_file?
        return @new_content_sha if defined?(@new_content_sha)
64 65

        refs = diff_refs || fallback_diff_refs
66
        @new_content_sha = refs&.head_sha
67 68
      end

69 70
      def new_content_commit
        return @new_content_commit if defined?(@new_content_commit)
71

72 73
        sha = new_content_commit
        @new_content_commit = repository.commit(sha) if sha
74 75 76 77 78
      end

      def old_content_sha
        return if new_file?
        return @old_content_sha if defined?(@old_content_sha)
79

80 81
        refs = diff_refs || fallback_diff_refs
        @old_content_sha = refs&.base_sha
D
Douwe Maan 已提交
82 83
      end

84
      def old_content_commit
85
        return @old_content_commit if defined?(@old_content_commit)
86

87 88
        sha = old_content_sha
        @old_content_commit = repository.commit(sha) if sha
89 90
      end

91 92
      def new_blob
        return @new_blob if defined?(@new_blob)
93

94 95
        sha = new_content_sha
        return @new_blob = nil unless sha
96

97
        @new_blob = repository.blob_at(sha, file_path)
98 99
      end

100 101 102 103 104 105 106
      def old_blob
        return @old_blob if defined?(@old_blob)

        sha = old_content_sha
        return @old_blob = nil unless sha

        @old_blob = repository.blob_at(sha, old_path)
D
Dmitriy Zaporozhets 已提交
107 108
      end

109 110 111 112 113 114 115 116 117 118 119 120
      def content_sha
        new_content_sha || old_content_sha
      end

      def content_commit
        new_content_commit || old_content_commit
      end

      def blob
        new_blob || old_blob
      end

121
      attr_writer :highlighted_diff_lines
122

123
      # Array of Gitlab::Diff::Line objects
D
Dmitriy Zaporozhets 已提交
124
      def diff_lines
125
        @diff_lines ||= Gitlab::Diff::Parser.new.parse(raw_diff.each_line).to_a
126 127
      end

128
      def highlighted_diff_lines
129
        @highlighted_diff_lines ||= Gitlab::Diff::Highlight.new(self, repository: self.repository).highlight
130 131
      end

132
      # Array[<Hash>] with right/left keys that contains Gitlab::Diff::Line objects which text is hightlighted
133
      def parallel_diff_lines
134
        @parallel_diff_lines ||= Gitlab::Diff::ParallelDiff.new(self).parallelize
135 136
      end

137
      def raw_diff
138
        diff.diff.to_s
139 140
      end

D
Dmitriy Zaporozhets 已提交
141 142 143 144 145
      def next_line(index)
        diff_lines[index + 1]
      end

      def prev_line(index)
146
        diff_lines[index - 1] if index > 0
D
Dmitriy Zaporozhets 已提交
147
      end
148

D
Douwe Maan 已提交
149 150 151 152
      def paths
        [old_path, new_path].compact
      end

153
      def file_path
154
        new_path.presence || old_path
155
      end
156 157

      def added_lines
G
Gabriel Mazetto 已提交
158
        diff_lines.count(&:added?)
159 160 161
      end

      def removed_lines
G
Gabriel Mazetto 已提交
162
        diff_lines.count(&:removed?)
163
      end
D
Douwe Maan 已提交
164

165
      def file_identifier
166
        "#{file_path}-#{new_file?}-#{deleted_file?}-#{renamed_file?}"
167
      end
168 169 170 171 172 173 174 175 176 177 178 179

      def diffable?
        repository.attributes(file_path).fetch('diff') { true }
      end

      def binary?
        old_blob&.binary? || new_blob&.binary?
      end

      def text?
        !binary?
      end
D
Dmitriy Zaporozhets 已提交
180 181 182
    end
  end
end