1# frozen_string_literal: true
2
3module Gitlab
4  module Git
5    module Conflict
6      class Resolver
7        include Gitlab::Git::WrapsGitalyErrors
8
9        ConflictSideMissing = Class.new(StandardError)
10        ResolutionError = Class.new(StandardError)
11
12        def initialize(target_repository, our_commit_oid, their_commit_oid, allow_tree_conflicts: false)
13          @target_repository = target_repository
14          @our_commit_oid = our_commit_oid
15          @their_commit_oid = their_commit_oid
16          @allow_tree_conflicts = allow_tree_conflicts
17        end
18
19        def conflicts
20          @conflicts ||= wrapped_gitaly_errors do
21            gitaly_conflicts_client(@target_repository).list_conflict_files(allow_tree_conflicts: @allow_tree_conflicts).to_a
22          rescue GRPC::FailedPrecondition => e
23            raise Gitlab::Git::Conflict::Resolver::ConflictSideMissing, e.message
24          end
25        rescue GRPC::BadStatus => e
26          raise Gitlab::Git::CommandError, e
27        end
28
29        def resolve_conflicts(source_repository, resolution, source_branch:, target_branch:)
30          wrapped_gitaly_errors do
31            gitaly_conflicts_client(source_repository).resolve_conflicts(@target_repository, resolution, source_branch, target_branch)
32          end
33        end
34
35        def conflict_for_path(conflicts, old_path, new_path)
36          conflicts.find do |conflict|
37            conflict.their_path == old_path && conflict.our_path == new_path
38          end
39        end
40
41        private
42
43        def conflict_files(repository, index)
44          index.conflicts.map do |conflict|
45            raise ConflictSideMissing unless conflict[:theirs] && conflict[:ours]
46
47            Gitlab::Git::Conflict::File.new(
48              repository,
49              @our_commit_oid,
50              conflict,
51              index.merge_file(conflict[:ours][:path])[:data]
52            )
53          end
54        end
55
56        def gitaly_conflicts_client(repository)
57          repository.gitaly_conflicts_client(@our_commit_oid, @their_commit_oid)
58        end
59      end
60    end
61  end
62end
63