40
41
FILE_SUFFIX = '.weave'
42
def __init__(self, transport, prefixed=False, precious=False):
43
self._transport = transport
44
self._prefixed = prefixed
43
def __init__(self, transport, prefixed=False, precious=False,
44
dir_mode=None, file_mode=None):
45
super(WeaveStore, self).__init__(transport,
46
dir_mode=dir_mode, file_mode=file_mode,
47
prefixed=prefixed, compressed=False)
45
48
self._precious = precious
47
50
def filename(self, file_id):
48
51
"""Return the path relative to the transport root."""
50
return hash_prefix(file_id) + file_id + WeaveStore.FILE_SUFFIX
53
return hash_prefix(file_id) + urllib.quote(file_id) + WeaveStore.FILE_SUFFIX
52
return file_id + WeaveStore.FILE_SUFFIX
55
return urllib.quote(file_id) + WeaveStore.FILE_SUFFIX
54
57
def __iter__(self):
55
58
l = len(WeaveStore.FILE_SUFFIX)
56
for relpath, st in self._iter_relpaths():
59
for relpath in self._iter_files_recursive():
57
60
if relpath.endswith(WeaveStore.FILE_SUFFIX):
58
61
yield os.path.basename(relpath[:-l])
60
def __contains__(self, fileid):
63
def has_id(self, fileid):
62
64
return self._transport.has(self.filename(fileid))
64
66
def _get(self, file_id):
65
67
return self._transport.get(self.filename(file_id))
67
69
def _put(self, file_id, f):
70
self._transport.mkdir(hash_prefix(file_id))
73
return self._transport.put(self.filename(file_id), f)
70
# less round trips to mkdir on failure than mkdir always
72
return self._transport.put(self.filename(file_id), f, mode=self._file_mode)
74
if not self._prefixed:
76
self._transport.mkdir(hash_prefix(file_id), mode=self._dir_mode)
77
return self._transport.put(self.filename(file_id), f, mode=self._file_mode)
75
79
def get_weave(self, file_id, transaction):
76
80
weave = transaction.map.find_weave(file_id)
80
84
w = read_weave(self._get(file_id))
81
85
transaction.map.add_weave(file_id, w)
82
86
transaction.register_clean(w, precious=self._precious)
87
# TODO: jam 20051219 This should check if there is a prelude
88
# which is already cached, and if so, should remove it
89
# But transaction doesn't seem to have a 'remove'
90
# One workaround would be to re-add the object with
94
def get_weave_prelude(self, file_id, transaction):
96
weave = transaction.map.find_weave(weave_id)
98
mutter("cache hit in %s for %s", self, weave_id)
100
# We want transactions to also cache preludes if that
101
# is all that we are loading. So we need a unique
102
# identifier, so that someone who wants the whole text
103
# won't get just the prelude
104
weave_id = 'PRELUDE-' + file_id
105
weave = transaction.map.find_weave(weave_id)
107
mutter("cache hit in %s for %s", self, weave_id)
109
w = read_weave(self._get(file_id), prelude=True)
110
transaction.map.add_weave(weave_id, w)
111
transaction.register_clean(w, precious=self._precious)
85
114
def get_lines(self, file_id, rev_id, transaction):
89
118
w = self.get_weave(file_id, transaction)
90
119
return w.get(w.lookup(rev_id))
121
def get_weave_prelude_or_empty(self, file_id, transaction):
122
"""cheap version that reads the prelude but not the lines
125
return self.get_weave_prelude(file_id, transaction)
127
# We can cache here, because we know that there
128
# is no complete object, since we got NoSuchFile
129
weave = Weave(weave_name=file_id)
130
transaction.map.add_weave(file_id, weave)
131
transaction.register_clean(weave, precious=self._precious)
92
134
def get_weave_or_empty(self, file_id, transaction):
93
135
"""Return a weave, or an empty one if it doesn't exist."""
122
164
w.add_identical(old_rev_id, new_rev_id, parent_idxs)
123
165
self.put_weave(file_id, w, transaction)
125
def copy_multi(self, from_store, file_ids):
167
def copy_multi(self, from_store, file_ids, pb=None):
126
168
assert isinstance(from_store, WeaveStore)
169
for count, f in enumerate(file_ids):
128
170
mutter("copy weave {%s} into %s", f, self)
172
pb.update('copy', count, len(file_ids))
129
173
self._put(f, from_store._get(f))