~bzr-pqm/bzr/bzr.dev

1393.2.2 by John Arbash Meinel
Updated stores to use Transport
1
# Copyright (C) 2005 by Canonical Development Ltd
2
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1608.2.1 by Martin Pool
[merge] Storage filename escaping
17
"""A store that keeps the full text of every version.
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
18
19
This store keeps uncompressed versions of the full text. It does not
20
do any sort of delta compression.
21
"""
22
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
23
import os
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
24
import bzrlib.store
25
from bzrlib.trace import mutter
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
26
from bzrlib.errors import BzrError, NoSuchFile, FileExists
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
27
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
28
import gzip
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
29
from cStringIO import StringIO
30
1092.2.24 by Robert Collins
merge from martins newformat branch - brings in transport abstraction
31
32
class TextStore(bzrlib.store.TransportStore):
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
33
    """Store that holds files indexed by unique names.
34
35
    Files can be added, but not modified once they are in.  Typically
36
    the hash is used as the name, or something else known to be unique,
37
    such as a UUID.
38
1393.2.4 by John Arbash Meinel
All tests pass.
39
    Files are stored uncompressed, with no delta compression.
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
40
    """
41
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
42
    def _add_compressed(self, fn, f):
43
        from cStringIO import StringIO
44
        from bzrlib.osutils import pumpfile
45
        
46
        if isinstance(f, basestring):
47
            f = StringIO(f)
48
            
49
        sio = StringIO()
50
        gf = gzip.GzipFile(mode='wb', fileobj=sio)
51
        # if pumpfile handles files that don't fit in ram,
52
        # so will this function
53
        pumpfile(f, gf)
54
        gf.close()
55
        sio.seek(0)
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
56
        self._try_put(fn, sio)
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
57
1442.1.28 by Robert Collins
pull up core TransportStore.add from TextStore.add and CompressedTextStore.add
58
    def _add(self, fn, f):
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
59
        if self._compressed:
60
            self._add_compressed(fn, f)
61
        else:
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
62
            self._try_put(fn, f)
63
64
    def _try_put(self, fn, f):
65
        try:
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
66
            self._transport.put(fn, f, mode=self._file_mode)
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
67
        except NoSuchFile:
68
            if not self._prefixed:
69
                raise
70
            try:
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
71
                self._transport.mkdir(os.path.dirname(fn), mode=self._dir_mode)
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
72
            except FileExists:
73
                pass
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
74
            self._transport.put(fn, f, mode=self._file_mode)
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
75
1442.1.39 by Robert Collins
unify has() implementations for TransportStore classes
76
    def _get(self, fn):
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
77
        if fn.endswith('.gz'):
78
            return self._get_compressed(fn)
79
        else:
80
            return self._transport.get(fn)
81
82
    def _copy_one(self, fileid, suffix, other, pb):
83
        # TODO: Once the copy_to interface is improved to allow a source
84
        #       and destination targets, then we can always do the copy
85
        #       as long as other is a TextStore
86
        if not (isinstance(other, TextStore)
87
            and other._prefixed == self._prefixed):
88
            return super(TextStore, self)._copy_one(fileid, suffix, other, pb)
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
89
90
        mutter('_copy_one: %r, %r', fileid, suffix)
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
91
        path = other._get_name(fileid, suffix)
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
92
        if path is None:
93
            raise KeyError(fileid + '-' + str(suffix))
94
95
        try:
1608.2.1 by Martin Pool
[merge] Storage filename escaping
96
            result = other._transport.copy_to([path], self._transport,
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
97
                                              mode=self._file_mode)
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
98
        except NoSuchFile:
99
            if not self._prefixed:
100
                raise
101
            try:
1608.2.1 by Martin Pool
[merge] Storage filename escaping
102
                self._transport.mkdir(self.hash_prefix(fileid)[:-1], mode=self._dir_mode)
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
103
            except FileExists:
104
                pass
1551.3.11 by Aaron Bentley
Merge from Robert
105
            result = other._transport.copy_to([path], self._transport,
1185.58.4 by John Arbash Meinel
Added permission checking to Branch, and propogated that change into the stores.
106
                                              mode=self._file_mode)
1185.16.159 by John Arbash Meinel
Updated the stores, all tests pass, and a store doesn't have to be 100% compressed
107
1185.16.157 by John Arbash Meinel
Added ability for TextStore to handle both compressed and uncompressed, it just looks for one type first
108
        if result != 1:
109
            raise BzrError('Unable to copy file: %r' % (path,))
110
111
    def _get_compressed(self, filename):
112
        """Returns a file reading from a particular entry."""
113
        f = self._transport.get(filename)
114
        # gzip.GzipFile.read() requires a tell() function
115
        # but some transports return objects that cannot seek
116
        # so buffer them in a StringIO instead
117
        if hasattr(f, 'tell'):
118
            return gzip.GzipFile(mode='rb', fileobj=f)
119
        else:
120
            from cStringIO import StringIO
121
            sio = StringIO(f.read())
122
            return gzip.GzipFile(mode='rb', fileobj=sio)