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

  • Committer: Martin Pool
  • Date: 2007-02-15 01:23:29 UTC
  • mfrom: (2284 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2309.
  • Revision ID: mbp@sourcefrog.net-20070215012329-blt2xfhup97r6w8h
merge up from bzr.dev to get metadir changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
from bzrlib.lazy_import import lazy_import
20
20
lazy_import(globals(), """
21
 
from binascii import hexlify
22
 
from copy import deepcopy
23
21
import re
24
22
import time
25
23
import unittest
27
25
from bzrlib import (
28
26
    bzrdir,
29
27
    check,
30
 
    delta,
31
28
    errors,
32
29
    generate_ids,
33
30
    gpg,
34
31
    graph,
35
 
    knit,
36
32
    lazy_regex,
37
33
    lockable_files,
38
34
    lockdir,
39
35
    osutils,
 
36
    registry,
40
37
    revision as _mod_revision,
41
38
    symbol_versioning,
42
39
    transactions,
43
40
    ui,
44
 
    weave,
45
 
    weavefile,
46
 
    xml5,
47
 
    xml6,
48
 
    )
49
 
from bzrlib.osutils import (
50
 
    rand_bytes,
51
 
    compact_date, 
52
 
    local_time_offset,
53
41
    )
54
42
from bzrlib.revisiontree import RevisionTree
55
43
from bzrlib.store.versioned import VersionedFileStore
56
44
from bzrlib.store.text import TextStore
57
45
from bzrlib.testament import Testament
 
46
 
58
47
""")
59
48
 
60
49
from bzrlib.decorators import needs_read_lock, needs_write_lock
100
89
 
101
90
        returns the sha1 of the serialized inventory.
102
91
        """
 
92
        _mod_revision.check_not_reserved_id(revid)
103
93
        assert inv.revision_id is None or inv.revision_id == revid, \
104
94
            "Mismatch between inventory revision" \
105
95
            " id and insertion revid (%r, %r)" % (inv.revision_id, revid)
131
121
                       If supplied its signature_needed method will be used
132
122
                       to determine if a signature should be made.
133
123
        """
 
124
        _mod_revision.check_not_reserved_id(rev_id)
134
125
        if config is not None and config.signature_needed():
135
126
            if inv is None:
136
127
                inv = self.get_inventory(rev_id)
224
215
        # TODO: make sure to construct the right store classes, etc, depending
225
216
        # on whether escaping is required.
226
217
        self._warn_if_deprecated()
227
 
        self._serializer = xml5.serializer_v5
228
218
 
229
219
    def __repr__(self):
230
220
        return '%s(%r)' % (self.__class__.__name__, 
243
233
        return self.control_files.get_physical_lock_status()
244
234
 
245
235
    @needs_read_lock
 
236
    def gather_stats(self, revid=None, committers=None):
 
237
        """Gather statistics from a revision id.
 
238
 
 
239
        :param revid: The revision id to gather statistics from, if None, then
 
240
            no revision specific statistics are gathered.
 
241
        :param committers: Optional parameter controlling whether to grab
 
242
            a count of committers from the revision specific statistics.
 
243
        :return: A dictionary of statistics. Currently this contains:
 
244
            committers: The number of committers if requested.
 
245
            firstrev: A tuple with timestamp, timezone for the penultimate left
 
246
                most ancestor of revid, if revid is not the NULL_REVISION.
 
247
            latestrev: A tuple with timestamp, timezone for revid, if revid is
 
248
                not the NULL_REVISION.
 
249
            revisions: The total revision count in the repository.
 
250
            size: An estimate disk size of the repository in bytes.
 
251
        """
 
252
        result = {}
 
253
        if revid and committers:
 
254
            result['committers'] = 0
 
255
        if revid and revid != _mod_revision.NULL_REVISION:
 
256
            if committers:
 
257
                all_committers = set()
 
258
            revisions = self.get_ancestry(revid)
 
259
            # pop the leading None
 
260
            revisions.pop(0)
 
261
            first_revision = None
 
262
            if not committers:
 
263
                # ignore the revisions in the middle - just grab first and last
 
264
                revisions = revisions[0], revisions[-1]
 
265
            for revision in self.get_revisions(revisions):
 
266
                if not first_revision:
 
267
                    first_revision = revision
 
268
                if committers:
 
269
                    all_committers.add(revision.committer)
 
270
            last_revision = revision
 
271
            if committers:
 
272
                result['committers'] = len(all_committers)
 
273
            result['firstrev'] = (first_revision.timestamp,
 
274
                first_revision.timezone)
 
275
            result['latestrev'] = (last_revision.timestamp,
 
276
                last_revision.timezone)
 
277
 
 
278
        # now gather global repository information
 
279
        if self.bzrdir.root_transport.listable():
 
280
            c, t = self._revision_store.total_size(self.get_transaction())
 
281
            result['revisions'] = c
 
282
            result['size'] = t
 
283
        return result
 
284
 
 
285
    @needs_read_lock
246
286
    def missing_revision_ids(self, other, revision_id=None):
247
287
        """Return the revision ids that other has that this does not.
248
288
        
304
344
 
305
345
        Currently no check is made that the format of this repository and
306
346
        the bzrdir format are compatible. FIXME RBC 20060201.
 
347
 
 
348
        :return: The newly created destination repository.
307
349
        """
308
350
        if not isinstance(a_bzrdir._format, self.bzrdir._format.__class__):
309
351
            # use target default format.
310
 
            result = a_bzrdir.create_repository()
311
 
        # FIXME RBC 20060209 split out the repository type to avoid this check ?
312
 
        elif isinstance(a_bzrdir._format,
313
 
                      (bzrdir.BzrDirFormat4,
314
 
                       bzrdir.BzrDirFormat5,
315
 
                       bzrdir.BzrDirFormat6)):
316
 
            result = a_bzrdir.open_repository()
 
352
            dest_repo = a_bzrdir.create_repository()
317
353
        else:
318
 
            result = self._format.initialize(a_bzrdir, shared=self.is_shared())
319
 
        self.copy_content_into(result, revision_id, basis)
320
 
        return result
 
354
            # Most control formats need the repository to be specifically
 
355
            # created, but on some old all-in-one formats it's not needed
 
356
            try:
 
357
                dest_repo = self._format.initialize(a_bzrdir, shared=self.is_shared())
 
358
            except errors.UninitializableFormat:
 
359
                dest_repo = a_bzrdir.open_repository()
 
360
        self.copy_content_into(dest_repo, revision_id, basis)
 
361
        return dest_repo
321
362
 
322
363
    @needs_read_lock
323
364
    def has_revision(self, revision_id):
779
820
                    raise errors.NonAsciiRevisionId(method, self)
780
821
 
781
822
 
782
 
class AllInOneRepository(Repository):
783
 
    """Legacy support - the repository behaviour for all-in-one branches."""
784
 
 
785
 
    def __init__(self, _format, a_bzrdir, _revision_store, control_store, text_store):
786
 
        # we reuse one control files instance.
787
 
        dir_mode = a_bzrdir._control_files._dir_mode
788
 
        file_mode = a_bzrdir._control_files._file_mode
789
 
 
790
 
        def get_store(name, compressed=True, prefixed=False):
791
 
            # FIXME: This approach of assuming stores are all entirely compressed
792
 
            # or entirely uncompressed is tidy, but breaks upgrade from 
793
 
            # some existing branches where there's a mixture; we probably 
794
 
            # still want the option to look for both.
795
 
            relpath = a_bzrdir._control_files._escape(name)
796
 
            store = TextStore(a_bzrdir._control_files._transport.clone(relpath),
797
 
                              prefixed=prefixed, compressed=compressed,
798
 
                              dir_mode=dir_mode,
799
 
                              file_mode=file_mode)
800
 
            #if self._transport.should_cache():
801
 
            #    cache_path = os.path.join(self.cache_root, name)
802
 
            #    os.mkdir(cache_path)
803
 
            #    store = bzrlib.store.CachedStore(store, cache_path)
804
 
            return store
805
 
 
806
 
        # not broken out yet because the controlweaves|inventory_store
807
 
        # and text_store | weave_store bits are still different.
808
 
        if isinstance(_format, RepositoryFormat4):
809
 
            # cannot remove these - there is still no consistent api 
810
 
            # which allows access to this old info.
811
 
            self.inventory_store = get_store('inventory-store')
812
 
            text_store = get_store('text-store')
813
 
        super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files, _revision_store, control_store, text_store)
814
 
 
815
 
    def get_commit_builder(self, branch, parents, config, timestamp=None,
816
 
                           timezone=None, committer=None, revprops=None,
817
 
                           revision_id=None):
818
 
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
819
 
        return Repository.get_commit_builder(self, branch, parents, config,
820
 
            timestamp, timezone, committer, revprops, revision_id)
821
 
 
822
 
    @needs_read_lock
823
 
    def is_shared(self):
824
 
        """AllInOne repositories cannot be shared."""
825
 
        return False
826
 
 
827
 
    @needs_write_lock
828
 
    def set_make_working_trees(self, new_value):
829
 
        """Set the policy flag for making working trees when creating branches.
830
 
 
831
 
        This only applies to branches that use this repository.
832
 
 
833
 
        The default is 'True'.
834
 
        :param new_value: True to restore the default, False to disable making
835
 
                          working trees.
836
 
        """
837
 
        raise NotImplementedError(self.set_make_working_trees)
838
 
    
839
 
    def make_working_trees(self):
840
 
        """Returns the policy for making working trees on new branches."""
841
 
        return True
 
823
 
 
824
# remove these delegates a while after bzr 0.15
 
825
def __make_delegated(name, from_module):
 
826
    def _deprecated_repository_forwarder():
 
827
        symbol_versioning.warn('%s moved to %s in bzr 0.15'
 
828
            % (name, from_module),
 
829
            DeprecationWarning,
 
830
            stacklevel=2)
 
831
        m = __import__(from_module, globals(), locals(), [name])
 
832
        try:
 
833
            return getattr(m, name)
 
834
        except AttributeError:
 
835
            raise AttributeError('module %s has no name %s'
 
836
                    % (m, name))
 
837
    globals()[name] = _deprecated_repository_forwarder
 
838
 
 
839
for _name in [
 
840
        'AllInOneRepository',
 
841
        'WeaveMetaDirRepository',
 
842
        'PreSplitOutRepositoryFormat',
 
843
        'RepositoryFormat4',
 
844
        'RepositoryFormat5',
 
845
        'RepositoryFormat6',
 
846
        'RepositoryFormat7',
 
847
        ]:
 
848
    __make_delegated(_name, 'bzrlib.repofmt.weaverepo')
 
849
 
 
850
for _name in [
 
851
        'KnitRepository',
 
852
        'KnitRepository2',
 
853
        'RepositoryFormatKnit',
 
854
        'RepositoryFormatKnit1',
 
855
        'RepositoryFormatKnit2',
 
856
        ]:
 
857
    __make_delegated(_name, 'bzrlib.repofmt.knitrepo')
842
858
 
843
859
 
844
860
def install_revision(repository, rev, revision_tree):
930
946
        return not self.control_files._transport.has('no-working-trees')
931
947
 
932
948
 
933
 
class WeaveMetaDirRepository(MetaDirRepository):
934
 
    """A subclass of MetaDirRepository to set weave specific policy."""
935
 
 
936
 
    def get_commit_builder(self, branch, parents, config, timestamp=None,
937
 
                           timezone=None, committer=None, revprops=None,
938
 
                           revision_id=None):
939
 
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
940
 
        return MetaDirRepository.get_commit_builder(self, branch, parents,
941
 
            config, timestamp, timezone, committer, revprops, revision_id)
942
 
 
943
 
 
944
 
class KnitRepository(MetaDirRepository):
945
 
    """Knit format repository."""
946
 
 
947
 
    def _warn_if_deprecated(self):
948
 
        # This class isn't deprecated
949
 
        pass
950
 
 
951
 
    def _inventory_add_lines(self, inv_vf, revid, parents, lines):
952
 
        inv_vf.add_lines_with_ghosts(revid, parents, lines)
953
 
 
954
 
    @needs_read_lock
955
 
    def _all_revision_ids(self):
956
 
        """See Repository.all_revision_ids()."""
957
 
        # Knits get the revision graph from the index of the revision knit, so
958
 
        # it's always possible even if they're on an unlistable transport.
959
 
        return self._revision_store.all_revision_ids(self.get_transaction())
960
 
 
961
 
    def fileid_involved_between_revs(self, from_revid, to_revid):
962
 
        """Find file_id(s) which are involved in the changes between revisions.
963
 
 
964
 
        This determines the set of revisions which are involved, and then
965
 
        finds all file ids affected by those revisions.
966
 
        """
967
 
        vf = self._get_revision_vf()
968
 
        from_set = set(vf.get_ancestry(from_revid))
969
 
        to_set = set(vf.get_ancestry(to_revid))
970
 
        changed = to_set.difference(from_set)
971
 
        return self._fileid_involved_by_set(changed)
972
 
 
973
 
    def fileid_involved(self, last_revid=None):
974
 
        """Find all file_ids modified in the ancestry of last_revid.
975
 
 
976
 
        :param last_revid: If None, last_revision() will be used.
977
 
        """
978
 
        if not last_revid:
979
 
            changed = set(self.all_revision_ids())
980
 
        else:
981
 
            changed = set(self.get_ancestry(last_revid))
982
 
        if None in changed:
983
 
            changed.remove(None)
984
 
        return self._fileid_involved_by_set(changed)
985
 
 
986
 
    @needs_read_lock
987
 
    def get_ancestry(self, revision_id):
988
 
        """Return a list of revision-ids integrated by a revision.
989
 
        
990
 
        This is topologically sorted.
991
 
        """
992
 
        if revision_id is None:
993
 
            return [None]
994
 
        vf = self._get_revision_vf()
995
 
        try:
996
 
            return [None] + vf.get_ancestry(revision_id)
997
 
        except errors.RevisionNotPresent:
998
 
            raise errors.NoSuchRevision(self, revision_id)
999
 
 
1000
 
    @needs_read_lock
1001
 
    def get_revision(self, revision_id):
1002
 
        """Return the Revision object for a named revision"""
1003
 
        return self.get_revision_reconcile(revision_id)
1004
 
 
1005
 
    @needs_read_lock
1006
 
    def get_revision_graph(self, revision_id=None):
1007
 
        """Return a dictionary containing the revision graph.
1008
 
 
1009
 
        :param revision_id: The revision_id to get a graph from. If None, then
1010
 
        the entire revision graph is returned. This is a deprecated mode of
1011
 
        operation and will be removed in the future.
1012
 
        :return: a dictionary of revision_id->revision_parents_list.
1013
 
        """
1014
 
        # special case NULL_REVISION
1015
 
        if revision_id == _mod_revision.NULL_REVISION:
1016
 
            return {}
1017
 
        a_weave = self._get_revision_vf()
1018
 
        entire_graph = a_weave.get_graph()
1019
 
        if revision_id is None:
1020
 
            return a_weave.get_graph()
1021
 
        elif revision_id not in a_weave:
1022
 
            raise errors.NoSuchRevision(self, revision_id)
1023
 
        else:
1024
 
            # add what can be reached from revision_id
1025
 
            result = {}
1026
 
            pending = set([revision_id])
1027
 
            while len(pending) > 0:
1028
 
                node = pending.pop()
1029
 
                result[node] = a_weave.get_parents(node)
1030
 
                for revision_id in result[node]:
1031
 
                    if revision_id not in result:
1032
 
                        pending.add(revision_id)
1033
 
            return result
1034
 
 
1035
 
    @needs_read_lock
1036
 
    def get_revision_graph_with_ghosts(self, revision_ids=None):
1037
 
        """Return a graph of the revisions with ghosts marked as applicable.
1038
 
 
1039
 
        :param revision_ids: an iterable of revisions to graph or None for all.
1040
 
        :return: a Graph object with the graph reachable from revision_ids.
1041
 
        """
1042
 
        result = graph.Graph()
1043
 
        vf = self._get_revision_vf()
1044
 
        versions = set(vf.versions())
1045
 
        if not revision_ids:
1046
 
            pending = set(self.all_revision_ids())
1047
 
            required = set([])
1048
 
        else:
1049
 
            pending = set(revision_ids)
1050
 
            # special case NULL_REVISION
1051
 
            if _mod_revision.NULL_REVISION in pending:
1052
 
                pending.remove(_mod_revision.NULL_REVISION)
1053
 
            required = set(pending)
1054
 
        done = set([])
1055
 
        while len(pending):
1056
 
            revision_id = pending.pop()
1057
 
            if not revision_id in versions:
1058
 
                if revision_id in required:
1059
 
                    raise errors.NoSuchRevision(self, revision_id)
1060
 
                # a ghost
1061
 
                result.add_ghost(revision_id)
1062
 
                # mark it as done so we don't try for it again.
1063
 
                done.add(revision_id)
1064
 
                continue
1065
 
            parent_ids = vf.get_parents_with_ghosts(revision_id)
1066
 
            for parent_id in parent_ids:
1067
 
                # is this queued or done ?
1068
 
                if (parent_id not in pending and
1069
 
                    parent_id not in done):
1070
 
                    # no, queue it.
1071
 
                    pending.add(parent_id)
1072
 
            result.add_node(revision_id, parent_ids)
1073
 
            done.add(revision_id)
1074
 
        return result
1075
 
 
1076
 
    def _get_revision_vf(self):
1077
 
        """:return: a versioned file containing the revisions."""
1078
 
        vf = self._revision_store.get_revision_file(self.get_transaction())
1079
 
        return vf
1080
 
 
1081
 
    @needs_write_lock
1082
 
    def reconcile(self, other=None, thorough=False):
1083
 
        """Reconcile this repository."""
1084
 
        from bzrlib.reconcile import KnitReconciler
1085
 
        reconciler = KnitReconciler(self, thorough=thorough)
1086
 
        reconciler.reconcile()
1087
 
        return reconciler
1088
 
    
1089
 
    def revision_parents(self, revision_id):
1090
 
        return self._get_revision_vf().get_parents(revision_id)
1091
 
 
1092
 
 
1093
 
class KnitRepository2(KnitRepository):
1094
 
    """Experimental enhanced knit format"""
1095
 
 
1096
 
    # corresponds to RepositoryFormatKnit2
1097
 
    
1098
 
    def __init__(self, _format, a_bzrdir, control_files, _revision_store,
1099
 
                 control_store, text_store):
1100
 
        KnitRepository.__init__(self, _format, a_bzrdir, control_files,
1101
 
                              _revision_store, control_store, text_store)
1102
 
        self._transport = control_files._transport
1103
 
        self._serializer = xml6.serializer_v6
1104
 
 
1105
 
    def deserialise_inventory(self, revision_id, xml):
1106
 
        """Transform the xml into an inventory object. 
1107
 
 
1108
 
        :param revision_id: The expected revision id of the inventory.
1109
 
        :param xml: A serialised inventory.
1110
 
        """
1111
 
        result = self._serializer.read_inventory_from_string(xml)
1112
 
        assert result.root.revision is not None
1113
 
        return result
1114
 
 
1115
 
    def serialise_inventory(self, inv):
1116
 
        """Transform the inventory object into XML text.
1117
 
 
1118
 
        :param revision_id: The expected revision id of the inventory.
1119
 
        :param xml: A serialised inventory.
1120
 
        """
1121
 
        assert inv.revision_id is not None
1122
 
        assert inv.root.revision is not None
1123
 
        return KnitRepository.serialise_inventory(self, inv)
1124
 
 
1125
 
    def get_commit_builder(self, branch, parents, config, timestamp=None, 
1126
 
                           timezone=None, committer=None, revprops=None, 
1127
 
                           revision_id=None):
1128
 
        """Obtain a CommitBuilder for this repository.
1129
 
        
1130
 
        :param branch: Branch to commit to.
1131
 
        :param parents: Revision ids of the parents of the new revision.
1132
 
        :param config: Configuration to use.
1133
 
        :param timestamp: Optional timestamp recorded for commit.
1134
 
        :param timezone: Optional timezone for timestamp.
1135
 
        :param committer: Optional committer to set for commit.
1136
 
        :param revprops: Optional dictionary of revision properties.
1137
 
        :param revision_id: Optional revision id.
1138
 
        """
1139
 
        return RootCommitBuilder(self, parents, config, timestamp, timezone,
1140
 
                                 committer, revprops, revision_id)
 
949
class RepositoryFormatRegistry(registry.Registry):
 
950
    """Registry of RepositoryFormats.
 
951
    """
 
952
 
 
953
    def get(self, format_string):
 
954
        r = registry.Registry.get(self, format_string)
 
955
        if callable(r):
 
956
            r = r()
 
957
        return r
 
958
    
 
959
 
 
960
format_registry = RepositoryFormatRegistry()
 
961
"""Registry of formats, indexed by their identifying format string.
 
962
 
 
963
This can contain either format instances themselves, or classes/factories that
 
964
can be called to obtain one.
 
965
"""
1141
966
 
1142
967
 
1143
968
#####################################################################
1167
992
    parameterisation.
1168
993
    """
1169
994
 
1170
 
    _default_format = None
1171
 
    """The default format used for new repositories."""
1172
 
 
1173
 
    _formats = {}
1174
 
    """The known formats."""
1175
 
 
1176
995
    def __str__(self):
1177
996
        return "<%s>" % self.__class__.__name__
1178
997
 
 
998
    def __eq__(self, other):
 
999
        # format objects are generally stateless
 
1000
        return isinstance(other, self.__class__)
 
1001
 
1179
1002
    @classmethod
1180
1003
    def find_format(klass, a_bzrdir):
1181
 
        """Return the format for the repository object in a_bzrdir."""
 
1004
        """Return the format for the repository object in a_bzrdir.
 
1005
        
 
1006
        This is used by bzr native formats that have a "format" file in
 
1007
        the repository.  Other methods may be used by different types of 
 
1008
        control directory.
 
1009
        """
1182
1010
        try:
1183
1011
            transport = a_bzrdir.get_repository_transport(None)
1184
1012
            format_string = transport.get("format").read()
1185
 
            return klass._formats[format_string]
 
1013
            return format_registry.get(format_string)
1186
1014
        except errors.NoSuchFile:
1187
1015
            raise errors.NoRepositoryPresent(a_bzrdir)
1188
1016
        except KeyError:
1189
1017
            raise errors.UnknownFormatError(format=format_string)
1190
1018
 
1191
 
    def _get_control_store(self, repo_transport, control_files):
1192
 
        """Return the control store for this repository."""
1193
 
        raise NotImplementedError(self._get_control_store)
 
1019
    @classmethod
 
1020
    def register_format(klass, format):
 
1021
        format_registry.register(format.get_format_string(), format)
 
1022
 
 
1023
    @classmethod
 
1024
    def unregister_format(klass, format):
 
1025
        format_registry.remove(format.get_format_string())
1194
1026
    
1195
1027
    @classmethod
1196
1028
    def get_default_format(klass):
1197
1029
        """Return the current default format."""
1198
 
        return klass._default_format
 
1030
        from bzrlib import bzrdir
 
1031
        return bzrdir.format_registry.make_bzrdir('default').repository_format
 
1032
 
 
1033
    def _get_control_store(self, repo_transport, control_files):
 
1034
        """Return the control store for this repository."""
 
1035
        raise NotImplementedError(self._get_control_store)
1199
1036
 
1200
1037
    def get_format_string(self):
1201
1038
        """Return the ASCII format string that identifies this format.
1236
1073
        _revision_store = TextRevisionStore(text_store, serializer)
1237
1074
        return _revision_store
1238
1075
 
 
1076
    # TODO: this shouldn't be in the base class, it's specific to things that
 
1077
    # use weaves or knits -- mbp 20070207
1239
1078
    def _get_versioned_file_store(self,
1240
1079
                                  name,
1241
1080
                                  transport,
1242
1081
                                  control_files,
1243
1082
                                  prefixed=True,
1244
 
                                  versionedfile_class=weave.WeaveFile,
 
1083
                                  versionedfile_class=None,
1245
1084
                                  versionedfile_kwargs={},
1246
1085
                                  escaped=False):
 
1086
        if versionedfile_class is None:
 
1087
            versionedfile_class = self._versionedfile_class
1247
1088
        weave_transport = control_files._transport.clone(name)
1248
1089
        dir_mode = control_files._dir_mode
1249
1090
        file_mode = control_files._file_mode
1283
1124
        """
1284
1125
        raise NotImplementedError(self.open)
1285
1126
 
1286
 
    @classmethod
1287
 
    def register_format(klass, format):
1288
 
        klass._formats[format.get_format_string()] = format
1289
 
 
1290
 
    @classmethod
1291
 
    def set_default_format(klass, format):
1292
 
        klass._default_format = format
1293
 
 
1294
 
    @classmethod
1295
 
    def unregister_format(klass, format):
1296
 
        assert klass._formats[format.get_format_string()] is format
1297
 
        del klass._formats[format.get_format_string()]
1298
 
 
1299
 
 
1300
 
class PreSplitOutRepositoryFormat(RepositoryFormat):
1301
 
    """Base class for the pre split out repository formats."""
1302
 
 
1303
 
    rich_root_data = False
1304
 
 
1305
 
    def initialize(self, a_bzrdir, shared=False, _internal=False):
1306
 
        """Create a weave repository.
1307
 
        
1308
 
        TODO: when creating split out bzr branch formats, move this to a common
1309
 
        base for Format5, Format6. or something like that.
1310
 
        """
1311
 
        if shared:
1312
 
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
1313
 
 
1314
 
        if not _internal:
1315
 
            # always initialized when the bzrdir is.
1316
 
            return self.open(a_bzrdir, _found=True)
1317
 
        
1318
 
        # Create an empty weave
1319
 
        sio = StringIO()
1320
 
        weavefile.write_weave_v5(weave.Weave(), sio)
1321
 
        empty_weave = sio.getvalue()
1322
 
 
1323
 
        mutter('creating repository in %s.', a_bzrdir.transport.base)
1324
 
        dirs = ['revision-store', 'weaves']
1325
 
        files = [('inventory.weave', StringIO(empty_weave)),
1326
 
                 ]
1327
 
        
1328
 
        # FIXME: RBC 20060125 don't peek under the covers
1329
 
        # NB: no need to escape relative paths that are url safe.
1330
 
        control_files = lockable_files.LockableFiles(a_bzrdir.transport,
1331
 
                                'branch-lock', lockable_files.TransportLock)
1332
 
        control_files.create_lock()
1333
 
        control_files.lock_write()
1334
 
        control_files._transport.mkdir_multi(dirs,
1335
 
                mode=control_files._dir_mode)
1336
 
        try:
1337
 
            for file, content in files:
1338
 
                control_files.put(file, content)
1339
 
        finally:
1340
 
            control_files.unlock()
1341
 
        return self.open(a_bzrdir, _found=True)
1342
 
 
1343
 
    def _get_control_store(self, repo_transport, control_files):
1344
 
        """Return the control store for this repository."""
1345
 
        return self._get_versioned_file_store('',
1346
 
                                              repo_transport,
1347
 
                                              control_files,
1348
 
                                              prefixed=False)
1349
 
 
1350
 
    def _get_text_store(self, transport, control_files):
1351
 
        """Get a store for file texts for this format."""
1352
 
        raise NotImplementedError(self._get_text_store)
1353
 
 
1354
 
    def open(self, a_bzrdir, _found=False):
1355
 
        """See RepositoryFormat.open()."""
1356
 
        if not _found:
1357
 
            # we are being called directly and must probe.
1358
 
            raise NotImplementedError
1359
 
 
1360
 
        repo_transport = a_bzrdir.get_repository_transport(None)
1361
 
        control_files = a_bzrdir._control_files
1362
 
        text_store = self._get_text_store(repo_transport, control_files)
1363
 
        control_store = self._get_control_store(repo_transport, control_files)
1364
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1365
 
        return AllInOneRepository(_format=self,
1366
 
                                  a_bzrdir=a_bzrdir,
1367
 
                                  _revision_store=_revision_store,
1368
 
                                  control_store=control_store,
1369
 
                                  text_store=text_store)
1370
 
 
1371
 
    def check_conversion_target(self, target_format):
1372
 
        pass
1373
 
 
1374
 
 
1375
 
class RepositoryFormat4(PreSplitOutRepositoryFormat):
1376
 
    """Bzr repository format 4.
1377
 
 
1378
 
    This repository format has:
1379
 
     - flat stores
1380
 
     - TextStores for texts, inventories,revisions.
1381
 
 
1382
 
    This format is deprecated: it indexes texts using a text id which is
1383
 
    removed in format 5; initialization and write support for this format
1384
 
    has been removed.
1385
 
    """
1386
 
 
1387
 
    def __init__(self):
1388
 
        super(RepositoryFormat4, self).__init__()
1389
 
        self._matchingbzrdir = bzrdir.BzrDirFormat4()
1390
 
 
1391
 
    def get_format_description(self):
1392
 
        """See RepositoryFormat.get_format_description()."""
1393
 
        return "Repository format 4"
1394
 
 
1395
 
    def initialize(self, url, shared=False, _internal=False):
1396
 
        """Format 4 branches cannot be created."""
1397
 
        raise errors.UninitializableFormat(self)
1398
 
 
1399
 
    def is_supported(self):
1400
 
        """Format 4 is not supported.
1401
 
 
1402
 
        It is not supported because the model changed from 4 to 5 and the
1403
 
        conversion logic is expensive - so doing it on the fly was not 
1404
 
        feasible.
1405
 
        """
1406
 
        return False
1407
 
 
1408
 
    def _get_control_store(self, repo_transport, control_files):
1409
 
        """Format 4 repositories have no formal control store at this point.
1410
 
        
1411
 
        This will cause any control-file-needing apis to fail - this is desired.
1412
 
        """
1413
 
        return None
1414
 
    
1415
 
    def _get_revision_store(self, repo_transport, control_files):
1416
 
        """See RepositoryFormat._get_revision_store()."""
1417
 
        from bzrlib.xml4 import serializer_v4
1418
 
        return self._get_text_rev_store(repo_transport,
1419
 
                                        control_files,
1420
 
                                        'revision-store',
1421
 
                                        serializer=serializer_v4)
1422
 
 
1423
 
    def _get_text_store(self, transport, control_files):
1424
 
        """See RepositoryFormat._get_text_store()."""
1425
 
 
1426
 
 
1427
 
class RepositoryFormat5(PreSplitOutRepositoryFormat):
1428
 
    """Bzr control format 5.
1429
 
 
1430
 
    This repository format has:
1431
 
     - weaves for file texts and inventory
1432
 
     - flat stores
1433
 
     - TextStores for revisions and signatures.
1434
 
    """
1435
 
 
1436
 
    def __init__(self):
1437
 
        super(RepositoryFormat5, self).__init__()
1438
 
        self._matchingbzrdir = bzrdir.BzrDirFormat5()
1439
 
 
1440
 
    def get_format_description(self):
1441
 
        """See RepositoryFormat.get_format_description()."""
1442
 
        return "Weave repository format 5"
1443
 
 
1444
 
    def _get_revision_store(self, repo_transport, control_files):
1445
 
        """See RepositoryFormat._get_revision_store()."""
1446
 
        """Return the revision store object for this a_bzrdir."""
1447
 
        return self._get_text_rev_store(repo_transport,
1448
 
                                        control_files,
1449
 
                                        'revision-store',
1450
 
                                        compressed=False)
1451
 
 
1452
 
    def _get_text_store(self, transport, control_files):
1453
 
        """See RepositoryFormat._get_text_store()."""
1454
 
        return self._get_versioned_file_store('weaves', transport, control_files, prefixed=False)
1455
 
 
1456
 
 
1457
 
class RepositoryFormat6(PreSplitOutRepositoryFormat):
1458
 
    """Bzr control format 6.
1459
 
 
1460
 
    This repository format has:
1461
 
     - weaves for file texts and inventory
1462
 
     - hash subdirectory based stores.
1463
 
     - TextStores for revisions and signatures.
1464
 
    """
1465
 
 
1466
 
    def __init__(self):
1467
 
        super(RepositoryFormat6, self).__init__()
1468
 
        self._matchingbzrdir = bzrdir.BzrDirFormat6()
1469
 
 
1470
 
    def get_format_description(self):
1471
 
        """See RepositoryFormat.get_format_description()."""
1472
 
        return "Weave repository format 6"
1473
 
 
1474
 
    def _get_revision_store(self, repo_transport, control_files):
1475
 
        """See RepositoryFormat._get_revision_store()."""
1476
 
        return self._get_text_rev_store(repo_transport,
1477
 
                                        control_files,
1478
 
                                        'revision-store',
1479
 
                                        compressed=False,
1480
 
                                        prefixed=True)
1481
 
 
1482
 
    def _get_text_store(self, transport, control_files):
1483
 
        """See RepositoryFormat._get_text_store()."""
1484
 
        return self._get_versioned_file_store('weaves', transport, control_files)
1485
 
 
1486
1127
 
1487
1128
class MetaDirRepositoryFormat(RepositoryFormat):
1488
1129
    """Common base class for the new repositories using the metadir layout."""
1489
1130
 
1490
1131
    rich_root_data = False
 
1132
    _matchingbzrdir = bzrdir.BzrDirMetaFormat1()
1491
1133
 
1492
1134
    def __init__(self):
1493
1135
        super(MetaDirRepositoryFormat, self).__init__()
1494
 
        self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
1495
1136
 
1496
1137
    def _create_control_files(self, a_bzrdir):
1497
1138
        """Create the required files and the initial control_files object."""
1520
1161
            control_files.unlock()
1521
1162
 
1522
1163
 
1523
 
class RepositoryFormat7(MetaDirRepositoryFormat):
1524
 
    """Bzr repository 7.
1525
 
 
1526
 
    This repository format has:
1527
 
     - weaves for file texts and inventory
1528
 
     - hash subdirectory based stores.
1529
 
     - TextStores for revisions and signatures.
1530
 
     - a format marker of its own
1531
 
     - an optional 'shared-storage' flag
1532
 
     - an optional 'no-working-trees' flag
1533
 
    """
1534
 
 
1535
 
    def _get_control_store(self, repo_transport, control_files):
1536
 
        """Return the control store for this repository."""
1537
 
        return self._get_versioned_file_store('',
1538
 
                                              repo_transport,
1539
 
                                              control_files,
1540
 
                                              prefixed=False)
1541
 
 
1542
 
    def get_format_string(self):
1543
 
        """See RepositoryFormat.get_format_string()."""
1544
 
        return "Bazaar-NG Repository format 7"
1545
 
 
1546
 
    def get_format_description(self):
1547
 
        """See RepositoryFormat.get_format_description()."""
1548
 
        return "Weave repository format 7"
1549
 
 
1550
 
    def check_conversion_target(self, target_format):
1551
 
        pass
1552
 
 
1553
 
    def _get_revision_store(self, repo_transport, control_files):
1554
 
        """See RepositoryFormat._get_revision_store()."""
1555
 
        return self._get_text_rev_store(repo_transport,
1556
 
                                        control_files,
1557
 
                                        'revision-store',
1558
 
                                        compressed=False,
1559
 
                                        prefixed=True,
1560
 
                                        )
1561
 
 
1562
 
    def _get_text_store(self, transport, control_files):
1563
 
        """See RepositoryFormat._get_text_store()."""
1564
 
        return self._get_versioned_file_store('weaves',
1565
 
                                              transport,
1566
 
                                              control_files)
1567
 
 
1568
 
    def initialize(self, a_bzrdir, shared=False):
1569
 
        """Create a weave repository.
1570
 
 
1571
 
        :param shared: If true the repository will be initialized as a shared
1572
 
                       repository.
1573
 
        """
1574
 
        # Create an empty weave
1575
 
        sio = StringIO()
1576
 
        weavefile.write_weave_v5(weave.Weave(), sio)
1577
 
        empty_weave = sio.getvalue()
1578
 
 
1579
 
        mutter('creating repository in %s.', a_bzrdir.transport.base)
1580
 
        dirs = ['revision-store', 'weaves']
1581
 
        files = [('inventory.weave', StringIO(empty_weave)), 
1582
 
                 ]
1583
 
        utf8_files = [('format', self.get_format_string())]
1584
 
 
1585
 
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
1586
 
        return self.open(a_bzrdir=a_bzrdir, _found=True)
1587
 
 
1588
 
    def open(self, a_bzrdir, _found=False, _override_transport=None):
1589
 
        """See RepositoryFormat.open().
1590
 
        
1591
 
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
1592
 
                                    repository at a slightly different url
1593
 
                                    than normal. I.e. during 'upgrade'.
1594
 
        """
1595
 
        if not _found:
1596
 
            format = RepositoryFormat.find_format(a_bzrdir)
1597
 
            assert format.__class__ ==  self.__class__
1598
 
        if _override_transport is not None:
1599
 
            repo_transport = _override_transport
1600
 
        else:
1601
 
            repo_transport = a_bzrdir.get_repository_transport(None)
1602
 
        control_files = lockable_files.LockableFiles(repo_transport,
1603
 
                                'lock', lockdir.LockDir)
1604
 
        text_store = self._get_text_store(repo_transport, control_files)
1605
 
        control_store = self._get_control_store(repo_transport, control_files)
1606
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1607
 
        return WeaveMetaDirRepository(_format=self,
1608
 
            a_bzrdir=a_bzrdir,
1609
 
            control_files=control_files,
1610
 
            _revision_store=_revision_store,
1611
 
            control_store=control_store,
1612
 
            text_store=text_store)
1613
 
 
1614
 
 
1615
 
class RepositoryFormatKnit(MetaDirRepositoryFormat):
1616
 
    """Bzr repository knit format (generalized). 
1617
 
 
1618
 
    This repository format has:
1619
 
     - knits for file texts and inventory
1620
 
     - hash subdirectory based stores.
1621
 
     - knits for revisions and signatures
1622
 
     - TextStores for revisions and signatures.
1623
 
     - a format marker of its own
1624
 
     - an optional 'shared-storage' flag
1625
 
     - an optional 'no-working-trees' flag
1626
 
     - a LockDir lock
1627
 
    """
1628
 
 
1629
 
    def _get_control_store(self, repo_transport, control_files):
1630
 
        """Return the control store for this repository."""
1631
 
        return VersionedFileStore(
1632
 
            repo_transport,
1633
 
            prefixed=False,
1634
 
            file_mode=control_files._file_mode,
1635
 
            versionedfile_class=knit.KnitVersionedFile,
1636
 
            versionedfile_kwargs={'factory':knit.KnitPlainFactory()},
1637
 
            )
1638
 
 
1639
 
    def _get_revision_store(self, repo_transport, control_files):
1640
 
        """See RepositoryFormat._get_revision_store()."""
1641
 
        from bzrlib.store.revision.knit import KnitRevisionStore
1642
 
        versioned_file_store = VersionedFileStore(
1643
 
            repo_transport,
1644
 
            file_mode=control_files._file_mode,
1645
 
            prefixed=False,
1646
 
            precious=True,
1647
 
            versionedfile_class=knit.KnitVersionedFile,
1648
 
            versionedfile_kwargs={'delta':False,
1649
 
                                  'factory':knit.KnitPlainFactory(),
1650
 
                                 },
1651
 
            escaped=True,
1652
 
            )
1653
 
        return KnitRevisionStore(versioned_file_store)
1654
 
 
1655
 
    def _get_text_store(self, transport, control_files):
1656
 
        """See RepositoryFormat._get_text_store()."""
1657
 
        return self._get_versioned_file_store('knits',
1658
 
                                  transport,
1659
 
                                  control_files,
1660
 
                                  versionedfile_class=knit.KnitVersionedFile,
1661
 
                                  versionedfile_kwargs={
1662
 
                                      'create_parent_dir':True,
1663
 
                                      'delay_create':True,
1664
 
                                      'dir_mode':control_files._dir_mode,
1665
 
                                  },
1666
 
                                  escaped=True)
1667
 
 
1668
 
    def initialize(self, a_bzrdir, shared=False):
1669
 
        """Create a knit format 1 repository.
1670
 
 
1671
 
        :param a_bzrdir: bzrdir to contain the new repository; must already
1672
 
            be initialized.
1673
 
        :param shared: If true the repository will be initialized as a shared
1674
 
                       repository.
1675
 
        """
1676
 
        mutter('creating repository in %s.', a_bzrdir.transport.base)
1677
 
        dirs = ['revision-store', 'knits']
1678
 
        files = []
1679
 
        utf8_files = [('format', self.get_format_string())]
1680
 
        
1681
 
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
1682
 
        repo_transport = a_bzrdir.get_repository_transport(None)
1683
 
        control_files = lockable_files.LockableFiles(repo_transport,
1684
 
                                'lock', lockdir.LockDir)
1685
 
        control_store = self._get_control_store(repo_transport, control_files)
1686
 
        transaction = transactions.WriteTransaction()
1687
 
        # trigger a write of the inventory store.
1688
 
        control_store.get_weave_or_empty('inventory', transaction)
1689
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1690
 
        # the revision id here is irrelevant: it will not be stored, and cannot
1691
 
        # already exist.
1692
 
        _revision_store.has_revision_id('A', transaction)
1693
 
        _revision_store.get_signature_file(transaction)
1694
 
        return self.open(a_bzrdir=a_bzrdir, _found=True)
1695
 
 
1696
 
    def open(self, a_bzrdir, _found=False, _override_transport=None):
1697
 
        """See RepositoryFormat.open().
1698
 
        
1699
 
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
1700
 
                                    repository at a slightly different url
1701
 
                                    than normal. I.e. during 'upgrade'.
1702
 
        """
1703
 
        if not _found:
1704
 
            format = RepositoryFormat.find_format(a_bzrdir)
1705
 
            assert format.__class__ ==  self.__class__
1706
 
        if _override_transport is not None:
1707
 
            repo_transport = _override_transport
1708
 
        else:
1709
 
            repo_transport = a_bzrdir.get_repository_transport(None)
1710
 
        control_files = lockable_files.LockableFiles(repo_transport,
1711
 
                                'lock', lockdir.LockDir)
1712
 
        text_store = self._get_text_store(repo_transport, control_files)
1713
 
        control_store = self._get_control_store(repo_transport, control_files)
1714
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1715
 
        return KnitRepository(_format=self,
1716
 
                              a_bzrdir=a_bzrdir,
1717
 
                              control_files=control_files,
1718
 
                              _revision_store=_revision_store,
1719
 
                              control_store=control_store,
1720
 
                              text_store=text_store)
1721
 
 
1722
 
 
1723
 
class RepositoryFormatKnit1(RepositoryFormatKnit):
1724
 
    """Bzr repository knit format 1.
1725
 
 
1726
 
    This repository format has:
1727
 
     - knits for file texts and inventory
1728
 
     - hash subdirectory based stores.
1729
 
     - knits for revisions and signatures
1730
 
     - TextStores for revisions and signatures.
1731
 
     - a format marker of its own
1732
 
     - an optional 'shared-storage' flag
1733
 
     - an optional 'no-working-trees' flag
1734
 
     - a LockDir lock
1735
 
 
1736
 
    This format was introduced in bzr 0.8.
1737
 
    """
1738
 
    def get_format_string(self):
1739
 
        """See RepositoryFormat.get_format_string()."""
1740
 
        return "Bazaar-NG Knit Repository Format 1"
1741
 
 
1742
 
    def get_format_description(self):
1743
 
        """See RepositoryFormat.get_format_description()."""
1744
 
        return "Knit repository format 1"
1745
 
 
1746
 
    def check_conversion_target(self, target_format):
1747
 
        pass
1748
 
 
1749
 
 
1750
 
class RepositoryFormatKnit2(RepositoryFormatKnit):
1751
 
    """Bzr repository knit format 2.
1752
 
 
1753
 
    THIS FORMAT IS EXPERIMENTAL
1754
 
    This repository format has:
1755
 
     - knits for file texts and inventory
1756
 
     - hash subdirectory based stores.
1757
 
     - knits for revisions and signatures
1758
 
     - TextStores for revisions and signatures.
1759
 
     - a format marker of its own
1760
 
     - an optional 'shared-storage' flag
1761
 
     - an optional 'no-working-trees' flag
1762
 
     - a LockDir lock
1763
 
     - Support for recording full info about the tree root
1764
 
    """
1765
 
    
1766
 
    rich_root_data = True
1767
 
 
1768
 
    def get_format_string(self):
1769
 
        """See RepositoryFormat.get_format_string()."""
1770
 
        return "Bazaar Knit Repository Format 2\n"
1771
 
 
1772
 
    def get_format_description(self):
1773
 
        """See RepositoryFormat.get_format_description()."""
1774
 
        return "Knit repository format 2"
1775
 
 
1776
 
    def check_conversion_target(self, target_format):
1777
 
        if not target_format.rich_root_data:
1778
 
            raise errors.BadConversionTarget(
1779
 
                'Does not support rich root data.', target_format)
1780
 
 
1781
 
    def open(self, a_bzrdir, _found=False, _override_transport=None):
1782
 
        """See RepositoryFormat.open().
1783
 
        
1784
 
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
1785
 
                                    repository at a slightly different url
1786
 
                                    than normal. I.e. during 'upgrade'.
1787
 
        """
1788
 
        if not _found:
1789
 
            format = RepositoryFormat.find_format(a_bzrdir)
1790
 
            assert format.__class__ ==  self.__class__
1791
 
        if _override_transport is not None:
1792
 
            repo_transport = _override_transport
1793
 
        else:
1794
 
            repo_transport = a_bzrdir.get_repository_transport(None)
1795
 
        control_files = lockable_files.LockableFiles(repo_transport, 'lock',
1796
 
                                                     lockdir.LockDir)
1797
 
        text_store = self._get_text_store(repo_transport, control_files)
1798
 
        control_store = self._get_control_store(repo_transport, control_files)
1799
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1800
 
        return KnitRepository2(_format=self,
1801
 
                               a_bzrdir=a_bzrdir,
1802
 
                               control_files=control_files,
1803
 
                               _revision_store=_revision_store,
1804
 
                               control_store=control_store,
1805
 
                                text_store=text_store)
1806
 
 
1807
 
    def initialize(self, a_bzrdir, shared=False):
1808
 
        repo = super(RepositoryFormatKnit2, self).initialize(a_bzrdir, shared)
1809
 
        repo._transport.put_bytes_non_atomic('tags', '')
1810
 
        return repo
1811
 
 
1812
 
    def supports_tags(self):
1813
 
        return True
1814
 
 
1815
 
 
1816
 
 
1817
1164
# formats which have no format string are not discoverable
1818
 
# and not independently creatable, so are not registered.
1819
 
RepositoryFormat.register_format(RepositoryFormat7())
1820
 
# KEEP in sync with bzrdir.format_registry default
1821
 
_default_format = RepositoryFormatKnit1()
1822
 
RepositoryFormat.register_format(_default_format)
1823
 
RepositoryFormat.register_format(RepositoryFormatKnit2())
1824
 
RepositoryFormat.set_default_format(_default_format)
1825
 
_legacy_formats = [RepositoryFormat4(),
1826
 
                   RepositoryFormat5(),
1827
 
                   RepositoryFormat6()]
 
1165
# and not independently creatable, so are not registered.  They're 
 
1166
# all in bzrlib.repofmt.weaverepo now.  When an instance of one of these is
 
1167
# needed, it's constructed directly by the BzrDir.  Non-native formats where
 
1168
# the repository is not separately opened are similar.
 
1169
 
 
1170
format_registry.register_lazy(
 
1171
    'Bazaar-NG Repository format 7',
 
1172
    'bzrlib.repofmt.weaverepo',
 
1173
    'RepositoryFormat7'
 
1174
    )
 
1175
# KEEP in sync with bzrdir.format_registry default, which controls the overall
 
1176
# default control directory format
 
1177
 
 
1178
format_registry.register_lazy(
 
1179
    'Bazaar-NG Knit Repository Format 1',
 
1180
    'bzrlib.repofmt.knitrepo',
 
1181
    'RepositoryFormatKnit1',
 
1182
    )
 
1183
format_registry.default_key = 'Bazaar-NG Knit Repository Format 1'
 
1184
 
 
1185
format_registry.register_lazy(
 
1186
    'Bazaar Knit Repository Format 2\n',
 
1187
    'bzrlib.repofmt.knitrepo',
 
1188
    'RepositoryFormatKnit2',
 
1189
    )
1828
1190
 
1829
1191
 
1830
1192
class InterRepository(InterObject):
1883
1245
        # that we've decided we need.
1884
1246
        return [rev_id for rev_id in source_ids if rev_id in result_set]
1885
1247
 
1886
 
    def copy_tags(self):
1887
 
        """Copy all tags from source to the target."""
1888
 
        # A default implementation is provided even though not all
1889
 
        # Repositories will support tags... we'll just get an error back from
1890
 
        # the underlying method.
1891
 
        if self.target == self.source:
1892
 
            return
1893
 
        self.target.lock_write()
1894
 
        try:
1895
 
            self.target._set_tag_dict(self.source.get_tag_dict())
1896
 
        finally:
1897
 
            self.target.unlock()
1898
 
 
1899
1248
 
1900
1249
class InterSameDataRepository(InterRepository):
1901
1250
    """Code for converting between repositories that represent the same data.
1903
1252
    Data format and model must match for this to work.
1904
1253
    """
1905
1254
 
1906
 
    _matching_repo_format = RepositoryFormat4()
1907
 
    """Repository format for testing with."""
 
1255
    @classmethod
 
1256
    def _get_repo_format_to_test(self):
 
1257
        """Repository format for testing with."""
 
1258
        return RepositoryFormat.get_default_format()
1908
1259
 
1909
1260
    @staticmethod
1910
1261
    def is_compatible(source, target):
1958
1309
class InterWeaveRepo(InterSameDataRepository):
1959
1310
    """Optimised code paths between Weave based repositories."""
1960
1311
 
1961
 
    _matching_repo_format = RepositoryFormat7()
1962
 
    """Repository format for testing with."""
 
1312
    @classmethod
 
1313
    def _get_repo_format_to_test(self):
 
1314
        from bzrlib.repofmt import weaverepo
 
1315
        return weaverepo.RepositoryFormat7()
1963
1316
 
1964
1317
    @staticmethod
1965
1318
    def is_compatible(source, target):
1969
1322
        could lead to confusing results, and there is no need to be 
1970
1323
        overly general.
1971
1324
        """
 
1325
        from bzrlib.repofmt.weaverepo import (
 
1326
                RepositoryFormat5,
 
1327
                RepositoryFormat6,
 
1328
                RepositoryFormat7,
 
1329
                )
1972
1330
        try:
1973
1331
            return (isinstance(source._format, (RepositoryFormat5,
1974
1332
                                                RepositoryFormat6,
2076
1434
class InterKnitRepo(InterSameDataRepository):
2077
1435
    """Optimised code paths between Knit based repositories."""
2078
1436
 
2079
 
    _matching_repo_format = RepositoryFormatKnit1()
2080
 
    """Repository format for testing with."""
 
1437
    @classmethod
 
1438
    def _get_repo_format_to_test(self):
 
1439
        from bzrlib.repofmt import knitrepo
 
1440
        return knitrepo.RepositoryFormatKnit1()
2081
1441
 
2082
1442
    @staticmethod
2083
1443
    def is_compatible(source, target):
2087
1447
        could lead to confusing results, and there is no need to be 
2088
1448
        overly general.
2089
1449
        """
 
1450
        from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
2090
1451
        try:
2091
1452
            return (isinstance(source._format, (RepositoryFormatKnit1)) and
2092
1453
                    isinstance(target._format, (RepositoryFormatKnit1)))
2138
1499
 
2139
1500
class InterModel1and2(InterRepository):
2140
1501
 
2141
 
    _matching_repo_format = None
 
1502
    @classmethod
 
1503
    def _get_repo_format_to_test(self):
 
1504
        return None
2142
1505
 
2143
1506
    @staticmethod
2144
1507
    def is_compatible(source, target):
2188
1551
 
2189
1552
class InterKnit1and2(InterKnitRepo):
2190
1553
 
2191
 
    _matching_repo_format = None
 
1554
    @classmethod
 
1555
    def _get_repo_format_to_test(self):
 
1556
        return None
2192
1557
 
2193
1558
    @staticmethod
2194
1559
    def is_compatible(source, target):
2195
1560
        """Be compatible with Knit1 source and Knit2 target"""
 
1561
        from bzrlib.repofmt.knitrepo import RepositoryFormatKnit2
2196
1562
        try:
 
1563
            from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1, \
 
1564
                    RepositoryFormatKnit2
2197
1565
            return (isinstance(source._format, (RepositoryFormatKnit1)) and
2198
1566
                    isinstance(target._format, (RepositoryFormatKnit2)))
2199
1567
        except AttributeError:
2237
1605
    def adapt(self, test):
2238
1606
        result = unittest.TestSuite()
2239
1607
        for repository_format, bzrdir_format in self._formats:
 
1608
            from copy import deepcopy
2240
1609
            new_test = deepcopy(test)
2241
1610
            new_test.transport_server = self._transport_server
2242
1611
            new_test.transport_readonly_server = self._transport_readonly_server
2267
1636
    def adapt(self, test):
2268
1637
        result = unittest.TestSuite()
2269
1638
        for interrepo_class, repository_format, repository_format_to in self._formats:
 
1639
            from copy import deepcopy
2270
1640
            new_test = deepcopy(test)
2271
1641
            new_test.transport_server = self._transport_server
2272
1642
            new_test.transport_readonly_server = self._transport_readonly_server
2283
1653
    @staticmethod
2284
1654
    def default_test_list():
2285
1655
        """Generate the default list of interrepo permutations to test."""
 
1656
        from bzrlib.repofmt import knitrepo, weaverepo
2286
1657
        result = []
2287
1658
        # test the default InterRepository between format 6 and the current 
2288
1659
        # default format.
2291
1662
        #result.append((InterRepository,
2292
1663
        #               RepositoryFormat6(),
2293
1664
        #               RepositoryFormatKnit1()))
2294
 
        for optimiser in InterRepository._optimisers:
2295
 
            if optimiser._matching_repo_format is not None:
2296
 
                result.append((optimiser,
2297
 
                               optimiser._matching_repo_format,
2298
 
                               optimiser._matching_repo_format
2299
 
                               ))
 
1665
        for optimiser_class in InterRepository._optimisers:
 
1666
            format_to_test = optimiser_class._get_repo_format_to_test()
 
1667
            if format_to_test is not None:
 
1668
                result.append((optimiser_class,
 
1669
                               format_to_test, format_to_test))
2300
1670
        # if there are specific combinations we want to use, we can add them 
2301
1671
        # here.
2302
 
        result.append((InterModel1and2, RepositoryFormat5(),
2303
 
                       RepositoryFormatKnit2()))
2304
 
        result.append((InterKnit1and2, RepositoryFormatKnit1(),
2305
 
                       RepositoryFormatKnit2()))
 
1672
        result.append((InterModel1and2,
 
1673
                       weaverepo.RepositoryFormat5(),
 
1674
                       knitrepo.RepositoryFormatKnit2()))
 
1675
        result.append((InterKnit1and2,
 
1676
                       knitrepo.RepositoryFormatKnit1(),
 
1677
                       knitrepo.RepositoryFormatKnit2()))
2306
1678
        return result
2307
1679
 
2308
1680
 
2403
1775
        self._timestamp = round(timestamp, 3)
2404
1776
 
2405
1777
        if timezone is None:
2406
 
            self._timezone = local_time_offset()
 
1778
            self._timezone = osutils.local_time_offset()
2407
1779
        else:
2408
1780
            self._timezone = int(timezone)
2409
1781