1
# Copyright (C) 2005, 2006, 2008, 2009, 2010 Canonical Ltd
1
# Copyright (C) 2005 by Canonical Development Ltd
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.
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.
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
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""A store that keeps the full text of every version.
20
20
do any sort of delta compression.
23
from __future__ import absolute_import
25
from bzrlib.trace import mutter
26
from bzrlib.errors import BzrError, NoSuchFile, FileExists
28
from .... import osutils
29
from ....errors import BzrError, NoSuchFile, FileExists
30
from ....sixish import (
33
from . import TransportStore
34
from ....trace import mutter
37
class TextStore(TransportStore):
29
from cStringIO import StringIO
32
class TextStore(bzrlib.store.TransportStore):
38
33
"""Store that holds files indexed by unique names.
40
35
Files can be added, but not modified once they are in. Typically
47
42
def _add_compressed(self, fn, f):
48
if isinstance(f, bytes):
43
from cStringIO import StringIO
44
from bzrlib.osutils import pumpfile
46
if isinstance(f, basestring):
52
50
gf = gzip.GzipFile(mode='wb', fileobj=sio)
53
51
# if pumpfile handles files that don't fit in ram,
54
52
# so will this function
55
osutils.pumpfile(f, gf)
58
56
self._try_put(fn, sio)
66
64
def _try_put(self, fn, f):
68
self._transport.put_file(fn, f, mode=self._file_mode)
66
self._transport.put(fn, f, mode=self._file_mode)
70
68
if not self._prefixed:
73
71
self._transport.mkdir(os.path.dirname(fn), mode=self._dir_mode)
76
self._transport.put_file(fn, f, mode=self._file_mode)
74
self._transport.put(fn, f, mode=self._file_mode)
78
76
def _get(self, fn):
79
77
if fn.endswith('.gz'):
82
80
return self._transport.get(fn)
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)
90
mutter('_copy_one: %r, %r', fileid, suffix)
91
path = other._get_name(fileid, suffix)
93
raise KeyError(fileid + '-' + str(suffix))
96
result = other._transport.copy_to([path], self._transport,
99
if not self._prefixed:
102
self._transport.mkdir(self.hash_prefix(fileid)[:-1], mode=self._dir_mode)
105
result = other._transport.copy_to([path], self._transport,
106
mode=self._file_mode)
109
raise BzrError('Unable to copy file: %r' % (path,))
84
111
def _get_compressed(self, filename):
85
112
"""Returns a file reading from a particular entry."""
86
113
f = self._transport.get(filename)
87
114
# gzip.GzipFile.read() requires a tell() function
88
115
# but some transports return objects that cannot seek
89
# so buffer them in a BytesIO instead
90
if getattr(f, 'tell', None) is not None:
116
# so buffer them in a StringIO instead
117
if hasattr(f, 'tell'):
91
118
return gzip.GzipFile(mode='rb', fileobj=f)
93
sio = BytesIO(f.read())
120
from cStringIO import StringIO
121
sio = StringIO(f.read())
94
122
return gzip.GzipFile(mode='rb', fileobj=sio)
125
def ScratchTextStore():
126
return TextStore(ScratchTransport())