17
17
# Author: Martin Pool <mbp@canonical.com>
20
19
"""Weave - storage of related text file versions"""
21
from __future__ import absolute_import
23
23
# XXX: If we do weaves this way, will a merge still behave the same
24
24
# way if it's done in a different order? That's a pretty desirable
67
67
# FIXME: the conflict markers should be *7* characters
69
69
from copy import copy
70
from cStringIO import StringIO
73
from bzrlib.lazy_import import lazy_import
72
from ..lazy_import import lazy_import
74
73
lazy_import(globals(), """
75
from bzrlib import tsort
74
from breezy import tsort
81
from bzrlib.errors import (WeaveError, WeaveFormatError, WeaveParentMismatch,
80
from ..errors import (WeaveError, WeaveFormatError, WeaveParentMismatch,
82
81
RevisionAlreadyPresent,
83
82
RevisionNotPresent,
84
83
UnavailableRepresentation,
86
from bzrlib.osutils import dirname, sha, sha_strings, split_lines
87
import bzrlib.patiencediff
88
from bzrlib.revision import NULL_REVISION
89
from bzrlib.symbol_versioning import *
90
from bzrlib.trace import mutter
91
from bzrlib.versionedfile import (
85
from ..osutils import dirname, sha, sha_strings, split_lines
86
from .. import patiencediff
87
from ..revision import NULL_REVISION
88
from ..sixish import (
91
from ..trace import mutter
92
from .versionedfile import (
92
93
AbsentContentFactory,
95
96
sort_groupcompress,
98
from bzrlib.weavefile import _read_weave_v5, write_weave_v5
99
from .weavefile import _read_weave_v5, write_weave_v5
101
102
class WeaveContentFactory(ContentFactory):
391
392
def _add_lines(self, version_id, parents, lines, parent_texts,
392
393
left_matching_blocks, nostore_sha, random_id, check_content):
393
394
"""See VersionedFile.add_lines."""
394
idx = self._add(version_id, lines, map(self._lookup, parents),
395
idx = self._add(version_id, lines, list(map(self._lookup, parents)),
395
396
nostore_sha=nostore_sha)
396
397
return sha_strings(lines), sum(map(len, lines)), idx
425
426
return self._check_repeated_add(version_id, parents, lines, sha1)
427
428
self._check_versions(parents)
428
## self._check_lines(lines)
429
429
new_version = len(self._parents)
431
431
# if we abort after here the (in-memory) weave will be corrupt because only
520
520
if not len(versions):
522
522
i = set(versions)
523
for v in xrange(max(versions), 0, -1):
523
for v in range(max(versions), 0, -1):
525
525
# include all its parents
526
526
i.update(self._parents[v])
528
## except IndexError:
529
## raise ValueError("version %d not present in weave" % v)
531
529
def get_ancestry(self, version_ids, topo_sorted=True):
532
530
"""See VersionedFile.get_ancestry."""
533
if isinstance(version_ids, basestring):
531
if isinstance(version_ids, bytes):
534
532
version_ids = [version_ids]
535
533
i = self._inclusions([self._lookup(v) for v in version_ids])
536
534
return [self._idx_to_name(v) for v in i]
538
def _check_lines(self, text):
539
if not isinstance(text, list):
540
raise ValueError("text should be a list, not %s" % type(text))
543
if not isinstance(l, basestring):
544
raise ValueError("text line should be a string or unicode, not %s"
549
536
def _check_versions(self, indexes):
550
537
"""Check everything in the sequence of indexes is valid"""
551
538
for i in indexes:
688
675
WFE = WeaveFormatError
691
# 449 0 4474.6820 2356.5590 bzrlib.weave:556(_extract)
678
# 449 0 4474.6820 2356.5590 breezy.weave:556(_extract)
692
679
# +285282 0 1676.8040 1676.8040 +<isinstance>
693
680
# 1.6 seconds in 'isinstance'.
694
681
# changing the first isinstance:
695
# 449 0 2814.2660 1577.1760 bzrlib.weave:556(_extract)
682
# 449 0 2814.2660 1577.1760 breezy.weave:556(_extract)
696
683
# +140414 0 762.8050 762.8050 +<isinstance>
697
684
# note that the inline time actually dropped (less function calls)
698
685
# and total processing time was halved.
699
686
# we're still spending ~1/4 of the method in isinstance though.
700
687
# so lets hard code the acceptable string classes we expect:
701
# 449 0 1202.9420 786.2930 bzrlib.weave:556(_extract)
688
# 449 0 1202.9420 786.2930 breezy.weave:556(_extract)
702
689
# +71352 0 377.5560 377.5560 +<method 'append' of 'list'
704
691
# yay, down to ~1/4 the initial extract time, and our inline time
705
692
# has shrunk again, with isinstance no longer dominating.
706
693
# tweaking the stack inclusion test to use a set gives:
707
# 449 0 1122.8030 713.0080 bzrlib.weave:556(_extract)
694
# 449 0 1122.8030 713.0080 breezy.weave:556(_extract)
708
695
# +71352 0 354.9980 354.9980 +<method 'append' of 'list'
710
697
# - a 5% win, or possibly just noise. However with large istacks that
751
738
NOT FOR PUBLIC USE.
753
if isinstance(name_or_index, (int, long)):
740
# GZ 2017-04-01: This used to check for long as well, but I don't think
741
# there are python implementations with sys.maxsize > sys.maxint
742
if isinstance(name_or_index, int):
754
743
return name_or_index
756
745
return self._lookup(name_or_index)
878
867
raise errors.WeaveTextDiffers(name, self, other)
879
868
self_parents = self._parents[this_idx]
880
869
other_parents = other._parents[other_idx]
881
n1 = set([self._names[i] for i in self_parents])
882
n2 = set([other._names[i] for i in other_parents])
870
n1 = {self._names[i] for i in self_parents}
871
n2 = {other._names[i] for i in other_parents}
883
872
if not self._compatible_parents(n1, n2):
884
873
raise WeaveParentMismatch("inconsistent parents "
885
874
"for version {%s}: %s vs %s" % (name, n1, n2))
920
909
self._transport = transport
921
910
self._filemode = filemode
923
_read_weave_v5(self._transport.get(name + WeaveFile.WEAVE_SUFFIX), self)
912
f = self._transport.get(name + WeaveFile.WEAVE_SUFFIX)
913
_read_weave_v5(BytesIO(f.read()), self)
924
914
except errors.NoSuchFile:
940
930
def copy_to(self, name, transport):
941
931
"""See VersionedFile.copy_to()."""
942
932
# as we are all in memory always, just serialise to the new place.
944
934
write_weave_v5(self, sio)
946
936
transport.put_file(name + WeaveFile.WEAVE_SUFFIX, sio, self._filemode)
985
975
:param msg: An optional message for the progress
989
queue_a = range(wa.num_versions())
990
queue_b = range(wb.num_versions())
991
978
# first determine combined parents of all versions
992
979
# map from version name -> all parent names
993
980
combined_parents = _reweave_parent_graphs(wa, wb)
994
981
mutter("combined parents: %r", combined_parents)
995
order = tsort.topo_sort(combined_parents.iteritems())
982
order = tsort.topo_sort(combined_parents.items())
996
983
mutter("order to reweave: %r", order)
998
985
if pb and not msg: