parser.rb 1.86 KB
Newer Older
1 2 3
module Gitlab
  module Conflict
    class Parser
4
      class ParserError < StandardError
5 6
      end

7 8 9 10
      class UnexpectedDelimiter < ParserError
      end

      class MissingEndDelimiter < ParserError
11 12
      end

13 14 15
      class UnmergeableFile < ParserError
      end

16 17 18
      class UnsupportedEncoding < ParserError
      end

Sean McGivern's avatar
Sean McGivern committed
19
      def parse(text, our_path:, their_path:, parent_file: nil)
20 21
        raise UnmergeableFile if text.blank? # Typically a binary file
        raise UnmergeableFile if text.length > 102400
22

23 24 25 26 27 28
        begin
          text.to_json
        rescue Encoding::UndefinedConversionError
          raise UnsupportedEncoding
        end

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
        line_obj_index = 0
        line_old = 1
        line_new = 1
        type = nil
        lines = []
        conflict_start = "<<<<<<< #{our_path}"
        conflict_middle = '======='
        conflict_end = ">>>>>>> #{their_path}"

        text.each_line.map do |line|
          full_line = line.delete("\n")

          if full_line == conflict_start
            raise UnexpectedDelimiter unless type.nil?

            type = 'new'
          elsif full_line == conflict_middle
            raise UnexpectedDelimiter unless type == 'new'

            type = 'old'
          elsif full_line == conflict_end
            raise UnexpectedDelimiter unless type == 'old'

            type = nil
          elsif line[0] == '\\'
            type = 'nonewline'
Sean McGivern's avatar
Sean McGivern committed
55
            lines << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new, parent_file: parent_file)
56
          else
Sean McGivern's avatar
Sean McGivern committed
57
            lines << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new, parent_file: parent_file)
58 59 60 61 62 63 64
            line_old += 1 if type != 'new'
            line_new += 1 if type != 'old'

            line_obj_index += 1
          end
        end

65
        raise MissingEndDelimiter unless type.nil?
66 67 68 69 70 71

        lines
      end
    end
  end
end