Skip to content

Commit bb1c7c3

Browse files
authored
Merge pull request #4 from wallarm/dev
Allow to use StringIO as a download dest
2 parents 0109d85 + 9d10197 commit bb1c7c3

File tree

14 files changed

+236
-38
lines changed

14 files changed

+236
-38
lines changed

.rubocop.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,6 @@ RSpec/ExampleLength:
3636

3737
RSpec/NestedGroups:
3838
Max: 4
39+
40+
Lint/SuppressedException:
41+
Enabled: false

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ cli = CloudStorage::Client.new(
8585
> f = cli.upload_file(key: 'test.txt', file: File.open('test.txt', 'rb'))
8686
> f.name
8787
=> 'test.txt'
88+
89+
> stream = StringIO.new('test')
90+
> f = cli.upload_file(key: 'test.txt', file: stream)
91+
> f.name
92+
=> 'test.txt'
8893
```
8994

9095
### signed url:
@@ -107,6 +112,11 @@ cli = CloudStorage::Client.new(
107112
```ruby
108113
> cli.find('test.txt').download.read
109114
=> "This is a test download\n"
115+
116+
s = StringIO.new
117+
> cli.find('test.txt').download(s)
118+
> s.read
119+
=> "This is a test download\n"
110120
```
111121

112122
```ruby

dip.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ provision:
3737
- ./docker/prepare_env.sh
3838
- mkdir -p uploads/s3/$S3_BUCKET
3939
- rm -rf uploads/gcs/$GCS_BUCKET
40+
- rm -rf Gemfile.lock
4041
- mkdir -p uploads/gcs/$GCS_BUCKET
4142
- docker volume create --name bundler_data
4243
- dip bundle install

lib/cloud_storage/objects/base.rb

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ def size
1414
end
1515

1616
def download(local_file = Tempfile.new)
17-
internal_download(local_file.path)
18-
19-
local_file.rewind
20-
local_file
17+
internal_download(local_file).tap(&:rewind)
2118
end
2219

2320
def signed_url(**opts)
@@ -30,7 +27,7 @@ def delete!
3027

3128
private
3229

33-
def internal_download(path)
30+
def internal_download(local_file)
3431
raise 'not implemented'
3532
end
3633
end

lib/cloud_storage/objects/gcs.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ def delete!
3232

3333
private
3434

35-
def internal_download(path)
36-
@internal.download(path)
35+
def internal_download(local_file)
36+
@internal.download(local_file)
3737
end
3838
end
3939
end

lib/cloud_storage/objects/s3.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ def delete!
3737

3838
private
3939

40-
def internal_download(path)
41-
@resource.bucket(bucket_name).object(key).download_file(path)
40+
def internal_download(local_file)
41+
@resource.bucket(bucket_name).object(key).download_file(local_file)
42+
43+
local_file
4244
end
4345
end
4446
end

lib/cloud_storage/wrappers/gcs.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def exist?(key)
5252

5353
def upload_file(key:, file:, **opts)
5454
Objects::Gcs.new \
55-
bucket.create_file(file.path, key, **opts),
55+
bucket.create_file(file, key, **opts),
5656
uri: uri
5757
end
5858

@@ -96,6 +96,7 @@ def bucket
9696
def build_bucket
9797
bucket = storage.bucket(@bucket_name)
9898
raise ObjectNotFound, @bucket_name unless bucket
99+
99100
bucket
100101
end
101102
end

lib/cloud_storage/wrappers/s3.rb

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ def each
3434
resource: @resource,
3535
client: @client
3636
end
37-
38-
rescue Aws::S3::Errors::NoSuchBucket, Aws::S3::Errors::NotFound
37+
rescue Aws::S3::Errors::NoSuchBucket, Aws::S3::Errors::NotFound
3938
end
4039
end
4140

@@ -50,7 +49,7 @@ def exist?(key)
5049
def upload_file(key:, file:, **opts)
5150
obj = resource.bucket(@bucket_name).object(key)
5251

53-
return unless obj.upload_file(file.path, **opts)
52+
return unless upload_file_or_io(obj, file, **opts)
5453

5554
Objects::S3.new \
5655
obj,
@@ -74,12 +73,13 @@ def find(key)
7473
end
7574

7675
def delete_files(keys)
77-
resource.bucket(@bucket_name).delete_objects({
78-
delete: {
79-
objects: keys.map { |key| {key: key} },
80-
quiet: true
81-
}
82-
})
76+
resource
77+
.bucket(@bucket_name)
78+
.delete_objects \
79+
delete: {
80+
objects: keys.map { |key| { key: key } },
81+
quiet: true
82+
}
8383
rescue Aws::S3::Errors::NoSuchBucket, Aws::S3::Errors::NotFound
8484
end
8585

@@ -92,6 +92,14 @@ def client
9292
def resource
9393
@resource ||= Aws::S3::Resource.new(@options)
9494
end
95+
96+
def upload_file_or_io(obj, file_or_io, **opts)
97+
if file_or_io.respond_to?(:path)
98+
obj.upload_file(file_or_io.path, **opts)
99+
else
100+
obj.upload_stream(**opts) { |write_stream| IO.copy_stream(file_or_io, write_stream) }
101+
end
102+
end
95103
end
96104
end
97105
end

spec/cloud_storage/objects/gcs_spec.rb

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
let(:file) { File.open('spec/fixtures/test.txt', 'rb') }
66
let!(:obj) { cli.upload_file(key: 'test_1.txt', file: file) }
77

8+
after { file.close }
9+
810
describe '#signed_url' do
911
after { obj.delete! }
1012

@@ -45,16 +47,50 @@
4547
after { obj.delete! }
4648

4749
context 'when default' do
50+
subject(:content) { tmp.read }
51+
52+
let(:tmp) { obj.download }
53+
54+
after do
55+
tmp.close
56+
tmp.unlink
57+
end
58+
4859
it do
49-
expect(obj.download.read).to eq("This is a test upload\n")
60+
expect { content }.to change { opened_tmp_files_count }.by(1)
61+
62+
expect(content).to eq("This is a test upload\n")
5063
end
5164
end
5265

5366
context 'when download to a custom tmp' do
67+
subject(:content) { obj.download(tmp) }
68+
5469
let(:tmp) { Tempfile.new }
5570

71+
after do
72+
tmp.close
73+
tmp.unlink
74+
end
75+
76+
it do
77+
tmp
78+
79+
expect { content }
80+
.to change(tmp, :read)
81+
.from('')
82+
.to("This is a test upload\n")
83+
.and change { opened_tmp_files_count }.by(0)
84+
end
85+
end
86+
87+
context 'when download to a string io' do
88+
subject(:content) { obj.download(StringIO.new).read }
89+
5690
it do
57-
expect { obj.download(tmp) }.to change(tmp, :read).from('').to("This is a test upload\n")
91+
expect { content }.not_to(change { opened_tmp_files_count })
92+
93+
expect(content).to eq("This is a test upload\n")
5894
end
5995
end
6096
end

spec/cloud_storage/objects/s3_spec.rb

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
let(:file) { File.open('spec/fixtures/test.txt', 'rb') }
66
let!(:obj) { cli.upload_file(key: 'test_1.txt', file: file) }
77

8+
after { file.close }
9+
810
describe '#signed_url' do
911
subject(:url) { obj.signed_url(expires_in: 30) }
1012

@@ -36,16 +38,50 @@
3638
after { obj.delete! }
3739

3840
context 'when default' do
41+
subject(:content) { tmp.read }
42+
43+
let(:tmp) { obj.download }
44+
45+
after do
46+
tmp.close
47+
tmp.unlink
48+
end
49+
50+
it do
51+
expect { content }.to change { opened_tmp_files_count }.by(1)
52+
53+
expect(content).to eq("This is a test upload\n")
54+
end
55+
end
56+
57+
context 'when download to a string io' do
58+
subject(:content) { obj.download(StringIO.new).read }
59+
3960
it do
40-
expect(obj.download.read).to eq("This is a test upload\n")
61+
expect { content }.not_to(change { opened_tmp_files_count })
62+
63+
expect(content).to eq("This is a test upload\n")
4164
end
4265
end
4366

4467
context 'when download to a custom tmp' do
68+
subject(:content) { obj.download(tmp) }
69+
4570
let(:tmp) { Tempfile.new }
4671

72+
after do
73+
tmp.close
74+
tmp.unlink
75+
end
76+
4777
it do
48-
expect { obj.download(tmp) }.to change(tmp, :read).from('').to("This is a test upload\n")
78+
tmp
79+
80+
expect { content }
81+
.to change(tmp, :read)
82+
.from('')
83+
.to("This is a test upload\n")
84+
.and change { opened_tmp_files_count }.by(0)
4985
end
5086
end
5187
end

0 commit comments

Comments
 (0)