24
24
import os, tempfile
26
26
import bzrlib.store
27
from bzrlib.store import hash_prefix
27
28
from bzrlib.trace import mutter
28
from bzrlib.errors import BzrError
29
from bzrlib.errors import BzrError, FileExists
30
31
from cStringIO import StringIO
31
from stat import ST_SIZE
32
from stat import ST_SIZE, ST_MODE, S_ISDIR
34
35
class TextStore(bzrlib.store.TransportStore):
41
42
Files are stored uncompressed, with no delta compression.
44
def __init__(self, transport):
45
def __init__(self, transport, prefixed=False):
45
46
super(TextStore, self).__init__(transport)
47
self._prefixed = prefixed
47
49
def _check_fileid(self, fileid):
48
50
if not isinstance(fileid, basestring):
53
55
def _relpath(self, fileid):
54
56
self._check_fileid(fileid)
58
return hash_prefix(fileid) + fileid
57
62
def add(self, f, fileid):
58
63
"""Add contents of a file into the store.
65
70
if self._transport.has(fn):
66
71
raise BzrError("store %r already contains id %r" % (self._transport.base, fileid))
75
self._transport.mkdir(hash_prefix(fileid))
68
79
self._transport.put(fn, f)
70
def _do_copy(self, other, to_copy, pb, permit_failure=False):
71
if isinstance(other, TextStore):
72
return self._copy_multi_text(other, to_copy, pb,
73
permit_failure=permit_failure)
74
return super(TextStore, self)._do_copy(other, to_copy,
75
pb, permit_failure=permit_failure)
77
def _copy_multi_text(self, other, to_copy, pb,
78
permit_failure=False):
79
# Because of _transport, we can no longer assume
80
# that they are on the same filesystem, we can, however
81
# assume that we only need to copy the exact bytes,
82
# we don't need to process the files.
87
for fileid, has in zip(to_copy, other.has(to_copy)):
89
new_to_copy.add(fileid)
93
#mutter('_copy_multi_text copying %s, failed %s' % (to_copy, failed))
95
paths = [self._relpath(fileid) for fileid in to_copy]
96
count = other._transport.copy_to(paths, self._transport, pb=pb)
97
assert count == len(to_copy)
100
81
def __contains__(self, fileid):
102
83
fn = self._relpath(fileid)
140
def _iter_relpaths(self):
141
transport = self._transport
142
queue = list(transport.list_dir('.'))
144
relpath = queue.pop(0)
145
st = transport.stat(relpath)
146
if S_ISDIR(st[ST_MODE]):
147
for i, basename in enumerate(transport.list_dir(relpath)):
148
queue.insert(i, relpath+'/'+basename)
159
152
def __iter__(self):
160
# TODO: case-insensitive?
161
for f in self._transport.list_dir('.'):
153
for relpath, st in self._iter_relpaths():
154
yield os.path.basename(relpath)
164
156
def __len__(self):
165
return len([f for f in self._transport.list_dir('.')])
157
return len(list(self._iter_relpath()))
168
159
def __getitem__(self, fileid):
169
160
"""Returns a file reading from a particular entry."""