~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

Merged mailine

Show diffs side-by-side

added added

removed removed

Lines of Context:
67
67
# the possible relationships.
68
68
 
69
69
 
 
70
import os
70
71
import sha
71
72
from difflib import SequenceMatcher
72
73
 
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
77
79
 
78
80
 
483
485
                yield lineno, istack[-1], dset, l
484
486
            lineno += 1
485
487
 
486
 
 
 
488
        if istack:
 
489
            raise WeaveFormatError("unclosed insertion blocks "
 
490
                    "at end of weave: %s" % istack)
 
491
        if dset:
 
492
            raise WeaveFormatError("unclosed deletion blocks at end of weave: %s"
 
493
                                   % dset)
487
494
 
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)]
 
558
        if len(incls) == 1:
 
559
            index = incls[0]
 
560
            cur_sha = sha.new()
 
561
        else:
 
562
            # We don't have sha1 sums for multiple entries
 
563
            cur_sha = None
551
564
        for origin, lineno, line in self._extract(incls):
 
565
            if cur_sha:
 
566
                cur_sha.update(line)
552
567
            yield line
 
568
        if cur_sha:
 
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))
553
576
 
554
577
 
555
578
    def get_text(self, name_or_index):
564
587
    get = get_lines
565
588
 
566
589
 
 
590
    def get_sha1(self, name):
 
591
        """Get the stored sha1 sum for the given revision.
 
592
        
 
593
        :param name: The name of the version to lookup
 
594
        """
 
595
        return self._sha1s[self.lookup(name)]
 
596
 
567
597
    def mash_iter(self, included):
568
598
        """Return composed version of multiple included versions."""
569
599
        included = map(self.maybe_lookup, included)
589
619
    def __len__(self):
590
620
        return self.numversions()
591
621
 
592
 
 
593
622
    def check(self, progress_bar=None):
594
623
        # check no circular inclusions
595
624
        for version in range(self.numversions()):
600
629
                    raise WeaveFormatError("invalid included version %d for index %d"
601
630
                                           % (inclusions[-1], version))
602
631
 
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)]
 
636
        inclusions = []
 
637
        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
 
640
            new_inc = set([i])
 
641
            for p in self._parents[i]:
 
642
                new_inc.update(inclusions[p])
 
643
 
 
644
            #assert set(new_inc) == self.inclusions([i]), 'failed %s != %s' % (new_inc, self.inclusions([i]))
 
645
            inclusions.append(new_inc)
 
646
 
 
647
        nlines = len(self._weave)
 
648
 
 
649
        update_text = 'checking weave'
 
650
        if self._weave_name:
 
651
            short_name = os.path.basename(self._weave_name)
 
652
            update_text = 'checking %s' % (short_name,)
 
653
            update_text = update_text[:25]
 
654
 
 
655
        for lineno, insert, deleteset, line in self._walk():
 
656
            if progress_bar:
 
657
                progress_bar.update(update_text, lineno, nlines)
 
658
 
 
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)
 
665
 
606
666
        for version in range(nv):
607
 
            if progress_bar:
608
 
                progress_bar.update('checking text', version, nv)
609
 
            s = sha.new()
610
 
            for l in self.get_iter(version):
611
 
                s.update(l)
612
 
            hd = s.hexdigest()
 
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))
618
674
 
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.
622
678
 
623
 
 
624
679
    def _delta(self, included, lines):
625
680
        """Return changes from basis to new revision.
626
681