diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-19 04:45:44 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-19 04:45:44 +0300 |
commit | 85dc423f7090da0a52c73eb66faf22ddb20efff9 (patch) | |
tree | 9160f299afd8c80c038f08e1545be119f5e3f1e1 /lib/gitlab/lfs/client.rb | |
parent | 15c2c8c66dbe422588e5411eee7e68f1fa440bb8 (diff) |
Add latest changes from gitlab-org/gitlab@13-4-stable-ee
Diffstat (limited to 'lib/gitlab/lfs/client.rb')
-rw-r--r-- | lib/gitlab/lfs/client.rb | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/lib/gitlab/lfs/client.rb b/lib/gitlab/lfs/client.rb new file mode 100644 index 00000000000..e4d600694c2 --- /dev/null +++ b/lib/gitlab/lfs/client.rb @@ -0,0 +1,101 @@ +# 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 |