debian-mirror-gitlab/lib/gitlab/lfs/client.rb
2020-11-24 15:15:51 +05:30

102 lines
2.7 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module Lfs
# Gitlab::Lfs::Client implements a simple LFS client, designed to talk to
# LFS servers as described in these documents:
# * https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md
# * https://github.com/git-lfs/git-lfs/blob/master/docs/api/basic-transfers.md
class Client
attr_reader :base_url
def initialize(base_url, credentials:)
@base_url = base_url
@credentials = credentials
end
def batch(operation, objects)
body = {
operation: operation,
transfers: ['basic'],
# We don't know `ref`, so can't send it
objects: objects.map { |object| { oid: object.oid, size: object.size } }
}
rsp = Gitlab::HTTP.post(
batch_url,
basic_auth: basic_auth,
body: body.to_json,
headers: { 'Content-Type' => 'application/vnd.git-lfs+json' }
)
raise BatchSubmitError unless rsp.success?
# HTTParty provides rsp.parsed_response, but it only kicks in for the
# application/json content type in the response, which we can't rely on
body = Gitlab::Json.parse(rsp.body)
transfer = body.fetch('transfer', 'basic')
raise UnsupportedTransferError.new(transfer.inspect) unless transfer == 'basic'
body
end
def upload(object, upload_action, authenticated:)
file = object.file.open
params = {
body_stream: file,
headers: {
'Content-Length' => object.size.to_s,
'Content-Type' => 'application/octet-stream'
}.merge(upload_action['header'] || {})
}
params[:basic_auth] = basic_auth unless authenticated
rsp = Gitlab::HTTP.put(upload_action['href'], params)
raise ObjectUploadError unless rsp.success?
ensure
file&.close
end
private
attr_reader :credentials
def batch_url
base_url + '/info/lfs/objects/batch'
end
def basic_auth
return unless credentials[:auth_method] == "password"
{ username: credentials[:user], password: credentials[:password] }
end
class BatchSubmitError < StandardError
def message
"Failed to submit batch"
end
end
class UnsupportedTransferError < StandardError
def initialize(transfer = nil)
super
@transfer = transfer
end
def message
"Unsupported transfer: #{@transfer}"
end
end
class ObjectUploadError < StandardError
def message
"Failed to upload object"
end
end
end
end
end