67
67
# the possible relationships.
71
72
from difflib import SequenceMatcher
73
74
from bzrlib.trace import mutter
74
from bzrlib.errors import WeaveError, WeaveFormatError, WeaveParentMismatch, \
75
WeaveRevisionNotPresent, WeaveRevisionAlreadyPresent
75
from bzrlib.errors import (WeaveError, WeaveFormatError, WeaveParentMismatch,
76
WeaveRevisionNotPresent, WeaveRevisionAlreadyPresent)
77
import bzrlib.errors as errors
76
78
from bzrlib.tsort import topo_sort
483
485
yield lineno, istack[-1], dset, l
489
raise WeaveFormatError("unclosed insertion blocks "
490
"at end of weave: %s" % istack)
492
raise WeaveFormatError("unclosed deletion blocks at end of weave: %s"
488
495
def _extract(self, versions):
489
496
"""Yield annotation of lines in included set.
548
555
def get_iter(self, name_or_index):
549
556
"""Yield lines for the specified version."""
550
557
incls = [self.maybe_lookup(name_or_index)]
562
# We don't have sha1 sums for multiple entries
551
564
for origin, lineno, line in self._extract(incls):
569
expected_sha1 = self._sha1s[index]
570
measured_sha1 = cur_sha.hexdigest()
571
if measured_sha1 != expected_sha1:
572
raise errors.WeaveInvalidChecksum(
573
'file %s, revision %s, expected: %s, measured %s'
574
% (self._weave_name, self._names[index],
575
expected_sha1, measured_sha1))
555
578
def get_text(self, name_or_index):
590
def get_sha1(self, name):
591
"""Get the stored sha1 sum for the given revision.
593
:param name: The name of the version to lookup
595
return self._sha1s[self.lookup(name)]
567
597
def mash_iter(self, included):
568
598
"""Return composed version of multiple included versions."""
569
599
included = map(self.maybe_lookup, included)
600
629
raise WeaveFormatError("invalid included version %d for index %d"
601
630
% (inclusions[-1], version))
603
# try extracting all versions; this is a bit slow and parallel
604
# extraction could be used
632
# try extracting all versions; parallel extraction is used
605
633
nv = self.numversions()
634
sha1s = [sha.new() for i in range(nv)]
635
texts = [[] for i in range(nv)]
638
# For creating the ancestry, IntSet is much faster (3.7s vs 0.17s)
639
# The problem is that set membership is much more expensive
641
for p in self._parents[i]:
642
new_inc.update(inclusions[p])
644
#assert set(new_inc) == self.inclusions([i]), 'failed %s != %s' % (new_inc, self.inclusions([i]))
645
inclusions.append(new_inc)
647
nlines = len(self._weave)
649
update_text = 'checking weave'
651
short_name = os.path.basename(self._weave_name)
652
update_text = 'checking %s' % (short_name,)
653
update_text = update_text[:25]
655
for lineno, insert, deleteset, line in self._walk():
657
progress_bar.update(update_text, lineno, nlines)
659
for j, j_inc in enumerate(inclusions):
660
# The active inclusion must be an ancestor,
661
# and no ancestors must have deleted this line,
662
# because we don't support resurrection.
663
if (insert in j_inc) and not (deleteset & j_inc):
664
sha1s[j].update(line)
606
666
for version in range(nv):
608
progress_bar.update('checking text', version, nv)
610
for l in self.get_iter(version):
667
hd = sha1s[version].hexdigest()
613
668
expected = self._sha1s[version]
614
669
if hd != expected:
615
raise WeaveError("mismatched sha1 for version %d; "
616
"got %s, expected %s"
617
% (version, hd, expected))
670
raise errors.WeaveInvalidChecksum(
671
"mismatched sha1 for version %s: "
672
"got %s, expected %s"
673
% (self._names[version], hd, expected))
619
675
# TODO: check insertions are properly nested, that there are
620
676
# no lines outside of insertion blocks, that deletions are
621
677
# properly paired, etc.
624
679
def _delta(self, included, lines):
625
680
"""Return changes from basis to new revision.
757
817
# work through in index order to make sure we get all dependencies
758
818
for other_idx, name in enumerate(other._names):
759
if self._check_version_consistent(other, other_idx, name):
819
self._check_version_consistent(other, other_idx, name)
761
824
for other_idx, name in enumerate(other._names):
762
# TODO: If all the parents of the other version are already
825
# TODO: If all the parents of the other version are already
763
826
# present then we can avoid some work by just taking the delta
764
827
# and adjusting the offsets.
765
828
new_parents = self._imported_parents(other, other_idx)
829
sha1 = other._sha1s[other_idx]
833
if name in self._names:
834
idx = self.lookup(name)
835
n1 = map(other.idx_to_name, other._parents[other_idx] )
836
n2 = map(self.idx_to_name, self._parents[other_idx] )
837
if sha1 == self._sha1s[idx] and n1 == n2:
766
841
lines = other.get_lines(other_idx)
767
sha1 = other._sha1s[other_idx]
768
842
self.add(name, new_parents, lines, sha1)
844
mutter("merged = %d, processed = %d, file_id=%s; deltat=%d"%(
845
merged,processed,self._weave_name, time.time( )-time0))
771
850
def _imported_parents(self, other, other_idx):
772
851
"""Return list of parents in self corresponding to indexes in other."""