/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 breezy/bzr/weave.py

  • Committer: Jelmer Vernooij
  • Date: 2017-10-27 00:18:42 UTC
  • mto: This revision was merged to the branch mainline in revision 6799.
  • Revision ID: jelmer@jelmer.uk-20171027001842-o77sekj0g2t2zwbn
Properly escape backslashes.

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
 
 
20
19
"""Weave - storage of related text file versions"""
21
20
 
 
21
from __future__ import absolute_import
22
22
 
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
68
68
 
69
69
from copy import copy
70
 
from cStringIO import StringIO
71
70
import os
72
71
 
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
76
75
""")
77
 
from bzrlib import (
 
76
from .. import (
78
77
    errors,
79
78
    osutils,
80
79
    )
81
 
from bzrlib.errors import (WeaveError, WeaveFormatError, WeaveParentMismatch,
82
 
        RevisionAlreadyPresent,
83
 
        RevisionNotPresent,
84
 
        UnavailableRepresentation,
85
 
        )
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 (
 
80
from ..errors import (
 
81
    RevisionAlreadyPresent,
 
82
    RevisionNotPresent,
 
83
    UnavailableRepresentation,
 
84
    )
 
85
from ..osutils import dirname, sha, sha_strings, split_lines
 
86
from .. import patiencediff
 
87
from ..revision import NULL_REVISION
 
88
from ..sixish import (
 
89
    BytesIO,
 
90
    )
 
91
from ..trace import mutter
 
92
from .versionedfile import (
92
93
    AbsentContentFactory,
93
94
    adapter_registry,
94
95
    ContentFactory,
95
96
    sort_groupcompress,
96
97
    VersionedFile,
97
98
    )
98
 
from bzrlib.weavefile import _read_weave_v5, write_weave_v5
 
99
from .weavefile import _read_weave_v5, write_weave_v5
 
100
 
 
101
 
 
102
class WeaveError(errors.BzrError):
 
103
 
 
104
    _fmt = "Error in processing weave: %(msg)s"
 
105
 
 
106
    def __init__(self, msg=None):
 
107
        errors.BzrError.__init__(self)
 
108
        self.msg = msg
 
109
 
 
110
 
 
111
class WeaveRevisionAlreadyPresent(WeaveError):
 
112
 
 
113
    _fmt = "Revision {%(revision_id)s} already present in %(weave)s"
 
114
 
 
115
    def __init__(self, revision_id, weave):
 
116
 
 
117
        WeaveError.__init__(self)
 
118
        self.revision_id = revision_id
 
119
        self.weave = weave
 
120
 
 
121
 
 
122
class WeaveRevisionNotPresent(WeaveError):
 
123
 
 
124
    _fmt = "Revision {%(revision_id)s} not present in %(weave)s"
 
125
 
 
126
    def __init__(self, revision_id, weave):
 
127
        WeaveError.__init__(self)
 
128
        self.revision_id = revision_id
 
129
        self.weave = weave
 
130
 
 
131
 
 
132
class WeaveFormatError(WeaveError):
 
133
 
 
134
    _fmt = "Weave invariant violated: %(what)s"
 
135
 
 
136
    def __init__(self, what):
 
137
        WeaveError.__init__(self)
 
138
        self.what = what
 
139
 
 
140
 
 
141
class WeaveParentMismatch(WeaveError):
 
142
 
 
143
    _fmt = "Parents are mismatched between two revisions. %(msg)s"
 
144
 
 
145
 
 
146
class WeaveInvalidChecksum(WeaveError):
 
147
 
 
148
    _fmt = "Text did not match its checksum: %(msg)s"
 
149
 
 
150
 
 
151
class WeaveTextDiffers(WeaveError):
 
152
 
 
153
    _fmt = ("Weaves differ on text content. Revision:"
 
154
            " {%(revision_id)s}, %(weave_a)s, %(weave_b)s")
 
155
 
 
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
 
161
 
 
162
 
 
163
class WeaveTextDiffers(WeaveError):
 
164
 
 
165
    _fmt = ("Weaves differ on text content. Revision:"
 
166
            " {%(revision_id)s}, %(weave_a)s, %(weave_b)s")
 
167
 
 
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
99
173
 
100
174
 
101
175
class WeaveContentFactory(ContentFactory):
231
305
        self._name_map = {}
232
306
        self._weave_name = weave_name
233
307
        if matcher is None:
234
 
            self._matcher = bzrlib.patiencediff.PatienceSequenceMatcher
 
308
            self._matcher = patiencediff.PatienceSequenceMatcher
235
309
        else:
236
310
            self._matcher = matcher
237
311
        if get_scope is None:
391
465
    def _add_lines(self, version_id, parents, lines, parent_texts,
392
466
       left_matching_blocks, nostore_sha, random_id, check_content):
393
467
        """See VersionedFile.add_lines."""
394
 
        idx = self._add(version_id, lines, map(self._lookup, parents),
 
468
        idx = self._add(version_id, lines, list(map(self._lookup, parents)),
395
469
            nostore_sha=nostore_sha)
396
470
        return sha_strings(lines), sum(map(len, lines)), idx
397
471
 
425
499
            return self._check_repeated_add(version_id, parents, lines, sha1)
426
500
 
427
501
        self._check_versions(parents)
428
 
        ## self._check_lines(lines)
429
502
        new_version = len(self._parents)
430
503
 
431
504
        # if we abort after here the (in-memory) weave will be corrupt because only
520
593
        if not len(versions):
521
594
            return []
522
595
        i = set(versions)
523
 
        for v in xrange(max(versions), 0, -1):
 
596
        for v in range(max(versions), 0, -1):
524
597
            if v in i:
525
598
                # include all its parents
526
599
                i.update(self._parents[v])
527
600
        return i
528
 
        ## except IndexError:
529
 
        ##     raise ValueError("version %d not present in weave" % v)
530
601
 
531
602
    def get_ancestry(self, version_ids, topo_sorted=True):
532
603
        """See VersionedFile.get_ancestry."""
533
 
        if isinstance(version_ids, basestring):
 
604
        if isinstance(version_ids, bytes):
534
605
            version_ids = [version_ids]
535
606
        i = self._inclusions([self._lookup(v) for v in version_ids])
536
607
        return [self._idx_to_name(v) for v in i]
537
608
 
538
 
    def _check_lines(self, text):
539
 
        if not isinstance(text, list):
540
 
            raise ValueError("text should be a list, not %s" % type(text))
541
 
 
542
 
        for l in text:
543
 
            if not isinstance(l, basestring):
544
 
                raise ValueError("text line should be a string or unicode, not %s"
545
 
                                 % type(l))
546
 
 
547
 
 
548
 
 
549
609
    def _check_versions(self, indexes):
550
610
        """Check everything in the sequence of indexes is valid"""
551
611
        for i in indexes:
688
748
        WFE = WeaveFormatError
689
749
 
690
750
        # wow.
691
 
        #  449       0   4474.6820   2356.5590   bzrlib.weave:556(_extract)
 
751
        #  449       0   4474.6820   2356.5590   breezy.weave:556(_extract)
692
752
        #  +285282   0   1676.8040   1676.8040   +<isinstance>
693
753
        # 1.6 seconds in 'isinstance'.
694
754
        # changing the first isinstance:
695
 
        #  449       0   2814.2660   1577.1760   bzrlib.weave:556(_extract)
 
755
        #  449       0   2814.2660   1577.1760   breezy.weave:556(_extract)
696
756
        #  +140414   0    762.8050    762.8050   +<isinstance>
697
757
        # note that the inline time actually dropped (less function calls)
698
758
        # and total processing time was halved.
699
759
        # we're still spending ~1/4 of the method in isinstance though.
700
760
        # so lets hard code the acceptable string classes we expect:
701
 
        #  449       0   1202.9420    786.2930   bzrlib.weave:556(_extract)
 
761
        #  449       0   1202.9420    786.2930   breezy.weave:556(_extract)
702
762
        # +71352     0    377.5560    377.5560   +<method 'append' of 'list'
703
763
        #                                          objects>
704
764
        # yay, down to ~1/4 the initial extract time, and our inline time
705
765
        # has shrunk again, with isinstance no longer dominating.
706
766
        # tweaking the stack inclusion test to use a set gives:
707
 
        #  449       0   1122.8030    713.0080   bzrlib.weave:556(_extract)
 
767
        #  449       0   1122.8030    713.0080   breezy.weave:556(_extract)
708
768
        # +71352     0    354.9980    354.9980   +<method 'append' of 'list'
709
769
        #                                          objects>
710
770
        # - a 5% win, or possibly just noise. However with large istacks that
750
810
 
751
811
        NOT FOR PUBLIC USE.
752
812
        """
753
 
        if isinstance(name_or_index, (int, long)):
 
813
        # GZ 2017-04-01: This used to check for long as well, but I don't think
 
814
        # there are python implementations with sys.maxsize > sys.maxint
 
815
        if isinstance(name_or_index, int):
754
816
            return name_or_index
755
817
        else:
756
818
            return self._lookup(name_or_index)
762
824
        expected_sha1 = self._sha1s[int_index]
763
825
        measured_sha1 = sha_strings(result)
764
826
        if measured_sha1 != expected_sha1:
765
 
            raise errors.WeaveInvalidChecksum(
 
827
            raise WeaveInvalidChecksum(
766
828
                    'file %s, revision %s, expected: %s, measured %s'
767
829
                    % (self._weave_name, version_id,
768
830
                       expected_sha1, measured_sha1))
805
867
            name = self._idx_to_name(i)
806
868
            sha1s[name] = sha()
807
869
            texts[name] = []
808
 
            new_inc = set([name])
 
870
            new_inc = {name}
809
871
            for p in self._parents[i]:
810
872
                new_inc.update(inclusions[self._idx_to_name(p)])
811
873
 
839
901
            hd = sha1s[version].hexdigest()
840
902
            expected = self._sha1s[i]
841
903
            if hd != expected:
842
 
                raise errors.WeaveInvalidChecksum(
 
904
                raise WeaveInvalidChecksum(
843
905
                        "mismatched sha1 for version %s: "
844
906
                        "got %s, expected %s"
845
907
                        % (version, hd, expected))
875
937
        this_idx = self._name_map.get(name, -1)
876
938
        if this_idx != -1:
877
939
            if self._sha1s[this_idx] != other._sha1s[other_idx]:
878
 
                raise errors.WeaveTextDiffers(name, self, other)
 
940
                raise WeaveTextDiffers(name, self, other)
879
941
            self_parents = self._parents[this_idx]
880
942
            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])
 
943
            n1 = {self._names[i] for i in self_parents}
 
944
            n2 = {other._names[i] for i in other_parents}
883
945
            if not self._compatible_parents(n1, n2):
884
946
                raise WeaveParentMismatch("inconsistent parents "
885
947
                    "for version {%s}: %s vs %s" % (name, n1, n2))
920
982
        self._transport = transport
921
983
        self._filemode = filemode
922
984
        try:
923
 
            _read_weave_v5(self._transport.get(name + WeaveFile.WEAVE_SUFFIX), self)
 
985
            f = self._transport.get(name + WeaveFile.WEAVE_SUFFIX)
 
986
            _read_weave_v5(BytesIO(f.read()), self)
924
987
        except errors.NoSuchFile:
925
988
            if not create:
926
989
                raise
940
1003
    def copy_to(self, name, transport):
941
1004
        """See VersionedFile.copy_to()."""
942
1005
        # as we are all in memory always, just serialise to the new place.
943
 
        sio = StringIO()
 
1006
        sio = BytesIO()
944
1007
        write_weave_v5(self, sio)
945
1008
        sio.seek(0)
946
1009
        transport.put_file(name + WeaveFile.WEAVE_SUFFIX, sio, self._filemode)
948
1011
    def _save(self):
949
1012
        """Save the weave."""
950
1013
        self._check_write_ok()
951
 
        sio = StringIO()
 
1014
        sio = BytesIO()
952
1015
        write_weave_v5(self, sio)
953
1016
        sio.seek(0)
954
1017
        bytes = sio.getvalue()
985
1048
    :param msg: An optional message for the progress
986
1049
    """
987
1050
    wr = Weave()
988
 
    ia = ib = 0
989
 
    queue_a = range(wa.num_versions())
990
 
    queue_b = range(wb.num_versions())
991
1051
    # first determine combined parents of all versions
992
1052
    # map from version name -> all parent names
993
1053
    combined_parents = _reweave_parent_graphs(wa, wb)
994
1054
    mutter("combined parents: %r", combined_parents)
995
 
    order = tsort.topo_sort(combined_parents.iteritems())
 
1055
    order = tsort.topo_sort(combined_parents.items())
996
1056
    mutter("order to reweave: %r", order)
997
1057
 
998
1058
    if pb and not msg:
1012
1072
                    lines = list(difflib.unified_diff(lines, lines_b,
1013
1073
                            wa._weave_name, wb._weave_name))
1014
1074
                    mutter('lines:\n%s', ''.join(lines))
1015
 
                    raise errors.WeaveTextDiffers(name, wa, wb)
 
1075
                    raise WeaveTextDiffers(name, wa, wb)
1016
1076
        else:
1017
1077
            lines = wb.get_lines(name)
1018
1078
        wr._add(name, lines, [wr._lookup(i) for i in combined_parents[name]])