/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/versionedfile.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2006-2010 Canonical Ltd
2
2
#
3
3
# Authors:
4
4
#   Johan Rydberg <jrydberg@gnu.org>
30
30
import urllib
31
31
 
32
32
from bzrlib import (
 
33
    annotate,
33
34
    errors,
 
35
    graph as _mod_graph,
34
36
    groupcompress,
35
37
    index,
36
38
    knit,
40
42
    revision,
41
43
    ui,
42
44
    )
43
 
from bzrlib.graph import DictParentsProvider, Graph, _StackedParentsProvider
 
45
from bzrlib.graph import DictParentsProvider, Graph, StackedParentsProvider
44
46
from bzrlib.transport.memory import MemoryTransport
45
47
""")
46
 
from bzrlib.inter import InterObject
47
48
from bzrlib.registry import Registry
48
49
from bzrlib.symbol_versioning import *
49
50
from bzrlib.textmerge import TextMerge
50
 
from bzrlib.util import bencode
 
51
from bzrlib import bencode
51
52
 
52
53
 
53
54
adapter_registry = Registry()
174
175
        self.key = key
175
176
        self.parents = None
176
177
 
 
178
    def get_bytes_as(self, storage_kind):
 
179
        raise ValueError('A request was made for key: %s, but that'
 
180
                         ' content is not available, and the calling'
 
181
                         ' code does not handle if it is missing.'
 
182
                         % (self.key,))
 
183
 
177
184
 
178
185
class AdapterFactory(ContentFactory):
179
186
    """A content factory to adapt between key prefix's."""
829
836
        """
830
837
        raise NotImplementedError(self.add_lines)
831
838
 
 
839
    def _add_text(self, key, parents, text, nostore_sha=None, random_id=False):
 
840
        """Add a text to the store.
 
841
 
 
842
        This is a private function for use by CommitBuilder.
 
843
 
 
844
        :param key: The key tuple of the text to add. If the last element is
 
845
            None, a CHK string will be generated during the addition.
 
846
        :param parents: The parents key tuples of the text to add.
 
847
        :param text: A string containing the text to be committed.
 
848
        :param nostore_sha: Raise ExistingContent and do not add the lines to
 
849
            the versioned file if the digest of the lines matches this.
 
850
        :param random_id: If True a random id has been selected rather than
 
851
            an id determined by some deterministic process such as a converter
 
852
            from a foreign VCS. When True the backend may choose not to check
 
853
            for uniqueness of the resulting key within the versioned file, so
 
854
            this should only be done when the result is expected to be unique
 
855
            anyway.
 
856
        :param check_content: If True, the lines supplied are verified to be
 
857
            bytestrings that are correctly formed lines.
 
858
        :return: The text sha1, the number of bytes in the text, and an opaque
 
859
                 representation of the inserted version which can be provided
 
860
                 back to future _add_text calls in the parent_texts dictionary.
 
861
        """
 
862
        # The default implementation just thunks over to .add_lines(),
 
863
        # inefficient, but it works.
 
864
        return self.add_lines(key, parents, osutils.split_lines(text),
 
865
                              nostore_sha=nostore_sha,
 
866
                              random_id=random_id,
 
867
                              check_content=True)
 
868
 
832
869
    def add_mpdiffs(self, records):
833
870
        """Add mpdiffs to this VersionedFile.
834
871
 
876
913
        raise NotImplementedError(self.annotate)
877
914
 
878
915
    def check(self, progress_bar=None):
879
 
        """Check this object for integrity."""
 
916
        """Check this object for integrity.
 
917
        
 
918
        :param progress_bar: A progress bar to output as the check progresses.
 
919
        :param keys: Specific keys within the VersionedFiles to check. When
 
920
            this parameter is not None, check() becomes a generator as per
 
921
            get_record_stream. The difference to get_record_stream is that
 
922
            more or deeper checks will be performed.
 
923
        :return: None, or if keys was supplied a generator as per
 
924
            get_record_stream.
 
925
        """
880
926
        raise NotImplementedError(self.check)
881
927
 
882
928
    @staticmethod
883
929
    def check_not_reserved_id(version_id):
884
930
        revision.check_not_reserved_id(version_id)
885
931
 
 
932
    def clear_cache(self):
 
933
        """Clear whatever caches this VersionedFile holds.
 
934
 
 
935
        This is generally called after an operation has been performed, when we
 
936
        don't expect to be using this versioned file again soon.
 
937
        """
 
938
 
886
939
    def _check_lines_not_unicode(self, lines):
887
940
        """Check that lines being added to a versioned file are not unicode."""
888
941
        for line in lines:
895
948
            if '\n' in line[:-1]:
896
949
                raise errors.BzrBadParameterContainsNewline("lines")
897
950
 
 
951
    def get_known_graph_ancestry(self, keys):
 
952
        """Get a KnownGraph instance with the ancestry of keys."""
 
953
        # most basic implementation is a loop around get_parent_map
 
954
        pending = set(keys)
 
955
        parent_map = {}
 
956
        while pending:
 
957
            this_parent_map = self.get_parent_map(pending)
 
958
            parent_map.update(this_parent_map)
 
959
            pending = set()
 
960
            map(pending.update, this_parent_map.itervalues())
 
961
            pending = pending.difference(parent_map)
 
962
        kg = _mod_graph.KnownGraph(parent_map)
 
963
        return kg
 
964
 
898
965
    def get_parent_map(self, keys):
899
966
        """Get a map of the parents of keys.
900
967
 
1092
1159
            result.append((prefix + (origin,), line))
1093
1160
        return result
1094
1161
 
1095
 
    def check(self, progress_bar=None):
 
1162
    def get_annotator(self):
 
1163
        return annotate.Annotator(self)
 
1164
 
 
1165
    def check(self, progress_bar=None, keys=None):
1096
1166
        """See VersionedFiles.check()."""
 
1167
        # XXX: This is over-enthusiastic but as we only thunk for Weaves today
 
1168
        # this is tolerable. Ideally we'd pass keys down to check() and 
 
1169
        # have the older VersiondFile interface updated too.
1097
1170
        for prefix, vf in self._iter_all_components():
1098
1171
            vf.check()
 
1172
        if keys is not None:
 
1173
            return self.get_record_stream(keys, 'unordered', True)
1099
1174
 
1100
1175
    def get_parent_map(self, keys):
1101
1176
        """Get a map of the parents of keys.
1333
1408
            result[revision.NULL_REVISION] = ()
1334
1409
        self._providers = self._providers[:1] + self.fallback_versionedfiles
1335
1410
        result.update(
1336
 
            _StackedParentsProvider(self._providers).get_parent_map(keys))
 
1411
            StackedParentsProvider(self._providers).get_parent_map(keys))
1337
1412
        for key, parents in result.iteritems():
1338
1413
            if parents == ():
1339
1414
                result[key] = (revision.NULL_REVISION,)
1350
1425
    def __init__(self, plan, a_marker=TextMerge.A_MARKER,
1351
1426
                 b_marker=TextMerge.B_MARKER):
1352
1427
        TextMerge.__init__(self, a_marker, b_marker)
1353
 
        self.plan = plan
 
1428
        self.plan = list(plan)
1354
1429
 
1355
1430
    def _merge_struct(self):
1356
1431
        lines_a = []
1403
1478
            elif state == 'conflicted-b':
1404
1479
                ch_b = ch_a = True
1405
1480
                lines_b.append(line)
 
1481
            elif state == 'killed-both':
 
1482
                # This counts as a change, even though there is no associated
 
1483
                # line
 
1484
                ch_b = ch_a = True
1406
1485
            else:
1407
1486
                if state not in ('irrelevant', 'ghost-a', 'ghost-b',
1408
 
                        'killed-base', 'killed-both'):
 
1487
                        'killed-base'):
1409
1488
                    raise AssertionError(state)
1410
1489
        for struct in outstanding_struct():
1411
1490
            yield struct
1412
1491
 
 
1492
    def base_from_plan(self):
 
1493
        """Construct a BASE file from the plan text."""
 
1494
        base_lines = []
 
1495
        for state, line in self.plan:
 
1496
            if state in ('killed-a', 'killed-b', 'killed-both', 'unchanged'):
 
1497
                # If unchanged, then this line is straight from base. If a or b
 
1498
                # or both killed the line, then it *used* to be in base.
 
1499
                base_lines.append(line)
 
1500
            else:
 
1501
                if state not in ('killed-base', 'irrelevant',
 
1502
                                 'ghost-a', 'ghost-b',
 
1503
                                 'new-a', 'new-b',
 
1504
                                 'conflicted-a', 'conflicted-b'):
 
1505
                    # killed-base, irrelevant means it doesn't apply
 
1506
                    # ghost-a/ghost-b are harder to say for sure, but they
 
1507
                    # aren't in the 'inc_c' which means they aren't in the
 
1508
                    # shared base of a & b. So we don't include them.  And
 
1509
                    # obviously if the line is newly inserted, it isn't in base
 
1510
 
 
1511
                    # If 'conflicted-a' or b, then it is new vs one base, but
 
1512
                    # old versus another base. However, if we make it present
 
1513
                    # in the base, it will be deleted from the target, and it
 
1514
                    # seems better to get a line doubled in the merge result,
 
1515
                    # rather than have it deleted entirely.
 
1516
                    # Example, each node is the 'text' at that point:
 
1517
                    #           MN
 
1518
                    #          /   \
 
1519
                    #        MaN   MbN
 
1520
                    #         |  X  |
 
1521
                    #        MabN MbaN
 
1522
                    #          \   /
 
1523
                    #           ???
 
1524
                    # There was a criss-cross conflict merge. Both sides
 
1525
                    # include the other, but put themselves first.
 
1526
                    # Weave marks this as a 'clean' merge, picking OTHER over
 
1527
                    # THIS. (Though the details depend on order inserted into
 
1528
                    # weave, etc.)
 
1529
                    # LCA generates a plan:
 
1530
                    # [('unchanged', M),
 
1531
                    #  ('conflicted-b', b),
 
1532
                    #  ('unchanged', a),
 
1533
                    #  ('conflicted-a', b),
 
1534
                    #  ('unchanged', N)]
 
1535
                    # If you mark 'conflicted-*' as part of BASE, then a 3-way
 
1536
                    # merge tool will cleanly generate "MaN" (as BASE vs THIS
 
1537
                    # removes one 'b', and BASE vs OTHER removes the other)
 
1538
                    # If you include neither, 3-way creates a clean "MbabN" as
 
1539
                    # THIS adds one 'b', and OTHER does too.
 
1540
                    # It seems that having the line 2 times is better than
 
1541
                    # having it omitted. (Easier to manually delete than notice
 
1542
                    # it needs to be added.)
 
1543
                    raise AssertionError('Unknown state: %s' % (state,))
 
1544
        return base_lines
 
1545
 
1413
1546
 
1414
1547
class WeaveMerge(PlanWeaveMerge):
1415
1548
    """Weave merge that takes a VersionedFile and two versions as its input."""
1513
1646
            record.get_bytes_as(record.storage_kind) call.
1514
1647
        """
1515
1648
        self._bytes_iterator = bytes_iterator
1516
 
        self._kind_factory = {'knit-ft-gz':knit.knit_network_to_record,
1517
 
            'knit-delta-gz':knit.knit_network_to_record,
1518
 
            'knit-annotated-ft-gz':knit.knit_network_to_record,
1519
 
            'knit-annotated-delta-gz':knit.knit_network_to_record,
1520
 
            'knit-delta-closure':knit.knit_delta_closure_to_records,
1521
 
            'fulltext':fulltext_network_to_record,
1522
 
            'groupcompress-block':groupcompress.network_block_to_records,
 
1649
        self._kind_factory = {
 
1650
            'fulltext': fulltext_network_to_record,
 
1651
            'groupcompress-block': groupcompress.network_block_to_records,
 
1652
            'knit-ft-gz': knit.knit_network_to_record,
 
1653
            'knit-delta-gz': knit.knit_network_to_record,
 
1654
            'knit-annotated-ft-gz': knit.knit_network_to_record,
 
1655
            'knit-annotated-delta-gz': knit.knit_network_to_record,
 
1656
            'knit-delta-closure': knit.knit_delta_closure_to_records,
1523
1657
            }
1524
1658
 
1525
1659
    def read(self):