bfs-gs 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 637ee81c056b08e88dea4194468a7cf88c749a93d5c74a76d53a2ebd33bbd538
4
+ data.tar.gz: 45de2c2033328feb46e7695a0a79a979bf7f6fdfa2332691098db1b9832329e9
5
+ SHA512:
6
+ metadata.gz: 5a38e3c19acceba3f87c7db63414b67db0c249a977a2045d0a214467b756a8ebb4f5e9d12247868f81b8e3afb9564bb1db848f434ad9ab7478a722adc0e64529
7
+ data.tar.gz: e35c73ffcae6f8975aa1fb56df86b85e3a47550be62536981f38c70b3bfcf74648c95a548fb45f5a790325ba481265c4d64656c6b3b6ef601dd768081b5c7fa6
data/bfs-gs.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'bfs-gs'
3
+ s.version = File.read(File.expand_path('../.version', __dir__)).strip
4
+ s.platform = Gem::Platform::RUBY
5
+
6
+ s.licenses = ['Apache-2.0']
7
+ s.summary = 'GS bucket adapter for bfs'
8
+ s.description = 'https://github.com/bsm/bfs.rb'
9
+
10
+ s.authors = ['Dimitrij Denissenko']
11
+ s.email = 'dimitrij@blacksquaremedia.com'
12
+ s.homepage = 'https://github.com/bsm/bfs.rb'
13
+
14
+ s.executables = []
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- spec/*`.split("\n")
17
+ s.require_paths = ['lib']
18
+ s.required_ruby_version = '>= 2.2.0'
19
+
20
+ s.add_dependency 'bfs', s.version
21
+ s.add_dependency 'google-cloud-storage'
22
+ end
@@ -0,0 +1,113 @@
1
+ require 'bfs'
2
+ require 'google/cloud/storage'
3
+ require 'cgi'
4
+
5
+ module BFS
6
+ module Bucket
7
+ # GS buckets are operating on Google Cloud Storage
8
+ class GS < Abstract
9
+ attr_reader :name
10
+
11
+ # Initializes a new GoogleCloudStorage bucket.
12
+ #
13
+ # @param [String] name the bucket name.
14
+ # @param [Hash] opts options.
15
+ # @option opts [String] :project_id project ID. Defaults to GCP_PROJECT env var. Required.
16
+ # @option opts [String, Hash, Google::Auth::Credentials] :credentials
17
+ # the path to the keyfile as a String, the contents of the keyfile as a Hash, or a Google::Auth::Credentials object.
18
+ # @option opts [Integer] :retries number of times to retry requests. Default: 3.
19
+ # @option opts [Integer] :timeout request timeout, in seconds.
20
+ # @option opts [String] :acl set the default ACL.
21
+ # @option opts [Google::Cloud::Storage] :client custom client.
22
+ def initialize(name, opts={})
23
+ opts = opts.dup
24
+ opts.keys.each do |key|
25
+ val = opts.delete(key)
26
+ opts[key.to_sym] = val unless val.nil?
27
+ end
28
+ opts[:project_id] ||= ENV['GCP_PROJECT'] || ENV['GCLOUD_PROJECT']
29
+
30
+ acl = opts.delete(:acl)
31
+ client = opts.delete(:client) || Google::Cloud::Storage.new(opts)
32
+
33
+ @name = name.to_s
34
+ @bucket = client.bucket(@name)
35
+ @bucket.default_acl.send(:"#{acl}!") if @bucket.default_acl.respond_to?(:"#{acl}!")
36
+ end
37
+
38
+ # Lists the contents of a bucket using a glob pattern
39
+ def ls(pattern='**/*', opts={})
40
+ Enumerator.new do |y|
41
+ @bucket.files(opts).each do |file|
42
+ y << file.name if File.fnmatch?(pattern, file.name, File::FNM_PATHNAME)
43
+ end
44
+ end
45
+ end
46
+
47
+ # Info returns the object info
48
+ def info(path, _opts={})
49
+ path = norm_path(path)
50
+ file = @bucket.file(path)
51
+ raise BFS::FileNotFound, path unless file
52
+
53
+ BFS::FileInfo.new(path, file.size, file.updated_at)
54
+ end
55
+
56
+ # Creates a new file and opens it for writing
57
+ def create(path, opts={}, &block)
58
+ path = norm_path(path)
59
+ temp = BFS::TempWriter.new(path) do |t|
60
+ File.open(t, binmode: true) do |file|
61
+ @bucket.create_file(file, path, opts)
62
+ end
63
+ end
64
+ return temp unless block
65
+
66
+ begin
67
+ yield temp
68
+ ensure
69
+ temp.close
70
+ end
71
+ end
72
+
73
+ # Opens an existing file for reading
74
+ def open(path, opts={}, &block)
75
+ path = norm_path(path)
76
+ file = @bucket.file(path)
77
+ raise BFS::FileNotFound, path unless file
78
+
79
+ temp = Tempfile.new(File.basename(path), binmode: true)
80
+ temp.close
81
+ file.download temp.path, opts
82
+
83
+ File.open(temp.path, binmode: true, &block)
84
+ end
85
+
86
+ # Deletes a file.
87
+ def rm(path, opts={})
88
+ path = norm_path(path)
89
+ file = @bucket.file(path)
90
+ file.delete(opts) if file
91
+ end
92
+
93
+ # Copies a file.
94
+ def cp(src, dst, opts={})
95
+ src = norm_path(src)
96
+ file = @bucket.file(src)
97
+ raise BFS::FileNotFound, src unless file
98
+
99
+ file.copy(norm_path(dst), opts)
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ BFS.register('gs') do |url|
106
+ params = CGI.parse(url.query.to_s)
107
+
108
+ BFS::Bucket::GS.new url.host,
109
+ project_id: params.key?('project_id') ? params['project_id'].first : nil,
110
+ acl: params.key?('acl') ? params['acl'].first : nil,
111
+ timeout: params.key?('timeout') ? params['timeout'].first.to_i : nil,
112
+ retries: params.key?('retries') ? params['retries'].first.to_i : nil
113
+ end
data/lib/bfs/gs.rb ADDED
@@ -0,0 +1 @@
1
+ require 'bfs/bucket/gs'
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe BFS::Bucket::GS do
4
+ let(:contents) { {} }
5
+ let(:mock_client) { double Google::Cloud::Storage, bucket: mock_bucket }
6
+
7
+ let :mock_bucket do
8
+ bucket = double Google::Cloud::Storage::Bucket,
9
+ default_acl: double(Google::Cloud::Storage::Bucket::Acl)
10
+ allow(bucket).to receive(:create_file) do |io, name, _|
11
+ contents[name] = double_file(name, io.read)
12
+ end
13
+ allow(bucket).to receive(:files) do |_|
14
+ contents.values
15
+ end
16
+ allow(bucket).to receive(:file) do |name|
17
+ contents[name]
18
+ end
19
+ bucket
20
+ end
21
+
22
+ def double_file(name, data)
23
+ file = double Google::Cloud::Storage::File,
24
+ name: name,
25
+ data: data,
26
+ size: data.bytesize,
27
+ updated_at: Time.now
28
+ allow(file).to receive(:download) do |path, _|
29
+ File.open(path, 'wb') {|f| f.write file.data }
30
+ end
31
+ allow(file).to receive(:delete) do |_|
32
+ contents.delete(file.name)
33
+ true
34
+ end
35
+ allow(file).to receive(:copy) do |dst, _|
36
+ contents[dst] = double_file(dst, file.data)
37
+ end
38
+ file
39
+ end
40
+
41
+ subject { described_class.new 'mock-bucket', client: mock_client }
42
+ it_behaves_like 'a bucket'
43
+
44
+ it 'should resolve from URL' do
45
+ expect(Google::Cloud::Storage).to receive(:new).with(project_id: 'my-project').and_return(mock_client)
46
+ expect(mock_client).to receive(:bucket).with('mock-bucket').and_return(mock_bucket)
47
+ expect(mock_bucket.default_acl).to receive(:private!).with(no_args)
48
+
49
+ bucket = BFS.resolve('gs://mock-bucket?acl=private&project_id=my-project')
50
+ expect(bucket).to be_instance_of(described_class)
51
+ expect(bucket.name).to eq('mock-bucket')
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bfs-gs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ platform: ruby
6
+ authors:
7
+ - Dimitrij Denissenko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-11-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bfs
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: google-cloud-storage
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: https://github.com/bsm/bfs.rb
42
+ email: dimitrij@blacksquaremedia.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - bfs-gs.gemspec
48
+ - lib/bfs/bucket/gs.rb
49
+ - lib/bfs/gs.rb
50
+ - spec/bfs/bucket/gs_spec.rb
51
+ homepage: https://github.com/bsm/bfs.rb
52
+ licenses:
53
+ - Apache-2.0
54
+ metadata: {}
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 2.2.0
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubyforge_project:
71
+ rubygems_version: 2.7.7
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: GS bucket adapter for bfs
75
+ test_files:
76
+ - spec/bfs/bucket/gs_spec.rb