blobby 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.rubocop.yml +22 -21
- data/.travis.yml +3 -3
- data/CHANGES.md +4 -0
- data/Gemfile +6 -3
- data/README.md +1 -1
- data/Rakefile +7 -0
- data/blobby.gemspec +3 -1
- data/lib/blobby.rb +3 -0
- data/lib/blobby/abstract_store.rb +7 -5
- data/lib/blobby/composite_store.rb +3 -0
- data/lib/blobby/fake_success_store.rb +3 -0
- data/lib/blobby/filesystem_store.rb +7 -3
- data/lib/blobby/http_store.rb +17 -14
- data/lib/blobby/in_memory_store.rb +8 -5
- data/lib/blobby/key_constraint.rb +2 -0
- data/lib/blobby/key_transforming_store.rb +2 -0
- data/lib/blobby/logging_store.rb +3 -0
- data/lib/blobby/version.rb +3 -1
- data/spec/blobby/composite_store_spec.rb +2 -0
- data/spec/blobby/fake_success_store_spec.rb +1 -1
- data/spec/blobby/filesystem_store_spec.rb +19 -10
- data/spec/blobby/http_store_spec.rb +4 -2
- data/spec/blobby/in_memory_store_spec.rb +2 -0
- data/spec/blobby/key_transforming_store_spec.rb +3 -1
- data/spec/blobby/logging_store_spec.rb +2 -0
- data/spec/blobby/store_behaviour.rb +2 -2
- data/spec/blobby_spec.rb +2 -0
- data/spec/spec_helper.rb +2 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 67ca328dc05a4815849e20344653b233411a73d1484105ce915f34d96a9cbf70
|
4
|
+
data.tar.gz: 8e8ab7afbf19d10d34bf21f289a5892ac9e82de52386a8da500681848a70b80b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8eb1a0c469b4a48df3f6ac73d16e6f2abff3d570b9ac7816b3362c07156bdb794c5ac568d4c31d23045e3e42619553b8d5bbcc948e8d1f5656903ea265543ef6
|
7
|
+
data.tar.gz: b10329fb3b4068503e1e3062d7644687274a5ce62f823db786055f54f97d3a3f2c58a273dd082efff1b6a7d5f411c47b1bdd897617ccc85c51bb06bfdd325513
|
data/.rubocop.yml
CHANGED
@@ -1,17 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
- "Rakefile"
|
4
|
-
- "**/version.rb"
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.4
|
5
3
|
|
6
|
-
|
4
|
+
Layout/EmptyLinesAroundBlockBody:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Layout/EmptyLinesAroundClassBody:
|
8
|
+
EnforcedStyle: empty_lines
|
9
|
+
|
10
|
+
Layout/EmptyLinesAroundModuleBody:
|
7
11
|
Enabled: false
|
8
12
|
|
9
|
-
|
13
|
+
Layout/LineLength:
|
10
14
|
Max: 120
|
11
15
|
|
16
|
+
Metrics/AbcSize:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Metrics/BlockLength:
|
20
|
+
Exclude:
|
21
|
+
- "spec/**/*"
|
22
|
+
|
12
23
|
Metrics/MethodLength:
|
13
24
|
Max: 30
|
14
25
|
|
26
|
+
Naming/FileName:
|
27
|
+
Exclude:
|
28
|
+
- "bin/*"
|
29
|
+
|
15
30
|
Style/ClassAndModuleChildren:
|
16
31
|
EnforcedStyle: nested
|
17
32
|
Exclude:
|
@@ -21,23 +36,9 @@ Style/Documentation:
|
|
21
36
|
Exclude:
|
22
37
|
- "spec/**/*"
|
23
38
|
|
24
|
-
Style/
|
39
|
+
Style/FormatStringToken:
|
25
40
|
Enabled: false
|
26
41
|
|
27
|
-
Style/EmptyLinesAroundClassBody:
|
28
|
-
EnforcedStyle: empty_lines
|
29
|
-
|
30
|
-
Style/EmptyLinesAroundModuleBody:
|
31
|
-
Enabled: false
|
32
|
-
|
33
|
-
Style/Encoding:
|
34
|
-
EnforcedStyle: when_needed
|
35
|
-
Enabled: true
|
36
|
-
|
37
|
-
Style/FileName:
|
38
|
-
Exclude:
|
39
|
-
- "bin/*"
|
40
|
-
|
41
42
|
Style/HashSyntax:
|
42
43
|
EnforcedStyle: hash_rockets
|
43
44
|
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
data/Gemfile
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source "https://rubygems.org"
|
2
4
|
|
3
5
|
# Runtime dependencies in blobby.gemspec
|
4
6
|
gemspec
|
5
7
|
|
6
8
|
# Development/test dependencies below
|
7
|
-
gem "rake", "~>
|
8
|
-
gem "rspec", "~> 3.
|
9
|
+
gem "rake", "~> 13.0"
|
10
|
+
gem "rspec", "~> 3.9"
|
11
|
+
gem "rubocop", "~> 0.78.0"
|
12
|
+
gem "sham_rack", "~> 1.4.1"
|
9
13
|
gem "sinatra"
|
10
|
-
gem "sham_rack", "~> 1.3.5"
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require "bundler"
|
4
5
|
|
@@ -11,3 +12,9 @@ task "default" => "spec"
|
|
11
12
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
12
13
|
t.rspec_opts = ["--colour"]
|
13
14
|
end
|
15
|
+
|
16
|
+
require "rubocop/rake_task"
|
17
|
+
|
18
|
+
RuboCop::RakeTask.new
|
19
|
+
|
20
|
+
task "default" => "rubocop"
|
data/blobby.gemspec
CHANGED
data/lib/blobby.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "blobby/filesystem_store"
|
2
4
|
require "blobby/http_store"
|
3
5
|
require "blobby/in_memory_store"
|
@@ -20,6 +22,7 @@ module Blobby
|
|
20
22
|
uri = URI(uri)
|
21
23
|
factory = store_factories[uri.scheme]
|
22
24
|
fail ArgumentError, "unknown store type: #{uri}" if factory.nil?
|
25
|
+
|
23
26
|
factory.from_uri(uri)
|
24
27
|
end
|
25
28
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "blobby/key_constraint"
|
2
4
|
|
3
5
|
module Blobby
|
@@ -48,11 +50,11 @@ module Blobby
|
|
48
50
|
end
|
49
51
|
|
50
52
|
def write(content)
|
51
|
-
if content.respond_to?(:read)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
content = if content.respond_to?(:read)
|
54
|
+
content.read
|
55
|
+
else
|
56
|
+
content.to_str.dup
|
57
|
+
end
|
56
58
|
content = content.force_encoding("BINARY") if content.respond_to?(:force_encoding)
|
57
59
|
@hash[key] = content
|
58
60
|
nil
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "blobby/key_constraint"
|
2
4
|
require "fileutils"
|
3
5
|
require "forwardable"
|
@@ -40,6 +42,7 @@ module Blobby
|
|
40
42
|
->(key) { key }
|
41
43
|
end
|
42
44
|
|
45
|
+
# Represents an object in the store.
|
43
46
|
class StoredObject
|
44
47
|
|
45
48
|
def initialize(path, umask)
|
@@ -106,16 +109,16 @@ module Blobby
|
|
106
109
|
|
107
110
|
tmp = nil
|
108
111
|
begin
|
109
|
-
tmp = tmp_path.open(File::CREAT | File::EXCL | File::WRONLY,
|
112
|
+
tmp = tmp_path.open(File::CREAT | File::EXCL | File::WRONLY, 0o666)
|
110
113
|
tmp.binmode
|
111
114
|
rescue Errno::ENOENT
|
112
|
-
FileUtils.mkdir_p(store_dir.to_s, :mode => apply_umask(
|
115
|
+
FileUtils.mkdir_p(store_dir.to_s, :mode => apply_umask(0o777))
|
113
116
|
retry
|
114
117
|
end
|
115
118
|
|
116
119
|
begin
|
117
120
|
yield tmp
|
118
|
-
tmp.chmod(apply_umask(
|
121
|
+
tmp.chmod(apply_umask(0o666)) unless using_default_umask?
|
119
122
|
ensure
|
120
123
|
tmp.close
|
121
124
|
end
|
@@ -125,6 +128,7 @@ module Blobby
|
|
125
128
|
tmp_path.rename(store_path)
|
126
129
|
rescue Errno::ESTALE
|
127
130
|
raise unless first_try
|
131
|
+
|
128
132
|
first_try = false
|
129
133
|
now = Time.now
|
130
134
|
File.utime(now, now, store_dir.to_s)
|
data/lib/blobby/http_store.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "blobby/key_constraint"
|
2
4
|
require "net/http"
|
3
5
|
|
@@ -25,7 +27,7 @@ module Blobby
|
|
25
27
|
with_http_connection do
|
26
28
|
true
|
27
29
|
end
|
28
|
-
rescue
|
30
|
+
rescue StandardError
|
29
31
|
false
|
30
32
|
end
|
31
33
|
|
@@ -42,6 +44,7 @@ module Blobby
|
|
42
44
|
end
|
43
45
|
rescue *retryable_exceptions => e
|
44
46
|
raise e if remaining_retry_intervals.empty?
|
47
|
+
|
45
48
|
sleep(remaining_retry_intervals.shift) && retry
|
46
49
|
end
|
47
50
|
end
|
@@ -52,12 +55,13 @@ module Blobby
|
|
52
55
|
[EOFError, Errno::ECONNRESET]
|
53
56
|
end
|
54
57
|
|
55
|
-
def retry_intervals(
|
58
|
+
def retry_intervals(count)
|
56
59
|
# exponential backoff: [0.5, 1, 2, 4, 8, ...]
|
57
60
|
scaling_factor = (0.5 + Kernel.rand * 0.1) # a little random avoids throbbing
|
58
|
-
Array.new(
|
61
|
+
Array.new(count) { |i| (2**i) * scaling_factor }
|
59
62
|
end
|
60
63
|
|
64
|
+
# Represents an object in the store.
|
61
65
|
class StoredObject
|
62
66
|
|
63
67
|
def initialize(store, key)
|
@@ -78,15 +82,14 @@ module Blobby
|
|
78
82
|
with_http_connection do |http, path|
|
79
83
|
http.request_get(path) do |response|
|
80
84
|
case response
|
81
|
-
when Net::HTTPNotFound
|
85
|
+
when Net::HTTPNotFound
|
82
86
|
return nil
|
83
|
-
when Net::HTTPSuccess
|
87
|
+
when Net::HTTPSuccess
|
84
88
|
if block_given?
|
85
89
|
response.read_body(&block)
|
86
90
|
return nil
|
87
|
-
else
|
88
|
-
return response.read_body
|
89
91
|
end
|
92
|
+
return response.read_body
|
90
93
|
end
|
91
94
|
response.error!
|
92
95
|
end
|
@@ -94,11 +97,11 @@ module Blobby
|
|
94
97
|
end
|
95
98
|
|
96
99
|
def write(content)
|
97
|
-
if content.respond_to?(:read)
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
100
|
+
content = if content.respond_to?(:read)
|
101
|
+
content.read
|
102
|
+
else
|
103
|
+
content.dup
|
104
|
+
end
|
102
105
|
with_http_connection do |http, path|
|
103
106
|
put = Net::HTTP::Put.new(path)
|
104
107
|
put.body = content
|
@@ -115,9 +118,9 @@ module Blobby
|
|
115
118
|
delete = Net::HTTP::Delete.new(path)
|
116
119
|
response = http.request(delete)
|
117
120
|
case response
|
118
|
-
when Net::HTTPSuccess
|
121
|
+
when Net::HTTPSuccess
|
119
122
|
true
|
120
|
-
when Net::HTTPNotFound
|
123
|
+
when Net::HTTPNotFound
|
121
124
|
false
|
122
125
|
else
|
123
126
|
response.error!
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "blobby/key_constraint"
|
2
4
|
|
3
5
|
module Blobby
|
@@ -23,6 +25,7 @@ module Blobby
|
|
23
25
|
StoredObject.new(@hash, key)
|
24
26
|
end
|
25
27
|
|
28
|
+
# Represents an object in the store.
|
26
29
|
class StoredObject
|
27
30
|
|
28
31
|
def initialize(hash, key)
|
@@ -47,11 +50,11 @@ module Blobby
|
|
47
50
|
end
|
48
51
|
|
49
52
|
def write(content)
|
50
|
-
if content.respond_to?(:read)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
content = if content.respond_to?(:read)
|
54
|
+
content.read
|
55
|
+
else
|
56
|
+
content.to_str.dup
|
57
|
+
end
|
55
58
|
content = content.force_encoding("BINARY") if content.respond_to?(:force_encoding)
|
56
59
|
@hash[key] = content
|
57
60
|
nil
|
data/lib/blobby/logging_store.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Blobby
|
2
4
|
|
3
5
|
# A store decorator that logs writes and deletes
|
@@ -28,6 +30,7 @@ module Blobby
|
|
28
30
|
attr_reader :store
|
29
31
|
attr_reader :store_name
|
30
32
|
|
33
|
+
# Represents an object in the store.
|
31
34
|
class StoredObject
|
32
35
|
|
33
36
|
def initialize(object, callbacks = {})
|
data/lib/blobby/version.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
require "blobby/filesystem_store"
|
@@ -17,7 +19,7 @@ describe Blobby::FilesystemStore do
|
|
17
19
|
around(:each) do |example|
|
18
20
|
original_umask = File.umask
|
19
21
|
begin
|
20
|
-
File.umask(
|
22
|
+
File.umask(0o077) # something stupid
|
21
23
|
example.run
|
22
24
|
ensure
|
23
25
|
File.umask(original_umask)
|
@@ -46,13 +48,20 @@ describe Blobby::FilesystemStore do
|
|
46
48
|
it "should have correct contents" do
|
47
49
|
expect do
|
48
50
|
subject[key].write(content)
|
49
|
-
end.to change {
|
51
|
+
end.to change {
|
52
|
+
begin
|
53
|
+
File.read(expected_file_path)
|
54
|
+
rescue StandardError
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
} .from(nil).to(content)
|
50
58
|
end
|
51
59
|
|
52
60
|
it "retries if renaming throws an ESTALE" do
|
53
61
|
raise_stack = [Errno::ESTALE]
|
54
62
|
expect_any_instance_of(Pathname).to receive(:rename).twice do |_args|
|
55
63
|
fail(raise_stack.shift) unless raise_stack.empty?
|
64
|
+
|
56
65
|
1
|
57
66
|
end
|
58
67
|
expect { subject[key].write(content) }.to_not raise_error
|
@@ -98,9 +107,9 @@ describe Blobby::FilesystemStore do
|
|
98
107
|
context "when the directory isn't writable" do
|
99
108
|
|
100
109
|
around do |example|
|
101
|
-
FileUtils.chmod(
|
110
|
+
FileUtils.chmod(0o500, @tmpdir)
|
102
111
|
example.run
|
103
|
-
FileUtils.chmod(
|
112
|
+
FileUtils.chmod(0o700, @tmpdir)
|
104
113
|
end
|
105
114
|
|
106
115
|
it { is_expected.not_to be_available }
|
@@ -110,9 +119,9 @@ describe Blobby::FilesystemStore do
|
|
110
119
|
context "when the directory isn't readable" do
|
111
120
|
|
112
121
|
around do |example|
|
113
|
-
FileUtils.chmod(
|
122
|
+
FileUtils.chmod(0o300, @tmpdir)
|
114
123
|
example.run
|
115
|
-
FileUtils.chmod(
|
124
|
+
FileUtils.chmod(0o700, @tmpdir)
|
116
125
|
end
|
117
126
|
|
118
127
|
it { is_expected.not_to be_available }
|
@@ -156,17 +165,17 @@ describe Blobby::FilesystemStore do
|
|
156
165
|
end
|
157
166
|
|
158
167
|
def mode_string_of(path)
|
159
|
-
format("0%o", path.stat.mode &
|
168
|
+
format("0%o", path.stat.mode & 0o777)
|
160
169
|
end
|
161
170
|
|
162
171
|
context "with a umask of 0027" do
|
163
172
|
|
164
173
|
subject do
|
165
|
-
described_class.new(@tmpdir, :umask =>
|
174
|
+
described_class.new(@tmpdir, :umask => 0o027)
|
166
175
|
end
|
167
176
|
|
168
177
|
it "has the specified umask" do
|
169
|
-
expect(subject.umask).to eq(
|
178
|
+
expect(subject.umask).to eq(0o027)
|
170
179
|
end
|
171
180
|
|
172
181
|
describe "#write" do
|
@@ -189,7 +198,7 @@ describe Blobby::FilesystemStore do
|
|
189
198
|
|
190
199
|
context "without an explicit umask" do
|
191
200
|
|
192
|
-
let(:system_umask) {
|
201
|
+
let(:system_umask) { 0o024 }
|
193
202
|
|
194
203
|
around(:each) do |example|
|
195
204
|
original_umask = File.umask
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
require "ostruct"
|
@@ -10,7 +12,7 @@ require "sham_rack"
|
|
10
12
|
describe Blobby::HttpStore do
|
11
13
|
|
12
14
|
let(:backing_store) do
|
13
|
-
|
15
|
+
{}
|
14
16
|
end
|
15
17
|
|
16
18
|
class FakeStorageService < Sinatra::Base
|
@@ -58,7 +60,7 @@ describe Blobby::HttpStore do
|
|
58
60
|
let(:http_storage_host) { "storeit.com" }
|
59
61
|
|
60
62
|
before do
|
61
|
-
ShamRack.mount(fake_storage_service
|
63
|
+
ShamRack.at(http_storage_host).mount(fake_storage_service)
|
62
64
|
end
|
63
65
|
|
64
66
|
after do
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
require "blobby/filesystem_store"
|
@@ -7,7 +9,7 @@ require "tmpdir"
|
|
7
9
|
|
8
10
|
describe Blobby::KeyTransformingStore do
|
9
11
|
|
10
|
-
let(:memory) {
|
12
|
+
let(:memory) { {} }
|
11
13
|
|
12
14
|
subject do
|
13
15
|
described_class.new(Blobby::InMemoryStore.new(memory)) { |key| key }
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
@@ -100,7 +100,7 @@ shared_examples_for Blobby::Store do
|
|
100
100
|
|
101
101
|
context "for UTF-8 content" do
|
102
102
|
|
103
|
-
let(:content) { "SN☃WMAN"
|
103
|
+
let(:content) { "SN☃WMAN" }
|
104
104
|
|
105
105
|
before do
|
106
106
|
stored_object.write(content)
|
data/spec/blobby_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blobby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-01 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -67,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
67
|
version: '0'
|
68
68
|
requirements: []
|
69
69
|
rubyforge_project:
|
70
|
-
rubygems_version: 2.
|
70
|
+
rubygems_version: 2.7.6
|
71
71
|
signing_key:
|
72
72
|
specification_version: 4
|
73
73
|
summary: Various ways of storing BLOBs
|