asset_cloud 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +2 -1
- data/Gemfile +2 -0
- data/History.md +4 -0
- data/README.rdoc +8 -0
- data/asset_cloud.gemspec +6 -1
- data/lib/asset_cloud.rb +2 -2
- data/lib/asset_cloud/buckets/bucket_chain.rb +0 -2
- data/lib/asset_cloud/buckets/file_system_bucket.rb +22 -17
- data/lib/asset_cloud/buckets/memory_bucket.rb +0 -5
- data/lib/asset_cloud/buckets/s3_bucket.rb +62 -0
- data/lib/asset_cloud/buckets/versioned_memory_bucket.rb +0 -4
- data/lib/asset_cloud/callbacks.rb +0 -2
- data/spec/base_spec.rb +14 -0
- data/spec/bucket_spec.rb +25 -0
- data/spec/callbacks_spec.rb +0 -7
- data/spec/file_system_spec.rb +1 -2
- data/spec/memory_bucket_spec.rb +0 -4
- data/spec/mock_s3_interface.rb +167 -0
- data/spec/remote_s3_bucket_spec.rb +69 -0
- data/spec/s3_bucket_spec.rb +64 -0
- data/spec/spec_helper.rb +2 -0
- metadata +54 -25
- checksums.yaml.gz.sig +0 -2
- data.tar.gz.sig +0 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c73b8628c09c25c2e05eae7b097b38a55a40175a
|
4
|
+
data.tar.gz: b78f3c69d1bf5346d88bf6c3a2608e2c92cbf13a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eaa3b2f1e39aefa77383c50e9d3248d97d8df7f02fd7b229747c346f12b56b8f36a907e570c8b80cc7364f79fedd61527e0b0f092947898073dca045a108dabd
|
7
|
+
data.tar.gz: 24eab9467aaa4243b98c82350a504ae9fc1a3b14e4ea45dc9d7002228c9f585d0b4ae1a0c0ca3efb573547277ff193d41bb92b5862a94e528245859bdcc16bf5
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/History.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Asset Cloud Version History
|
2
2
|
|
3
|
+
## Version 2.1.0, 2015-03-03
|
4
|
+
|
5
|
+
* Add support for S3 assests https://github.com/Shopify/asset_cloud/pull/7
|
6
|
+
|
3
7
|
## Version 2.0.0, 2014-09-26
|
4
8
|
|
5
9
|
* Change the way methods on asset extensions are invoke so it won't silently swallow exceptions [#3](https://github.com/Shopify/asset_cloud/pull/3).
|
data/README.rdoc
CHANGED
@@ -10,6 +10,14 @@ An abstraction layer around arbitrary and diverse asset stores.
|
|
10
10
|
|
11
11
|
gem install asset_cloud
|
12
12
|
|
13
|
+
== Testing
|
14
|
+
|
15
|
+
bundle exec rake spec
|
16
|
+
|
17
|
+
With S3 Remote test:
|
18
|
+
|
19
|
+
AWS_ACCESS_KEY_ID="<s3_key>" AWS_SECRET_ACCESS_KEY="<s3_secret_key>" S3_BUCKET_NAME="<bucket_name>" bundle exec rake spec
|
20
|
+
|
13
21
|
== Copyright
|
14
22
|
|
15
23
|
Copyright (c) 2008-2014 Tobias Lütke & Shopify, Inc. Released under the MIT license (see LICENSE for details).
|
data/asset_cloud.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{asset_cloud}
|
5
|
-
s.version = "2.
|
5
|
+
s.version = "2.1.0"
|
6
6
|
|
7
7
|
s.authors = %w(Shopify)
|
8
8
|
s.summary = %q{An abstraction layer around arbitrary and diverse asset stores.}
|
@@ -20,4 +20,9 @@ Gem::Specification.new do |s|
|
|
20
20
|
|
21
21
|
s.add_development_dependency 'rspec'
|
22
22
|
s.add_development_dependency 'rake'
|
23
|
+
s.add_development_dependency 'mocha'
|
24
|
+
if RUBY_VERSION >= "2.0.0"
|
25
|
+
s.add_development_dependency 'pry'
|
26
|
+
s.add_development_dependency 'pry-byebug'
|
27
|
+
end
|
23
28
|
end
|
data/lib/asset_cloud.rb
CHANGED
@@ -13,6 +13,8 @@ require 'asset_cloud/buckets/memory_bucket'
|
|
13
13
|
require 'asset_cloud/buckets/versioned_memory_bucket'
|
14
14
|
require 'asset_cloud/base'
|
15
15
|
|
16
|
+
#S3
|
17
|
+
require 'asset_cloud/buckets/s3_bucket'
|
16
18
|
|
17
19
|
# Extensions
|
18
20
|
require 'asset_cloud/free_key_locator'
|
@@ -21,7 +23,6 @@ require 'asset_cloud/validations'
|
|
21
23
|
|
22
24
|
require 'asset_cloud/asset_extension'
|
23
25
|
|
24
|
-
|
25
26
|
AssetCloud::Base.class_eval do
|
26
27
|
include AssetCloud::FreeKeyLocator
|
27
28
|
include AssetCloud::Callbacks
|
@@ -51,4 +52,3 @@ AssetCloud::Asset.class_eval do
|
|
51
52
|
end
|
52
53
|
end
|
53
54
|
end
|
54
|
-
|
@@ -12,7 +12,6 @@ module AssetCloud
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
15
|
def ls(key=nil)
|
17
16
|
first_possible_bucket {|b| b.ls(key)}
|
18
17
|
end
|
@@ -29,7 +28,6 @@ module AssetCloud
|
|
29
28
|
first_possible_bucket {|b| b.versions(key)}
|
30
29
|
end
|
31
30
|
|
32
|
-
|
33
31
|
def write(key, data)
|
34
32
|
every_bucket_with_transaction_on_key(key) {|b| b.write(key, data)}
|
35
33
|
end
|
@@ -25,23 +25,9 @@ module AssetCloud
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def write(key, data)
|
28
|
-
|
29
|
-
|
30
|
-
retried = false
|
31
|
-
|
32
|
-
begin
|
33
|
-
File.open(full_path, "wb+") { |fp| fp << data }
|
28
|
+
execute_in_full_path(key) do |path|
|
29
|
+
File.open(path, "wb+") { |fp| fp << data }
|
34
30
|
true
|
35
|
-
rescue Errno::ENOENT => e
|
36
|
-
if retried == false
|
37
|
-
directory = File.dirname(full_path)
|
38
|
-
FileUtils.mkdir_p(File.dirname(full_path))
|
39
|
-
retried = true
|
40
|
-
retry
|
41
|
-
else
|
42
|
-
raise
|
43
|
-
end
|
44
|
-
false
|
45
31
|
end
|
46
32
|
end
|
47
33
|
|
@@ -73,7 +59,26 @@ module AssetCloud
|
|
73
59
|
def relative_path_for(f)
|
74
60
|
f.sub(remove_full_path_regexp, '')
|
75
61
|
end
|
76
|
-
end
|
77
62
|
|
63
|
+
def execute_in_full_path(key, &block)
|
64
|
+
path = path_for(key)
|
65
|
+
|
66
|
+
find_or_create_and_execute(path, &block)
|
67
|
+
end
|
68
|
+
|
69
|
+
def find_or_create_and_execute(path)
|
70
|
+
retried = false
|
71
|
+
|
72
|
+
begin
|
73
|
+
yield(path)
|
74
|
+
rescue Errno::ENOENT => e
|
75
|
+
raise if retried
|
78
76
|
|
77
|
+
directory = File.dirname(path)
|
78
|
+
FileUtils.mkdir_p(File.dirname(path))
|
79
|
+
retried = true
|
80
|
+
retry
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
79
84
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'aws'
|
2
|
+
|
3
|
+
module AssetCloud
|
4
|
+
class S3Bucket < Bucket
|
5
|
+
def ls(key = nil)
|
6
|
+
key = absolute_key(key)
|
7
|
+
|
8
|
+
objects = cloud.s3_bucket(key).objects
|
9
|
+
objects = objects.with_prefix(key) if key
|
10
|
+
|
11
|
+
objects.map { |o| cloud[relative_key(o.key)] }
|
12
|
+
end
|
13
|
+
|
14
|
+
def read(key)
|
15
|
+
cloud.s3_bucket(key).objects[absolute_key(key)].read
|
16
|
+
rescue ::AWS::Errors::Base
|
17
|
+
raise AssetCloud::AssetNotFoundError, key
|
18
|
+
end
|
19
|
+
|
20
|
+
def write(key, data, options = {})
|
21
|
+
object = cloud.s3_bucket(key).objects[absolute_key(key)]
|
22
|
+
|
23
|
+
object.write(data, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete(key)
|
27
|
+
object = cloud.s3_bucket(key).objects[absolute_key(key)]
|
28
|
+
|
29
|
+
object.delete
|
30
|
+
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
def stat(key)
|
35
|
+
object = cloud.s3_bucket(key).objects[absolute_key(key)]
|
36
|
+
metadata = object.head
|
37
|
+
|
38
|
+
AssetCloud::Metadata.new(true, metadata[:content_length], nil, metadata[:last_modified])
|
39
|
+
rescue AWS::S3::Errors::NoSuchKey
|
40
|
+
AssetCloud::Metadata.new(false)
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
def path_prefix
|
45
|
+
@path_prefix ||= @cloud.url
|
46
|
+
end
|
47
|
+
|
48
|
+
def absolute_key(key = nil)
|
49
|
+
if key.to_s.starts_with?(path_prefix)
|
50
|
+
return key
|
51
|
+
else
|
52
|
+
args = [path_prefix]
|
53
|
+
args << key.to_s if key
|
54
|
+
args.join('/')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def relative_key(key)
|
59
|
+
key =~ /^#{path_prefix}\/(.+)/ ? $1 : key
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -8,7 +8,6 @@ module AssetCloud
|
|
8
8
|
def callback_methods(*symbols)
|
9
9
|
symbols.each do |method|
|
10
10
|
code = <<-"end_eval"
|
11
|
-
|
12
11
|
def self.before_#{method}(*callbacks, &block)
|
13
12
|
callbacks << block if block_given?
|
14
13
|
write_inheritable_array(:before_#{method}, callbacks)
|
@@ -19,7 +18,6 @@ module AssetCloud
|
|
19
18
|
write_inheritable_array(:after_#{method}, callbacks)
|
20
19
|
end
|
21
20
|
|
22
|
-
|
23
21
|
def #{method}_with_callbacks(*args)
|
24
22
|
if execute_callbacks(:before_#{method}, args)
|
25
23
|
result = #{method}_without_callbacks(*args)
|
data/spec/base_spec.rb
CHANGED
@@ -75,6 +75,20 @@ describe BasicCloud do
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
+
describe "#move" do
|
79
|
+
it "should return move a resource" do
|
80
|
+
asset = @fs['products/key.txt']
|
81
|
+
asset.key.should == 'products/key.txt'
|
82
|
+
asset.value.should == 'value'
|
83
|
+
@fs.move('products/key.txt', 'products/key2.txt')
|
84
|
+
new_asset = @fs['products/key2.txt']
|
85
|
+
new_asset.key.should == 'products/key2.txt'
|
86
|
+
new_asset.value.should == 'value'
|
87
|
+
expect {@fs['products/key.txt'].value }.to raise_error(AssetCloud::AssetNotFoundError)
|
88
|
+
@fs.move('products/key2.txt', 'products/key.txt')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
78
92
|
describe "#[]=" do
|
79
93
|
it "should write through the Asset object (and thus run any callbacks on the asset)" do
|
80
94
|
special_asset = double(:special_asset)
|
data/spec/bucket_spec.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AssetCloud::Bucket do
|
4
|
+
before do
|
5
|
+
@bucket = AssetCloud::Bucket.new(nil, nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "operations not supported" do
|
9
|
+
it "#ls not supported" do
|
10
|
+
expect { @bucket.ls('foo')}.to raise_error NotImplementedError
|
11
|
+
end
|
12
|
+
|
13
|
+
it "#read(key) not supported" do
|
14
|
+
expect { @bucket.read('foo')}.to raise_error NotImplementedError
|
15
|
+
end
|
16
|
+
|
17
|
+
it "#write(key, data) not supported" do
|
18
|
+
expect { @bucket.write('foo', 'bar')}.to raise_error NotImplementedError
|
19
|
+
end
|
20
|
+
|
21
|
+
it "#delete(key) not supported" do
|
22
|
+
expect { @bucket.delete('foo')}.to raise_error NotImplementedError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/callbacks_spec.rb
CHANGED
@@ -42,7 +42,6 @@ class MethodRecordingCloud < AssetCloud::Base
|
|
42
42
|
before_write :callback_before_write
|
43
43
|
after_write :callback_before_write
|
44
44
|
|
45
|
-
|
46
45
|
def method_missing(method, *args)
|
47
46
|
@run_callbacks << method.to_sym
|
48
47
|
end
|
@@ -52,21 +51,17 @@ describe CallbackCloud do
|
|
52
51
|
before { @fs = CallbackCloud.new(File.dirname(__FILE__) + '/files', 'http://assets/') }
|
53
52
|
|
54
53
|
it "should invoke callbacks after store" do
|
55
|
-
|
56
54
|
@fs.should_receive(:callback_before_write).with('tmp/file.txt', 'text').and_return(true)
|
57
55
|
@fs.should_receive(:callback_after_write).with('tmp/file.txt', 'text').and_return(true)
|
58
56
|
|
59
57
|
|
60
58
|
@fs.write 'tmp/file.txt', 'text'
|
61
|
-
|
62
59
|
end
|
63
60
|
|
64
61
|
it "should invoke callbacks after delete" do
|
65
|
-
|
66
62
|
@fs.should_receive(:callback_before_delete).with('tmp/file.txt').and_return(true)
|
67
63
|
@fs.should_receive(:callback_after_delete).with('tmp/file.txt').and_return(true)
|
68
64
|
|
69
|
-
|
70
65
|
@fs.delete 'tmp/file.txt'
|
71
66
|
end
|
72
67
|
|
@@ -78,9 +73,7 @@ describe CallbackCloud do
|
|
78
73
|
asset = @fs.build('tmp/file.txt')
|
79
74
|
asset.value = 'hello'
|
80
75
|
asset.store
|
81
|
-
|
82
76
|
end
|
83
|
-
|
84
77
|
end
|
85
78
|
|
86
79
|
describe MethodRecordingCloud do
|
data/spec/file_system_spec.rb
CHANGED
@@ -24,7 +24,7 @@ describe FileSystemCloud do
|
|
24
24
|
@fs.bucket_for('does-not-exist/file.txt').should be_an_instance_of(AssetCloud::InvalidBucket)
|
25
25
|
end
|
26
26
|
|
27
|
-
it "should use filesystem
|
27
|
+
it "should use filesystem bucket for products/ and tmp/ directories" do
|
28
28
|
@fs.bucket_for('products/file.txt').should be_an_instance_of(AssetCloud::FileSystemBucket)
|
29
29
|
@fs.bucket_for('tmp/file.txt').should be_an_instance_of(AssetCloud::FileSystemBucket)
|
30
30
|
end
|
@@ -44,7 +44,6 @@ describe FileSystemCloud do
|
|
44
44
|
end
|
45
45
|
|
46
46
|
describe 'when modifying file system' do
|
47
|
-
|
48
47
|
it "should call write after storing an asset" do
|
49
48
|
@fs.buckets[:tmp].should_receive(:write).with('tmp/new_file.test', 'hello world').and_return(true)
|
50
49
|
|
data/spec/memory_bucket_spec.rb
CHANGED
@@ -11,7 +11,6 @@ describe AssetCloud::MemoryBucket do
|
|
11
11
|
@fs = MemoryCloud.new(directory , 'http://assets/files' )
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
14
|
describe 'modifying items in subfolder' do
|
16
15
|
|
17
16
|
it "should return nil when file does not exist" do
|
@@ -46,7 +45,4 @@ describe AssetCloud::MemoryBucket do
|
|
46
45
|
@fs.buckets[:memory].ls.size.should == 4
|
47
46
|
end
|
48
47
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
48
|
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
class MockS3Interface
|
2
|
+
attr_reader :bucket_storage
|
3
|
+
|
4
|
+
def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
|
5
|
+
@bucket_storage = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def buckets
|
9
|
+
@bucket_collection ||= BucketCollection.new(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
def client
|
13
|
+
@client ||= Client.new
|
14
|
+
end
|
15
|
+
|
16
|
+
class Client
|
17
|
+
end
|
18
|
+
|
19
|
+
class BucketCollection
|
20
|
+
def initialize(interface)
|
21
|
+
@interface = interface
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](name)
|
25
|
+
@interface.bucket_storage[name] ||= Bucket.new(name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Bucket
|
30
|
+
attr_reader :name
|
31
|
+
def initialize(name)
|
32
|
+
@name = name
|
33
|
+
@storage = {}
|
34
|
+
@storage_options = {}
|
35
|
+
end
|
36
|
+
|
37
|
+
def with_prefix(prefix)
|
38
|
+
keys = @storage
|
39
|
+
keys = keys.select {|k,v| k.starts_with?(prefix)}
|
40
|
+
keys.map {|k,v| S3Object.new(self, k, v)}
|
41
|
+
end
|
42
|
+
|
43
|
+
def objects
|
44
|
+
Collection.new(self, @storage.keys)
|
45
|
+
end
|
46
|
+
|
47
|
+
def get(key)
|
48
|
+
if @storage.key?(key)
|
49
|
+
@storage[key]
|
50
|
+
else
|
51
|
+
raise AWS::S3::Errors::NoSuchKey.new(nil, nil)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_options(key)
|
56
|
+
if @storage_options.key?(key)
|
57
|
+
@storage_options[key]
|
58
|
+
else
|
59
|
+
raise AWS::S3::Errors::NoSuchKey.new(nil, nil)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def put(key, data, options={})
|
64
|
+
@storage[key] = data.dup.force_encoding(Encoding::BINARY)
|
65
|
+
@storage_options[key] = options.dup
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
def delete(key)
|
70
|
+
@storage.delete(key)
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def clear
|
75
|
+
@storage = {}
|
76
|
+
end
|
77
|
+
|
78
|
+
def inspect
|
79
|
+
"#<MockS3Interface::Bucket @name=#{@name.inspect}, @storage.keys = #{@storage.keys.inspect}>"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class Collection
|
84
|
+
include Enumerable
|
85
|
+
|
86
|
+
def initialize(bucket, objects)
|
87
|
+
@bucket = bucket
|
88
|
+
@objects = objects
|
89
|
+
end
|
90
|
+
|
91
|
+
def with_prefix(prefix)
|
92
|
+
self.class.new(@bucket, @objects.select {|k| k.start_with?(prefix)})
|
93
|
+
end
|
94
|
+
|
95
|
+
def [](name)
|
96
|
+
S3Object.new(@bucket, name)
|
97
|
+
end
|
98
|
+
|
99
|
+
def each
|
100
|
+
@objects.each { |e| yield S3Object.new(@bucket, e) }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class S3Object
|
105
|
+
attr_reader :key
|
106
|
+
|
107
|
+
def initialize(bucket, key, data=nil)
|
108
|
+
@bucket = bucket
|
109
|
+
@key = key
|
110
|
+
end
|
111
|
+
|
112
|
+
def delete
|
113
|
+
@bucket.delete(@key)
|
114
|
+
end
|
115
|
+
|
116
|
+
def read(headers={})
|
117
|
+
@bucket.get(@key)
|
118
|
+
end
|
119
|
+
|
120
|
+
def options()
|
121
|
+
@bucket.get_options(@key)
|
122
|
+
end
|
123
|
+
|
124
|
+
def write(data, options={})
|
125
|
+
@bucket.put(@key, data, options)
|
126
|
+
end
|
127
|
+
|
128
|
+
def multipart_upload(options = {})
|
129
|
+
MockMultipartUpload.new(@bucket, @key)
|
130
|
+
end
|
131
|
+
|
132
|
+
def url_for(permission, options={})
|
133
|
+
if options[:secure]
|
134
|
+
URI.parse("https://www.youtube.com/watch?v=oHg5SJYRHA0")
|
135
|
+
else
|
136
|
+
URI.parse("http://www.youtube.com/watch?v=oHg5SJYRHA0")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def head
|
141
|
+
{
|
142
|
+
content_length: read.size,
|
143
|
+
last_modified: Time.parse("Mon Aug 27 17:37:51 UTC 2007")
|
144
|
+
}
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
class MockMultipartUpload
|
149
|
+
def initialize(bucket, key)
|
150
|
+
@bucket =bucket
|
151
|
+
@key = key
|
152
|
+
@data = ""
|
153
|
+
end
|
154
|
+
|
155
|
+
def add_part(data)
|
156
|
+
@data << data
|
157
|
+
end
|
158
|
+
|
159
|
+
def abort
|
160
|
+
@bucket.delete(@key)
|
161
|
+
end
|
162
|
+
|
163
|
+
def complete(arg)
|
164
|
+
@bucket.put(@key, @data, {})
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class RemoteS3Cloud < AssetCloud::Base
|
4
|
+
attr_accessor :s3_connection
|
5
|
+
bucket :tmp, AssetCloud::S3Bucket
|
6
|
+
|
7
|
+
def s3_bucket(key)
|
8
|
+
s3_connection.buckets[ENV['S3_BUCKET_NAME']]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'Remote test for AssetCloud::S3Bucket', if: ENV['AWS_ACCESS_KEY_ID'] && ENV['AWS_SECRET_ACCESS_KEY'] && ENV['S3_BUCKET_NAME'] do
|
13
|
+
require 'aws-sdk'
|
14
|
+
|
15
|
+
directory = File.dirname(__FILE__) + '/files'
|
16
|
+
|
17
|
+
before(:all) do
|
18
|
+
AWS.config({
|
19
|
+
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
|
20
|
+
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
|
21
|
+
})
|
22
|
+
@cloud = RemoteS3Cloud.new(directory , 'testing/assets/files' )
|
23
|
+
@cloud.s3_connection = AWS::S3.new()
|
24
|
+
@bucket = @cloud.buckets[:tmp]
|
25
|
+
end
|
26
|
+
|
27
|
+
after(:all) do
|
28
|
+
listing = @bucket.ls('tmp')
|
29
|
+
listing.each { |object| object.delete }
|
30
|
+
end
|
31
|
+
|
32
|
+
it "#ls should return assets with proper keys" do
|
33
|
+
@cloud['tmp/test1.txt'] = 'test1'
|
34
|
+
@cloud['tmp/test2.txt'] = 'test2'
|
35
|
+
|
36
|
+
ls = @bucket.ls('tmp')
|
37
|
+
|
38
|
+
ls.first.class.should == AssetCloud::Asset
|
39
|
+
keys = ls.map(&:key)
|
40
|
+
['tmp/test1.txt', 'tmp/test2.txt'].all? {|key| keys.include? key }
|
41
|
+
end
|
42
|
+
|
43
|
+
it "#delete should ignore errors when deleting" do
|
44
|
+
@bucket.delete('tmp/a_file_that_should_not_exist.txt')
|
45
|
+
end
|
46
|
+
|
47
|
+
it "#delete should always return true" do
|
48
|
+
@cloud['tmp/test1.txt'] = 'test1'
|
49
|
+
|
50
|
+
@bucket.delete('tmp/test1.txt').should == true
|
51
|
+
end
|
52
|
+
|
53
|
+
it "#stat should get metadata from S3" do
|
54
|
+
start_time = Time.now
|
55
|
+
value = 'hello world'
|
56
|
+
@cloud.build('tmp/new_file.test', value).store
|
57
|
+
metadata = @bucket.stat('tmp/new_file.test')
|
58
|
+
metadata.size.should == value.size
|
59
|
+
metadata.updated_at.should >= start_time
|
60
|
+
end
|
61
|
+
|
62
|
+
it "#read " do
|
63
|
+
value = 'hello world'
|
64
|
+
key = 'tmp/new_file.txt'
|
65
|
+
@bucket.write(key, value)
|
66
|
+
data = @bucket.read(key)
|
67
|
+
data.should == value
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mock_s3_interface'
|
3
|
+
|
4
|
+
class S3Cloud < AssetCloud::Base
|
5
|
+
bucket :tmp, AssetCloud::S3Bucket
|
6
|
+
attr_accessor :s3_connection, :s3_bucket_name
|
7
|
+
|
8
|
+
def s3_bucket(key)
|
9
|
+
s3_connection.buckets[s3_bucket_name]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe AssetCloud::S3Bucket do
|
14
|
+
directory = File.dirname(__FILE__) + '/files'
|
15
|
+
|
16
|
+
before(:all) do
|
17
|
+
@cloud = S3Cloud.new(directory , 'http://assets/files')
|
18
|
+
@cloud.s3_connection = MockS3Interface.new('a', 'b')
|
19
|
+
@cloud.s3_bucket_name = 'asset-cloud-test'
|
20
|
+
|
21
|
+
@bucket = @cloud.buckets[:tmp]
|
22
|
+
FileUtils.mkdir_p(directory + '/tmp')
|
23
|
+
end
|
24
|
+
|
25
|
+
after(:each) do
|
26
|
+
FileUtils.rm_rf(directory + '/tmp')
|
27
|
+
end
|
28
|
+
|
29
|
+
it "#ls should return assets with proper keys" do
|
30
|
+
collection = MockS3Interface::Collection.new(nil, ["#{@cloud.url}/tmp/blah.gif", "#{@cloud.url}/tmp/add_to_cart.gif"])
|
31
|
+
expect_any_instance_of(MockS3Interface::Bucket).to receive(:objects).and_return(collection)
|
32
|
+
ls = @bucket.ls('tmp')
|
33
|
+
ls.first.class.should == AssetCloud::Asset
|
34
|
+
ls.map(&:key).should == ['tmp/blah.gif', 'tmp/add_to_cart.gif']
|
35
|
+
end
|
36
|
+
|
37
|
+
it "#delete should not ignore errors when deleting" do
|
38
|
+
expect_any_instance_of(MockS3Interface::Bucket).to receive(:delete).and_raise(StandardError)
|
39
|
+
|
40
|
+
expect { @bucket.delete('assets/fail.gif') }.to raise_error(StandardError)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "#delete should always return true" do
|
44
|
+
expect_any_instance_of(MockS3Interface::Bucket).to receive(:delete).and_return(nil)
|
45
|
+
|
46
|
+
@bucket.delete('assets/fail.gif').should == true
|
47
|
+
end
|
48
|
+
|
49
|
+
it "#stat should get metadata from S3" do
|
50
|
+
value = 'hello world'
|
51
|
+
@cloud.build('tmp/new_file.test', value).store
|
52
|
+
metadata = @bucket.stat('tmp/new_file.test')
|
53
|
+
metadata.size.should == value.size
|
54
|
+
metadata.updated_at.should == Time.parse("Mon Aug 27 17:37:51 UTC 2007")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "#read " do
|
58
|
+
value = 'hello world'
|
59
|
+
key = 'tmp/new_file.txt'
|
60
|
+
@bucket.write(key, value)
|
61
|
+
data = @bucket.read(key)
|
62
|
+
data.should == value
|
63
|
+
end
|
64
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,36 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asset_cloud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
-
|
12
|
-
-----BEGIN CERTIFICATE-----
|
13
|
-
MIIDcDCCAligAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MQ8wDQYDVQQDDAZhZG1p
|
14
|
-
bnMxFzAVBgoJkiaJk/IsZAEZFgdzaG9waWZ5MRMwEQYKCZImiZPyLGQBGRYDY29t
|
15
|
-
MB4XDTE0MDUxNTIwMzM0OFoXDTE1MDUxNTIwMzM0OFowPzEPMA0GA1UEAwwGYWRt
|
16
|
-
aW5zMRcwFQYKCZImiZPyLGQBGRYHc2hvcGlmeTETMBEGCgmSJomT8ixkARkWA2Nv
|
17
|
-
bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL0/81O3e1vh5smcwp2G
|
18
|
-
MpLQ6q0kejQLa65bPYPxdzWA1SYOKyGfw+yR9LdFzsuKpwWzKq6zX35lj1IckWS4
|
19
|
-
bNBEQzxmufUxU0XPM02haFB8fOfDJzdXsWte9Ge4IFwahwn68gpMqN+BvxL+KMYz
|
20
|
-
Iut9YmN44d4LZdsENEIO5vmybuG2vYDz7R56qB0PA+Q2P2CdhymsBad2DQs69FBo
|
21
|
-
uico9V6VMYYctL9lCYdzu9IXrOYNTt88suKIVzzAlHOKeN0Ng5qdztFoTR8sfxDr
|
22
|
-
Ydg3KHl5n47wlpgd8R0f/4b5gGxW+v9pyJCgQnLlRu7DedVSvv7+GMtj3g9r3nhJ
|
23
|
-
KqECAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFI/o
|
24
|
-
maf34HXbUOQsdoLHacEKQgunMB0GA1UdEQQWMBSBEmFkbWluc0BzaG9waWZ5LmNv
|
25
|
-
bTAdBgNVHRIEFjAUgRJhZG1pbnNAc2hvcGlmeS5jb20wDQYJKoZIhvcNAQEFBQAD
|
26
|
-
ggEBADkK9aj5T0HPExsov4EoMWFnO+G7RQ28C30VAfKxnL2UxG6i4XMHVs6Xi94h
|
27
|
-
qXFw1ec9Y2eDUqaolT3bviOk9BB197+A8Vz/k7MC6ci2NE+yDDB7HAC8zU6LAx8Y
|
28
|
-
Iqvw7B/PSZ/pz4bUVFlTATif4mi1vO3lidRkdHRtM7UePSn2rUpOi0gtXBP3bLu5
|
29
|
-
YjHJN7wx5cugMEyroKITG5gL0Nxtu21qtOlHX4Hc4KdE2JqzCPOsS4zsZGhgwhPs
|
30
|
-
fl3hbtVFTqbOlwL9vy1fudXcolIE/ZTcxQ+er07ZFZdKCXayR9PPs64heamfn0fp
|
31
|
-
TConQSX2BnZdhIEYW+cKzEC/bLc=
|
32
|
-
-----END CERTIFICATE-----
|
33
|
-
date: 2014-09-26 00:00:00.000000000 Z
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-03 00:00:00.000000000 Z
|
34
12
|
dependencies:
|
35
13
|
- !ruby/object:Gem::Dependency
|
36
14
|
name: activesupport
|
@@ -88,6 +66,48 @@ dependencies:
|
|
88
66
|
- - ">="
|
89
67
|
- !ruby/object:Gem::Version
|
90
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mocha
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry-byebug
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
91
111
|
description: An abstraction layer around arbitrary and diverse asset stores.
|
92
112
|
email: developers@shopify.com
|
93
113
|
executables: []
|
@@ -113,6 +133,7 @@ files:
|
|
113
133
|
- lib/asset_cloud/buckets/file_system_bucket.rb
|
114
134
|
- lib/asset_cloud/buckets/invalid_bucket.rb
|
115
135
|
- lib/asset_cloud/buckets/memory_bucket.rb
|
136
|
+
- lib/asset_cloud/buckets/s3_bucket.rb
|
116
137
|
- lib/asset_cloud/buckets/versioned_memory_bucket.rb
|
117
138
|
- lib/asset_cloud/callbacks.rb
|
118
139
|
- lib/asset_cloud/free_key_locator.rb
|
@@ -125,12 +146,16 @@ files:
|
|
125
146
|
- spec/base_spec.rb
|
126
147
|
- spec/blackhole_bucket_spec.rb
|
127
148
|
- spec/bucket_chain_spec.rb
|
149
|
+
- spec/bucket_spec.rb
|
128
150
|
- spec/callbacks_spec.rb
|
129
151
|
- spec/file_system_spec.rb
|
130
152
|
- spec/files/products/key.txt
|
131
153
|
- spec/files/versioned_stuff/foo
|
132
154
|
- spec/find_free_key_spec.rb
|
133
155
|
- spec/memory_bucket_spec.rb
|
156
|
+
- spec/mock_s3_interface.rb
|
157
|
+
- spec/remote_s3_bucket_spec.rb
|
158
|
+
- spec/s3_bucket_spec.rb
|
134
159
|
- spec/spec_helper.rb
|
135
160
|
- spec/validations_spec.rb
|
136
161
|
- spec/versioned_memory_bucket_spec.rb
|
@@ -164,12 +189,16 @@ test_files:
|
|
164
189
|
- spec/base_spec.rb
|
165
190
|
- spec/blackhole_bucket_spec.rb
|
166
191
|
- spec/bucket_chain_spec.rb
|
192
|
+
- spec/bucket_spec.rb
|
167
193
|
- spec/callbacks_spec.rb
|
168
194
|
- spec/file_system_spec.rb
|
169
195
|
- spec/files/products/key.txt
|
170
196
|
- spec/files/versioned_stuff/foo
|
171
197
|
- spec/find_free_key_spec.rb
|
172
198
|
- spec/memory_bucket_spec.rb
|
199
|
+
- spec/mock_s3_interface.rb
|
200
|
+
- spec/remote_s3_bucket_spec.rb
|
201
|
+
- spec/s3_bucket_spec.rb
|
173
202
|
- spec/spec_helper.rb
|
174
203
|
- spec/validations_spec.rb
|
175
204
|
- spec/versioned_memory_bucket_spec.rb
|
checksums.yaml.gz.sig
DELETED
data.tar.gz.sig
DELETED
metadata.gz.sig
DELETED
Binary file
|