67
67
# FIXME: the conflict markers should be *7* characters
69
69
from copy import copy
70
from cStringIO import StringIO
72
from ..lazy_import import lazy_import
73
from bzrlib.lazy_import import lazy_import
73
74
lazy_import(globals(), """
74
from breezy import tsort
75
from bzrlib import tsort
80
from ..errors import (
81
RevisionAlreadyPresent,
83
UnavailableRepresentation,
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 (
81
from bzrlib.errors import (WeaveError, WeaveFormatError, WeaveParentMismatch,
82
RevisionAlreadyPresent,
84
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 (
93
92
AbsentContentFactory,
96
95
sort_groupcompress,
99
from .weavefile import _read_weave_v5, write_weave_v5
102
class WeaveError(errors.BzrError):
104
_fmt = "Error in processing weave: %(msg)s"
106
def __init__(self, msg=None):
107
errors.BzrError.__init__(self)
111
class WeaveRevisionAlreadyPresent(WeaveError):
113
_fmt = "Revision {%(revision_id)s} already present in %(weave)s"
115
def __init__(self, revision_id, weave):
117
WeaveError.__init__(self)
118
self.revision_id = revision_id
122
class WeaveRevisionNotPresent(WeaveError):
124
_fmt = "Revision {%(revision_id)s} not present in %(weave)s"
126
def __init__(self, revision_id, weave):
127
WeaveError.__init__(self)
128
self.revision_id = revision_id
132
class WeaveFormatError(WeaveError):
134
_fmt = "Weave invariant violated: %(what)s"
136
def __init__(self, what):
137
WeaveError.__init__(self)
141
class WeaveParentMismatch(WeaveError):
143
_fmt = "Parents are mismatched between two revisions. %(msg)s"
146
class WeaveInvalidChecksum(WeaveError):
148
_fmt = "Text did not match its checksum: %(msg)s"
151
class WeaveTextDiffers(WeaveError):
153
_fmt = ("Weaves differ on text content. Revision:"
154
" {%(revision_id)s}, %(weave_a)s, %(weave_b)s")
156
def __init__(self, revision_id, weave_a, weave_b):
157
WeaveError.__init__(self)
158
self.revision_id = revision_id
159
self.weave_a = weave_a
160
self.weave_b = weave_b
163
class WeaveTextDiffers(WeaveError):
165
_fmt = ("Weaves differ on text content. Revision:"
166
" {%(revision_id)s}, %(weave_a)s, %(weave_b)s")
168
def __init__(self, revision_id, weave_a, weave_b):
169
WeaveError.__init__(self)
170
self.revision_id = revision_id
171
self.weave_a = weave_a
172
self.weave_b = weave_b
98
from bzrlib.weavefile import _read_weave_v5, write_weave_v5
175
101
class WeaveContentFactory(ContentFactory):
465
391
def _add_lines(self, version_id, parents, lines, parent_texts,
466
392
left_matching_blocks, nostore_sha, random_id, check_content):
467
393
"""See VersionedFile.add_lines."""
468
idx = self._add(version_id, lines, list(map(self._lookup, parents)),
394
idx = self._add(version_id, lines, map(self._lookup, parents),
469
395
nostore_sha=nostore_sha)
470
396
return sha_strings(lines), sum(map(len, lines)), idx
510
437
self._names.append(version_id)
511
438
self._name_map[version_id] = new_version
514
442
# special case; adding with no parents revision; can do
515
443
# this more quickly by just appending unconditionally.
516
444
# even more specially, if we're adding an empty text we
517
445
# need do nothing at all.
519
self._weave.append((b'{', new_version))
447
self._weave.append(('{', new_version))
520
448
self._weave.extend(lines)
521
self._weave.append((b'}', None))
449
self._weave.append(('}', None))
522
450
return new_version
524
452
if len(parents) == 1:
592
520
if not len(versions):
594
522
i = set(versions)
595
for v in range(max(versions), 0, -1):
523
for v in xrange(max(versions), 0, -1):
597
525
# include all its parents
598
526
i.update(self._parents[v])
528
## except IndexError:
529
## raise ValueError("version %d not present in weave" % v)
601
531
def get_ancestry(self, version_ids, topo_sorted=True):
602
532
"""See VersionedFile.get_ancestry."""
603
if isinstance(version_ids, bytes):
533
if isinstance(version_ids, basestring):
604
534
version_ids = [version_ids]
605
535
i = self._inclusions([self._lookup(v) for v in version_ids])
606
536
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"
608
549
def _check_versions(self, indexes):
609
550
"""Check everything in the sequence of indexes is valid"""
610
551
for i in indexes:
747
688
WFE = WeaveFormatError
750
# 449 0 4474.6820 2356.5590 breezy.weave:556(_extract)
691
# 449 0 4474.6820 2356.5590 bzrlib.weave:556(_extract)
751
692
# +285282 0 1676.8040 1676.8040 +<isinstance>
752
693
# 1.6 seconds in 'isinstance'.
753
694
# changing the first isinstance:
754
# 449 0 2814.2660 1577.1760 breezy.weave:556(_extract)
695
# 449 0 2814.2660 1577.1760 bzrlib.weave:556(_extract)
755
696
# +140414 0 762.8050 762.8050 +<isinstance>
756
697
# note that the inline time actually dropped (less function calls)
757
698
# and total processing time was halved.
758
699
# we're still spending ~1/4 of the method in isinstance though.
759
700
# so lets hard code the acceptable string classes we expect:
760
# 449 0 1202.9420 786.2930 breezy.weave:556(_extract)
701
# 449 0 1202.9420 786.2930 bzrlib.weave:556(_extract)
761
702
# +71352 0 377.5560 377.5560 +<method 'append' of 'list'
763
704
# yay, down to ~1/4 the initial extract time, and our inline time
764
705
# has shrunk again, with isinstance no longer dominating.
765
706
# tweaking the stack inclusion test to use a set gives:
766
# 449 0 1122.8030 713.0080 breezy.weave:556(_extract)
707
# 449 0 1122.8030 713.0080 bzrlib.weave:556(_extract)
767
708
# +71352 0 354.9980 354.9980 +<method 'append' of 'list'
769
710
# - a 5% win, or possibly just noise. However with large istacks that
770
711
# 'in' test could dominate, so I'm leaving this change in place -
771
712
# when its fast enough to consider profiling big datasets we can review.
773
717
for l in self._weave:
774
718
if l.__class__ == tuple:
781
725
iset.remove(istack.pop())
783
727
if v in included:
786
730
if v in included:
933
875
this_idx = self._name_map.get(name, -1)
934
876
if this_idx != -1:
935
877
if self._sha1s[this_idx] != other._sha1s[other_idx]:
936
raise WeaveTextDiffers(name, self, other)
878
raise errors.WeaveTextDiffers(name, self, other)
937
879
self_parents = self._parents[this_idx]
938
880
other_parents = other._parents[other_idx]
939
n1 = {self._names[i] for i in self_parents}
940
n2 = {other._names[i] for i in other_parents}
881
n1 = set([self._names[i] for i in self_parents])
882
n2 = set([other._names[i] for i in other_parents])
941
883
if not self._compatible_parents(n1, n2):
942
884
raise WeaveParentMismatch("inconsistent parents "
943
885
"for version {%s}: %s vs %s" % (name, n1, n2))
1044
985
:param msg: An optional message for the progress
989
queue_a = range(wa.num_versions())
990
queue_b = range(wb.num_versions())
1047
991
# first determine combined parents of all versions
1048
992
# map from version name -> all parent names
1049
993
combined_parents = _reweave_parent_graphs(wa, wb)
1050
994
mutter("combined parents: %r", combined_parents)
1051
order = tsort.topo_sort(combined_parents.items())
995
order = tsort.topo_sort(combined_parents.iteritems())
1052
996
mutter("order to reweave: %r", order)
1054
998
if pb and not msg:
1068
1012
lines = list(difflib.unified_diff(lines, lines_b,
1069
1013
wa._weave_name, wb._weave_name))
1070
1014
mutter('lines:\n%s', ''.join(lines))
1071
raise WeaveTextDiffers(name, wa, wb)
1015
raise errors.WeaveTextDiffers(name, wa, wb)
1073
1017
lines = wb.get_lines(name)
1074
1018
wr._add(name, lines, [wr._lookup(i) for i in combined_parents[name]])