gitlab-org--gitlab-foss/lib/gitlab/conflict/parser.rb
Sean McGivern 3f71c43e88 Allow setting content for resolutions
When reading conflicts:

1. Add a `type` field. `text` works as before, and has `sections`;
   `text-editor` is a file with ambiguous conflict markers that can only
   be resolved in an editor.
2. Add a `content_path` field pointing to a JSON representation of the
   file's content for a single file.
3. Hitting `content_path` returns a similar datastructure to the `file`,
   but without the `content_path` and `sections` fields, and with a
   `content` field containing the full contents of the file (with
   conflict markers).

When writing conflicts:

1. Instead of `sections` being at the top level, they are now in a
   `files` array. This matches the read format better.
2. The `files` array contains file hashes, each of which must contain:
   a. `new_path`
   b. `old_path`
   c. EITHER `sections` (which works as before) or `content` (with the
      full content of the resolved file).
2016-10-13 14:16:34 -05:00

76 lines
2 KiB
Ruby

module Gitlab
module Conflict
class Parser
class UnresolvableError < StandardError
end
class UnmergeableFile < UnresolvableError
end
class UnsupportedEncoding < UnresolvableError
end
# Recoverable errors - the conflict can be resolved in an editor, but not with
# sections.
class ParserError < StandardError
end
class UnexpectedDelimiter < ParserError
end
class MissingEndDelimiter < ParserError
end
def parse(text, our_path:, their_path:, parent_file: nil)
raise UnmergeableFile if text.blank? # Typically a binary file
raise UnmergeableFile if text.length > 200.kilobytes
begin
text.to_json
rescue Encoding::UndefinedConversionError
raise UnsupportedEncoding
end
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'
lines << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new, parent_file: parent_file)
else
lines << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new, parent_file: parent_file)
line_old += 1 if type != 'new'
line_new += 1 if type != 'old'
line_obj_index += 1
end
end
raise MissingEndDelimiter unless type.nil?
lines
end
end
end
end