summaryrefslogtreecommitdiff
path: root/lib/gitlab/diff/file.rb
blob: b0c50edba59642975157000039c07753361018ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
module Gitlab
  module Diff
    class File
      attr_reader :diff, :repository, :diff_refs

      delegate :new_file, :deleted_file, :renamed_file,
        :old_path, :new_path, :a_mode, :b_mode,
        :submodule?, :too_large?, to: :diff, prefix: false

      def initialize(diff, repository:, diff_refs: nil)
        @diff = diff
        @repository = repository
        @diff_refs = diff_refs
      end

      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,
          diff_refs: diff_refs
        )
      end

      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

      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

      def content_commit
        return unless diff_refs

        repository.commit(deleted_file ? old_ref : new_ref)
      end

      def old_ref
        diff_refs.try(:base_sha)
      end

      def new_ref
        diff_refs.try(:head_sha)
      end

      # Array of Gitlab::Diff::Line objects
      def diff_lines
        @lines ||= Gitlab::Diff::Parser.new.parse(raw_diff.each_line).to_a
      end

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

      def parallel_diff_lines
        @parallel_diff_lines ||= Gitlab::Diff::ParallelDiff.new(self).parallelize
      end

      def mode_changed?
        a_mode && b_mode && a_mode != b_mode
      end

      def raw_diff
        diff.diff.to_s
      end

      def next_line(index)
        diff_lines[index + 1]
      end

      def prev_line(index)
        diff_lines[index - 1] if index > 0
      end

      def paths
        [old_path, new_path].compact
      end

      def file_path
        new_path.presence || old_path
      end

      def added_lines
        diff_lines.count(&:added?)
      end

      def removed_lines
        diff_lines.count(&:removed?)
      end

      def old_blob(commit = content_commit)
        return unless commit

        parent_id = commit.parent_id
        return unless parent_id

        repository.blob_at(parent_id, old_path)
      end

      def blob(commit = content_commit)
        return unless commit

        repository.blob_at(commit.id, file_path)
      end
    end
  end
end