store-digest 0.3.1 → 0.4.3
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 +4 -4
- data/TODO.org +115 -4
- data/lib/store/digest/blob/filesystem.rb +9 -4
- data/lib/store/digest/driver.rb +4 -0
- data/lib/store/digest/entry.rb +1214 -0
- data/lib/store/digest/error.rb +28 -0
- data/lib/store/digest/meta/lmdb/v0.rb +388 -0
- data/lib/store/digest/meta/lmdb/v1.rb +737 -0
- data/lib/store/digest/meta/lmdb.rb +59 -1041
- data/lib/store/digest/meta.rb +1 -1
- data/lib/store/digest/readwrapper.rb +174 -0
- data/lib/store/digest/version.rb +1 -1
- data/lib/store/digest.rb +335 -117
- data/store-digest.gemspec +6 -7
- metadata +45 -17
- data/lib/store/digest/object.rb +0 -623
data/lib/store/digest/meta.rb
CHANGED
|
@@ -37,7 +37,7 @@ module Store::Digest::Meta
|
|
|
37
37
|
|
|
38
38
|
# Set/add an individual object's metadata to the database.
|
|
39
39
|
#
|
|
40
|
-
# @param obj [Store::Digest::
|
|
40
|
+
# @param obj [Store::Digest::Entry] the object to store
|
|
41
41
|
# @param preserve [false, true] flag to preserve modification time
|
|
42
42
|
#
|
|
43
43
|
# @return [void]
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
require 'store/digest/version'
|
|
2
|
+
|
|
3
|
+
require 'thread'
|
|
4
|
+
require 'stringio'
|
|
5
|
+
|
|
6
|
+
# This class is an attempt to normalize input so that it can be
|
|
7
|
+
# {#read} like an IO handle. Use the class method {.coerce} to
|
|
8
|
+
# determine if it's even necessary.
|
|
9
|
+
#
|
|
10
|
+
class Store::Digest::ReadWrapper
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
# Test if the object quacks like an IO.
|
|
15
|
+
#
|
|
16
|
+
# @param obj [Object] said object
|
|
17
|
+
#
|
|
18
|
+
# @return [false, true]
|
|
19
|
+
#
|
|
20
|
+
def self.quacks? obj
|
|
21
|
+
obj.is_a?(IO) or %i[gets read close].all? do |m|
|
|
22
|
+
obj.respond_to? m
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# close the pipe and join the thread.
|
|
27
|
+
#
|
|
28
|
+
# @return [void]
|
|
29
|
+
#
|
|
30
|
+
def cleanup
|
|
31
|
+
@mutex.synchronize do
|
|
32
|
+
return if @done
|
|
33
|
+
@done = true
|
|
34
|
+
@read.close unless @read.closed?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
@thread.join
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
public
|
|
41
|
+
|
|
42
|
+
# XXX maybe later lol
|
|
43
|
+
# def self.assert! obj, thunk: false
|
|
44
|
+
# return true if obj.is_a?(self) || quacks?(obj) || obj.respond_to?(:each)
|
|
45
|
+
|
|
46
|
+
# if obj.respond_to?(:call)
|
|
47
|
+
# elsif obj.respond.to_?
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
|
|
51
|
+
# Attempt to coerce a suitable object or no-op.
|
|
52
|
+
#
|
|
53
|
+
# @param obj [Object] an object to be coerced
|
|
54
|
+
#
|
|
55
|
+
# @param thunk [false, true] let a thunk (a zero-arity callable that
|
|
56
|
+
# in this case returns a read handle) pass through; if falsy, it
|
|
57
|
+
# will execute the thunk and expect it to return something that
|
|
58
|
+
# quacks like a read handle, and throw an error if it isn't.
|
|
59
|
+
#
|
|
60
|
+
# @raise [ArgumentError] if the input is not sufficiently coercible
|
|
61
|
+
#
|
|
62
|
+
# @return [ReadWrapper,Object] a new proxy object around whatever
|
|
63
|
+
# the input is, or the original input if file-handle-ey enough
|
|
64
|
+
#
|
|
65
|
+
def self.coerce obj, thunk: false
|
|
66
|
+
return obj if [self, Store::Digest::Entry].any? { |c| obj.is_a? c }
|
|
67
|
+
|
|
68
|
+
return obj.open('rb') if obj.is_a? Pathname
|
|
69
|
+
|
|
70
|
+
return obj if quacks? obj # no need for this if it can read
|
|
71
|
+
|
|
72
|
+
return StringIO.new(obj) if obj.is_a? String
|
|
73
|
+
|
|
74
|
+
# response bodies /don't do this but other stuff does
|
|
75
|
+
if obj.respond_to?(:arity) && obj.arity == 0 ||
|
|
76
|
+
obj.respond_to?(:call) && obj.method(:call).arity == 0
|
|
77
|
+
# let the thunk through
|
|
78
|
+
return obj if thunk
|
|
79
|
+
|
|
80
|
+
out = obj.call
|
|
81
|
+
raise ArgumentError,
|
|
82
|
+
'a `call` with no arguments must return an IO-like object' unless
|
|
83
|
+
quacks? out
|
|
84
|
+
|
|
85
|
+
return out
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
new obj
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class << self
|
|
92
|
+
alias_method :[], :coerce
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Initialize a wrapper.
|
|
96
|
+
#
|
|
97
|
+
# @param obj [#call, #each] a suitable object
|
|
98
|
+
#
|
|
99
|
+
# @raise [ArgumentError] said object is unsuitable
|
|
100
|
+
#
|
|
101
|
+
def initialize obj
|
|
102
|
+
test = obj.respond_to?(:arity) ? obj :
|
|
103
|
+
obj.respond_to?(:call) ? obj.method(:call) : nil
|
|
104
|
+
|
|
105
|
+
if test
|
|
106
|
+
raise ArgumentError,
|
|
107
|
+
'Callable object is expected to take a write handle as an argument' if
|
|
108
|
+
test.arity == 0
|
|
109
|
+
elsif obj.respond_to?(:each)
|
|
110
|
+
nil
|
|
111
|
+
elsif obj.respond_to? :to_s
|
|
112
|
+
obj = [obj.to_s]
|
|
113
|
+
else
|
|
114
|
+
raise ArgumentError,
|
|
115
|
+
'Argument must respond to #call(write_fh) or #each or #to_s'
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
@done = false
|
|
119
|
+
@mutex = Mutex.new
|
|
120
|
+
|
|
121
|
+
@read, @write = IO.pipe
|
|
122
|
+
|
|
123
|
+
@thread = Thread.new do
|
|
124
|
+
if obj.respond_to? :call
|
|
125
|
+
obj.call @write
|
|
126
|
+
else
|
|
127
|
+
obj.each { |x| @write << x.to_s.b }
|
|
128
|
+
end
|
|
129
|
+
rescue Errno::EPIPE # => e
|
|
130
|
+
nil # not sure if we do anything here
|
|
131
|
+
ensure
|
|
132
|
+
@write.close unless @write.closed?
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# `gets` for parity with IO
|
|
137
|
+
#
|
|
138
|
+
# @return [String, nil]
|
|
139
|
+
#
|
|
140
|
+
def gets sep = $/, chomp = false
|
|
141
|
+
unless @read.closed?
|
|
142
|
+
out = @read.gets sep, chomp
|
|
143
|
+
cleanup if out.nil?
|
|
144
|
+
|
|
145
|
+
out
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# `read` for parity with IO
|
|
150
|
+
#
|
|
151
|
+
# @param maxlen [Integer] the length to read
|
|
152
|
+
# @param string [String] an optional string
|
|
153
|
+
#
|
|
154
|
+
# @return [String, nil]
|
|
155
|
+
#
|
|
156
|
+
def read maxlen = nil, string = nil
|
|
157
|
+
unless @read.closed?
|
|
158
|
+
out = @read.read maxlen, string
|
|
159
|
+
cleanup if out.nil?
|
|
160
|
+
|
|
161
|
+
out
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# `close` for parity with IO
|
|
166
|
+
#
|
|
167
|
+
def close
|
|
168
|
+
cleanup
|
|
169
|
+
nil # close returns nil
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# for the symbol
|
|
174
|
+
class Store::Digest::Entry; end
|
data/lib/store/digest/version.rb
CHANGED