~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-02-13 11:48:14 UTC
  • mfrom: (2241.1.20 repoformats)
  • Revision ID: pqm@pqm.ubuntu.com-20070213114814-9606106906ac312f
(mbp) split repository formats into repofmt (r=john)

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,
42
38
    symbol_versioning,
43
39
    transactions,
44
40
    ui,
45
 
    weave,
46
 
    weavefile,
47
 
    xml5,
48
 
    xml6,
49
 
    )
50
 
from bzrlib.osutils import (
51
 
    rand_bytes,
52
 
    compact_date, 
53
 
    local_time_offset,
54
41
    )
55
42
from bzrlib.revisiontree import RevisionTree
56
43
from bzrlib.store.versioned import VersionedFileStore
57
44
from bzrlib.store.text import TextStore
58
45
from bzrlib.testament import Testament
 
46
 
59
47
""")
60
48
 
61
49
from bzrlib.decorators import needs_read_lock, needs_write_lock
224
212
        # TODO: make sure to construct the right store classes, etc, depending
225
213
        # on whether escaping is required.
226
214
        self._warn_if_deprecated()
227
 
        self._serializer = xml5.serializer_v5
228
215
 
229
216
    def __repr__(self):
230
217
        return '%s(%r)' % (self.__class__.__name__, 
354
341
 
355
342
        Currently no check is made that the format of this repository and
356
343
        the bzrdir format are compatible. FIXME RBC 20060201.
 
344
 
 
345
        :return: The newly created destination repository.
357
346
        """
358
347
        if not isinstance(a_bzrdir._format, self.bzrdir._format.__class__):
359
348
            # use target default format.
360
 
            result = a_bzrdir.create_repository()
361
 
        # FIXME RBC 20060209 split out the repository type to avoid this check ?
362
 
        elif isinstance(a_bzrdir._format,
363
 
                      (bzrdir.BzrDirFormat4,
364
 
                       bzrdir.BzrDirFormat5,
365
 
                       bzrdir.BzrDirFormat6)):
366
 
            result = a_bzrdir.open_repository()
 
349
            dest_repo = a_bzrdir.create_repository()
367
350
        else:
368
 
            result = self._format.initialize(a_bzrdir, shared=self.is_shared())
369
 
        self.copy_content_into(result, revision_id, basis)
370
 
        return result
 
351
            # Most control formats need the repository to be specifically
 
352
            # created, but on some old all-in-one formats it's not needed
 
353
            try:
 
354
                dest_repo = self._format.initialize(a_bzrdir, shared=self.is_shared())
 
355
            except errors.UninitializableFormat:
 
356
                dest_repo = a_bzrdir.open_repository()
 
357
        self.copy_content_into(dest_repo, revision_id, basis)
 
358
        return dest_repo
371
359
 
372
360
    @needs_read_lock
373
361
    def has_revision(self, revision_id):
829
817
                    raise errors.NonAsciiRevisionId(method, self)
830
818
 
831
819
 
832
 
class AllInOneRepository(Repository):
833
 
    """Legacy support - the repository behaviour for all-in-one branches."""
834
 
 
835
 
    def __init__(self, _format, a_bzrdir, _revision_store, control_store, text_store):
836
 
        # we reuse one control files instance.
837
 
        dir_mode = a_bzrdir._control_files._dir_mode
838
 
        file_mode = a_bzrdir._control_files._file_mode
839
 
 
840
 
        def get_store(name, compressed=True, prefixed=False):
841
 
            # FIXME: This approach of assuming stores are all entirely compressed
842
 
            # or entirely uncompressed is tidy, but breaks upgrade from 
843
 
            # some existing branches where there's a mixture; we probably 
844
 
            # still want the option to look for both.
845
 
            relpath = a_bzrdir._control_files._escape(name)
846
 
            store = TextStore(a_bzrdir._control_files._transport.clone(relpath),
847
 
                              prefixed=prefixed, compressed=compressed,
848
 
                              dir_mode=dir_mode,
849
 
                              file_mode=file_mode)
850
 
            #if self._transport.should_cache():
851
 
            #    cache_path = os.path.join(self.cache_root, name)
852
 
            #    os.mkdir(cache_path)
853
 
            #    store = bzrlib.store.CachedStore(store, cache_path)
854
 
            return store
855
 
 
856
 
        # not broken out yet because the controlweaves|inventory_store
857
 
        # and text_store | weave_store bits are still different.
858
 
        if isinstance(_format, RepositoryFormat4):
859
 
            # cannot remove these - there is still no consistent api 
860
 
            # which allows access to this old info.
861
 
            self.inventory_store = get_store('inventory-store')
862
 
            text_store = get_store('text-store')
863
 
        super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files, _revision_store, control_store, text_store)
864
 
 
865
 
    def get_commit_builder(self, branch, parents, config, timestamp=None,
866
 
                           timezone=None, committer=None, revprops=None,
867
 
                           revision_id=None):
868
 
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
869
 
        return Repository.get_commit_builder(self, branch, parents, config,
870
 
            timestamp, timezone, committer, revprops, revision_id)
871
 
 
872
 
    @needs_read_lock
873
 
    def is_shared(self):
874
 
        """AllInOne repositories cannot be shared."""
875
 
        return False
876
 
 
877
 
    @needs_write_lock
878
 
    def set_make_working_trees(self, new_value):
879
 
        """Set the policy flag for making working trees when creating branches.
880
 
 
881
 
        This only applies to branches that use this repository.
882
 
 
883
 
        The default is 'True'.
884
 
        :param new_value: True to restore the default, False to disable making
885
 
                          working trees.
886
 
        """
887
 
        raise NotImplementedError(self.set_make_working_trees)
888
 
    
889
 
    def make_working_trees(self):
890
 
        """Returns the policy for making working trees on new branches."""
891
 
        return True
 
820
 
 
821
# remove these delegates a while after bzr 0.15
 
822
def __make_delegated(name, from_module):
 
823
    def _deprecated_repository_forwarder():
 
824
        symbol_versioning.warn('%s moved to %s in bzr 0.15'
 
825
            % (name, from_module),
 
826
            DeprecationWarning,
 
827
            stacklevel=2)
 
828
        m = __import__(from_module, globals(), locals(), [name])
 
829
        try:
 
830
            return getattr(m, name)
 
831
        except AttributeError:
 
832
            raise AttributeError('module %s has no name %s'
 
833
                    % (m, name))
 
834
    globals()[name] = _deprecated_repository_forwarder
 
835
 
 
836
for _name in [
 
837
        'AllInOneRepository',
 
838
        'WeaveMetaDirRepository',
 
839
        'PreSplitOutRepositoryFormat',
 
840
        'RepositoryFormat4',
 
841
        'RepositoryFormat5',
 
842
        'RepositoryFormat6',
 
843
        'RepositoryFormat7',
 
844
        ]:
 
845
    __make_delegated(_name, 'bzrlib.repofmt.weaverepo')
 
846
 
 
847
for _name in [
 
848
        'KnitRepository',
 
849
        'KnitRepository2',
 
850
        'RepositoryFormatKnit',
 
851
        'RepositoryFormatKnit1',
 
852
        'RepositoryFormatKnit2',
 
853
        ]:
 
854
    __make_delegated(_name, 'bzrlib.repofmt.knitrepo')
892
855
 
893
856
 
894
857
def install_revision(repository, rev, revision_tree):
980
943
        return not self.control_files._transport.has('no-working-trees')
981
944
 
982
945
 
983
 
class WeaveMetaDirRepository(MetaDirRepository):
984
 
    """A subclass of MetaDirRepository to set weave specific policy."""
985
 
 
986
 
    def get_commit_builder(self, branch, parents, config, timestamp=None,
987
 
                           timezone=None, committer=None, revprops=None,
988
 
                           revision_id=None):
989
 
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
990
 
        return MetaDirRepository.get_commit_builder(self, branch, parents,
991
 
            config, timestamp, timezone, committer, revprops, revision_id)
992
 
 
993
 
 
994
 
class KnitRepository(MetaDirRepository):
995
 
    """Knit format repository."""
996
 
 
997
 
    def _warn_if_deprecated(self):
998
 
        # This class isn't deprecated
999
 
        pass
1000
 
 
1001
 
    def _inventory_add_lines(self, inv_vf, revid, parents, lines):
1002
 
        inv_vf.add_lines_with_ghosts(revid, parents, lines)
1003
 
 
1004
 
    @needs_read_lock
1005
 
    def _all_revision_ids(self):
1006
 
        """See Repository.all_revision_ids()."""
1007
 
        # Knits get the revision graph from the index of the revision knit, so
1008
 
        # it's always possible even if they're on an unlistable transport.
1009
 
        return self._revision_store.all_revision_ids(self.get_transaction())
1010
 
 
1011
 
    def fileid_involved_between_revs(self, from_revid, to_revid):
1012
 
        """Find file_id(s) which are involved in the changes between revisions.
1013
 
 
1014
 
        This determines the set of revisions which are involved, and then
1015
 
        finds all file ids affected by those revisions.
1016
 
        """
1017
 
        vf = self._get_revision_vf()
1018
 
        from_set = set(vf.get_ancestry(from_revid))
1019
 
        to_set = set(vf.get_ancestry(to_revid))
1020
 
        changed = to_set.difference(from_set)
1021
 
        return self._fileid_involved_by_set(changed)
1022
 
 
1023
 
    def fileid_involved(self, last_revid=None):
1024
 
        """Find all file_ids modified in the ancestry of last_revid.
1025
 
 
1026
 
        :param last_revid: If None, last_revision() will be used.
1027
 
        """
1028
 
        if not last_revid:
1029
 
            changed = set(self.all_revision_ids())
1030
 
        else:
1031
 
            changed = set(self.get_ancestry(last_revid))
1032
 
        if None in changed:
1033
 
            changed.remove(None)
1034
 
        return self._fileid_involved_by_set(changed)
1035
 
 
1036
 
    @needs_read_lock
1037
 
    def get_ancestry(self, revision_id):
1038
 
        """Return a list of revision-ids integrated by a revision.
1039
 
        
1040
 
        This is topologically sorted.
1041
 
        """
1042
 
        if revision_id is None:
1043
 
            return [None]
1044
 
        vf = self._get_revision_vf()
1045
 
        try:
1046
 
            return [None] + vf.get_ancestry(revision_id)
1047
 
        except errors.RevisionNotPresent:
1048
 
            raise errors.NoSuchRevision(self, revision_id)
1049
 
 
1050
 
    @needs_read_lock
1051
 
    def get_revision(self, revision_id):
1052
 
        """Return the Revision object for a named revision"""
1053
 
        return self.get_revision_reconcile(revision_id)
1054
 
 
1055
 
    @needs_read_lock
1056
 
    def get_revision_graph(self, revision_id=None):
1057
 
        """Return a dictionary containing the revision graph.
1058
 
 
1059
 
        :param revision_id: The revision_id to get a graph from. If None, then
1060
 
        the entire revision graph is returned. This is a deprecated mode of
1061
 
        operation and will be removed in the future.
1062
 
        :return: a dictionary of revision_id->revision_parents_list.
1063
 
        """
1064
 
        # special case NULL_REVISION
1065
 
        if revision_id == _mod_revision.NULL_REVISION:
1066
 
            return {}
1067
 
        a_weave = self._get_revision_vf()
1068
 
        entire_graph = a_weave.get_graph()
1069
 
        if revision_id is None:
1070
 
            return a_weave.get_graph()
1071
 
        elif revision_id not in a_weave:
1072
 
            raise errors.NoSuchRevision(self, revision_id)
1073
 
        else:
1074
 
            # add what can be reached from revision_id
1075
 
            result = {}
1076
 
            pending = set([revision_id])
1077
 
            while len(pending) > 0:
1078
 
                node = pending.pop()
1079
 
                result[node] = a_weave.get_parents(node)
1080
 
                for revision_id in result[node]:
1081
 
                    if revision_id not in result:
1082
 
                        pending.add(revision_id)
1083
 
            return result
1084
 
 
1085
 
    @needs_read_lock
1086
 
    def get_revision_graph_with_ghosts(self, revision_ids=None):
1087
 
        """Return a graph of the revisions with ghosts marked as applicable.
1088
 
 
1089
 
        :param revision_ids: an iterable of revisions to graph or None for all.
1090
 
        :return: a Graph object with the graph reachable from revision_ids.
1091
 
        """
1092
 
        result = graph.Graph()
1093
 
        vf = self._get_revision_vf()
1094
 
        versions = set(vf.versions())
1095
 
        if not revision_ids:
1096
 
            pending = set(self.all_revision_ids())
1097
 
            required = set([])
1098
 
        else:
1099
 
            pending = set(revision_ids)
1100
 
            # special case NULL_REVISION
1101
 
            if _mod_revision.NULL_REVISION in pending:
1102
 
                pending.remove(_mod_revision.NULL_REVISION)
1103
 
            required = set(pending)
1104
 
        done = set([])
1105
 
        while len(pending):
1106
 
            revision_id = pending.pop()
1107
 
            if not revision_id in versions:
1108
 
                if revision_id in required:
1109
 
                    raise errors.NoSuchRevision(self, revision_id)
1110
 
                # a ghost
1111
 
                result.add_ghost(revision_id)
1112
 
                # mark it as done so we don't try for it again.
1113
 
                done.add(revision_id)
1114
 
                continue
1115
 
            parent_ids = vf.get_parents_with_ghosts(revision_id)
1116
 
            for parent_id in parent_ids:
1117
 
                # is this queued or done ?
1118
 
                if (parent_id not in pending and
1119
 
                    parent_id not in done):
1120
 
                    # no, queue it.
1121
 
                    pending.add(parent_id)
1122
 
            result.add_node(revision_id, parent_ids)
1123
 
            done.add(revision_id)
1124
 
        return result
1125
 
 
1126
 
    def _get_revision_vf(self):
1127
 
        """:return: a versioned file containing the revisions."""
1128
 
        vf = self._revision_store.get_revision_file(self.get_transaction())
1129
 
        return vf
1130
 
 
1131
 
    @needs_write_lock
1132
 
    def reconcile(self, other=None, thorough=False):
1133
 
        """Reconcile this repository."""
1134
 
        from bzrlib.reconcile import KnitReconciler
1135
 
        reconciler = KnitReconciler(self, thorough=thorough)
1136
 
        reconciler.reconcile()
1137
 
        return reconciler
1138
 
    
1139
 
    def revision_parents(self, revision_id):
1140
 
        return self._get_revision_vf().get_parents(revision_id)
1141
 
 
1142
 
 
1143
 
class KnitRepository2(KnitRepository):
1144
 
    """"""
1145
 
    def __init__(self, _format, a_bzrdir, control_files, _revision_store,
1146
 
                 control_store, text_store):
1147
 
        KnitRepository.__init__(self, _format, a_bzrdir, control_files,
1148
 
                              _revision_store, control_store, text_store)
1149
 
        self._serializer = xml6.serializer_v6
1150
 
 
1151
 
    def deserialise_inventory(self, revision_id, xml):
1152
 
        """Transform the xml into an inventory object. 
1153
 
 
1154
 
        :param revision_id: The expected revision id of the inventory.
1155
 
        :param xml: A serialised inventory.
1156
 
        """
1157
 
        result = self._serializer.read_inventory_from_string(xml)
1158
 
        assert result.root.revision is not None
1159
 
        return result
1160
 
 
1161
 
    def serialise_inventory(self, inv):
1162
 
        """Transform the inventory object into XML text.
1163
 
 
1164
 
        :param revision_id: The expected revision id of the inventory.
1165
 
        :param xml: A serialised inventory.
1166
 
        """
1167
 
        assert inv.revision_id is not None
1168
 
        assert inv.root.revision is not None
1169
 
        return KnitRepository.serialise_inventory(self, inv)
1170
 
 
1171
 
    def get_commit_builder(self, branch, parents, config, timestamp=None, 
1172
 
                           timezone=None, committer=None, revprops=None, 
1173
 
                           revision_id=None):
1174
 
        """Obtain a CommitBuilder for this repository.
1175
 
        
1176
 
        :param branch: Branch to commit to.
1177
 
        :param parents: Revision ids of the parents of the new revision.
1178
 
        :param config: Configuration to use.
1179
 
        :param timestamp: Optional timestamp recorded for commit.
1180
 
        :param timezone: Optional timezone for timestamp.
1181
 
        :param committer: Optional committer to set for commit.
1182
 
        :param revprops: Optional dictionary of revision properties.
1183
 
        :param revision_id: Optional revision id.
1184
 
        """
1185
 
        return RootCommitBuilder(self, parents, config, timestamp, timezone,
1186
 
                                 committer, revprops, revision_id)
1187
 
 
1188
 
 
1189
946
class RepositoryFormatRegistry(registry.Registry):
1190
947
    """Registry of RepositoryFormats.
1191
948
    """
 
949
 
 
950
    def get(self, format_string):
 
951
        r = registry.Registry.get(self, format_string)
 
952
        if callable(r):
 
953
            r = r()
 
954
        return r
1192
955
    
1193
956
 
1194
957
format_registry = RepositoryFormatRegistry()
1195
 
"""Registry of formats, indexed by their identifying format string."""
 
958
"""Registry of formats, indexed by their identifying format string.
 
959
 
 
960
This can contain either format instances themselves, or classes/factories that
 
961
can be called to obtain one.
 
962
"""
1196
963
 
1197
964
 
1198
965
class RepositoryFormat(object):
1222
989
    def __str__(self):
1223
990
        return "<%s>" % self.__class__.__name__
1224
991
 
 
992
    def __eq__(self, other):
 
993
        # format objects are generally stateless
 
994
        return isinstance(other, self.__class__)
 
995
 
1225
996
    @classmethod
1226
997
    def find_format(klass, a_bzrdir):
1227
998
        """Return the format for the repository object in a_bzrdir.
1296
1067
        _revision_store = TextRevisionStore(text_store, serializer)
1297
1068
        return _revision_store
1298
1069
 
 
1070
    # TODO: this shouldn't be in the base class, it's specific to things that
 
1071
    # use weaves or knits -- mbp 20070207
1299
1072
    def _get_versioned_file_store(self,
1300
1073
                                  name,
1301
1074
                                  transport,
1302
1075
                                  control_files,
1303
1076
                                  prefixed=True,
1304
 
                                  versionedfile_class=weave.WeaveFile,
 
1077
                                  versionedfile_class=None,
1305
1078
                                  versionedfile_kwargs={},
1306
1079
                                  escaped=False):
 
1080
        if versionedfile_class is None:
 
1081
            versionedfile_class = self._versionedfile_class
1307
1082
        weave_transport = control_files._transport.clone(name)
1308
1083
        dir_mode = control_files._dir_mode
1309
1084
        file_mode = control_files._file_mode
1344
1119
        raise NotImplementedError(self.open)
1345
1120
 
1346
1121
 
1347
 
class PreSplitOutRepositoryFormat(RepositoryFormat):
1348
 
    """Base class for the pre split out repository formats."""
1349
 
 
1350
 
    rich_root_data = False
1351
 
 
1352
 
    def initialize(self, a_bzrdir, shared=False, _internal=False):
1353
 
        """Create a weave repository.
1354
 
        
1355
 
        TODO: when creating split out bzr branch formats, move this to a common
1356
 
        base for Format5, Format6. or something like that.
1357
 
        """
1358
 
        if shared:
1359
 
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
1360
 
 
1361
 
        if not _internal:
1362
 
            # always initialized when the bzrdir is.
1363
 
            return self.open(a_bzrdir, _found=True)
1364
 
        
1365
 
        # Create an empty weave
1366
 
        sio = StringIO()
1367
 
        weavefile.write_weave_v5(weave.Weave(), sio)
1368
 
        empty_weave = sio.getvalue()
1369
 
 
1370
 
        mutter('creating repository in %s.', a_bzrdir.transport.base)
1371
 
        dirs = ['revision-store', 'weaves']
1372
 
        files = [('inventory.weave', StringIO(empty_weave)),
1373
 
                 ]
1374
 
        
1375
 
        # FIXME: RBC 20060125 don't peek under the covers
1376
 
        # NB: no need to escape relative paths that are url safe.
1377
 
        control_files = lockable_files.LockableFiles(a_bzrdir.transport,
1378
 
                                'branch-lock', lockable_files.TransportLock)
1379
 
        control_files.create_lock()
1380
 
        control_files.lock_write()
1381
 
        control_files._transport.mkdir_multi(dirs,
1382
 
                mode=control_files._dir_mode)
1383
 
        try:
1384
 
            for file, content in files:
1385
 
                control_files.put(file, content)
1386
 
        finally:
1387
 
            control_files.unlock()
1388
 
        return self.open(a_bzrdir, _found=True)
1389
 
 
1390
 
    def _get_control_store(self, repo_transport, control_files):
1391
 
        """Return the control store for this repository."""
1392
 
        return self._get_versioned_file_store('',
1393
 
                                              repo_transport,
1394
 
                                              control_files,
1395
 
                                              prefixed=False)
1396
 
 
1397
 
    def _get_text_store(self, transport, control_files):
1398
 
        """Get a store for file texts for this format."""
1399
 
        raise NotImplementedError(self._get_text_store)
1400
 
 
1401
 
    def open(self, a_bzrdir, _found=False):
1402
 
        """See RepositoryFormat.open()."""
1403
 
        if not _found:
1404
 
            # we are being called directly and must probe.
1405
 
            raise NotImplementedError
1406
 
 
1407
 
        repo_transport = a_bzrdir.get_repository_transport(None)
1408
 
        control_files = a_bzrdir._control_files
1409
 
        text_store = self._get_text_store(repo_transport, control_files)
1410
 
        control_store = self._get_control_store(repo_transport, control_files)
1411
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1412
 
        return AllInOneRepository(_format=self,
1413
 
                                  a_bzrdir=a_bzrdir,
1414
 
                                  _revision_store=_revision_store,
1415
 
                                  control_store=control_store,
1416
 
                                  text_store=text_store)
1417
 
 
1418
 
    def check_conversion_target(self, target_format):
1419
 
        pass
1420
 
 
1421
 
 
1422
 
class RepositoryFormat4(PreSplitOutRepositoryFormat):
1423
 
    """Bzr repository format 4.
1424
 
 
1425
 
    This repository format has:
1426
 
     - flat stores
1427
 
     - TextStores for texts, inventories,revisions.
1428
 
 
1429
 
    This format is deprecated: it indexes texts using a text id which is
1430
 
    removed in format 5; initialization and write support for this format
1431
 
    has been removed.
1432
 
    """
1433
 
 
1434
 
    def __init__(self):
1435
 
        super(RepositoryFormat4, self).__init__()
1436
 
        self._matchingbzrdir = bzrdir.BzrDirFormat4()
1437
 
 
1438
 
    def get_format_description(self):
1439
 
        """See RepositoryFormat.get_format_description()."""
1440
 
        return "Repository format 4"
1441
 
 
1442
 
    def initialize(self, url, shared=False, _internal=False):
1443
 
        """Format 4 branches cannot be created."""
1444
 
        raise errors.UninitializableFormat(self)
1445
 
 
1446
 
    def is_supported(self):
1447
 
        """Format 4 is not supported.
1448
 
 
1449
 
        It is not supported because the model changed from 4 to 5 and the
1450
 
        conversion logic is expensive - so doing it on the fly was not 
1451
 
        feasible.
1452
 
        """
1453
 
        return False
1454
 
 
1455
 
    def _get_control_store(self, repo_transport, control_files):
1456
 
        """Format 4 repositories have no formal control store at this point.
1457
 
        
1458
 
        This will cause any control-file-needing apis to fail - this is desired.
1459
 
        """
1460
 
        return None
1461
 
    
1462
 
    def _get_revision_store(self, repo_transport, control_files):
1463
 
        """See RepositoryFormat._get_revision_store()."""
1464
 
        from bzrlib.xml4 import serializer_v4
1465
 
        return self._get_text_rev_store(repo_transport,
1466
 
                                        control_files,
1467
 
                                        'revision-store',
1468
 
                                        serializer=serializer_v4)
1469
 
 
1470
 
    def _get_text_store(self, transport, control_files):
1471
 
        """See RepositoryFormat._get_text_store()."""
1472
 
 
1473
 
 
1474
 
class RepositoryFormat5(PreSplitOutRepositoryFormat):
1475
 
    """Bzr control format 5.
1476
 
 
1477
 
    This repository format has:
1478
 
     - weaves for file texts and inventory
1479
 
     - flat stores
1480
 
     - TextStores for revisions and signatures.
1481
 
    """
1482
 
 
1483
 
    def __init__(self):
1484
 
        super(RepositoryFormat5, self).__init__()
1485
 
        self._matchingbzrdir = bzrdir.BzrDirFormat5()
1486
 
 
1487
 
    def get_format_description(self):
1488
 
        """See RepositoryFormat.get_format_description()."""
1489
 
        return "Weave repository format 5"
1490
 
 
1491
 
    def _get_revision_store(self, repo_transport, control_files):
1492
 
        """See RepositoryFormat._get_revision_store()."""
1493
 
        """Return the revision store object for this a_bzrdir."""
1494
 
        return self._get_text_rev_store(repo_transport,
1495
 
                                        control_files,
1496
 
                                        'revision-store',
1497
 
                                        compressed=False)
1498
 
 
1499
 
    def _get_text_store(self, transport, control_files):
1500
 
        """See RepositoryFormat._get_text_store()."""
1501
 
        return self._get_versioned_file_store('weaves', transport, control_files, prefixed=False)
1502
 
 
1503
 
 
1504
 
class RepositoryFormat6(PreSplitOutRepositoryFormat):
1505
 
    """Bzr control format 6.
1506
 
 
1507
 
    This repository format has:
1508
 
     - weaves for file texts and inventory
1509
 
     - hash subdirectory based stores.
1510
 
     - TextStores for revisions and signatures.
1511
 
    """
1512
 
 
1513
 
    def __init__(self):
1514
 
        super(RepositoryFormat6, self).__init__()
1515
 
        self._matchingbzrdir = bzrdir.BzrDirFormat6()
1516
 
 
1517
 
    def get_format_description(self):
1518
 
        """See RepositoryFormat.get_format_description()."""
1519
 
        return "Weave repository format 6"
1520
 
 
1521
 
    def _get_revision_store(self, repo_transport, control_files):
1522
 
        """See RepositoryFormat._get_revision_store()."""
1523
 
        return self._get_text_rev_store(repo_transport,
1524
 
                                        control_files,
1525
 
                                        'revision-store',
1526
 
                                        compressed=False,
1527
 
                                        prefixed=True)
1528
 
 
1529
 
    def _get_text_store(self, transport, control_files):
1530
 
        """See RepositoryFormat._get_text_store()."""
1531
 
        return self._get_versioned_file_store('weaves', transport, control_files)
1532
 
 
1533
 
 
1534
1122
class MetaDirRepositoryFormat(RepositoryFormat):
1535
1123
    """Common base class for the new repositories using the metadir layout."""
1536
1124
 
1537
1125
    rich_root_data = False
 
1126
    _matchingbzrdir = bzrdir.BzrDirMetaFormat1()
1538
1127
 
1539
1128
    def __init__(self):
1540
1129
        super(MetaDirRepositoryFormat, self).__init__()
1541
 
        self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
1542
1130
 
1543
1131
    def _create_control_files(self, a_bzrdir):
1544
1132
        """Create the required files and the initial control_files object."""
1567
1155
            control_files.unlock()
1568
1156
 
1569
1157
 
1570
 
class RepositoryFormat7(MetaDirRepositoryFormat):
1571
 
    """Bzr repository 7.
1572
 
 
1573
 
    This repository format has:
1574
 
     - weaves for file texts and inventory
1575
 
     - hash subdirectory based stores.
1576
 
     - TextStores for revisions and signatures.
1577
 
     - a format marker of its own
1578
 
     - an optional 'shared-storage' flag
1579
 
     - an optional 'no-working-trees' flag
1580
 
    """
1581
 
 
1582
 
    def _get_control_store(self, repo_transport, control_files):
1583
 
        """Return the control store for this repository."""
1584
 
        return self._get_versioned_file_store('',
1585
 
                                              repo_transport,
1586
 
                                              control_files,
1587
 
                                              prefixed=False)
1588
 
 
1589
 
    def get_format_string(self):
1590
 
        """See RepositoryFormat.get_format_string()."""
1591
 
        return "Bazaar-NG Repository format 7"
1592
 
 
1593
 
    def get_format_description(self):
1594
 
        """See RepositoryFormat.get_format_description()."""
1595
 
        return "Weave repository format 7"
1596
 
 
1597
 
    def check_conversion_target(self, target_format):
1598
 
        pass
1599
 
 
1600
 
    def _get_revision_store(self, repo_transport, control_files):
1601
 
        """See RepositoryFormat._get_revision_store()."""
1602
 
        return self._get_text_rev_store(repo_transport,
1603
 
                                        control_files,
1604
 
                                        'revision-store',
1605
 
                                        compressed=False,
1606
 
                                        prefixed=True,
1607
 
                                        )
1608
 
 
1609
 
    def _get_text_store(self, transport, control_files):
1610
 
        """See RepositoryFormat._get_text_store()."""
1611
 
        return self._get_versioned_file_store('weaves',
1612
 
                                              transport,
1613
 
                                              control_files)
1614
 
 
1615
 
    def initialize(self, a_bzrdir, shared=False):
1616
 
        """Create a weave repository.
1617
 
 
1618
 
        :param shared: If true the repository will be initialized as a shared
1619
 
                       repository.
1620
 
        """
1621
 
        # Create an empty weave
1622
 
        sio = StringIO()
1623
 
        weavefile.write_weave_v5(weave.Weave(), sio)
1624
 
        empty_weave = sio.getvalue()
1625
 
 
1626
 
        mutter('creating repository in %s.', a_bzrdir.transport.base)
1627
 
        dirs = ['revision-store', 'weaves']
1628
 
        files = [('inventory.weave', StringIO(empty_weave)), 
1629
 
                 ]
1630
 
        utf8_files = [('format', self.get_format_string())]
1631
 
 
1632
 
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
1633
 
        return self.open(a_bzrdir=a_bzrdir, _found=True)
1634
 
 
1635
 
    def open(self, a_bzrdir, _found=False, _override_transport=None):
1636
 
        """See RepositoryFormat.open().
1637
 
        
1638
 
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
1639
 
                                    repository at a slightly different url
1640
 
                                    than normal. I.e. during 'upgrade'.
1641
 
        """
1642
 
        if not _found:
1643
 
            format = RepositoryFormat.find_format(a_bzrdir)
1644
 
            assert format.__class__ ==  self.__class__
1645
 
        if _override_transport is not None:
1646
 
            repo_transport = _override_transport
1647
 
        else:
1648
 
            repo_transport = a_bzrdir.get_repository_transport(None)
1649
 
        control_files = lockable_files.LockableFiles(repo_transport,
1650
 
                                'lock', lockdir.LockDir)
1651
 
        text_store = self._get_text_store(repo_transport, control_files)
1652
 
        control_store = self._get_control_store(repo_transport, control_files)
1653
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1654
 
        return WeaveMetaDirRepository(_format=self,
1655
 
            a_bzrdir=a_bzrdir,
1656
 
            control_files=control_files,
1657
 
            _revision_store=_revision_store,
1658
 
            control_store=control_store,
1659
 
            text_store=text_store)
1660
 
 
1661
 
 
1662
 
class RepositoryFormatKnit(MetaDirRepositoryFormat):
1663
 
    """Bzr repository knit format (generalized). 
1664
 
 
1665
 
    This repository format has:
1666
 
     - knits for file texts and inventory
1667
 
     - hash subdirectory based stores.
1668
 
     - knits for revisions and signatures
1669
 
     - TextStores for revisions and signatures.
1670
 
     - a format marker of its own
1671
 
     - an optional 'shared-storage' flag
1672
 
     - an optional 'no-working-trees' flag
1673
 
     - a LockDir lock
1674
 
    """
1675
 
 
1676
 
    def _get_control_store(self, repo_transport, control_files):
1677
 
        """Return the control store for this repository."""
1678
 
        return VersionedFileStore(
1679
 
            repo_transport,
1680
 
            prefixed=False,
1681
 
            file_mode=control_files._file_mode,
1682
 
            versionedfile_class=knit.KnitVersionedFile,
1683
 
            versionedfile_kwargs={'factory':knit.KnitPlainFactory()},
1684
 
            )
1685
 
 
1686
 
    def _get_revision_store(self, repo_transport, control_files):
1687
 
        """See RepositoryFormat._get_revision_store()."""
1688
 
        from bzrlib.store.revision.knit import KnitRevisionStore
1689
 
        versioned_file_store = VersionedFileStore(
1690
 
            repo_transport,
1691
 
            file_mode=control_files._file_mode,
1692
 
            prefixed=False,
1693
 
            precious=True,
1694
 
            versionedfile_class=knit.KnitVersionedFile,
1695
 
            versionedfile_kwargs={'delta':False,
1696
 
                                  'factory':knit.KnitPlainFactory(),
1697
 
                                 },
1698
 
            escaped=True,
1699
 
            )
1700
 
        return KnitRevisionStore(versioned_file_store)
1701
 
 
1702
 
    def _get_text_store(self, transport, control_files):
1703
 
        """See RepositoryFormat._get_text_store()."""
1704
 
        return self._get_versioned_file_store('knits',
1705
 
                                  transport,
1706
 
                                  control_files,
1707
 
                                  versionedfile_class=knit.KnitVersionedFile,
1708
 
                                  versionedfile_kwargs={
1709
 
                                      'create_parent_dir':True,
1710
 
                                      'delay_create':True,
1711
 
                                      'dir_mode':control_files._dir_mode,
1712
 
                                  },
1713
 
                                  escaped=True)
1714
 
 
1715
 
    def initialize(self, a_bzrdir, shared=False):
1716
 
        """Create a knit format 1 repository.
1717
 
 
1718
 
        :param a_bzrdir: bzrdir to contain the new repository; must already
1719
 
            be initialized.
1720
 
        :param shared: If true the repository will be initialized as a shared
1721
 
                       repository.
1722
 
        """
1723
 
        mutter('creating repository in %s.', a_bzrdir.transport.base)
1724
 
        dirs = ['revision-store', 'knits']
1725
 
        files = []
1726
 
        utf8_files = [('format', self.get_format_string())]
1727
 
        
1728
 
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
1729
 
        repo_transport = a_bzrdir.get_repository_transport(None)
1730
 
        control_files = lockable_files.LockableFiles(repo_transport,
1731
 
                                'lock', lockdir.LockDir)
1732
 
        control_store = self._get_control_store(repo_transport, control_files)
1733
 
        transaction = transactions.WriteTransaction()
1734
 
        # trigger a write of the inventory store.
1735
 
        control_store.get_weave_or_empty('inventory', transaction)
1736
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1737
 
        # the revision id here is irrelevant: it will not be stored, and cannot
1738
 
        # already exist.
1739
 
        _revision_store.has_revision_id('A', transaction)
1740
 
        _revision_store.get_signature_file(transaction)
1741
 
        return self.open(a_bzrdir=a_bzrdir, _found=True)
1742
 
 
1743
 
    def open(self, a_bzrdir, _found=False, _override_transport=None):
1744
 
        """See RepositoryFormat.open().
1745
 
        
1746
 
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
1747
 
                                    repository at a slightly different url
1748
 
                                    than normal. I.e. during 'upgrade'.
1749
 
        """
1750
 
        if not _found:
1751
 
            format = RepositoryFormat.find_format(a_bzrdir)
1752
 
            assert format.__class__ ==  self.__class__
1753
 
        if _override_transport is not None:
1754
 
            repo_transport = _override_transport
1755
 
        else:
1756
 
            repo_transport = a_bzrdir.get_repository_transport(None)
1757
 
        control_files = lockable_files.LockableFiles(repo_transport,
1758
 
                                'lock', lockdir.LockDir)
1759
 
        text_store = self._get_text_store(repo_transport, control_files)
1760
 
        control_store = self._get_control_store(repo_transport, control_files)
1761
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1762
 
        return KnitRepository(_format=self,
1763
 
                              a_bzrdir=a_bzrdir,
1764
 
                              control_files=control_files,
1765
 
                              _revision_store=_revision_store,
1766
 
                              control_store=control_store,
1767
 
                              text_store=text_store)
1768
 
 
1769
 
 
1770
 
class RepositoryFormatKnit1(RepositoryFormatKnit):
1771
 
    """Bzr repository knit format 1.
1772
 
 
1773
 
    This repository format has:
1774
 
     - knits for file texts and inventory
1775
 
     - hash subdirectory based stores.
1776
 
     - knits for revisions and signatures
1777
 
     - TextStores for revisions and signatures.
1778
 
     - a format marker of its own
1779
 
     - an optional 'shared-storage' flag
1780
 
     - an optional 'no-working-trees' flag
1781
 
     - a LockDir lock
1782
 
 
1783
 
    This format was introduced in bzr 0.8.
1784
 
    """
1785
 
    def get_format_string(self):
1786
 
        """See RepositoryFormat.get_format_string()."""
1787
 
        return "Bazaar-NG Knit Repository Format 1"
1788
 
 
1789
 
    def get_format_description(self):
1790
 
        """See RepositoryFormat.get_format_description()."""
1791
 
        return "Knit repository format 1"
1792
 
 
1793
 
    def check_conversion_target(self, target_format):
1794
 
        pass
1795
 
 
1796
 
 
1797
 
class RepositoryFormatKnit2(RepositoryFormatKnit):
1798
 
    """Bzr repository knit format 2.
1799
 
 
1800
 
    THIS FORMAT IS EXPERIMENTAL
1801
 
    This repository format has:
1802
 
     - knits for file texts and inventory
1803
 
     - hash subdirectory based stores.
1804
 
     - knits for revisions and signatures
1805
 
     - TextStores for revisions and signatures.
1806
 
     - a format marker of its own
1807
 
     - an optional 'shared-storage' flag
1808
 
     - an optional 'no-working-trees' flag
1809
 
     - a LockDir lock
1810
 
     - Support for recording full info about the tree root
1811
 
 
1812
 
    """
1813
 
    
1814
 
    rich_root_data = True
1815
 
 
1816
 
    def get_format_string(self):
1817
 
        """See RepositoryFormat.get_format_string()."""
1818
 
        return "Bazaar Knit Repository Format 2\n"
1819
 
 
1820
 
    def get_format_description(self):
1821
 
        """See RepositoryFormat.get_format_description()."""
1822
 
        return "Knit repository format 2"
1823
 
 
1824
 
    def check_conversion_target(self, target_format):
1825
 
        if not target_format.rich_root_data:
1826
 
            raise errors.BadConversionTarget(
1827
 
                'Does not support rich root data.', target_format)
1828
 
 
1829
 
    def open(self, a_bzrdir, _found=False, _override_transport=None):
1830
 
        """See RepositoryFormat.open().
1831
 
        
1832
 
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
1833
 
                                    repository at a slightly different url
1834
 
                                    than normal. I.e. during 'upgrade'.
1835
 
        """
1836
 
        if not _found:
1837
 
            format = RepositoryFormat.find_format(a_bzrdir)
1838
 
            assert format.__class__ ==  self.__class__
1839
 
        if _override_transport is not None:
1840
 
            repo_transport = _override_transport
1841
 
        else:
1842
 
            repo_transport = a_bzrdir.get_repository_transport(None)
1843
 
        control_files = lockable_files.LockableFiles(repo_transport, 'lock',
1844
 
                                                     lockdir.LockDir)
1845
 
        text_store = self._get_text_store(repo_transport, control_files)
1846
 
        control_store = self._get_control_store(repo_transport, control_files)
1847
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1848
 
        return KnitRepository2(_format=self,
1849
 
                               a_bzrdir=a_bzrdir,
1850
 
                               control_files=control_files,
1851
 
                               _revision_store=_revision_store,
1852
 
                               control_store=control_store,
1853
 
                               text_store=text_store)
1854
 
 
1855
 
 
1856
 
 
1857
1158
# formats which have no format string are not discoverable
1858
 
# and not independently creatable, so are not registered.
1859
 
RepositoryFormat.register_format(RepositoryFormat7())
1860
 
# KEEP in sync with bzrdir.format_registry default
1861
 
RepositoryFormat.register_format(RepositoryFormatKnit1())
1862
 
RepositoryFormat.register_format(RepositoryFormatKnit2())
1863
 
_legacy_formats = [RepositoryFormat4(),
1864
 
                   RepositoryFormat5(),
1865
 
                   RepositoryFormat6()]
 
1159
# and not independently creatable, so are not registered.  They're 
 
1160
# all in bzrlib.repofmt.weaverepo now.  When an instance of one of these is
 
1161
# needed, it's constructed directly by the BzrDir.  Non-native formats where
 
1162
# the repository is not separately opened are similar.
 
1163
 
 
1164
format_registry.register_lazy(
 
1165
    'Bazaar-NG Repository format 7',
 
1166
    'bzrlib.repofmt.weaverepo',
 
1167
    'RepositoryFormat7'
 
1168
    )
 
1169
# KEEP in sync with bzrdir.format_registry default, which controls the overall
 
1170
# default control directory format
 
1171
 
 
1172
format_registry.register_lazy(
 
1173
    'Bazaar-NG Knit Repository Format 1',
 
1174
    'bzrlib.repofmt.knitrepo',
 
1175
    'RepositoryFormatKnit1',
 
1176
    )
 
1177
format_registry.default_key = 'Bazaar-NG Knit Repository Format 1'
 
1178
 
 
1179
format_registry.register_lazy(
 
1180
    'Bazaar Knit Repository Format 2\n',
 
1181
    'bzrlib.repofmt.knitrepo',
 
1182
    'RepositoryFormatKnit2',
 
1183
    )
1866
1184
 
1867
1185
 
1868
1186
class InterRepository(InterObject):
1928
1246
    Data format and model must match for this to work.
1929
1247
    """
1930
1248
 
1931
 
    _matching_repo_format = RepositoryFormat4()
1932
 
    """Repository format for testing with."""
 
1249
    @classmethod
 
1250
    def _get_repo_format_to_test(self):
 
1251
        """Repository format for testing with."""
 
1252
        return RepositoryFormat.get_default_format()
1933
1253
 
1934
1254
    @staticmethod
1935
1255
    def is_compatible(source, target):
1983
1303
class InterWeaveRepo(InterSameDataRepository):
1984
1304
    """Optimised code paths between Weave based repositories."""
1985
1305
 
1986
 
    _matching_repo_format = RepositoryFormat7()
1987
 
    """Repository format for testing with."""
 
1306
    @classmethod
 
1307
    def _get_repo_format_to_test(self):
 
1308
        from bzrlib.repofmt import weaverepo
 
1309
        return weaverepo.RepositoryFormat7()
1988
1310
 
1989
1311
    @staticmethod
1990
1312
    def is_compatible(source, target):
1994
1316
        could lead to confusing results, and there is no need to be 
1995
1317
        overly general.
1996
1318
        """
 
1319
        from bzrlib.repofmt.weaverepo import (
 
1320
                RepositoryFormat5,
 
1321
                RepositoryFormat6,
 
1322
                RepositoryFormat7,
 
1323
                )
1997
1324
        try:
1998
1325
            return (isinstance(source._format, (RepositoryFormat5,
1999
1326
                                                RepositoryFormat6,
2101
1428
class InterKnitRepo(InterSameDataRepository):
2102
1429
    """Optimised code paths between Knit based repositories."""
2103
1430
 
2104
 
    _matching_repo_format = RepositoryFormatKnit1()
2105
 
    """Repository format for testing with."""
 
1431
    @classmethod
 
1432
    def _get_repo_format_to_test(self):
 
1433
        from bzrlib.repofmt import knitrepo
 
1434
        return knitrepo.RepositoryFormatKnit1()
2106
1435
 
2107
1436
    @staticmethod
2108
1437
    def is_compatible(source, target):
2112
1441
        could lead to confusing results, and there is no need to be 
2113
1442
        overly general.
2114
1443
        """
 
1444
        from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
2115
1445
        try:
2116
1446
            return (isinstance(source._format, (RepositoryFormatKnit1)) and
2117
1447
                    isinstance(target._format, (RepositoryFormatKnit1)))
2163
1493
 
2164
1494
class InterModel1and2(InterRepository):
2165
1495
 
2166
 
    _matching_repo_format = None
 
1496
    @classmethod
 
1497
    def _get_repo_format_to_test(self):
 
1498
        return None
2167
1499
 
2168
1500
    @staticmethod
2169
1501
    def is_compatible(source, target):
2213
1545
 
2214
1546
class InterKnit1and2(InterKnitRepo):
2215
1547
 
2216
 
    _matching_repo_format = None
 
1548
    @classmethod
 
1549
    def _get_repo_format_to_test(self):
 
1550
        return None
2217
1551
 
2218
1552
    @staticmethod
2219
1553
    def is_compatible(source, target):
2220
1554
        """Be compatible with Knit1 source and Knit2 target"""
 
1555
        from bzrlib.repofmt.knitrepo import RepositoryFormatKnit2
2221
1556
        try:
 
1557
            from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1, \
 
1558
                    RepositoryFormatKnit2
2222
1559
            return (isinstance(source._format, (RepositoryFormatKnit1)) and
2223
1560
                    isinstance(target._format, (RepositoryFormatKnit2)))
2224
1561
        except AttributeError:
2262
1599
    def adapt(self, test):
2263
1600
        result = unittest.TestSuite()
2264
1601
        for repository_format, bzrdir_format in self._formats:
 
1602
            from copy import deepcopy
2265
1603
            new_test = deepcopy(test)
2266
1604
            new_test.transport_server = self._transport_server
2267
1605
            new_test.transport_readonly_server = self._transport_readonly_server
2292
1630
    def adapt(self, test):
2293
1631
        result = unittest.TestSuite()
2294
1632
        for interrepo_class, repository_format, repository_format_to in self._formats:
 
1633
            from copy import deepcopy
2295
1634
            new_test = deepcopy(test)
2296
1635
            new_test.transport_server = self._transport_server
2297
1636
            new_test.transport_readonly_server = self._transport_readonly_server
2308
1647
    @staticmethod
2309
1648
    def default_test_list():
2310
1649
        """Generate the default list of interrepo permutations to test."""
 
1650
        from bzrlib.repofmt import knitrepo, weaverepo
2311
1651
        result = []
2312
1652
        # test the default InterRepository between format 6 and the current 
2313
1653
        # default format.
2316
1656
        #result.append((InterRepository,
2317
1657
        #               RepositoryFormat6(),
2318
1658
        #               RepositoryFormatKnit1()))
2319
 
        for optimiser in InterRepository._optimisers:
2320
 
            if optimiser._matching_repo_format is not None:
2321
 
                result.append((optimiser,
2322
 
                               optimiser._matching_repo_format,
2323
 
                               optimiser._matching_repo_format
2324
 
                               ))
 
1659
        for optimiser_class in InterRepository._optimisers:
 
1660
            format_to_test = optimiser_class._get_repo_format_to_test()
 
1661
            if format_to_test is not None:
 
1662
                result.append((optimiser_class,
 
1663
                               format_to_test, format_to_test))
2325
1664
        # if there are specific combinations we want to use, we can add them 
2326
1665
        # here.
2327
 
        result.append((InterModel1and2, RepositoryFormat5(),
2328
 
                       RepositoryFormatKnit2()))
2329
 
        result.append((InterKnit1and2, RepositoryFormatKnit1(),
2330
 
                       RepositoryFormatKnit2()))
 
1666
        result.append((InterModel1and2,
 
1667
                       weaverepo.RepositoryFormat5(),
 
1668
                       knitrepo.RepositoryFormatKnit2()))
 
1669
        result.append((InterKnit1and2,
 
1670
                       knitrepo.RepositoryFormatKnit1(),
 
1671
                       knitrepo.RepositoryFormatKnit2()))
2331
1672
        return result
2332
1673
 
2333
1674
 
2428
1769
        self._timestamp = round(timestamp, 3)
2429
1770
 
2430
1771
        if timezone is None:
2431
 
            self._timezone = local_time_offset()
 
1772
            self._timezone = osutils.local_time_offset()
2432
1773
        else:
2433
1774
            self._timezone = int(timezone)
2434
1775