~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Martin Pool
  • Date: 2007-02-07 09:11:31 UTC
  • mto: This revision was merged to the branch mainline in revision 2283.
  • Revision ID: mbp@sourcefrog.net-20070207091131-458fw18bgytvaz7t
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
lazily load from the registry.

InterRepo._matching_repo_format is now a method not a class field so that
it can load repositories when we need them.

Show diffs side-by-side

added added

removed removed

Lines of Context:
869
869
        return not self.control_files._transport.has('no-working-trees')
870
870
 
871
871
 
872
 
class KnitRepository(MetaDirRepository):
873
 
    """Knit format repository."""
874
 
 
875
 
    def _warn_if_deprecated(self):
876
 
        # This class isn't deprecated
877
 
        pass
878
 
 
879
 
    def _inventory_add_lines(self, inv_vf, revid, parents, lines):
880
 
        inv_vf.add_lines_with_ghosts(revid, parents, lines)
881
 
 
882
 
    @needs_read_lock
883
 
    def _all_revision_ids(self):
884
 
        """See Repository.all_revision_ids()."""
885
 
        # Knits get the revision graph from the index of the revision knit, so
886
 
        # it's always possible even if they're on an unlistable transport.
887
 
        return self._revision_store.all_revision_ids(self.get_transaction())
888
 
 
889
 
    def fileid_involved_between_revs(self, from_revid, to_revid):
890
 
        """Find file_id(s) which are involved in the changes between revisions.
891
 
 
892
 
        This determines the set of revisions which are involved, and then
893
 
        finds all file ids affected by those revisions.
894
 
        """
895
 
        vf = self._get_revision_vf()
896
 
        from_set = set(vf.get_ancestry(from_revid))
897
 
        to_set = set(vf.get_ancestry(to_revid))
898
 
        changed = to_set.difference(from_set)
899
 
        return self._fileid_involved_by_set(changed)
900
 
 
901
 
    def fileid_involved(self, last_revid=None):
902
 
        """Find all file_ids modified in the ancestry of last_revid.
903
 
 
904
 
        :param last_revid: If None, last_revision() will be used.
905
 
        """
906
 
        if not last_revid:
907
 
            changed = set(self.all_revision_ids())
908
 
        else:
909
 
            changed = set(self.get_ancestry(last_revid))
910
 
        if None in changed:
911
 
            changed.remove(None)
912
 
        return self._fileid_involved_by_set(changed)
913
 
 
914
 
    @needs_read_lock
915
 
    def get_ancestry(self, revision_id):
916
 
        """Return a list of revision-ids integrated by a revision.
917
 
        
918
 
        This is topologically sorted.
919
 
        """
920
 
        if revision_id is None:
921
 
            return [None]
922
 
        vf = self._get_revision_vf()
923
 
        try:
924
 
            return [None] + vf.get_ancestry(revision_id)
925
 
        except errors.RevisionNotPresent:
926
 
            raise errors.NoSuchRevision(self, revision_id)
927
 
 
928
 
    @needs_read_lock
929
 
    def get_revision(self, revision_id):
930
 
        """Return the Revision object for a named revision"""
931
 
        return self.get_revision_reconcile(revision_id)
932
 
 
933
 
    @needs_read_lock
934
 
    def get_revision_graph(self, revision_id=None):
935
 
        """Return a dictionary containing the revision graph.
936
 
 
937
 
        :param revision_id: The revision_id to get a graph from. If None, then
938
 
        the entire revision graph is returned. This is a deprecated mode of
939
 
        operation and will be removed in the future.
940
 
        :return: a dictionary of revision_id->revision_parents_list.
941
 
        """
942
 
        # special case NULL_REVISION
943
 
        if revision_id == _mod_revision.NULL_REVISION:
944
 
            return {}
945
 
        a_weave = self._get_revision_vf()
946
 
        entire_graph = a_weave.get_graph()
947
 
        if revision_id is None:
948
 
            return a_weave.get_graph()
949
 
        elif revision_id not in a_weave:
950
 
            raise errors.NoSuchRevision(self, revision_id)
951
 
        else:
952
 
            # add what can be reached from revision_id
953
 
            result = {}
954
 
            pending = set([revision_id])
955
 
            while len(pending) > 0:
956
 
                node = pending.pop()
957
 
                result[node] = a_weave.get_parents(node)
958
 
                for revision_id in result[node]:
959
 
                    if revision_id not in result:
960
 
                        pending.add(revision_id)
961
 
            return result
962
 
 
963
 
    @needs_read_lock
964
 
    def get_revision_graph_with_ghosts(self, revision_ids=None):
965
 
        """Return a graph of the revisions with ghosts marked as applicable.
966
 
 
967
 
        :param revision_ids: an iterable of revisions to graph or None for all.
968
 
        :return: a Graph object with the graph reachable from revision_ids.
969
 
        """
970
 
        result = graph.Graph()
971
 
        vf = self._get_revision_vf()
972
 
        versions = set(vf.versions())
973
 
        if not revision_ids:
974
 
            pending = set(self.all_revision_ids())
975
 
            required = set([])
976
 
        else:
977
 
            pending = set(revision_ids)
978
 
            # special case NULL_REVISION
979
 
            if _mod_revision.NULL_REVISION in pending:
980
 
                pending.remove(_mod_revision.NULL_REVISION)
981
 
            required = set(pending)
982
 
        done = set([])
983
 
        while len(pending):
984
 
            revision_id = pending.pop()
985
 
            if not revision_id in versions:
986
 
                if revision_id in required:
987
 
                    raise errors.NoSuchRevision(self, revision_id)
988
 
                # a ghost
989
 
                result.add_ghost(revision_id)
990
 
                # mark it as done so we don't try for it again.
991
 
                done.add(revision_id)
992
 
                continue
993
 
            parent_ids = vf.get_parents_with_ghosts(revision_id)
994
 
            for parent_id in parent_ids:
995
 
                # is this queued or done ?
996
 
                if (parent_id not in pending and
997
 
                    parent_id not in done):
998
 
                    # no, queue it.
999
 
                    pending.add(parent_id)
1000
 
            result.add_node(revision_id, parent_ids)
1001
 
            done.add(revision_id)
1002
 
        return result
1003
 
 
1004
 
    def _get_revision_vf(self):
1005
 
        """:return: a versioned file containing the revisions."""
1006
 
        vf = self._revision_store.get_revision_file(self.get_transaction())
1007
 
        return vf
1008
 
 
1009
 
    @needs_write_lock
1010
 
    def reconcile(self, other=None, thorough=False):
1011
 
        """Reconcile this repository."""
1012
 
        from bzrlib.reconcile import KnitReconciler
1013
 
        reconciler = KnitReconciler(self, thorough=thorough)
1014
 
        reconciler.reconcile()
1015
 
        return reconciler
1016
 
    
1017
 
    def revision_parents(self, revision_id):
1018
 
        return self._get_revision_vf().get_parents(revision_id)
1019
 
 
1020
 
 
1021
872
class RepositoryFormatRegistry(registry.Registry):
1022
873
    """Registry of RepositoryFormats.
1023
874
    """
1140
991
        _revision_store = TextRevisionStore(text_store, serializer)
1141
992
        return _revision_store
1142
993
 
 
994
    # TODO: this shouldn't be in the base class, it's specific to things that
 
995
    # use weaves or knits -- mbp 20070207
1143
996
    def _get_versioned_file_store(self,
1144
997
                                  name,
1145
998
                                  transport,
1224
1077
            control_files.unlock()
1225
1078
 
1226
1079
 
1227
 
class RepositoryFormatKnit(MetaDirRepositoryFormat):
1228
 
    """Bzr repository knit format (generalized). 
1229
 
 
1230
 
    This repository format has:
1231
 
     - knits for file texts and inventory
1232
 
     - hash subdirectory based stores.
1233
 
     - knits for revisions and signatures
1234
 
     - TextStores for revisions and signatures.
1235
 
     - a format marker of its own
1236
 
     - an optional 'shared-storage' flag
1237
 
     - an optional 'no-working-trees' flag
1238
 
     - a LockDir lock
1239
 
    """
1240
 
 
1241
 
    def _get_control_store(self, repo_transport, control_files):
1242
 
        """Return the control store for this repository."""
1243
 
        return VersionedFileStore(
1244
 
            repo_transport,
1245
 
            prefixed=False,
1246
 
            file_mode=control_files._file_mode,
1247
 
            versionedfile_class=knit.KnitVersionedFile,
1248
 
            versionedfile_kwargs={'factory':knit.KnitPlainFactory()},
1249
 
            )
1250
 
 
1251
 
    def _get_revision_store(self, repo_transport, control_files):
1252
 
        """See RepositoryFormat._get_revision_store()."""
1253
 
        from bzrlib.store.revision.knit import KnitRevisionStore
1254
 
        versioned_file_store = VersionedFileStore(
1255
 
            repo_transport,
1256
 
            file_mode=control_files._file_mode,
1257
 
            prefixed=False,
1258
 
            precious=True,
1259
 
            versionedfile_class=knit.KnitVersionedFile,
1260
 
            versionedfile_kwargs={'delta':False,
1261
 
                                  'factory':knit.KnitPlainFactory(),
1262
 
                                 },
1263
 
            escaped=True,
1264
 
            )
1265
 
        return KnitRevisionStore(versioned_file_store)
1266
 
 
1267
 
    def _get_text_store(self, transport, control_files):
1268
 
        """See RepositoryFormat._get_text_store()."""
1269
 
        return self._get_versioned_file_store('knits',
1270
 
                                  transport,
1271
 
                                  control_files,
1272
 
                                  versionedfile_class=knit.KnitVersionedFile,
1273
 
                                  versionedfile_kwargs={
1274
 
                                      'create_parent_dir':True,
1275
 
                                      'delay_create':True,
1276
 
                                      'dir_mode':control_files._dir_mode,
1277
 
                                  },
1278
 
                                  escaped=True)
1279
 
 
1280
 
    def initialize(self, a_bzrdir, shared=False):
1281
 
        """Create a knit format 1 repository.
1282
 
 
1283
 
        :param a_bzrdir: bzrdir to contain the new repository; must already
1284
 
            be initialized.
1285
 
        :param shared: If true the repository will be initialized as a shared
1286
 
                       repository.
1287
 
        """
1288
 
        mutter('creating repository in %s.', a_bzrdir.transport.base)
1289
 
        dirs = ['revision-store', 'knits']
1290
 
        files = []
1291
 
        utf8_files = [('format', self.get_format_string())]
1292
 
        
1293
 
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
1294
 
        repo_transport = a_bzrdir.get_repository_transport(None)
1295
 
        control_files = lockable_files.LockableFiles(repo_transport,
1296
 
                                'lock', lockdir.LockDir)
1297
 
        control_store = self._get_control_store(repo_transport, control_files)
1298
 
        transaction = transactions.WriteTransaction()
1299
 
        # trigger a write of the inventory store.
1300
 
        control_store.get_weave_or_empty('inventory', transaction)
1301
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1302
 
        # the revision id here is irrelevant: it will not be stored, and cannot
1303
 
        # already exist.
1304
 
        _revision_store.has_revision_id('A', transaction)
1305
 
        _revision_store.get_signature_file(transaction)
1306
 
        return self.open(a_bzrdir=a_bzrdir, _found=True)
1307
 
 
1308
 
    def open(self, a_bzrdir, _found=False, _override_transport=None):
1309
 
        """See RepositoryFormat.open().
1310
 
        
1311
 
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
1312
 
                                    repository at a slightly different url
1313
 
                                    than normal. I.e. during 'upgrade'.
1314
 
        """
1315
 
        if not _found:
1316
 
            format = RepositoryFormat.find_format(a_bzrdir)
1317
 
            assert format.__class__ ==  self.__class__
1318
 
        if _override_transport is not None:
1319
 
            repo_transport = _override_transport
1320
 
        else:
1321
 
            repo_transport = a_bzrdir.get_repository_transport(None)
1322
 
        control_files = lockable_files.LockableFiles(repo_transport,
1323
 
                                'lock', lockdir.LockDir)
1324
 
        text_store = self._get_text_store(repo_transport, control_files)
1325
 
        control_store = self._get_control_store(repo_transport, control_files)
1326
 
        _revision_store = self._get_revision_store(repo_transport, control_files)
1327
 
        return KnitRepository(_format=self,
1328
 
                              a_bzrdir=a_bzrdir,
1329
 
                              control_files=control_files,
1330
 
                              _revision_store=_revision_store,
1331
 
                              control_store=control_store,
1332
 
                              text_store=text_store)
1333
 
 
1334
 
 
1335
 
class RepositoryFormatKnit1(RepositoryFormatKnit):
1336
 
    """Bzr repository knit format 1.
1337
 
 
1338
 
    This repository format has:
1339
 
     - knits for file texts and inventory
1340
 
     - hash subdirectory based stores.
1341
 
     - knits for revisions and signatures
1342
 
     - TextStores for revisions and signatures.
1343
 
     - a format marker of its own
1344
 
     - an optional 'shared-storage' flag
1345
 
     - an optional 'no-working-trees' flag
1346
 
     - a LockDir lock
1347
 
 
1348
 
    This format was introduced in bzr 0.8.
1349
 
    """
1350
 
    def get_format_string(self):
1351
 
        """See RepositoryFormat.get_format_string()."""
1352
 
        return "Bazaar-NG Knit Repository Format 1"
1353
 
 
1354
 
    def get_format_description(self):
1355
 
        """See RepositoryFormat.get_format_description()."""
1356
 
        return "Knit repository format 1"
1357
 
 
1358
 
    def check_conversion_target(self, target_format):
1359
 
        pass
1360
 
 
1361
 
 
1362
1080
# formats which have no format string are not discoverable
1363
1081
# and not independently creatable, so are not registered.  They're 
1364
1082
# all in bzrlib.repofmt.weaverepo now.
1369
1087
    )
1370
1088
# KEEP in sync with bzrdir.format_registry default, which controls the overall
1371
1089
# default control directory format
1372
 
_default_format = RepositoryFormatKnit1()
1373
 
RepositoryFormat.register_format(_default_format)
 
1090
 
 
1091
format_registry.register_lazy(
 
1092
    'Bazaar-NG Knit Repository Format 1',
 
1093
    'bzrlib.repofmt.knitrepo',
 
1094
    'RepositoryFormatKnit1_instance',
 
1095
    )
 
1096
format_registry.default_key = 'Bazaar-NG Knit Repository Format 1'
 
1097
 
1374
1098
format_registry.register_lazy(
1375
1099
    'Bazaar Knit Repository Format 2\n',
1376
1100
    'bzrlib.repofmt.knitrepo',
1377
1101
    'RepositoryFormatKnit2_instance',
1378
1102
    )
1379
 
RepositoryFormat._set_default_format(_default_format)
1380
1103
 
1381
1104
 
1382
1105
class InterRepository(InterObject):
1442
1165
    Data format and model must match for this to work.
1443
1166
    """
1444
1167
 
1445
 
    _matching_repo_format = _default_format
1446
 
    """Repository format for testing with."""
 
1168
    @classmethod
 
1169
    def _get_matching_repo_format(self):
 
1170
        """Repository format for testing with."""
 
1171
        return RepositoryFormat.get_default_format()
1447
1172
 
1448
1173
    @staticmethod
1449
1174
    def is_compatible(source, target):
1497
1222
class InterKnitRepo(InterSameDataRepository):
1498
1223
    """Optimised code paths between Knit based repositories."""
1499
1224
 
1500
 
    _matching_repo_format = RepositoryFormatKnit1()
1501
 
    """Repository format for testing with."""
 
1225
    @classmethod
 
1226
    def _get_matching_repo_format(self):
 
1227
        from bzrlib.repofmt import knitrepo
 
1228
        return knitrepo.RepositoryFormatKnit1()
1502
1229
 
1503
1230
    @staticmethod
1504
1231
    def is_compatible(source, target):
1508
1235
        could lead to confusing results, and there is no need to be 
1509
1236
        overly general.
1510
1237
        """
 
1238
        from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
1511
1239
        try:
1512
1240
            return (isinstance(source._format, (RepositoryFormatKnit1)) and
1513
1241
                    isinstance(target._format, (RepositoryFormatKnit1)))
1559
1287
 
1560
1288
class InterModel1and2(InterRepository):
1561
1289
 
1562
 
    _matching_repo_format = None
 
1290
    @classmethod
 
1291
    def _get_matching_repo_format(self):
 
1292
        return None
1563
1293
 
1564
1294
    @staticmethod
1565
1295
    def is_compatible(source, target):
1609
1339
 
1610
1340
class InterKnit1and2(InterKnitRepo):
1611
1341
 
1612
 
    _matching_repo_format = None
 
1342
    @classmethod
 
1343
    def _get_matching_repo_format(self):
 
1344
        return None
1613
1345
 
1614
1346
    @staticmethod
1615
1347
    def is_compatible(source, target):
1616
1348
        """Be compatible with Knit1 source and Knit2 target"""
1617
1349
        from bzrlib.repofmt.knitrepo import RepositoryFormatKnit2
1618
1350
        try:
 
1351
            from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1, \
 
1352
                    RepositoryFormatKnit2
1619
1353
            return (isinstance(source._format, (RepositoryFormatKnit1)) and
1620
1354
                    isinstance(target._format, (RepositoryFormatKnit2)))
1621
1355
        except AttributeError:
1713
1447
        #result.append((InterRepository,
1714
1448
        #               RepositoryFormat6(),
1715
1449
        #               RepositoryFormatKnit1()))
1716
 
        for optimiser in InterRepository._optimisers:
1717
 
            if optimiser._matching_repo_format is not None:
1718
 
                result.append((optimiser,
1719
 
                               optimiser._matching_repo_format,
1720
 
                               optimiser._matching_repo_format
1721
 
                               ))
 
1450
        for optimiser_class in InterRepository._optimisers:
 
1451
            format_to_test = optimiser_class._get_matching_repo_format()
 
1452
            if format_to_test is not None:
 
1453
                result.append((optimiser_class,
 
1454
                               format_to_test, format_to_test))
1722
1455
        # if there are specific combinations we want to use, we can add them 
1723
1456
        # here.
1724
1457
        result.append((InterModel1and2,
1725
1458
                       weaverepo.RepositoryFormat5(),
1726
1459
                       knitrepo.RepositoryFormatKnit2()))
1727
 
        result.append((InterKnit1and2, RepositoryFormatKnit1(),
 
1460
        result.append((InterKnit1and2,
 
1461
                       knitrepo.RepositoryFormatKnit1(),
1728
1462
                       knitrepo.RepositoryFormatKnit2()))
1729
1463
        return result
1730
1464