/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

  • Committer: John Ferlito
  • Date: 2009-09-02 04:31:45 UTC
  • mto: (4665.7.1 serve-init)
  • mto: This revision was merged to the branch mainline in revision 4913.
  • Revision ID: johnf@inodes.org-20090902043145-gxdsfw03ilcwbyn5
Add a debian init script for bzr --serve

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
# Author: Martin Pool <mbp@canonical.com>
18
18
 
 
19
 
19
20
"""Weave - storage of related text file versions"""
20
21
 
 
22
 
21
23
# XXX: If we do weaves this way, will a merge still behave the same
22
24
# way if it's done in a different order?  That's a pretty desirable
23
25
# property.
65
67
# FIXME: the conflict markers should be *7* characters
66
68
 
67
69
from copy import copy
68
 
from io import BytesIO
 
70
from cStringIO import StringIO
69
71
import os
70
 
import patiencediff
 
72
import time
 
73
import warnings
71
74
 
72
 
from ..lazy_import import lazy_import
 
75
from bzrlib.lazy_import import lazy_import
73
76
lazy_import(globals(), """
74
 
from breezy import tsort
 
77
from bzrlib import tsort
75
78
""")
76
 
from .. import (
 
79
from bzrlib import (
77
80
    errors,
78
81
    osutils,
79
 
    )
80
 
from ..errors import (
81
 
    RevisionAlreadyPresent,
82
 
    RevisionNotPresent,
83
 
    )
84
 
from ..osutils import dirname, sha, sha_strings, split_lines
85
 
from ..revision import NULL_REVISION
86
 
from ..trace import mutter
87
 
from .versionedfile import (
 
82
    progress,
 
83
    )
 
84
from bzrlib.errors import (WeaveError, WeaveFormatError, WeaveParentMismatch,
 
85
        RevisionAlreadyPresent,
 
86
        RevisionNotPresent,
 
87
        UnavailableRepresentation,
 
88
        WeaveRevisionAlreadyPresent,
 
89
        WeaveRevisionNotPresent,
 
90
        )
 
91
from bzrlib.osutils import dirname, sha, sha_strings, split_lines
 
92
import bzrlib.patiencediff
 
93
from bzrlib.revision import NULL_REVISION
 
94
from bzrlib.symbol_versioning import *
 
95
from bzrlib.trace import mutter
 
96
from bzrlib.versionedfile import (
88
97
    AbsentContentFactory,
89
98
    adapter_registry,
90
99
    ContentFactory,
91
 
    ExistingContent,
92
100
    sort_groupcompress,
93
 
    UnavailableRepresentation,
94
101
    VersionedFile,
95
102
    )
96
 
from .weavefile import _read_weave_v5, write_weave_v5
97
 
 
98
 
 
99
 
class WeaveError(errors.BzrError):
100
 
 
101
 
    _fmt = "Error in processing weave: %(msg)s"
102
 
 
103
 
    def __init__(self, msg=None):
104
 
        errors.BzrError.__init__(self)
105
 
        self.msg = msg
106
 
 
107
 
 
108
 
class WeaveRevisionAlreadyPresent(WeaveError):
109
 
 
110
 
    _fmt = "Revision {%(revision_id)s} already present in %(weave)s"
111
 
 
112
 
    def __init__(self, revision_id, weave):
113
 
 
114
 
        WeaveError.__init__(self)
115
 
        self.revision_id = revision_id
116
 
        self.weave = weave
117
 
 
118
 
 
119
 
class WeaveRevisionNotPresent(WeaveError):
120
 
 
121
 
    _fmt = "Revision {%(revision_id)s} not present in %(weave)s"
122
 
 
123
 
    def __init__(self, revision_id, weave):
124
 
        WeaveError.__init__(self)
125
 
        self.revision_id = revision_id
126
 
        self.weave = weave
127
 
 
128
 
 
129
 
class WeaveFormatError(WeaveError):
130
 
 
131
 
    _fmt = "Weave invariant violated: %(what)s"
132
 
 
133
 
    def __init__(self, what):
134
 
        WeaveError.__init__(self)
135
 
        self.what = what
136
 
 
137
 
 
138
 
class WeaveParentMismatch(WeaveError):
139
 
 
140
 
    _fmt = "Parents are mismatched between two revisions. %(msg)s"
141
 
 
142
 
 
143
 
class WeaveInvalidChecksum(WeaveError):
144
 
 
145
 
    _fmt = "Text did not match its checksum: %(msg)s"
146
 
 
147
 
 
148
 
class WeaveTextDiffers(WeaveError):
149
 
 
150
 
    _fmt = ("Weaves differ on text content. Revision:"
151
 
            " {%(revision_id)s}, %(weave_a)s, %(weave_b)s")
152
 
 
153
 
    def __init__(self, revision_id, weave_a, weave_b):
154
 
        WeaveError.__init__(self)
155
 
        self.revision_id = revision_id
156
 
        self.weave_a = weave_a
157
 
        self.weave_b = weave_b
 
103
from bzrlib.weavefile import _read_weave_v5, write_weave_v5
158
104
 
159
105
 
160
106
class WeaveContentFactory(ContentFactory):
176
122
    def get_bytes_as(self, storage_kind):
177
123
        if storage_kind == 'fulltext':
178
124
            return self._weave.get_text(self.key[-1])
179
 
        elif storage_kind in ('chunked', 'lines'):
 
125
        elif storage_kind == 'chunked':
180
126
            return self._weave.get_lines(self.key[-1])
181
127
        else:
182
128
            raise UnavailableRepresentation(self.key, storage_kind, 'fulltext')
183
129
 
184
 
    def iter_bytes_as(self, storage_kind):
185
 
        if storage_kind in ('chunked', 'lines'):
186
 
            return iter(self._weave.get_lines(self.key[-1]))
187
 
        else:
188
 
            raise UnavailableRepresentation(self.key, storage_kind, 'fulltext')
189
 
 
190
130
 
191
131
class Weave(VersionedFile):
192
132
    """weave - versioned text file storage.
296
236
        self._name_map = {}
297
237
        self._weave_name = weave_name
298
238
        if matcher is None:
299
 
            self._matcher = patiencediff.PatienceSequenceMatcher
 
239
            self._matcher = bzrlib.patiencediff.PatienceSequenceMatcher
300
240
        else:
301
241
            self._matcher = matcher
302
242
        if get_scope is None:
303
 
            def get_scope():
304
 
                return None
 
243
            get_scope = lambda:None
305
244
        self._get_scope = get_scope
306
245
        self._scope = get_scope()
307
246
        self._access_mode = access_mode
334
273
        if not isinstance(other, Weave):
335
274
            return False
336
275
        return self._parents == other._parents \
337
 
            and self._weave == other._weave \
338
 
            and self._sha1s == other._sha1s
 
276
               and self._weave == other._weave \
 
277
               and self._sha1s == other._sha1s
339
278
 
340
279
    def __ne__(self, other):
341
280
        return not self.__eq__(other)
425
364
                raise RevisionNotPresent([record.key[0]], self)
426
365
            # adapt to non-tuple interface
427
366
            parents = [parent[0] for parent in record.parents]
428
 
            if record.storage_kind in ('fulltext', 'chunked', 'lines'):
429
 
                self.add_lines(
430
 
                    record.key[0], parents,
431
 
                    record.get_bytes_as('lines'))
 
367
            if (record.storage_kind == 'fulltext'
 
368
                or record.storage_kind == 'chunked'):
 
369
                self.add_lines(record.key[0], parents,
 
370
                    osutils.chunks_to_lines(record.get_bytes_as('chunked')))
432
371
            else:
433
 
                adapter_key = record.storage_kind, 'lines'
 
372
                adapter_key = record.storage_kind, 'fulltext'
434
373
                try:
435
374
                    adapter = adapters[adapter_key]
436
375
                except KeyError:
437
376
                    adapter_factory = adapter_registry.get(adapter_key)
438
377
                    adapter = adapter_factory(self)
439
378
                    adapters[adapter_key] = adapter
440
 
                lines = adapter.get_bytes(record, 'lines')
 
379
                lines = split_lines(adapter.get_bytes(record))
441
380
                try:
442
381
                    self.add_lines(record.key[0], parents, lines)
443
382
                except RevisionAlreadyPresent:
450
389
        """
451
390
        idx = self._lookup(name)
452
391
        if sorted(self._parents[idx]) != sorted(parents) \
453
 
                or sha1 != self._sha1s[idx]:
 
392
            or sha1 != self._sha1s[idx]:
454
393
            raise RevisionAlreadyPresent(name, self._weave_name)
455
394
        return idx
456
395
 
457
396
    def _add_lines(self, version_id, parents, lines, parent_texts,
458
 
                   left_matching_blocks, nostore_sha, random_id,
459
 
                   check_content):
 
397
       left_matching_blocks, nostore_sha, random_id, check_content):
460
398
        """See VersionedFile.add_lines."""
461
 
        idx = self._add(version_id, lines, list(map(self._lookup, parents)),
462
 
                        nostore_sha=nostore_sha)
 
399
        idx = self._add(version_id, lines, map(self._lookup, parents),
 
400
            nostore_sha=nostore_sha)
463
401
        return sha_strings(lines), sum(map(len, lines)), idx
464
402
 
465
403
    def _add(self, version_id, lines, parents, sha1=None, nostore_sha=None):
485
423
        if not sha1:
486
424
            sha1 = sha_strings(lines)
487
425
        if sha1 == nostore_sha:
488
 
            raise ExistingContent
 
426
            raise errors.ExistingContent
489
427
        if version_id is None:
490
 
            version_id = b"sha1:" + sha1
 
428
            version_id = "sha1:" + sha1
491
429
        if version_id in self._name_map:
492
430
            return self._check_repeated_add(version_id, parents, lines, sha1)
493
431
 
494
432
        self._check_versions(parents)
 
433
        ## self._check_lines(lines)
495
434
        new_version = len(self._parents)
496
435
 
497
 
        # if we abort after here the (in-memory) weave will be corrupt because
498
 
        # only some fields are updated
 
436
        # if we abort after here the (in-memory) weave will be corrupt because only
 
437
        # some fields are updated
499
438
        # XXX: FIXME implement a succeed-or-fail of the rest of this routine.
500
439
        #      - Robert Collins 20060226
501
440
        self._parents.append(parents[:])
503
442
        self._names.append(version_id)
504
443
        self._name_map[version_id] = new_version
505
444
 
 
445
 
506
446
        if not parents:
507
447
            # special case; adding with no parents revision; can do
508
448
            # this more quickly by just appending unconditionally.
509
449
            # even more specially, if we're adding an empty text we
510
450
            # need do nothing at all.
511
451
            if lines:
512
 
                self._weave.append((b'{', new_version))
 
452
                self._weave.append(('{', new_version))
513
453
                self._weave.extend(lines)
514
 
                self._weave.append((b'}', None))
 
454
                self._weave.append(('}', None))
515
455
            return new_version
516
456
 
517
457
        if len(parents) == 1:
520
460
                # special case: same as the single parent
521
461
                return new_version
522
462
 
 
463
 
523
464
        ancestors = self._inclusions(parents)
524
465
 
525
466
        l = self._weave
543
484
        # matches the end of the file?  the current code says it's the
544
485
        # last line of the weave?
545
486
 
546
 
        # print 'basis_lines:', basis_lines
547
 
        # print 'new_lines:  ', lines
 
487
        #print 'basis_lines:', basis_lines
 
488
        #print 'new_lines:  ', lines
548
489
 
549
490
        s = self._matcher(None, basis_lines, lines)
550
491
 
551
492
        # offset gives the number of lines that have been inserted
552
 
        # into the weave up to the current point; if the original edit
553
 
        # instruction says to change line A then we actually change (A+offset)
 
493
        # into the weave up to the current point; if the original edit instruction
 
494
        # says to change line A then we actually change (A+offset)
554
495
        offset = 0
555
496
 
556
497
        for tag, i1, i2, j1, j2 in s.get_opcodes():
557
 
            # i1,i2 are given in offsets within basis_lines; we need to map
558
 
            # them back to offsets within the entire weave print 'raw match',
559
 
            # tag, i1, i2, j1, j2
 
498
            # i1,i2 are given in offsets within basis_lines; we need to map them
 
499
            # back to offsets within the entire weave
 
500
            #print 'raw match', tag, i1, i2, j1, j2
560
501
            if tag == 'equal':
561
502
                continue
562
503
            i1 = basis_lineno[i1]
564
505
            # the deletion and insertion are handled separately.
565
506
            # first delete the region.
566
507
            if i1 != i2:
567
 
                self._weave.insert(i1 + offset, (b'[', new_version))
568
 
                self._weave.insert(i2 + offset + 1, (b']', new_version))
 
508
                self._weave.insert(i1+offset, ('[', new_version))
 
509
                self._weave.insert(i2+offset+1, (']', new_version))
569
510
                offset += 2
570
511
 
571
512
            if j1 != j2:
573
514
                # i2; we want to insert after this region to make sure
574
515
                # we don't destroy ourselves
575
516
                i = i2 + offset
576
 
                self._weave[i:i] = ([(b'{', new_version)] +
577
 
                                    lines[j1:j2] +
578
 
                                    [(b'}', None)])
 
517
                self._weave[i:i] = ([('{', new_version)]
 
518
                                    + lines[j1:j2]
 
519
                                    + [('}', None)])
579
520
                offset += 2 + (j2 - j1)
580
521
        return new_version
581
522
 
582
523
    def _inclusions(self, versions):
583
524
        """Return set of all ancestors of given version(s)."""
584
525
        if not len(versions):
585
 
            return set()
 
526
            return []
586
527
        i = set(versions)
587
 
        for v in range(max(versions), 0, -1):
 
528
        for v in xrange(max(versions), 0, -1):
588
529
            if v in i:
589
530
                # include all its parents
590
531
                i.update(self._parents[v])
591
532
        return i
 
533
        ## except IndexError:
 
534
        ##     raise ValueError("version %d not present in weave" % v)
592
535
 
593
536
    def get_ancestry(self, version_ids, topo_sorted=True):
594
537
        """See VersionedFile.get_ancestry."""
595
 
        if isinstance(version_ids, bytes):
 
538
        if isinstance(version_ids, basestring):
596
539
            version_ids = [version_ids]
597
540
        i = self._inclusions([self._lookup(v) for v in version_ids])
598
 
        return set(self._idx_to_name(v) for v in i)
 
541
        return [self._idx_to_name(v) for v in i]
 
542
 
 
543
    def _check_lines(self, text):
 
544
        if not isinstance(text, list):
 
545
            raise ValueError("text should be a list, not %s" % type(text))
 
546
 
 
547
        for l in text:
 
548
            if not isinstance(l, basestring):
 
549
                raise ValueError("text line should be a string or unicode, not %s"
 
550
                                 % type(l))
 
551
 
 
552
 
599
553
 
600
554
    def _check_versions(self, indexes):
601
555
        """Check everything in the sequence of indexes is valid"""
619
573
        The index indicates when the line originated in the weave."""
620
574
        incls = [self._lookup(version_id)]
621
575
        return [(self._idx_to_name(origin), text) for origin, lineno, text in
622
 
                self._extract(incls)]
 
576
            self._extract(incls)]
623
577
 
624
578
    def iter_lines_added_or_present_in_versions(self, version_ids=None,
625
579
                                                pb=None):
627
581
        if version_ids is None:
628
582
            version_ids = self.versions()
629
583
        version_ids = set(version_ids)
630
 
        for lineno, inserted, deletes, line in self._walk_internal(
631
 
                version_ids):
632
 
            if inserted not in version_ids:
633
 
                continue
634
 
            if not line.endswith(b'\n'):
635
 
                yield line + b'\n', inserted
 
584
        for lineno, inserted, deletes, line in self._walk_internal(version_ids):
 
585
            if inserted not in version_ids: continue
 
586
            if line[-1] != '\n':
 
587
                yield line + '\n', inserted
636
588
            else:
637
589
                yield line, inserted
638
590
 
647
599
        for l in self._weave:
648
600
            if l.__class__ == tuple:
649
601
                c, v = l
650
 
                if c == b'{':
 
602
                isactive = None
 
603
                if c == '{':
651
604
                    istack.append(self._names[v])
652
 
                elif c == b'}':
 
605
                elif c == '}':
653
606
                    istack.pop()
654
 
                elif c == b'[':
 
607
                elif c == '[':
655
608
                    dset.add(self._names[v])
656
 
                elif c == b']':
 
609
                elif c == ']':
657
610
                    dset.remove(self._names[v])
658
611
                else:
659
612
                    raise WeaveFormatError('unexpected instruction %r' % v)
663
616
 
664
617
        if istack:
665
618
            raise WeaveFormatError("unclosed insertion blocks "
666
 
                                   "at end of weave: %s" % istack)
 
619
                    "at end of weave: %s" % istack)
667
620
        if dset:
668
 
            raise WeaveFormatError(
669
 
                "unclosed deletion blocks at end of weave: %s" % dset)
 
621
            raise WeaveFormatError("unclosed deletion blocks at end of weave: %s"
 
622
                                   % dset)
670
623
 
671
624
    def plan_merge(self, ver_a, ver_b):
672
625
        """Return pseudo-annotation indicating how the two versions merge.
676
629
 
677
630
        Weave lines present in none of them are skipped entirely.
678
631
        """
679
 
        inc_a = self.get_ancestry([ver_a])
680
 
        inc_b = self.get_ancestry([ver_b])
 
632
        inc_a = set(self.get_ancestry([ver_a]))
 
633
        inc_b = set(self.get_ancestry([ver_b]))
681
634
        inc_c = inc_a & inc_b
682
635
 
683
 
        for lineno, insert, deleteset, line in self._walk_internal(
684
 
                [ver_a, ver_b]):
 
636
        for lineno, insert, deleteset, line in self._walk_internal([ver_a, ver_b]):
685
637
            if deleteset & inc_c:
686
638
                # killed in parent; can't be in either a or b
687
639
                # not relevant to our work
738
690
 
739
691
        result = []
740
692
 
 
693
        WFE = WeaveFormatError
 
694
 
741
695
        # wow.
742
 
        #  449       0   4474.6820   2356.5590   breezy.weave:556(_extract)
 
696
        #  449       0   4474.6820   2356.5590   bzrlib.weave:556(_extract)
743
697
        #  +285282   0   1676.8040   1676.8040   +<isinstance>
744
698
        # 1.6 seconds in 'isinstance'.
745
699
        # changing the first isinstance:
746
 
        #  449       0   2814.2660   1577.1760   breezy.weave:556(_extract)
 
700
        #  449       0   2814.2660   1577.1760   bzrlib.weave:556(_extract)
747
701
        #  +140414   0    762.8050    762.8050   +<isinstance>
748
702
        # note that the inline time actually dropped (less function calls)
749
703
        # and total processing time was halved.
750
704
        # we're still spending ~1/4 of the method in isinstance though.
751
705
        # so lets hard code the acceptable string classes we expect:
752
 
        #  449       0   1202.9420    786.2930   breezy.weave:556(_extract)
 
706
        #  449       0   1202.9420    786.2930   bzrlib.weave:556(_extract)
753
707
        # +71352     0    377.5560    377.5560   +<method 'append' of 'list'
754
708
        #                                          objects>
755
709
        # yay, down to ~1/4 the initial extract time, and our inline time
756
710
        # has shrunk again, with isinstance no longer dominating.
757
711
        # tweaking the stack inclusion test to use a set gives:
758
 
        #  449       0   1122.8030    713.0080   breezy.weave:556(_extract)
 
712
        #  449       0   1122.8030    713.0080   bzrlib.weave:556(_extract)
759
713
        # +71352     0    354.9980    354.9980   +<method 'append' of 'list'
760
714
        #                                          objects>
761
715
        # - a 5% win, or possibly just noise. However with large istacks that
762
 
        # 'in' test could dominate, so I'm leaving this change in place - when
763
 
        # its fast enough to consider profiling big datasets we can review.
 
716
        # 'in' test could dominate, so I'm leaving this change in place -
 
717
        # when its fast enough to consider profiling big datasets we can review.
 
718
 
 
719
 
 
720
 
764
721
 
765
722
        for l in self._weave:
766
723
            if l.__class__ == tuple:
767
724
                c, v = l
768
725
                isactive = None
769
 
                if c == b'{':
 
726
                if c == '{':
770
727
                    istack.append(v)
771
728
                    iset.add(v)
772
 
                elif c == b'}':
 
729
                elif c == '}':
773
730
                    iset.remove(istack.pop())
774
 
                elif c == b'[':
 
731
                elif c == '[':
775
732
                    if v in included:
776
733
                        dset.add(v)
777
 
                elif c == b']':
 
734
                elif c == ']':
778
735
                    if v in included:
779
736
                        dset.remove(v)
780
737
                else:
781
738
                    raise AssertionError()
782
739
            else:
783
740
                if isactive is None:
784
 
                    isactive = (not dset) and istack and (
785
 
                        istack[-1] in included)
 
741
                    isactive = (not dset) and istack and (istack[-1] in included)
786
742
                if isactive:
787
743
                    result.append((istack[-1], lineno, l))
788
744
            lineno += 1
789
745
        if istack:
790
746
            raise WeaveFormatError("unclosed insertion blocks "
791
 
                                   "at end of weave: %s" % istack)
 
747
                    "at end of weave: %s" % istack)
792
748
        if dset:
793
 
            raise WeaveFormatError(
794
 
                "unclosed deletion blocks at end of weave: %s" % dset)
 
749
            raise WeaveFormatError("unclosed deletion blocks at end of weave: %s"
 
750
                                   % dset)
795
751
        return result
796
752
 
797
753
    def _maybe_lookup(self, name_or_index):
799
755
 
800
756
        NOT FOR PUBLIC USE.
801
757
        """
802
 
        # GZ 2017-04-01: This used to check for long as well, but I don't think
803
 
        # there are python implementations with sys.maxsize > sys.maxint
804
 
        if isinstance(name_or_index, int):
 
758
        if isinstance(name_or_index, (int, long)):
805
759
            return name_or_index
806
760
        else:
807
761
            return self._lookup(name_or_index)
809
763
    def get_lines(self, version_id):
810
764
        """See VersionedFile.get_lines()."""
811
765
        int_index = self._maybe_lookup(version_id)
812
 
        result = [line for (origin, lineno, line)
813
 
                  in self._extract([int_index])]
 
766
        result = [line for (origin, lineno, line) in self._extract([int_index])]
814
767
        expected_sha1 = self._sha1s[int_index]
815
768
        measured_sha1 = sha_strings(result)
816
769
        if measured_sha1 != expected_sha1:
817
 
            raise WeaveInvalidChecksum(
818
 
                'file %s, revision %s, expected: %s, measured %s'
819
 
                % (self._weave_name, version_id,
820
 
                   expected_sha1, measured_sha1))
 
770
            raise errors.WeaveInvalidChecksum(
 
771
                    'file %s, revision %s, expected: %s, measured %s'
 
772
                    % (self._weave_name, version_id,
 
773
                       expected_sha1, measured_sha1))
821
774
        return result
822
775
 
823
776
    def get_sha1s(self, version_ids):
829
782
 
830
783
    def num_versions(self):
831
784
        """How many versions are in this weave?"""
832
 
        return len(self._parents)
 
785
        l = len(self._parents)
 
786
        return l
833
787
 
834
788
    __len__ = num_versions
835
789
 
842
796
            if inclusions:
843
797
                inclusions.sort()
844
798
                if inclusions[-1] >= version:
845
 
                    raise WeaveFormatError(
846
 
                        "invalid included version %d for index %d"
847
 
                        % (inclusions[-1], version))
 
799
                    raise WeaveFormatError("invalid included version %d for index %d"
 
800
                                           % (inclusions[-1], version))
848
801
 
849
802
        # try extracting all versions; parallel extraction is used
850
803
        nv = self.num_versions()
857
810
            name = self._idx_to_name(i)
858
811
            sha1s[name] = sha()
859
812
            texts[name] = []
860
 
            new_inc = {name}
 
813
            new_inc = set([name])
861
814
            for p in self._parents[i]:
862
815
                new_inc.update(inclusions[self._idx_to_name(p)])
863
816
 
864
 
            if new_inc != self.get_ancestry(name):
 
817
            if set(new_inc) != set(self.get_ancestry(name)):
865
818
                raise AssertionError(
866
819
                    'failed %s != %s'
867
 
                    % (new_inc, self.get_ancestry(name)))
 
820
                    % (set(new_inc), set(self.get_ancestry(name))))
868
821
            inclusions[name] = new_inc
869
822
 
870
823
        nlines = len(self._weave)
883
836
                # The active inclusion must be an ancestor,
884
837
                # and no ancestors must have deleted this line,
885
838
                # because we don't support resurrection.
886
 
                if ((insert in name_inclusions) and
887
 
                        not (deleteset & name_inclusions)):
 
839
                if (insert in name_inclusions) and not (deleteset & name_inclusions):
888
840
                    sha1s[name].update(line)
889
841
 
890
842
        for i in range(nv):
891
843
            version = self._idx_to_name(i)
892
 
            hd = sha1s[version].hexdigest().encode()
 
844
            hd = sha1s[version].hexdigest()
893
845
            expected = self._sha1s[i]
894
846
            if hd != expected:
895
 
                raise WeaveInvalidChecksum(
896
 
                    "mismatched sha1 for version %s: "
897
 
                    "got %s, expected %s"
898
 
                    % (version, hd, expected))
 
847
                raise errors.WeaveInvalidChecksum(
 
848
                        "mismatched sha1 for version %s: "
 
849
                        "got %s, expected %s"
 
850
                        % (version, hd, expected))
899
851
 
900
852
        # TODO: check insertions are properly nested, that there are
901
853
        # no lines outside of insertion blocks, that deletions are
928
880
        this_idx = self._name_map.get(name, -1)
929
881
        if this_idx != -1:
930
882
            if self._sha1s[this_idx] != other._sha1s[other_idx]:
931
 
                raise WeaveTextDiffers(name, self, other)
 
883
                raise errors.WeaveTextDiffers(name, self, other)
932
884
            self_parents = self._parents[this_idx]
933
885
            other_parents = other._parents[other_idx]
934
 
            n1 = {self._names[i] for i in self_parents}
935
 
            n2 = {other._names[i] for i in other_parents}
 
886
            n1 = set([self._names[i] for i in self_parents])
 
887
            n2 = set([other._names[i] for i in other_parents])
936
888
            if not self._compatible_parents(n1, n2):
937
 
                raise WeaveParentMismatch(
938
 
                    "inconsistent parents "
 
889
                raise WeaveParentMismatch("inconsistent parents "
939
890
                    "for version {%s}: %s vs %s" % (name, n1, n2))
940
891
            else:
941
892
                return True         # ok!
964
915
 
965
916
    WEAVE_SUFFIX = '.weave'
966
917
 
967
 
    def __init__(self, name, transport, filemode=None, create=False,
968
 
                 access_mode='w', get_scope=None):
 
918
    def __init__(self, name, transport, filemode=None, create=False, access_mode='w', get_scope=None):
969
919
        """Create a WeaveFile.
970
920
 
971
921
        :param create: If not True, only open an existing knit.
972
922
        """
973
923
        super(WeaveFile, self).__init__(name, access_mode, get_scope=get_scope,
974
 
                                        allow_reserved=False)
 
924
            allow_reserved=False)
975
925
        self._transport = transport
976
926
        self._filemode = filemode
977
927
        try:
978
 
            f = self._transport.get(name + WeaveFile.WEAVE_SUFFIX)
979
 
            _read_weave_v5(BytesIO(f.read()), self)
 
928
            _read_weave_v5(self._transport.get(name + WeaveFile.WEAVE_SUFFIX), self)
980
929
        except errors.NoSuchFile:
981
930
            if not create:
982
931
                raise
984
933
            self._save()
985
934
 
986
935
    def _add_lines(self, version_id, parents, lines, parent_texts,
987
 
                   left_matching_blocks, nostore_sha, random_id,
988
 
                   check_content):
 
936
        left_matching_blocks, nostore_sha, random_id, check_content):
989
937
        """Add a version and save the weave."""
990
938
        self.check_not_reserved_id(version_id)
991
 
        result = super(WeaveFile, self)._add_lines(
992
 
            version_id, parents, lines, parent_texts, left_matching_blocks,
993
 
            nostore_sha, random_id, check_content)
 
939
        result = super(WeaveFile, self)._add_lines(version_id, parents, lines,
 
940
            parent_texts, left_matching_blocks, nostore_sha, random_id,
 
941
            check_content)
994
942
        self._save()
995
943
        return result
996
944
 
997
945
    def copy_to(self, name, transport):
998
946
        """See VersionedFile.copy_to()."""
999
947
        # as we are all in memory always, just serialise to the new place.
1000
 
        sio = BytesIO()
 
948
        sio = StringIO()
1001
949
        write_weave_v5(self, sio)
1002
950
        sio.seek(0)
1003
951
        transport.put_file(name + WeaveFile.WEAVE_SUFFIX, sio, self._filemode)
1005
953
    def _save(self):
1006
954
        """Save the weave."""
1007
955
        self._check_write_ok()
1008
 
        sio = BytesIO()
 
956
        sio = StringIO()
1009
957
        write_weave_v5(self, sio)
1010
958
        sio.seek(0)
1011
959
        bytes = sio.getvalue()
1042
990
    :param msg: An optional message for the progress
1043
991
    """
1044
992
    wr = Weave()
 
993
    ia = ib = 0
 
994
    queue_a = range(wa.num_versions())
 
995
    queue_b = range(wb.num_versions())
1045
996
    # first determine combined parents of all versions
1046
997
    # map from version name -> all parent names
1047
998
    combined_parents = _reweave_parent_graphs(wa, wb)
1048
999
    mutter("combined parents: %r", combined_parents)
1049
 
    order = tsort.topo_sort(combined_parents.items())
 
1000
    order = tsort.topo_sort(combined_parents.iteritems())
1050
1001
    mutter("order to reweave: %r", order)
1051
1002
 
1052
1003
    if pb and not msg:
1064
1015
                    mutter('weaves: %s, %s', wa._weave_name, wb._weave_name)
1065
1016
                    import difflib
1066
1017
                    lines = list(difflib.unified_diff(lines, lines_b,
1067
 
                                                      wa._weave_name, wb._weave_name))
 
1018
                            wa._weave_name, wb._weave_name))
1068
1019
                    mutter('lines:\n%s', ''.join(lines))
1069
 
                    raise WeaveTextDiffers(name, wa, wb)
 
1020
                    raise errors.WeaveTextDiffers(name, wa, wb)
1070
1021
        else:
1071
1022
            lines = wb.get_lines(name)
1072
1023
        wr._add(name, lines, [wr._lookup(i) for i in combined_parents[name]])