2019-02-15 15:39:39 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
module Gitlab
|
|
|
|
module GitalyClient
|
|
|
|
class BlobService
|
2018-03-17 18:26:18 +05:30
|
|
|
include Gitlab::EncodingHelper
|
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
def initialize(repository)
|
|
|
|
@gitaly_repo = repository.gitaly_repository
|
|
|
|
end
|
|
|
|
|
|
|
|
def get_blob(oid:, limit:)
|
|
|
|
request = Gitaly::GetBlobRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
|
|
|
oid: oid,
|
|
|
|
limit: limit
|
|
|
|
)
|
2018-11-08 19:23:39 +05:30
|
|
|
response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :get_blob, request, timeout: GitalyClient.fast_timeout)
|
2020-07-28 23:09:34 +05:30
|
|
|
consume_blob_response(response)
|
2017-09-10 17:25:29 +05:30
|
|
|
end
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2021-09-30 23:02:18 +05:30
|
|
|
def list_blobs(revisions, limit: 0, bytes_limit: 0, dynamic_timeout: nil)
|
|
|
|
request = Gitaly::ListBlobsRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
|
|
|
revisions: Array.wrap(revisions),
|
|
|
|
limit: limit,
|
|
|
|
bytes_limit: bytes_limit
|
|
|
|
)
|
|
|
|
|
|
|
|
timeout =
|
|
|
|
if dynamic_timeout
|
|
|
|
[dynamic_timeout, GitalyClient.medium_timeout].min
|
|
|
|
else
|
|
|
|
GitalyClient.medium_timeout
|
|
|
|
end
|
|
|
|
|
|
|
|
response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :list_blobs, request, timeout: timeout)
|
|
|
|
GitalyClient::BlobsStitcher.new(GitalyClient::ListBlobsAdapter.new(response))
|
|
|
|
end
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
def batch_lfs_pointers(blob_ids)
|
|
|
|
return [] if blob_ids.empty?
|
|
|
|
|
|
|
|
request = Gitaly::GetLFSPointersRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
|
|
|
blob_ids: blob_ids
|
|
|
|
)
|
|
|
|
|
2018-11-08 19:23:39 +05:30
|
|
|
response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :get_lfs_pointers, request, timeout: GitalyClient.medium_timeout)
|
2018-03-27 19:54:05 +05:30
|
|
|
map_lfs_pointers(response)
|
2018-03-17 18:26:18 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def get_blobs(revision_paths, limit = -1)
|
|
|
|
return [] if revision_paths.empty?
|
|
|
|
|
2019-07-31 22:56:46 +05:30
|
|
|
request_revision_paths = revision_paths.map do |rev, path|
|
2018-03-17 18:26:18 +05:30
|
|
|
Gitaly::GetBlobsRequest::RevisionPath.new(revision: rev, path: encode_binary(path))
|
|
|
|
end
|
|
|
|
|
|
|
|
request = Gitaly::GetBlobsRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
2019-07-31 22:56:46 +05:30
|
|
|
revision_paths: request_revision_paths,
|
2018-03-17 18:26:18 +05:30
|
|
|
limit: limit
|
|
|
|
)
|
|
|
|
|
|
|
|
response = GitalyClient.call(
|
|
|
|
@gitaly_repo.storage_name,
|
|
|
|
:blob_service,
|
|
|
|
:get_blobs,
|
|
|
|
request,
|
2020-07-28 23:09:34 +05:30
|
|
|
timeout: GitalyClient.fast_timeout)
|
2018-03-17 18:26:18 +05:30
|
|
|
|
|
|
|
GitalyClient::BlobsStitcher.new(response)
|
|
|
|
end
|
2018-03-27 19:54:05 +05:30
|
|
|
|
2019-12-21 20:55:43 +05:30
|
|
|
def get_blob_types(revision_paths, limit = -1)
|
|
|
|
return {} if revision_paths.empty?
|
|
|
|
|
|
|
|
request_revision_paths = revision_paths.map do |rev, path|
|
|
|
|
Gitaly::GetBlobsRequest::RevisionPath.new(revision: rev, path: encode_binary(path))
|
|
|
|
end
|
|
|
|
|
|
|
|
request = Gitaly::GetBlobsRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
|
|
|
revision_paths: request_revision_paths,
|
|
|
|
limit: limit
|
|
|
|
)
|
|
|
|
|
|
|
|
response = GitalyClient.call(
|
|
|
|
@gitaly_repo.storage_name,
|
|
|
|
:blob_service,
|
|
|
|
:get_blobs,
|
|
|
|
request,
|
|
|
|
timeout: GitalyClient.fast_timeout
|
|
|
|
)
|
|
|
|
map_blob_types(response)
|
|
|
|
end
|
|
|
|
|
2021-09-04 01:27:46 +05:30
|
|
|
def get_new_lfs_pointers(revisions, limit, not_in, dynamic_timeout = nil)
|
|
|
|
request, rpc = create_new_lfs_pointers_request(revisions, limit, not_in)
|
2018-03-27 19:54:05 +05:30
|
|
|
|
2018-12-13 13:39:08 +05:30
|
|
|
timeout =
|
|
|
|
if dynamic_timeout
|
|
|
|
[dynamic_timeout, GitalyClient.medium_timeout].min
|
|
|
|
else
|
|
|
|
GitalyClient.medium_timeout
|
|
|
|
end
|
|
|
|
|
|
|
|
response = GitalyClient.call(
|
|
|
|
@gitaly_repo.storage_name,
|
|
|
|
:blob_service,
|
2021-04-29 21:17:54 +05:30
|
|
|
rpc,
|
2018-12-13 13:39:08 +05:30
|
|
|
request,
|
|
|
|
timeout: timeout
|
|
|
|
)
|
2018-03-27 19:54:05 +05:30
|
|
|
map_lfs_pointers(response)
|
|
|
|
end
|
|
|
|
|
2020-04-22 19:07:51 +05:30
|
|
|
def get_all_lfs_pointers
|
2021-04-29 21:17:54 +05:30
|
|
|
request = Gitaly::ListLFSPointersRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
|
|
|
revisions: [encode_binary("--all")]
|
2018-03-27 19:54:05 +05:30
|
|
|
)
|
|
|
|
|
2021-04-29 21:17:54 +05:30
|
|
|
response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :list_lfs_pointers, request, timeout: GitalyClient.medium_timeout)
|
2018-03-27 19:54:05 +05:30
|
|
|
map_lfs_pointers(response)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2021-09-04 01:27:46 +05:30
|
|
|
def create_new_lfs_pointers_request(revisions, limit, not_in)
|
2021-04-29 21:17:54 +05:30
|
|
|
# If the check happens for a change which is using a quarantine
|
|
|
|
# environment for incoming objects, then we can avoid doing the
|
|
|
|
# necessary graph walk to detect only new LFS pointers and instead scan
|
|
|
|
# through all quarantined objects.
|
|
|
|
git_env = ::Gitlab::Git::HookEnv.all(@gitaly_repo.gl_repository)
|
2021-06-08 01:23:25 +05:30
|
|
|
if git_env['GIT_OBJECT_DIRECTORY_RELATIVE'].present?
|
2021-04-29 21:17:54 +05:30
|
|
|
repository = @gitaly_repo.dup
|
|
|
|
repository.git_alternate_object_directories = Google::Protobuf::RepeatedField.new(:string)
|
|
|
|
|
|
|
|
request = Gitaly::ListAllLFSPointersRequest.new(
|
|
|
|
repository: repository,
|
|
|
|
limit: limit || 0
|
|
|
|
)
|
|
|
|
|
|
|
|
[request, :list_all_lfs_pointers]
|
|
|
|
else
|
2021-09-04 01:27:46 +05:30
|
|
|
revisions = Array.wrap(revisions)
|
2021-04-29 21:17:54 +05:30
|
|
|
revisions += if not_in.nil? || not_in == :all
|
|
|
|
["--not", "--all"]
|
|
|
|
else
|
|
|
|
not_in.prepend "--not"
|
|
|
|
end
|
|
|
|
|
|
|
|
request = Gitaly::ListLFSPointersRequest.new(
|
|
|
|
repository: @gitaly_repo,
|
|
|
|
limit: limit || 0,
|
|
|
|
revisions: revisions.map { |rev| encode_binary(rev) }
|
|
|
|
)
|
|
|
|
|
|
|
|
[request, :list_lfs_pointers]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-07-28 23:09:34 +05:30
|
|
|
def consume_blob_response(response)
|
|
|
|
data = []
|
|
|
|
blob = nil
|
|
|
|
response.each do |msg|
|
|
|
|
if blob.nil?
|
|
|
|
blob = msg
|
|
|
|
end
|
|
|
|
|
|
|
|
data << msg.data
|
|
|
|
end
|
|
|
|
|
|
|
|
return if blob.oid.blank?
|
|
|
|
|
|
|
|
data = data.join
|
|
|
|
|
|
|
|
Gitlab::Git::Blob.new(
|
|
|
|
id: blob.oid,
|
|
|
|
size: blob.size,
|
|
|
|
data: data,
|
|
|
|
binary: Gitlab::Git::Blob.binary?(data)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2018-03-27 19:54:05 +05:30
|
|
|
def map_lfs_pointers(response)
|
|
|
|
response.flat_map do |message|
|
|
|
|
message.lfs_pointers.map do |lfs_pointer|
|
|
|
|
Gitlab::Git::Blob.new(
|
|
|
|
id: lfs_pointer.oid,
|
|
|
|
size: lfs_pointer.size,
|
|
|
|
data: lfs_pointer.data,
|
|
|
|
binary: Gitlab::Git::Blob.binary?(lfs_pointer.data)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-12-21 20:55:43 +05:30
|
|
|
|
|
|
|
def map_blob_types(response)
|
|
|
|
types = {}
|
|
|
|
|
|
|
|
response.each do |msg|
|
|
|
|
types[msg.path.dup.force_encoding('utf-8')] = msg.type.downcase
|
|
|
|
end
|
|
|
|
|
|
|
|
types
|
|
|
|
end
|
2017-09-10 17:25:29 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|