55
55
raise NotImplementedError('Children should define their length')
57
def get(self, file_id, suffix=None):
57
def get(self, fileid, suffix=None):
58
58
"""Returns a file reading from a particular entry.
60
If suffix is present, retrieve the named suffix for file_id.
60
If suffix is present, retrieve the named suffix for fileid.
62
62
raise NotImplementedError
64
64
def __getitem__(self, fileid):
65
"""DEPRECATED. Please use .get(file_id) instead."""
65
"""DEPRECATED. Please use .get(fileid) instead."""
66
66
raise NotImplementedError
68
68
#def __contains__(self, fileid):
76
76
"""Add a file object f to the store accessible from the given fileid"""
77
77
raise NotImplementedError('Children of Store must define their method of adding entries.')
79
def has_id(self, file_id, suffix=None):
80
"""Return True or false for the presence of file_id in the store.
79
def has_id(self, fileid, suffix=None):
80
"""Return True or false for the presence of fileid in the store.
82
82
suffix, if present, is a per file suffix, i.e. for digital signature
136
136
should call this if they have no optimised facility for a
137
137
specific 'other'.
139
mutter('Store._copy_one: %r', fileid)
139
140
f = other.get(fileid, suffix)
140
141
self.add(f, fileid, suffix)
149
150
f -- A file-like object, or string
151
mutter("add store entry %r" % (fileid))
152
mutter("add store entry %r", fileid)
153
if suffix is not None:
154
fn = self._relpath(fileid, [suffix])
156
fn = self._relpath(fileid)
157
if self._transport.has(fn):
158
raise BzrError("store %r already contains id %r" % (self._transport.base, fileid))
162
self._transport.mkdir(hash_prefix(fileid)[:-1])
163
except errors.FileExists:
154
names = self._id_to_names(fileid, suffix)
155
if self._transport.has_any(names):
156
raise BzrError("store %r already contains id %r"
157
% (self._transport.base, fileid))
159
# Most of the time, just adding the file will work
160
# if we find a time where it fails, (because the dir
161
# doesn't exist), then create the dir, and try again
162
self._add(names[0], f)
165
def _add(self, relpath, f):
166
"""Actually add the file to the given location.
167
This should be overridden by children.
169
raise NotImplementedError('children need to implement this function.')
168
171
def _check_fileid(self, fileid):
169
172
if not isinstance(fileid, basestring):
171
174
if '\\' in fileid or '/' in fileid:
172
175
raise ValueError("invalid store id %r" % fileid)
174
def has_id(self, fileid, suffix=None):
175
"""See Store.has_id."""
177
def _id_to_names(self, fileid, suffix):
178
"""Return the names in the expected order"""
176
179
if suffix is not None:
177
180
fn = self._relpath(fileid, [suffix])
179
182
fn = self._relpath(fileid)
180
return self._transport.has(fn)
190
def has_id(self, fileid, suffix=None):
191
"""See Store.has_id."""
192
return self._transport.has_any(self._id_to_names(fileid, suffix))
194
def _get_name(self, fileid, suffix=None):
195
"""A special check, which returns the name of an existing file.
197
This is similar in spirit to 'has_id', but it is designed
198
to return information about which file the store has.
200
for name in self._id_to_names(fileid, suffix=suffix):
201
if self._transport.has(name):
182
205
def _get(self, filename):
183
206
"""Return an vanilla file stream for clients to read from.
190
213
def get(self, fileid, suffix=None):
191
214
"""See Store.get()."""
192
if suffix is None or suffix == 'gz':
193
fn = self._relpath(fileid)
195
fn = self._relpath(fileid, [suffix])
198
except errors.NoSuchFile:
199
raise KeyError(fileid)
215
names = self._id_to_names(fileid, suffix)
218
return self._get(name)
219
except errors.NoSuchFile:
221
raise KeyError(fileid)
201
def __init__(self, a_transport, prefixed=False):
223
def __init__(self, a_transport, prefixed=False, compressed=False):
202
224
assert isinstance(a_transport, transport.Transport)
203
225
super(TransportStore, self).__init__()
204
226
self._transport = a_transport
205
227
self._prefixed = prefixed
206
# conflating the .gz extension and user suffixes was a mistake.
207
# RBC 20051017 - TODO SOON, separate them again.
228
self._compressed = compressed
208
229
self._suffixes = set()
210
231
def _iter_files_recursive(self):
229
250
def __len__(self):
230
251
return len(list(self.__iter__()))
232
def _relpath(self, fileid, suffixes=[]):
253
def _relpath(self, fileid, suffixes=None):
233
254
self._check_fileid(fileid)
234
for suffix in suffixes:
235
if not suffix in self._suffixes:
236
raise ValueError("Unregistered suffix %r" % suffix)
237
self._check_fileid(suffix)
256
for suffix in suffixes:
257
if not suffix in self._suffixes:
258
raise ValueError("Unregistered suffix %r" % suffix)
259
self._check_fileid(suffix)
238
262
if self._prefixed:
239
263
path = [hash_prefix(fileid) + fileid]
257
281
def register_suffix(self, suffix):
258
282
"""Register a suffix as being expected in this store."""
259
283
self._check_fileid(suffix)
285
raise ValueError('You cannot register the "gz" suffix.')
260
286
self._suffixes.add(suffix)
262
288
def total_size(self):
293
319
self.cache_store = store.__class__(LocalTransport(cache_dir))
295
321
def get(self, id):
296
mutter("Cache add %s" % id)
322
mutter("Cache add %s", id)
297
323
if id not in self.cache_store:
298
324
self.cache_store.add(self.source_store.get(id), id)
299
325
return self.cache_store.get(id)
303
329
if self.cache_store.has_id(fileid, suffix):
305
331
if self.source_store.has_id(fileid, suffix):
306
# We could copy at this time
332
# We could asynchronously copy at this time
314
340
if not store_from.listable():
315
341
raise UnlistableStore(store_from)
316
342
ids = [f for f in store_from]
343
mutter('copy_all ids: %r', ids)
317
344
store_to.copy_multi(store_from, ids)
319
def hash_prefix(file_id):
320
return "%02x/" % (adler32(file_id) & 0xff)
346
def hash_prefix(fileid):
347
return "%02x/" % (adler32(fileid) & 0xff)