81 lines
2.3 KiB
Ruby
81 lines
2.3 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)
|
||
|
# TODO: the remote has requested that we make another call to verify that
|
||
|
# the object has been sent correctly.
|
||
|
# https://gitlab.com/gitlab-org/gitlab/-/issues/250654
|
||
|
log_error("LFS upload verification requested, but not supported for #{object.oid}")
|
||
|
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
|