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
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."""
688
686
WFE = WeaveFormatError
691
# 449 0 4474.6820 2356.5590 bzrlib.weave:556(_extract)
689
# 449 0 4474.6820 2356.5590 breezy.weave:556(_extract)
692
690
# +285282 0 1676.8040 1676.8040 +<isinstance>
693
691
# 1.6 seconds in 'isinstance'.
694
692
# changing the first isinstance:
695
# 449 0 2814.2660 1577.1760 bzrlib.weave:556(_extract)
693
# 449 0 2814.2660 1577.1760 breezy.weave:556(_extract)
696
694
# +140414 0 762.8050 762.8050 +<isinstance>
697
695
# note that the inline time actually dropped (less function calls)
698
696
# and total processing time was halved.
699
697
# we're still spending ~1/4 of the method in isinstance though.
700
698
# so lets hard code the acceptable string classes we expect:
701
# 449 0 1202.9420 786.2930 bzrlib.weave:556(_extract)
699
# 449 0 1202.9420 786.2930 breezy.weave:556(_extract)
702
700
# +71352 0 377.5560 377.5560 +<method 'append' of 'list'
704
702
# yay, down to ~1/4 the initial extract time, and our inline time
705
703
# has shrunk again, with isinstance no longer dominating.
706
704
# tweaking the stack inclusion test to use a set gives:
707
# 449 0 1122.8030 713.0080 bzrlib.weave:556(_extract)
705
# 449 0 1122.8030 713.0080 breezy.weave:556(_extract)
708
706
# +71352 0 354.9980 354.9980 +<method 'append' of 'list'
710
708
# - a 5% win, or possibly just noise. However with large istacks that
751
749
NOT FOR PUBLIC USE.
753
if isinstance(name_or_index, (int, long)):
751
# GZ 2017-04-01: This used to check for long as well, but I don't think
752
# there are python implementations with sys.maxsize > sys.maxint
753
if isinstance(name_or_index, int):
754
754
return name_or_index
756
756
return self._lookup(name_or_index)
878
878
raise errors.WeaveTextDiffers(name, self, other)
879
879
self_parents = self._parents[this_idx]
880
880
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])
881
n1 = {self._names[i] for i in self_parents}
882
n2 = {other._names[i] for i in other_parents}
883
883
if not self._compatible_parents(n1, n2):
884
884
raise WeaveParentMismatch("inconsistent parents "
885
885
"for version {%s}: %s vs %s" % (name, n1, n2))
920
920
self._transport = transport
921
921
self._filemode = filemode
923
_read_weave_v5(self._transport.get(name + WeaveFile.WEAVE_SUFFIX), self)
923
f = self._transport.get(name + WeaveFile.WEAVE_SUFFIX)
924
_read_weave_v5(BytesIO(f.read()), self)
924
925
except errors.NoSuchFile:
940
941
def copy_to(self, name, transport):
941
942
"""See VersionedFile.copy_to()."""
942
943
# as we are all in memory always, just serialise to the new place.
944
945
write_weave_v5(self, sio)
946
947
transport.put_file(name + WeaveFile.WEAVE_SUFFIX, sio, self._filemode)
985
986
:param msg: An optional message for the progress
989
queue_a = range(wa.num_versions())
990
queue_b = range(wb.num_versions())
991
989
# first determine combined parents of all versions
992
990
# map from version name -> all parent names
993
991
combined_parents = _reweave_parent_graphs(wa, wb)
994
992
mutter("combined parents: %r", combined_parents)
995
order = tsort.topo_sort(combined_parents.iteritems())
993
order = tsort.topo_sort(combined_parents.items())
996
994
mutter("order to reweave: %r", order)
998
996
if pb and not msg: