bucket_brigade 0.0.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
+ SHA1:
3
+ metadata.gz: 8cdb69753762ea4144d0ac29a7debeff8fcefe8d
4
+ data.tar.gz: 9dfc9ad55eba0aa9e4b923949e477023a13b7c49
5
+ SHA512:
6
+ metadata.gz: 31a691b784f454d86ee13e308622cb51ebaff8bc3a9a3c714fa94745025e4ba71738ce82513a36f9ba6a9e2b9a7bd5252408ff1e9a09e77a02b0dfd71bc56009
7
+ data.tar.gz: a1f16f71752d1488930d0308fcb3865791a87f3dd59799051431ba5171795f2ed2902bca6b26ce6530e80461374f6d411442a06cc527bfddbe7884f23a1b51f6
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require rspec/legacy_formatters
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ This gem makes it easy to use a cache hierarchy of S3 buckets. Slower, more durable
2
+ layers can be on Amazon S3. Faster local layers can use another S3-compatible service
3
+ like Riak CS.
4
+
5
+ Usage:
6
+
7
+ ```ruby
8
+ require 'bucket_brigade/bucket_config
9
+
10
+ bucket_config1 = BucketBrigade::BucketConfig.new(
11
+ 'http://192.168.37.73:8080',
12
+ 'access_key_id',
13
+ 'secret_access_key',
14
+ 'test-bucket'
15
+ )
16
+
17
+ bucket_config2 = BucketBrigade::BucketConfig.new(
18
+ 'https://s3.amazonaws.com'
19
+ 'access_key_id',
20
+ 'secret_access_key',
21
+ 'test-bucket'
22
+ )
23
+
24
+
25
+ bucket_list = BucketBrigade::BucketList.new(
26
+ bucket_config1,
27
+ bucket_config2,
28
+ )
29
+
30
+ open('/tmp/file') do |f|
31
+ bucket_list.put('test-key', f)
32
+ end
33
+
34
+ puts bucket_list.get('test-key')
35
+ ```
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'bucket_brigade'
5
+ s.version = '0.0.1'
6
+ s.summary = 'S3 bucket cache hierarchy'
7
+ s.description = 'S3 bucket cache hierarchy'
8
+ s.author = 'Pivotal Labs'
9
+ s.homepage = 'https://github.com/pivotal-cf-experimental/bucket_brigade'
10
+ s.license = 'Apache 2.0'
11
+ s.email = 'support@cloudfoundry.com'
12
+ s.files = `git ls-files`.split("\n")
13
+
14
+ s.add_development_dependency 'rspec', '~> 3.0.0'
15
+ s.add_development_dependency 'rspec-legacy_formatters', '~> 1.0.0'
16
+ s.add_dependency 'aws-sdk', '~> 1.49.0'
17
+ end
@@ -0,0 +1 @@
1
+ module BucketBrigade; end
@@ -0,0 +1,51 @@
1
+ require 'bucket_brigade'
2
+
3
+ require 'aws-sdk'
4
+
5
+ require 'tempfile'
6
+
7
+ class BucketBrigade::Bucket
8
+ def initialize(bucket_config)
9
+ @s3_bucket = AWS::S3.new(
10
+ s3_endpoint: bucket_config.host,
11
+ s3_port: bucket_config.port,
12
+ access_key_id: bucket_config.access_key_id,
13
+ secret_access_key: bucket_config.secret_access_key,
14
+ use_ssl: bucket_config.use_ssl,
15
+ s3_force_path_style: true
16
+ ).buckets[bucket_config.bucket]
17
+ end
18
+
19
+ def has_key?(key)
20
+ object(key).exists?
21
+ end
22
+
23
+ def get(key)
24
+ has_key?(key) ? object(key) : nil
25
+ end
26
+
27
+ def put(key, io)
28
+ object(key).write(io)
29
+ end
30
+
31
+ def delete(key)
32
+ object(key).delete
33
+ end
34
+
35
+ def object(key)
36
+ @s3_bucket.objects[key]
37
+ end
38
+
39
+ def copy(key, other)
40
+ temp = Tempfile.new('bucket-copy')
41
+ object(key).read do |chunk|
42
+ temp.write(chunk)
43
+ end
44
+
45
+ temp.rewind
46
+
47
+ other.object(key).write(temp)
48
+
49
+ temp.close!
50
+ end
51
+ end
@@ -0,0 +1,25 @@
1
+ require 'bucket_brigade'
2
+
3
+ require 'uri'
4
+
5
+ class BucketBrigade::BucketConfig
6
+ attr_reader :endpoint
7
+ attr_reader :access_key_id
8
+ attr_reader :secret_access_key
9
+ attr_reader :bucket
10
+ attr_reader :host
11
+ attr_reader :port
12
+ attr_reader :use_ssl
13
+
14
+ def initialize(endpoint, access_key_id, secret_access_key, bucket)
15
+ @endpoint = endpoint
16
+ @access_key_id = access_key_id
17
+ @secret_access_key = secret_access_key
18
+ @bucket = bucket
19
+
20
+ uri = URI(@endpoint)
21
+ @host = uri.host
22
+ @port = uri.port
23
+ @use_ssl = uri.scheme == 'https'
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ require 'bucket_brigade'
2
+ require 'bucket_brigade/bucket'
3
+
4
+ require 'aws-sdk'
5
+
6
+ class BucketBrigade::BucketList
7
+ def initialize(*bucket_configs)
8
+ @buckets = bucket_configs.map do |bucket_config|
9
+ BucketBrigade::Bucket.new(bucket_config)
10
+ end
11
+ end
12
+
13
+ def get(key)
14
+ @buckets.each_with_index do |bucket, i|
15
+ if bucket.has_key?(key)
16
+ if i > 0
17
+ prev_bucket = @buckets[i - 1]
18
+ bucket.copy(key, prev_bucket)
19
+ return prev_bucket.get(key)
20
+ end
21
+ return bucket.get(key)
22
+ end
23
+ end
24
+ nil
25
+ end
26
+
27
+ def put(key, io)
28
+ @buckets.last.put(key, io)
29
+ # invalidate all the way down
30
+ @buckets.first(@buckets.size - 1).each do |bucket|
31
+ bucket.delete(key)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,42 @@
1
+ require 'bucket_brigade/bucket_config'
2
+ require 'bucket_brigade/bucket_list'
3
+
4
+ describe 'put and get data from the cache' do
5
+
6
+ it 'puts and gets a file from the cache' do
7
+ bucket_config1 = BucketBrigade::BucketConfig.new(
8
+ ENV.fetch('LOCAL_S3_ENDPOINT'),
9
+ ENV.fetch('LOCAL_S3_ID'),
10
+ ENV.fetch('LOCAL_S3_SECRET'),
11
+ 'test'
12
+ )
13
+
14
+ bucket_config2 = BucketBrigade::BucketConfig.new(
15
+ ENV.fetch('LOCAL_S3_ENDPOINT'),
16
+ ENV.fetch('LOCAL_S3_ID'),
17
+ ENV.fetch('LOCAL_S3_SECRET'),
18
+ 'test2'
19
+ )
20
+
21
+ bucket_config3 = BucketBrigade::BucketConfig.new(
22
+ 'http://s3.amazonaws.com',
23
+ ENV.fetch('S3_ID'),
24
+ ENV.fetch('S3_SECRET'),
25
+ 'bucket-brigade-test'
26
+ )
27
+
28
+ bucket_list = BucketBrigade::BucketList.new(
29
+ bucket_config1,
30
+ bucket_config2,
31
+ bucket_config3
32
+ )
33
+
34
+ io = StringIO.new
35
+ io.write('test 1 2 3')
36
+ io.rewind
37
+
38
+ bucket_list.put('test', io)
39
+
40
+ expect(bucket_list.get('test').read).to eq('test 1 2 3')
41
+ end
42
+ end
@@ -0,0 +1,72 @@
1
+ require 'bucket_brigade/bucket_config'
2
+
3
+ describe BucketBrigade::BucketConfig do
4
+ let(:endpoint) { 'http://host.com:1234' }
5
+ let(:access_key_id) { 'test-access-key-id' }
6
+ let(:secret_access_key) { 'secret-access-key' }
7
+ let(:bucket) { 'bucket' }
8
+
9
+ subject(:bucket_config) do
10
+ described_class.new(endpoint, access_key_id, secret_access_key, bucket)
11
+ end
12
+
13
+ describe '#endpoint' do
14
+ it 'returns the endpoint' do
15
+ expect(bucket_config.endpoint).to eq(endpoint)
16
+ end
17
+ end
18
+
19
+ describe '#access_key_id' do
20
+ it 'returns the access_key_id' do
21
+ expect(bucket_config.access_key_id).to eq(access_key_id)
22
+ end
23
+ end
24
+
25
+ describe '#secret_access_key' do
26
+ it 'returns the secret_access_key' do
27
+ expect(bucket_config.secret_access_key).to eq(secret_access_key)
28
+ end
29
+ end
30
+
31
+ describe '#bucket' do
32
+ it 'returns the bucket' do
33
+ expect(bucket_config.bucket).to eq(bucket)
34
+ end
35
+ end
36
+
37
+ describe '#port' do
38
+ context 'when the port is provided' do
39
+ it 'returns the port' do
40
+ expect(bucket_config.port).to eq(1234)
41
+ end
42
+ end
43
+
44
+ context 'when the port is not provided' do
45
+ let(:endpoint) { 'http://host.com' }
46
+ it 'returns port 80' do
47
+ expect(bucket_config.port).to eq(80)
48
+ end
49
+ end
50
+ end
51
+
52
+ describe '#host' do
53
+ it 'returns the host' do
54
+ expect(bucket_config.host).to eq('host.com')
55
+ end
56
+ end
57
+
58
+ describe '#use_ssl' do
59
+ context 'when the endpoint is https' do
60
+ let(:endpoint) { 'https://host.com/' }
61
+ it 'returns true' do
62
+ expect(bucket_config.use_ssl).to eq(true)
63
+ end
64
+ end
65
+
66
+ context 'when the endpoint is not https' do
67
+ it 'returns false' do
68
+ expect(bucket_config.use_ssl).to eq(false)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,150 @@
1
+ require 'bucket_brigade/bucket_config'
2
+ require 'bucket_brigade/bucket_list'
3
+
4
+ describe BucketBrigade::BucketList do
5
+
6
+ let(:bucket_configs) {
7
+ [
8
+ BucketBrigade::BucketConfig.new(
9
+ 'http://test-endpoint-1:1234',
10
+ 'test-access-key-id-1',
11
+ 'test-secret-access-key-1',
12
+ 'test-bucket-1'
13
+ ),
14
+ BucketBrigade::BucketConfig.new(
15
+ 'http://test-endpoint-2:1234',
16
+ 'test-access-key-id-2',
17
+ 'test-secret-access-key-2',
18
+ 'test-bucket-2'
19
+ )
20
+ ]
21
+ }
22
+
23
+ let(:s3_1) { instance_double(AWS::S3) }
24
+ let(:s3_2) { instance_double(AWS::S3) }
25
+
26
+ let(:bucket_collection_1) { instance_double(AWS::S3::BucketCollection) }
27
+ let(:bucket_collection_2) { instance_double(AWS::S3::BucketCollection) }
28
+
29
+ let(:bucket_1) { instance_double(AWS::S3::Bucket) }
30
+ let(:bucket_2) { instance_double(AWS::S3::Bucket) }
31
+
32
+ let(:object_collection_1) { instance_double(AWS::S3::ObjectCollection) }
33
+ let(:object_collection_2) { instance_double(AWS::S3::ObjectCollection) }
34
+
35
+ let(:object_1) { instance_double(AWS::S3::S3Object) }
36
+ let(:object_2) { instance_double(AWS::S3::S3Object) }
37
+
38
+ before do
39
+ allow(AWS::S3).to receive(:new).with(
40
+ s3_endpoint: 'test-endpoint-1',
41
+ s3_port: 1234,
42
+ access_key_id: 'test-access-key-id-1',
43
+ secret_access_key: 'test-secret-access-key-1',
44
+ use_ssl: false,
45
+ s3_force_path_style: true
46
+ ).and_return(s3_1)
47
+ allow(s3_1).to receive(:buckets).and_return(bucket_collection_1)
48
+ allow(bucket_collection_1).to receive(:[]).with('test-bucket-1').and_return(bucket_1)
49
+ allow(bucket_1).to receive(:objects).and_return(object_collection_1)
50
+ allow(object_collection_1).to receive(:[]).with('test-key').and_return(object_1)
51
+
52
+ allow(AWS::S3).to receive(:new).with(
53
+ s3_endpoint: 'test-endpoint-2',
54
+ s3_port: 1234,
55
+ access_key_id: 'test-access-key-id-2',
56
+ secret_access_key: 'test-secret-access-key-2',
57
+ use_ssl: false,
58
+ s3_force_path_style: true
59
+ ).and_return(s3_2)
60
+ allow(s3_2).to receive(:buckets).and_return(bucket_collection_2)
61
+ allow(bucket_collection_2).to receive(:[]).with('test-bucket-2').and_return(bucket_2)
62
+ allow(bucket_2).to receive(:objects).and_return(object_collection_2)
63
+ allow(object_collection_2).to receive(:[]).with('test-key').and_return(object_2)
64
+ end
65
+
66
+ subject(:bucket_list) { described_class.new(*bucket_configs) }
67
+
68
+ describe '#get' do
69
+ context 'when the object is found in the first bucket' do
70
+ before do
71
+ allow(object_1).to receive(:exists?).and_return(true)
72
+ end
73
+
74
+ it 'returns the object from the first bucket' do
75
+ expect(bucket_list.get('test-key')).to eq(object_1)
76
+ end
77
+ end
78
+
79
+ context 'when the object is not found in any buckets' do
80
+ before do
81
+ allow(object_1).to receive(:exists?).and_return(false)
82
+ allow(object_2).to receive(:exists?).and_return(false)
83
+ end
84
+
85
+ it 'returns nil' do
86
+ expect(bucket_list.get('test-key')).to eq(nil)
87
+ end
88
+ end
89
+
90
+ context 'when the object is found in the second bucket' do
91
+ let(:temp) { instance_double(Tempfile) }
92
+
93
+ before do
94
+ allow(object_1).to receive(:exists?).and_return(false)
95
+ allow(object_2).to receive(:exists?).and_return(true)
96
+
97
+ allow(Tempfile).to receive(:new).with('bucket-copy').and_return(temp)
98
+ allow(temp).to receive(:rewind)
99
+ allow(temp).to receive(:close!)
100
+ end
101
+
102
+ it 'writes the object to the first bucket' do
103
+ allow(object_2).to receive(:read)
104
+ expect(object_1).to receive(:write).with(temp)
105
+ bucket_list.get('test-key')
106
+ end
107
+
108
+ it 'returns the object from the first bucket' do
109
+ allow(object_2).to receive(:read)
110
+
111
+ allow(object_1).to receive(:write).with(temp) {
112
+ allow(object_1).to receive(:exists?).and_return(true)
113
+ }
114
+ expect(bucket_list.get('test-key')).to eq(object_1)
115
+ end
116
+
117
+ end
118
+
119
+ context 'when the object is found in both buckets' do
120
+ before do
121
+ allow(object_1).to receive(:exists?).and_return(true)
122
+ allow(object_2).to receive(:exists?).and_return(true)
123
+ end
124
+
125
+ it 'returns the object from the first bucket' do
126
+ expect(bucket_list.get('test-key')).to eq(object_1)
127
+ end
128
+ end
129
+ end
130
+
131
+ describe '#put' do
132
+ context 'when writing an object' do
133
+ let(:io) { instance_double(File) }
134
+
135
+ it 'puts the object in the last bucket' do
136
+ allow(object_1).to receive(:delete)
137
+
138
+ expect(object_2).to receive(:write).with(io)
139
+ bucket_list.put('test-key', io)
140
+ end
141
+
142
+ it 'delete the object from the first bucket' do
143
+ allow(object_2).to receive(:write).with(io)
144
+
145
+ expect(object_1).to receive(:delete)
146
+ bucket_list.put('test-key', io)
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,145 @@
1
+ require 'bucket_brigade/bucket'
2
+ require 'bucket_brigade/bucket_config'
3
+
4
+ require 'aws-sdk'
5
+
6
+ describe BucketBrigade::Bucket do
7
+
8
+ subject(:bucket) { described_class.new(bucket_config) }
9
+
10
+ let(:bucket_config) {
11
+ BucketBrigade::BucketConfig.new(
12
+ 'http://host.com:1234',
13
+ 'test-access-key-id',
14
+ 'test-secret-access-key',
15
+ 'bucket')
16
+ }
17
+
18
+ let(:s3) { instance_double(AWS::S3) }
19
+ let(:bucket_collection) { instance_double(AWS::S3::BucketCollection) }
20
+ let(:s3_bucket) { instance_double(AWS::S3::Bucket) }
21
+ let(:object_collection) { instance_double(AWS::S3::ObjectCollection) }
22
+ let(:object) { instance_double(AWS::S3::S3Object) }
23
+
24
+ before do
25
+ allow(AWS::S3).to receive(:new).with(
26
+ s3_endpoint: 'host.com',
27
+ s3_port: 1234,
28
+ access_key_id: 'test-access-key-id',
29
+ secret_access_key: 'test-secret-access-key',
30
+ use_ssl: false,
31
+ s3_force_path_style: true
32
+ ).and_return(s3)
33
+ allow(s3).to receive(:buckets).and_return(bucket_collection)
34
+ allow(bucket_collection).to receive(:[]).with('bucket').and_return(s3_bucket)
35
+ allow(s3_bucket).to receive(:objects).and_return(object_collection)
36
+ allow(object_collection).to receive(:[]).with('test-key').and_return(object)
37
+ end
38
+
39
+ describe '#has_key' do
40
+ context 'when the object does not exist' do
41
+ before { allow(object).to receive(:exists?).and_return(false) }
42
+
43
+ it 'returns false' do
44
+ expect(bucket).to_not have_key('test-key')
45
+ end
46
+ end
47
+
48
+ context 'when the object exists' do
49
+ before { allow(object).to receive(:exists?).and_return(true) }
50
+
51
+ it 'returns true' do
52
+ expect(bucket).to have_key('test-key')
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#get' do
58
+ context 'when the object does not exist' do
59
+ before { allow(object).to receive(:exists?).and_return(false) }
60
+
61
+ it 'returns nil' do
62
+ expect(bucket.get('test-key')).to be(nil)
63
+ end
64
+ end
65
+
66
+ context 'when the object exists' do
67
+ before { allow(object).to receive(:exists?).and_return(true) }
68
+
69
+ it 'gets an object from the bucket' do
70
+ expect(bucket.get('test-key')).to eq(object)
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#put' do
76
+ it 'puts an object in the bucket' do
77
+ io = instance_double(File)
78
+ expect(object).to receive(:write).with(io)
79
+ bucket.put('test-key', io)
80
+ end
81
+ end
82
+
83
+ describe '#delete' do
84
+ it 'delete the object from the bucket' do
85
+ expect(object).to receive(:delete)
86
+ bucket.delete('test-key')
87
+ end
88
+ end
89
+
90
+ describe '#object' do
91
+ it 'gets the object from the bucket' do
92
+ expect(bucket.object('test-key')).to eq(object)
93
+ end
94
+ end
95
+
96
+ describe '#copy' do
97
+ let(:other_bucket_config) {
98
+ BucketBrigade::BucketConfig.new(
99
+ 'http://host2.com:1234',
100
+ 'test-access-key-id',
101
+ 'test-secret-access-key',
102
+ 'bucket')
103
+ }
104
+
105
+ let(:other_bucket) { described_class.new(other_bucket_config) }
106
+
107
+ let(:other_s3) { instance_double(AWS::S3) }
108
+ let(:other_bucket_collection) { instance_double(AWS::S3::BucketCollection) }
109
+ let(:other_s3_bucket) { instance_double(AWS::S3::Bucket) }
110
+ let(:other_object_collection) { instance_double(AWS::S3::ObjectCollection) }
111
+ let(:other_object) { instance_double(AWS::S3::S3Object) }
112
+
113
+ before do
114
+ allow(AWS::S3).to receive(:new).with(
115
+ s3_endpoint: 'host2.com',
116
+ s3_port: 1234,
117
+ access_key_id: 'test-access-key-id',
118
+ secret_access_key: 'test-secret-access-key',
119
+ use_ssl: false,
120
+ s3_force_path_style: true
121
+ ).and_return(other_s3)
122
+
123
+ allow(other_s3).to receive(:buckets).and_return(other_bucket_collection)
124
+ allow(other_bucket_collection).to receive(:[]).with('bucket').and_return(
125
+ other_s3_bucket)
126
+ allow(other_s3_bucket).to receive(:objects).and_return(
127
+ other_object_collection)
128
+ allow(other_object_collection).to receive(:[]).with('test-key').and_return(
129
+ other_object)
130
+ end
131
+
132
+ it 'copies an object from one bucket to another' do
133
+ temp = instance_double(Tempfile)
134
+ allow(Tempfile).to receive(:new).with('bucket-copy').and_return(temp)
135
+ allow(temp).to receive(:write).with('test')
136
+ allow(temp).to receive(:rewind)
137
+ allow(object).to receive(:read).with(no_args).and_yield('test')
138
+
139
+ expect(other_object).to receive(:write).with(temp)
140
+ expect(temp).to receive(:close!)
141
+
142
+ bucket.copy('test-key', other_bucket)
143
+ end
144
+ end
145
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bucket_brigade
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Pivotal Labs
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-legacy_formatters
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: aws-sdk
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 1.49.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.49.0
55
+ description: S3 bucket cache hierarchy
56
+ email: support@cloudfoundry.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - .gitignore
62
+ - .rspec
63
+ - Gemfile
64
+ - README.md
65
+ - bucket_brigade.gemspec
66
+ - lib/bucket_brigade.rb
67
+ - lib/bucket_brigade/bucket.rb
68
+ - lib/bucket_brigade/bucket_config.rb
69
+ - lib/bucket_brigade/bucket_list.rb
70
+ - spec/integration/put_get_spec.rb
71
+ - spec/unit/bucket_brigade/bucket_config_spec.rb
72
+ - spec/unit/bucket_brigade/bucket_list_spec.rb
73
+ - spec/unit/bucket_brigade/bucket_spec.rb
74
+ homepage: https://github.com/pivotal-cf-experimental/bucket_brigade
75
+ licenses:
76
+ - Apache 2.0
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.0.14
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: S3 bucket cache hierarchy
98
+ test_files: []