86
89
WeaveRevisionNotPresent,
88
91
import bzrlib.errors as errors
89
from bzrlib.osutils import sha_strings, split_lines
92
from bzrlib.osutils import dirname, sha, sha_strings, split_lines
90
93
import bzrlib.patiencediff
94
from bzrlib.revision import NULL_REVISION
91
95
from bzrlib.symbol_versioning import *
92
96
from bzrlib.trace import mutter
93
from bzrlib.tsort import topo_sort
94
97
from bzrlib.versionedfile import (
95
98
AbsentContentFactory,
101
103
from bzrlib.weavefile import _read_weave_v5, write_weave_v5
110
112
def __init__(self, version, weave):
111
113
"""Create a WeaveContentFactory for version from weave."""
112
114
ContentFactory.__init__(self)
113
self.sha1 = weave.get_sha1s([version])[0]
115
self.sha1 = weave.get_sha1s([version])[version]
114
116
self.key = (version,)
115
117
parents = weave.get_parent_map([version])[version]
116
118
self.parents = tuple((parent,) for parent in parents)
120
122
def get_bytes_as(self, storage_kind):
121
123
if storage_kind == 'fulltext':
122
return self._weave.get_text(self.key[0])
124
return self._weave.get_text(self.key[-1])
124
126
raise UnavailableRepresentation(self.key, storage_kind, 'fulltext')
216
218
__slots__ = ['_weave', '_parents', '_sha1s', '_names', '_name_map',
217
'_weave_name', '_matcher']
219
def __init__(self, weave_name=None, access_mode='w', matcher=None, get_scope=None):
219
'_weave_name', '_matcher', '_allow_reserved']
221
def __init__(self, weave_name=None, access_mode='w', matcher=None,
222
get_scope=None, allow_reserved=False):
220
223
"""Create a weave.
222
225
:param get_scope: A callable that returns an opaque object to be used
223
226
for detecting when this weave goes out of scope (should stop
224
227
answering requests or allowing mutation).
226
super(Weave, self).__init__(access_mode)
229
super(Weave, self).__init__()
228
231
self._parents = []
307
312
:return: An iterator of ContentFactory objects, each of which is only
308
313
valid until the iterator is advanced.
315
versions = [version[-1] for version in versions]
310
316
if ordering == 'topological':
311
317
parents = self.get_parent_map(versions)
312
new_versions = topo_sort(parents)
318
new_versions = tsort.topo_sort(parents)
313
319
new_versions.extend(set(versions).difference(set(parents)))
314
320
versions = new_versions
315
321
for version in versions:
322
328
"""See VersionedFile.get_parent_map."""
324
330
for version_id in version_ids:
326
result[version_id] = tuple(
327
map(self._idx_to_name, self._parents[self._lookup(version_id)]))
328
except RevisionNotPresent:
331
if version_id == NULL_REVISION:
336
map(self._idx_to_name,
337
self._parents[self._lookup(version_id)]))
338
except RevisionNotPresent:
340
result[version_id] = parents
332
343
def get_parents_with_ghosts(self, version_id):
834
846
# no lines outside of insertion blocks, that deletions are
835
847
# properly paired, etc.
837
def _join(self, other, pb, msg, version_ids, ignore_missing):
838
"""Worker routine for join()."""
839
if not other.versions():
840
return # nothing to update, easy
843
# versions is never none, InterWeave checks this.
846
# two loops so that we do not change ourselves before verifying it
848
# work through in index order to make sure we get all dependencies
851
# get the selected versions only that are in other.versions.
852
version_ids = set(other.versions()).intersection(set(version_ids))
853
# pull in the referenced graph.
854
version_ids = other.get_ancestry(version_ids)
855
pending_parents = other.get_parent_map(version_ids)
856
pending_graph = pending_parents.items()
857
if len(pending_graph) != len(version_ids):
858
raise RevisionNotPresent(
859
set(version_ids) - set(pending_parents.keys()), self)
860
for name in topo_sort(pending_graph):
861
other_idx = other._name_map[name]
862
# returns True if we have it, False if we need it.
863
if not self._check_version_consistent(other, other_idx, name):
864
names_to_join.append((other_idx, name))
872
for other_idx, name in names_to_join:
873
# TODO: If all the parents of the other version are already
874
# present then we can avoid some work by just taking the delta
875
# and adjusting the offsets.
876
new_parents = self._imported_parents(other, other_idx)
877
sha1 = other._sha1s[other_idx]
882
pb.update(msg, merged, len(names_to_join))
884
lines = other.get_lines(other_idx)
885
self._add(name, lines, new_parents, sha1)
887
mutter("merged = %d, processed = %d, file_id=%s; deltat=%d"%(
888
merged, processed, self._weave_name, time.time()-time0))
890
849
def _imported_parents(self, other, other_idx):
891
850
"""Return list of parents in self corresponding to indexes in other."""
955
914
:param create: If not True, only open an existing knit.
957
super(WeaveFile, self).__init__(name, access_mode, get_scope=get_scope)
916
super(WeaveFile, self).__init__(name, access_mode, get_scope=get_scope,
917
allow_reserved=False)
958
918
self._transport = transport
959
919
self._filemode = filemode
990
950
write_weave_v5(self, sio)
992
self._transport.put_file(self._weave_name + WeaveFile.WEAVE_SUFFIX,
952
bytes = sio.getvalue()
953
path = self._weave_name + WeaveFile.WEAVE_SUFFIX
955
self._transport.put_bytes(path, bytes, self._filemode)
956
except errors.NoSuchFile:
957
self._transport.mkdir(dirname(path))
958
self._transport.put_bytes(path, bytes, self._filemode)
997
961
def get_suffixes():
1033
997
# map from version name -> all parent names
1034
998
combined_parents = _reweave_parent_graphs(wa, wb)
1035
999
mutter("combined parents: %r", combined_parents)
1036
order = topo_sort(combined_parents.iteritems())
1000
order = tsort.topo_sort(combined_parents.iteritems())
1037
1001
mutter("order to reweave: %r", order)
1039
1003
if pb and not msg:
1272
1236
if __name__ == '__main__':
1274
1238
sys.exit(main(sys.argv))
1277
class InterWeave(InterVersionedFile):
1278
"""Optimised code paths for weave to weave operations."""
1280
_matching_file_from_factory = staticmethod(WeaveFile)
1281
_matching_file_to_factory = staticmethod(WeaveFile)
1284
def is_compatible(source, target):
1285
"""Be compatible with weaves."""
1287
return (isinstance(source, Weave) and
1288
isinstance(target, Weave))
1289
except AttributeError:
1292
def join(self, pb=None, msg=None, version_ids=None, ignore_missing=False):
1293
"""See InterVersionedFile.join."""
1294
version_ids = self._get_source_version_ids(version_ids, ignore_missing)
1295
if self.target.versions() == [] and version_ids is None:
1296
self.target._copy_weave_content(self.source)
1298
self.target._join(self.source, pb, msg, version_ids, ignore_missing)
1301
InterVersionedFile.register_optimiser(InterWeave)