# 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