Welcome to mirror list, hosted at ThFree Co, Russian Federation.

commit_service.rb « gitaly_server « lib « ruby - gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 30fd9f182b0ed8e85c9c300d657c6b40bb30b473 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
module GitalyServer
  class CommitService < Gitaly::CommitService::Service
    include Utils
    include Gitlab::EncodingHelper

    # TODO remove in gitlab 12.0, this is implemented in Go now:
    # https://gitlab.com/gitlab-org/gitaly/issues/1471
    def commit_stats(request, call)
      repo = Gitlab::Git::Repository.from_gitaly(request.repository, call)
      revision = request.revision unless request.revision.empty?

      commit = Gitlab::Git::Commit.find(repo, revision)

      # In the odd case that the revision given doesn't exist we need to raise
      # an exception. Since GitLab (currently) already does this for us we don't
      # expect this to actually happen, just guarding against future code change
      raise GRPC::Internal.new("commit not found for revision '#{revision}'") unless commit

      stats = Gitlab::Git::CommitStats.new(repo, commit)

      Gitaly::CommitStatsResponse.new(oid: stats.id, additions: stats.additions, deletions: stats.deletions)
    end

    def find_commits(request, call)
      repository = Gitlab::Git::Repository.from_gitaly(request.repository, call)
      options = {
        ref: request.revision,
        limit: request.limit,
        follow: request.follow,
        skip_merges: request.skip_merges,
        disable_walk: request.disable_walk,
        offset: request.offset,
        all: request.all
      }
      options[:path] = request.paths unless request.paths.empty?

      options[:before] = Time.at(request.before.seconds).to_datetime if request.before
      options[:after] = Time.at(request.after.seconds).to_datetime if request.after

      Enumerator.new do |y|
        # Send back 'pages' with 20 commits each
        repository.raw_log(options).each_slice(20) do |rugged_commits|
          commits = rugged_commits.map do |rugged_commit|
            gitaly_commit_from_rugged(rugged_commit)
          end
          y.yield Gitaly::FindCommitsResponse.new(commits: commits)
        end
      end
    end

    def filter_shas_with_signatures(_session, call)
      Enumerator.new do |y|
        repository = nil

        call.each_remote_read.with_index do |request, index|
          repository = Gitlab::Git::Repository.from_gitaly(request.repository, call) if index.zero?

          y << Gitaly::FilterShasWithSignaturesResponse.new(shas: Gitlab::Git::Commit.shas_with_signatures(repository, request.shas))
        end
      end
    end

    def extract_commit_signature(request, call)
      repository = Gitlab::Git::Repository.from_gitaly(request.repository, call)

      Enumerator.new do |y|
        each_commit_signature_chunk(repository, request.commit_id) do |signature_chunk, signed_text_chunk|
          y.yield Gitaly::ExtractCommitSignatureResponse.new(signature: signature_chunk) if signature_chunk.present?

          y.yield Gitaly::ExtractCommitSignatureResponse.new(signed_text: signed_text_chunk) if signed_text_chunk.present?
        end
      end
    end

    def get_commit_signatures(request, call)
      repository = Gitlab::Git::Repository.from_gitaly(request.repository, call)

      Enumerator.new do |y|
        request.commit_ids.each do |commit_id|
          msg = Gitaly::GetCommitSignaturesResponse.new(commit_id: commit_id)

          each_commit_signature_chunk(repository, commit_id) do |signature_chunk, signed_text_chunk|
            if signature_chunk.present?
              msg.signature = signature_chunk
              y.yield msg
            end

            if signed_text_chunk.present?
              msg.signed_text = signed_text_chunk
              y.yield msg
            end

            msg = Gitaly::GetCommitSignaturesResponse.new
          end
        end
      end
    end

    private

    # yields either signature chunks or signed_text chunks to the passed block
    def each_commit_signature_chunk(repository, commit_id)
      raise ArgumentError.new("expected a block") unless block_given?

      begin
        signature_text, signed_text = Rugged::Commit.extract_signature(repository.rugged, commit_id)
      rescue Rugged::InvalidError
        raise GRPC::InvalidArgument.new("commit lookup failed for #{commit_id.inspect}")
      rescue Rugged::OdbError
        # The client does not care if the commit does not exist
        return
      end

      signature_text_io = binary_stringio(signature_text)
      loop do
        chunk = signature_text_io.read(Gitlab.config.git.write_buffer_size)
        break if chunk.nil?

        yield chunk, nil
      end

      signed_text_io = binary_stringio(signed_text)
      loop do
        chunk = signed_text_io.read(Gitlab.config.git.write_buffer_size)
        break if chunk.nil?

        yield nil, chunk
      end
    end
  end
end