/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/store/__init__.py

  • Committer: Robert Collins
  • Date: 2008-08-20 02:07:36 UTC
  • mfrom: (3640 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3682.
  • Revision ID: robertc@robertcollins.net-20080820020736-g2xe4921zzxtymle
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 by Canonical Development Ltd
2
 
 
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
# compressed or not.
19
19
 
20
20
"""
21
 
Stores are the main data-storage mechanism for Bazaar-NG.
 
21
Stores are the main data-storage mechanism for Bazaar.
22
22
 
23
23
A store is a simple write-once container indexed by a universally
24
24
unique ID.
30
30
from zlib import adler32
31
31
 
32
32
import bzrlib
33
 
import bzrlib.errors as errors
 
33
from bzrlib import (
 
34
    errors,
 
35
    osutils,
 
36
    symbol_versioning,
 
37
    urlutils,
 
38
    versionedfile,
 
39
    )
34
40
from bzrlib.errors import BzrError, UnlistableStore, TransportNotPossible
35
 
from bzrlib.symbol_versioning import *
 
41
from bzrlib.symbol_versioning import (
 
42
    deprecated_function,
 
43
    )
36
44
from bzrlib.trace import mutter
37
45
from bzrlib.transport import Transport
38
46
from bzrlib.transport.local import LocalTransport
39
 
import bzrlib.urlutils as urlutils
40
47
 
41
48
######################################################################
42
49
# stores
67
74
        """DEPRECATED. Please use .get(fileid) instead."""
68
75
        raise NotImplementedError
69
76
 
70
 
    #def __contains__(self, fileid):
71
 
    #    """Deprecated, please use has_id"""
72
 
    #    raise NotImplementedError
73
 
 
74
77
    def __iter__(self):
75
78
        raise NotImplementedError
76
79
 
87
90
 
88
91
    def listable(self):
89
92
        """Return True if this store is able to be listed."""
90
 
        return hasattr(self, "__iter__")
 
93
        return (getattr(self, "__iter__", None) is not None)
91
94
 
92
95
    def copy_all_ids(self, store_from, pb=None):
93
96
        """Copy all the file ids from store_from into self."""
121
124
            pb.update('preparing to copy')
122
125
        failed = set()
123
126
        count = 0
124
 
        ids = list(ids) # get the list for showing a length.
125
127
        for fileid in ids:
126
128
            count += 1
127
129
            if self.has_id(fileid):
140
142
                    failed.add(fileid)
141
143
                else:
142
144
                    raise
143
 
        assert count == len(ids)
144
145
        if pb:
145
146
            pb.clear()
146
147
        return count, failed
164
165
    def add(self, f, fileid, suffix=None):
165
166
        """Add contents of a file into the store.
166
167
 
167
 
        f -- A file-like object, or string
 
168
        f -- A file-like object
168
169
        """
169
170
        mutter("add store entry %r", fileid)
170
 
        
171
171
        names = self._id_to_names(fileid, suffix)
172
172
        if self._transport.has_any(names):
173
173
            raise BzrError("store %r already contains id %r" 
178
178
        # doesn't exist), then create the dir, and try again
179
179
        self._add(names[0], f)
180
180
 
181
 
 
182
181
    def _add(self, relpath, f):
183
182
        """Actually add the file to the given location.
184
183
        This should be overridden by children.
186
185
        raise NotImplementedError('children need to implement this function.')
187
186
 
188
187
    def _check_fileid(self, fileid):
189
 
        if not isinstance(fileid, basestring):
190
 
            raise TypeError('Fileids should be a string type: %s %r' % (type(fileid), fileid))
 
188
        if type(fileid) != str:
 
189
            raise TypeError('Fileids should be bytestrings: %s %r' % (
 
190
                type(fileid), fileid))
191
191
        if '\\' in fileid or '/' in fileid:
192
192
            raise ValueError("invalid store id %r" % fileid)
193
193
 
241
241
    def __init__(self, a_transport, prefixed=False, compressed=False,
242
242
                 dir_mode=None, file_mode=None,
243
243
                 escaped=False):
244
 
        assert isinstance(a_transport, Transport)
245
244
        super(TransportStore, self).__init__()
246
245
        self._transport = a_transport
247
246
        self._prefixed = prefixed
254
253
        # will just use the filesystem defaults
255
254
        self._dir_mode = dir_mode
256
255
        self._file_mode = file_mode
257
 
 
258
 
    def _unescape(self, file_id):
259
 
        """If filename escaping is enabled for this store, unescape and return the filename."""
260
 
        if self._escaped:
261
 
            return urllib.unquote(file_id)
 
256
        # Create a key mapper to use
 
257
        if escaped and prefixed:
 
258
            self._mapper = versionedfile.HashEscapedPrefixMapper()
 
259
        elif not escaped and prefixed:
 
260
            self._mapper = versionedfile.HashPrefixMapper()
 
261
        elif self._escaped:
 
262
            raise ValueError(
 
263
                "%r: escaped unprefixed stores are not permitted."
 
264
                % (self,))
262
265
        else:
263
 
            return file_id
 
266
            self._mapper = versionedfile.PrefixMapper()
264
267
 
265
268
    def _iter_files_recursive(self):
266
269
        """Iterate through the files in the transport."""
267
270
        for quoted_relpath in self._transport.iter_files_recursive():
268
 
            # transport iterator always returns quoted paths, regardless of
269
 
            # escaping
270
 
            yield urllib.unquote(quoted_relpath)
 
271
            yield quoted_relpath
271
272
 
272
273
    def __iter__(self):
273
274
        for relpath in self._iter_files_recursive():
281
282
                    if name.endswith('.' + suffix):
282
283
                        skip = True
283
284
            if not skip:
284
 
                yield self._unescape(name)
 
285
                yield self._mapper.unmap(name)[0]
285
286
 
286
287
    def __len__(self):
287
288
        return len(list(self.__iter__()))
295
296
                self._check_fileid(suffix)
296
297
        else:
297
298
            suffixes = []
298
 
        fileid = self._escape_file_id(fileid)
299
 
        if self._prefixed:
300
 
            # hash_prefix adds the '/' separator
301
 
            prefix = self.hash_prefix(fileid, escaped=True)
302
 
        else:
303
 
            prefix = ''
304
 
        path = prefix + fileid
305
 
        full_path = u'.'.join([path] + suffixes)
306
 
        return urlutils.escape(full_path)
307
 
 
308
 
    def _escape_file_id(self, file_id):
309
 
        """Turn a file id into a filesystem safe string.
310
 
 
311
 
        This is similar to a plain urllib.quote, except
312
 
        it uses specific safe characters, so that it doesn't
313
 
        have to translate a lot of valid file ids.
314
 
        """
315
 
        if not self._escaped:
316
 
            return file_id
317
 
        if isinstance(file_id, unicode):
318
 
            file_id = file_id.encode('utf-8')
319
 
        # @ does not get escaped. This is because it is a valid
320
 
        # filesystem character we use all the time, and it looks
321
 
        # a lot better than seeing %40 all the time.
322
 
        safe = "abcdefghijklmnopqrstuvwxyz0123456789-_@,."
323
 
        r = [((c in safe) and c or ('%%%02x' % ord(c)))
324
 
             for c in file_id]
325
 
        return ''.join(r)
326
 
 
327
 
    def hash_prefix(self, fileid, escaped=False):
328
 
        # fileid should be unescaped
329
 
        if not escaped and self._escaped:
330
 
            fileid = self._escape_file_id(fileid)
331
 
        return "%02x/" % (adler32(fileid) & 0xff)
 
299
        path = self._mapper.map((fileid,))
 
300
        full_path = '.'.join([path] + suffixes)
 
301
        return full_path
332
302
 
333
303
    def __repr__(self):
334
304
        if self._transport is None:
361
331
            total += self._transport.stat(relpath).st_size
362
332
                
363
333
        return count, total
364
 
 
365
 
 
366
 
@deprecated_function(zero_eight)
367
 
def copy_all(store_from, store_to, pb=None):
368
 
    """Copy all ids from one store to another."""
369
 
    store_to.copy_all_ids(store_from, pb)