3f71c43e88
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).
76 lines
2 KiB
Ruby
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
|