Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/lfs/client.rb')
-rw-r--r--lib/gitlab/lfs/client.rb101
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