gitlab-org--gitlab-foss/lib/gitlab/git/conflict/file.rb

110 lines
3.5 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module Git
module Conflict
class File
UnsupportedEncoding = Class.new(StandardError)
attr_reader :ancestor_path, :their_path, :our_path, :our_mode, :repository, :commit_oid
attr_accessor :raw_content
def initialize(repository, commit_oid, conflict, raw_content)
@repository = repository
@commit_oid = commit_oid
@ancestor_path = conflict[:ancestor][:path]
@their_path = conflict[:theirs][:path]
@our_path = conflict[:ours][:path]
@our_mode = conflict[:ours][:mode]
@raw_content = raw_content
end
def lines
return @lines if defined?(@lines)
begin
@type = 'text'
@lines = Gitlab::Git::Conflict::Parser.parse(content,
our_path: our_path,
their_path: their_path)
rescue Gitlab::Git::Conflict::Parser::ParserError
@type = 'text-editor'
@lines = nil
end
end
def content
@content ||= @raw_content.dup.force_encoding('UTF-8')
raise UnsupportedEncoding unless @content.valid_encoding?
@content
end
def type
lines unless @type
@type.inquiry
end
def our_blob
# REFACTOR NOTE: the source of `commit_oid` used to be
# `merge_request.diff_refs.head_sha`. Instead of passing this value
# around the new lib structure, I decided to use `@commit_oid` which is
# equivalent to `merge_request.source_branch_head.raw.rugged_commit.oid`.
# That is what `merge_request.diff_refs.head_sha` is equivalent to when
# `merge_request` is not persisted (see `MergeRequest#diff_head_commit`).
# I think using the same oid is more consistent anyways, but if Conflicts
# start breaking, the change described above is a good place to look at.
@our_blob ||= repository.blob_at(@commit_oid, our_path)
end
def line_code(line)
Gitlab::Git.diff_line_code(our_path, line[:line_new], line[:line_old])
end
def resolve_lines(resolution)
section_id = nil
lines.map do |line|
unless line[:type]
section_id = nil
next line
end
section_id ||= line_code(line)
case resolution[section_id]
when 'head'
next unless line[:type] == 'new'
when 'origin'
next unless line[:type] == 'old'
else
raise Gitlab::Git::Conflict::Resolver::ResolutionError, "Missing resolution for section ID: #{section_id}"
end
line
end.compact
end
def resolve_content(resolution)
if resolution == content
raise Gitlab::Git::Conflict::Resolver::ResolutionError, "Resolved content has no changes for file #{our_path}"
end
resolution
end
def path
# There are conflict scenarios (e.g. file is removed on source) wherein
# our_path will be blank/nil. Since we are indexing them by path in
# `#conflicts` helper and we want to match the diff file to a conflict
# in `DiffFileEntity#highlighted_diff_lines`, we need to fallback to
# their_path (this is the path on target).
our_path.presence || their_path
end
end
end
end
end