gitlab-org--gitlab-foss/app/services/lfs/push_service.rb

80 lines
2.2 KiB
Ruby

# frozen_string_literal: true
module Lfs
# Lfs::PushService pushes the LFS objects associated with a project to a
# remote URL
class PushService < BaseService
include Gitlab::Utils::StrongMemoize
# Match the canonical LFS client's batch size:
# https://github.com/git-lfs/git-lfs/blob/master/tq/transfer_queue.go#L19
BATCH_SIZE = 100
def execute
lfs_objects_relation.each_batch(of: BATCH_SIZE) do |objects|
push_objects!(objects)
end
success
rescue => err
error(err.message)
end
private
# Currently we only set repository_type for design repository objects, so
# push mirroring must send objects with a `nil` repository type - but if the
# wiki repository uses LFS, its objects will also be sent. This will be
# addressed by https://gitlab.com/gitlab-org/gitlab/-/issues/250346
def lfs_objects_relation
project.lfs_objects_for_repository_types(nil, :project)
end
def push_objects!(objects)
rsp = lfs_client.batch!('upload', objects)
objects = objects.index_by(&:oid)
rsp.fetch('objects', []).each do |spec|
actions = spec['actions']
object = objects[spec['oid']]
upload_object!(object, spec) if actions&.key?('upload')
verify_object!(object, spec) if actions&.key?('verify')
end
end
def upload_object!(object, spec)
authenticated = spec['authenticated']
upload = spec.dig('actions', 'upload')
# The server wants us to upload the object but something is wrong
unless object && object.size == spec['size'].to_i
log_error("Couldn't match object #{spec['oid']}/#{spec['size']}")
return
end
lfs_client.upload!(object, upload, authenticated: authenticated)
end
def verify_object!(object, spec)
authenticated = spec['authenticated']
verify = spec.dig('actions', 'verify')
lfs_client.verify!(object, verify, authenticated: authenticated)
end
def url
params.fetch(:url)
end
def credentials
params.fetch(:credentials)
end
def lfs_client
strong_memoize(:lfs_client) do
Gitlab::Lfs::Client.new(url, credentials: credentials)
end
end
end
end