~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/store/__init__.py

[merge] much integrated work from robert and john

Show diffs side-by-side

added added

removed removed

Lines of Context:
54
54
    def __len__(self):
55
55
        raise NotImplementedError('Children should define their length')
56
56
 
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.
59
59
        
60
 
        If suffix is present, retrieve the named suffix for file_id.
 
60
        If suffix is present, retrieve the named suffix for fileid.
61
61
        """
62
62
        raise NotImplementedError
63
63
 
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
67
67
 
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.')
78
78
 
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.
81
81
        
82
82
        suffix, if present, is a per file suffix, i.e. for digital signature 
83
83
        data."""
136
136
        should call this if they have no optimised facility for a 
137
137
        specific 'other'.
138
138
        """
 
139
        mutter('Store._copy_one: %r', fileid)
139
140
        f = other.get(fileid, suffix)
140
141
        self.add(f, fileid, suffix)
141
142
 
148
149
 
149
150
        f -- A file-like object, or string
150
151
        """
151
 
        mutter("add store entry %r" % (fileid))
 
152
        mutter("add store entry %r", fileid)
152
153
        
153
 
        if suffix is not None:
154
 
            fn = self._relpath(fileid, [suffix])
155
 
        else:
156
 
            fn = self._relpath(fileid)
157
 
        if self._transport.has(fn):
158
 
            raise BzrError("store %r already contains id %r" % (self._transport.base, fileid))
159
 
 
160
 
        if self._prefixed:
161
 
            try:
162
 
                self._transport.mkdir(hash_prefix(fileid)[:-1])
163
 
            except errors.FileExists:
164
 
                pass
165
 
 
166
 
        self._add(fn, f)
 
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))
 
158
 
 
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)
 
163
 
 
164
 
 
165
    def _add(self, relpath, f):
 
166
        """Actually add the file to the given location.
 
167
        This should be overridden by children.
 
168
        """
 
169
        raise NotImplementedError('children need to implement this function.')
167
170
 
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)
173
176
 
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])
178
181
        else:
179
182
            fn = self._relpath(fileid)
180
 
        return self._transport.has(fn)
 
183
 
 
184
        fn_gz = fn + '.gz'
 
185
        if self._compressed:
 
186
            return fn_gz, fn
 
187
        else:
 
188
            return fn, fn_gz
 
189
 
 
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))
 
193
 
 
194
    def _get_name(self, fileid, suffix=None):
 
195
        """A special check, which returns the name of an existing file.
 
196
        
 
197
        This is similar in spirit to 'has_id', but it is designed
 
198
        to return information about which file the store has.
 
199
        """
 
200
        for name in self._id_to_names(fileid, suffix=suffix):
 
201
            if self._transport.has(name):
 
202
                return name
 
203
        return None
181
204
 
182
205
    def _get(self, filename):
183
206
        """Return an vanilla file stream for clients to read from.
189
212
 
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)
194
 
        else:
195
 
            fn = self._relpath(fileid, [suffix])
196
 
        try:
197
 
            return self._get(fn)
198
 
        except errors.NoSuchFile:
199
 
            raise KeyError(fileid)
 
215
        names = self._id_to_names(fileid, suffix)
 
216
        for name in names:
 
217
            try:
 
218
                return self._get(name)
 
219
            except errors.NoSuchFile:
 
220
                pass
 
221
        raise KeyError(fileid)
200
222
 
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()
209
230
 
210
231
    def _iter_files_recursive(self):
229
250
    def __len__(self):
230
251
        return len(list(self.__iter__()))
231
252
 
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)
 
255
        if suffixes:
 
256
            for suffix in suffixes:
 
257
                if not suffix in self._suffixes:
 
258
                    raise ValueError("Unregistered suffix %r" % suffix)
 
259
                self._check_fileid(suffix)
 
260
        else:
 
261
            suffixes = []
238
262
        if self._prefixed:
239
263
            path = [hash_prefix(fileid) + fileid]
240
264
        else:
257
281
    def register_suffix(self, suffix):
258
282
        """Register a suffix as being expected in this store."""
259
283
        self._check_fileid(suffix)
 
284
        if suffix == 'gz':
 
285
            raise ValueError('You cannot register the "gz" suffix.')
260
286
        self._suffixes.add(suffix)
261
287
 
262
288
    def total_size(self):
293
319
        self.cache_store = store.__class__(LocalTransport(cache_dir))
294
320
 
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):
304
330
            return True
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
307
333
            return True
308
334
        return False
309
335
 
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)
318
345
 
319
 
def hash_prefix(file_id):
320
 
    return "%02x/" % (adler32(file_id) & 0xff)
 
346
def hash_prefix(fileid):
 
347
    return "%02x/" % (adler32(fileid) & 0xff)
321
348