~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: 2011-06-30 18:28:17 UTC
  • mfrom: (5967.10.2 test-cat)
  • Revision ID: pqm@pqm.ubuntu.com-20110630182817-83a5q9r9rxfkdn8r
(mbp) don't use subprocesses for testing cat (Martin Pool)

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from __future__ import absolute_import
18
 
 
19
17
from bzrlib.lazy_import import lazy_import
20
18
lazy_import(globals(), """
21
19
import itertools
22
20
import time
23
21
 
24
22
from bzrlib import (
 
23
    bzrdir,
25
24
    config,
26
25
    controldir,
27
26
    debug,
36
35
    gpg,
37
36
    )
38
37
from bzrlib.bundle import serializer
39
 
from bzrlib.i18n import gettext
40
38
""")
41
39
 
42
40
from bzrlib import (
43
 
    bzrdir,
44
41
    errors,
45
42
    registry,
46
43
    symbol_versioning,
76
73
    record_root_entry = True
77
74
    # whether this commit builder supports the record_entry_contents interface
78
75
    supports_record_entry_contents = False
79
 
    # whether this commit builder will automatically update the branch that is
80
 
    # being committed to
81
 
    updates_branch = False
82
76
 
83
 
    def __init__(self, repository, parents, config_stack, timestamp=None,
 
77
    def __init__(self, repository, parents, config, timestamp=None,
84
78
                 timezone=None, committer=None, revprops=None,
85
79
                 revision_id=None, lossy=False):
86
80
        """Initiate a CommitBuilder.
95
89
        :param lossy: Whether to discard data that can not be natively
96
90
            represented, when pushing to a foreign VCS 
97
91
        """
98
 
        self._config_stack = config_stack
 
92
        self._config = config
99
93
        self._lossy = lossy
100
94
 
101
95
        if committer is None:
102
 
            self._committer = self._config_stack.get('email')
 
96
            self._committer = self._config.username()
103
97
        elif not isinstance(committer, unicode):
104
98
            self._committer = committer.decode() # throw if non-ascii
105
99
        else:
286
280
                raise
287
281
            mutter('abort_write_group failed')
288
282
            log_exception_quietly()
289
 
            note(gettext('bzr: ERROR (ignored): %s'), exc)
 
283
            note('bzr: ERROR (ignored): %s', exc)
290
284
        self._write_group = None
291
285
 
292
286
    def _abort_write_group(self):
346
340
        """
347
341
        self.control_files.break_lock()
348
342
 
 
343
    @needs_read_lock
 
344
    def _eliminate_revisions_not_present(self, revision_ids):
 
345
        """Check every revision id in revision_ids to see if we have it.
 
346
 
 
347
        Returns a set of the present revisions.
 
348
        """
 
349
        result = []
 
350
        graph = self.get_graph()
 
351
        parent_map = graph.get_parent_map(revision_ids)
 
352
        # The old API returned a list, should this actually be a set?
 
353
        return parent_map.keys()
 
354
 
349
355
    @staticmethod
350
 
    def create(controldir):
351
 
        """Construct the current default format repository in controldir."""
352
 
        return RepositoryFormat.get_default_format().initialize(controldir)
 
356
    def create(a_bzrdir):
 
357
        """Construct the current default format repository in a_bzrdir."""
 
358
        return RepositoryFormat.get_default_format().initialize(a_bzrdir)
353
359
 
354
 
    def __init__(self, _format, controldir, control_files):
 
360
    def __init__(self, _format, a_bzrdir, control_files):
355
361
        """instantiate a Repository.
356
362
 
357
363
        :param _format: The format of the repository on disk.
358
 
        :param controldir: The ControlDir of the repository.
 
364
        :param a_bzrdir: The BzrDir of the repository.
359
365
        :param control_files: Control files to use for locking, etc.
360
366
        """
361
367
        # In the future we will have a single api for all stores for
364
370
        super(Repository, self).__init__()
365
371
        self._format = _format
366
372
        # the following are part of the public API for Repository:
367
 
        self.bzrdir = controldir
 
373
        self.bzrdir = a_bzrdir
368
374
        self.control_files = control_files
 
375
        self._transport = control_files._transport
 
376
        self.base = self._transport.base
369
377
        # for tests
370
378
        self._write_group = None
371
379
        # Additional places to query for data.
409
417
        """
410
418
        if self.__class__ is not other.__class__:
411
419
            return False
412
 
        return (self.control_url == other.control_url)
 
420
        return (self._transport.base == other._transport.base)
413
421
 
414
422
    def is_in_write_group(self):
415
423
        """Return True if there is an open write group.
552
560
            def __init__(self):
553
561
                self.first_call = True
554
562
 
555
 
            def __call__(self, controldir):
556
 
                # On the first call, the parameter is always the controldir
 
563
            def __call__(self, bzrdir):
 
564
                # On the first call, the parameter is always the bzrdir
557
565
                # containing the current repo.
558
566
                if not self.first_call:
559
567
                    try:
560
 
                        repository = controldir.open_repository()
 
568
                        repository = bzrdir.open_repository()
561
569
                    except errors.NoRepositoryPresent:
562
570
                        pass
563
571
                    else:
564
572
                        return False, ([], repository)
565
573
                self.first_call = False
566
 
                value = (controldir.list_branches(), None)
 
574
                value = (bzrdir.list_branches(), None)
567
575
                return True, value
568
576
 
569
577
        ret = []
570
 
        for branches, repository in controldir.ControlDir.find_bzrdirs(
 
578
        for branches, repository in bzrdir.BzrDir.find_bzrdirs(
571
579
                self.user_transport, evaluate=Evaluator()):
572
580
            if branches is not None:
573
581
                ret.extend(branches)
607
615
        For instance, if the repository is at URL/.bzr/repository,
608
616
        Repository.open(URL) -> a Repository instance.
609
617
        """
610
 
        control = controldir.ControlDir.open(base)
 
618
        control = bzrdir.BzrDir.open(base)
611
619
        return control.open_repository()
612
620
 
613
621
    def copy_content_into(self, destination, revision_id=None):
644
652
        """
645
653
 
646
654
    def suspend_write_group(self):
647
 
        """Suspend a write group.
648
 
 
649
 
        :raise UnsuspendableWriteGroup: If the write group can not be
650
 
            suspended.
651
 
        :return: List of tokens
652
 
        """
653
655
        raise errors.UnsuspendableWriteGroup(self)
654
656
 
655
657
    def refresh_data(self):
677
679
    def _resume_write_group(self, tokens):
678
680
        raise errors.UnsuspendableWriteGroup(self)
679
681
 
680
 
    def fetch(self, source, revision_id=None, find_ghosts=False):
 
682
    def fetch(self, source, revision_id=None, find_ghosts=False,
 
683
            fetch_spec=None):
681
684
        """Fetch the content required to construct revision_id from source.
682
685
 
683
 
        If revision_id is None, then all content is copied.
 
686
        If revision_id is None and fetch_spec is None, then all content is
 
687
        copied.
684
688
 
685
689
        fetch() may not be used when the repository is in a write group -
686
690
        either finish the current write group before using fetch, or use
692
696
        :param revision_id: If specified, all the content needed for this
693
697
            revision ID will be copied to the target.  Fetch will determine for
694
698
            itself which content needs to be copied.
 
699
        :param fetch_spec: If specified, a SearchResult or
 
700
            PendingAncestryResult that describes which revisions to copy.  This
 
701
            allows copying multiple heads at once.  Mutually exclusive with
 
702
            revision_id.
695
703
        """
 
704
        if fetch_spec is not None and revision_id is not None:
 
705
            raise AssertionError(
 
706
                "fetch_spec and revision_id are mutually exclusive.")
696
707
        if self.is_in_write_group():
697
708
            raise errors.InternalBzrError(
698
709
                "May not fetch while in a write group.")
700
711
        # TODO: lift out to somewhere common with RemoteRepository
701
712
        # <https://bugs.launchpad.net/bzr/+bug/401646>
702
713
        if (self.has_same_location(source)
 
714
            and fetch_spec is None
703
715
            and self._has_same_fallbacks(source)):
704
716
            # check that last_revision is in 'from' and then return a
705
717
            # no-operation.
708
720
                self.get_revision(revision_id)
709
721
            return 0, []
710
722
        inter = InterRepository.get(source, self)
711
 
        return inter.fetch(revision_id=revision_id, find_ghosts=find_ghosts)
 
723
        return inter.fetch(revision_id=revision_id,
 
724
            find_ghosts=find_ghosts, fetch_spec=fetch_spec)
712
725
 
713
726
    def create_bundle(self, target, base, fileobj, format=None):
714
727
        return serializer.write_bundle(self, target, base, fileobj, format)
715
728
 
716
 
    def get_commit_builder(self, branch, parents, config_stack, timestamp=None,
 
729
    def get_commit_builder(self, branch, parents, config, timestamp=None,
717
730
                           timezone=None, committer=None, revprops=None,
718
731
                           revision_id=None, lossy=False):
719
732
        """Obtain a CommitBuilder for this repository.
720
733
 
721
734
        :param branch: Branch to commit to.
722
735
        :param parents: Revision ids of the parents of the new revision.
723
 
        :param config_stack: Configuration stack to use.
 
736
        :param config: Configuration to use.
724
737
        :param timestamp: Optional timestamp recorded for commit.
725
738
        :param timezone: Optional timezone for timestamp.
726
739
        :param committer: Optional committer to set for commit.
746
759
                repo.unlock()
747
760
 
748
761
    @needs_read_lock
749
 
    def clone(self, controldir, revision_id=None):
750
 
        """Clone this repository into controldir using the current format.
 
762
    def clone(self, a_bzrdir, revision_id=None):
 
763
        """Clone this repository into a_bzrdir using the current format.
751
764
 
752
765
        Currently no check is made that the format of this repository and
753
766
        the bzrdir format are compatible. FIXME RBC 20060201.
756
769
        """
757
770
        # TODO: deprecate after 0.16; cloning this with all its settings is
758
771
        # probably not very useful -- mbp 20070423
759
 
        dest_repo = self._create_sprouting_repo(
760
 
            controldir, shared=self.is_shared())
 
772
        dest_repo = self._create_sprouting_repo(a_bzrdir, shared=self.is_shared())
761
773
        self.copy_content_into(dest_repo, revision_id)
762
774
        return dest_repo
763
775
 
930
942
        parent_ids.discard(_mod_revision.NULL_REVISION)
931
943
        return parent_ids
932
944
 
 
945
    def fileids_altered_by_revision_ids(self, revision_ids):
 
946
        """Find the file ids and versions affected by revisions.
 
947
 
 
948
        :param revisions: an iterable containing revision ids.
 
949
        :return: a dictionary mapping altered file-ids to an iterable of
 
950
            revision_ids. Each altered file-ids has the exact revision_ids
 
951
            that altered it listed explicitly.
 
952
        """
 
953
        raise NotImplementedError(self.fileids_altered_by_revision_ids)
 
954
 
933
955
    def iter_files_bytes(self, desired_files):
934
956
        """Iterate through file versions.
935
957
 
981
1003
            raise AssertionError('_iter_for_revno returned too much history')
982
1004
        return (True, partial_history[-1])
983
1005
 
 
1006
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
 
1007
    def iter_reverse_revision_history(self, revision_id):
 
1008
        """Iterate backwards through revision ids in the lefthand history
 
1009
 
 
1010
        :param revision_id: The revision id to start with.  All its lefthand
 
1011
            ancestors will be traversed.
 
1012
        """
 
1013
        graph = self.get_graph()
 
1014
        stop_revisions = (None, _mod_revision.NULL_REVISION)
 
1015
        return graph.iter_lefthand_ancestry(revision_id, stop_revisions)
 
1016
 
984
1017
    def is_shared(self):
985
1018
        """Return True if this repository is flagged as a shared repository."""
986
1019
        raise NotImplementedError(self.is_shared)
1023
1056
        """
1024
1057
        raise NotImplementedError(self.revision_trees)
1025
1058
 
 
1059
    @needs_read_lock
 
1060
    @symbol_versioning.deprecated_method(
 
1061
        symbol_versioning.deprecated_in((2, 4, 0)))
 
1062
    def get_ancestry(self, revision_id, topo_sorted=True):
 
1063
        """Return a list of revision-ids integrated by a revision.
 
1064
 
 
1065
        The first element of the list is always None, indicating the origin
 
1066
        revision.  This might change when we have history horizons, or
 
1067
        perhaps we should have a new API.
 
1068
 
 
1069
        This is topologically sorted.
 
1070
        """
 
1071
        if 'evil' in debug.debug_flags:
 
1072
            mutter_callsite(2, "get_ancestry is linear with history.")
 
1073
        if _mod_revision.is_null(revision_id):
 
1074
            return [None]
 
1075
        if not self.has_revision(revision_id):
 
1076
            raise errors.NoSuchRevision(self, revision_id)
 
1077
        graph = self.get_graph()
 
1078
        keys = set()
 
1079
        search = graph._make_breadth_first_searcher([revision_id])
 
1080
        while True:
 
1081
            try:
 
1082
                found, ghosts = search.next_with_ghosts()
 
1083
            except StopIteration:
 
1084
                break
 
1085
            keys.update(found)
 
1086
        if _mod_revision.NULL_REVISION in keys:
 
1087
            keys.remove(_mod_revision.NULL_REVISION)
 
1088
        if topo_sorted:
 
1089
            parent_map = graph.get_parent_map(keys)
 
1090
            keys = tsort.topo_sort(parent_map)
 
1091
        return [None] + list(keys)
 
1092
 
1026
1093
    def pack(self, hint=None, clean_obsolete_packs=False):
1027
1094
        """Compress the data within the repository.
1028
1095
 
1104
1171
                [parents_provider, other_repository._make_parents_provider()])
1105
1172
        return graph.Graph(parents_provider)
1106
1173
 
 
1174
    def revision_ids_to_search_result(self, result_set):
 
1175
        """Convert a set of revision ids to a graph SearchResult."""
 
1176
        result_parents = set()
 
1177
        for parents in self.get_graph().get_parent_map(
 
1178
            result_set).itervalues():
 
1179
            result_parents.update(parents)
 
1180
        included_keys = result_set.intersection(result_parents)
 
1181
        start_keys = result_set.difference(included_keys)
 
1182
        exclude_keys = result_parents.difference(result_set)
 
1183
        result = graph.SearchResult(start_keys, exclude_keys,
 
1184
            len(result_set), result_set)
 
1185
        return result
 
1186
 
1107
1187
    @needs_write_lock
1108
1188
    def set_make_working_trees(self, new_value):
1109
1189
        """Set the policy flag for making working trees when creating branches.
1127
1207
        self.store_revision_signature(gpg_strategy, plaintext, revision_id)
1128
1208
 
1129
1209
    @needs_read_lock
1130
 
    def verify_revision_signature(self, revision_id, gpg_strategy):
 
1210
    def verify_revision(self, revision_id, gpg_strategy):
1131
1211
        """Verify the signature on a revision.
1132
 
 
 
1212
        
1133
1213
        :param revision_id: the revision to verify
1134
1214
        :gpg_strategy: the GPGStrategy object to used
1135
 
 
 
1215
        
1136
1216
        :return: gpg.SIGNATURE_VALID or a failed SIGNATURE_ value
1137
1217
        """
1138
1218
        if not self.has_signature_for_revision_id(revision_id):
1144
1224
 
1145
1225
        return gpg_strategy.verify(signature, plaintext)
1146
1226
 
1147
 
    @needs_read_lock
1148
 
    def verify_revision_signatures(self, revision_ids, gpg_strategy):
1149
 
        """Verify revision signatures for a number of revisions.
1150
 
 
1151
 
        :param revision_id: the revision to verify
1152
 
        :gpg_strategy: the GPGStrategy object to used
1153
 
        :return: Iterator over tuples with revision id, result and keys
1154
 
        """
1155
 
        for revid in revision_ids:
1156
 
            (result, key) = self.verify_revision_signature(revid, gpg_strategy)
1157
 
            yield revid, result, key
1158
 
 
1159
1227
    def has_signature_for_revision_id(self, revision_id):
1160
1228
        """Query for a revision signature for revision_id in the repository."""
1161
1229
        raise NotImplementedError(self.has_signature_for_revision_id)
1191
1259
            return
1192
1260
        try:
1193
1261
            if branch is None:
1194
 
                conf = config.GlobalStack()
 
1262
                conf = config.GlobalConfig()
1195
1263
            else:
1196
 
                conf = branch.get_config_stack()
1197
 
            if 'format_deprecation' in conf.get('suppress_warnings'):
 
1264
                conf = branch.get_config()
 
1265
            if conf.suppress_warning('format_deprecation'):
1198
1266
                return
1199
1267
            warning("Format %s for %s is deprecated -"
1200
1268
                    " please use 'bzr upgrade' to get better performance"
1260
1328
        """Returns the policy for making working trees on new branches."""
1261
1329
        return not self._transport.has('no-working-trees')
1262
1330
 
1263
 
    @needs_write_lock
1264
 
    def update_feature_flags(self, updated_flags):
1265
 
        """Update the feature flags for this branch.
1266
 
 
1267
 
        :param updated_flags: Dictionary mapping feature names to necessities
1268
 
            A necessity can be None to indicate the feature should be removed
1269
 
        """
1270
 
        self._format._update_feature_flags(updated_flags)
1271
 
        self.control_transport.put_bytes('format', self._format.as_string())
1272
 
 
1273
1331
 
1274
1332
class RepositoryFormatRegistry(controldir.ControlComponentFormatRegistry):
1275
1333
    """Repository format registry."""
1276
1334
 
1277
1335
    def get_default(self):
1278
1336
        """Return the current default format."""
1279
 
        return controldir.format_registry.make_bzrdir('default').repository_format
 
1337
        from bzrlib import bzrdir
 
1338
        return bzrdir.format_registry.make_bzrdir('default').repository_format
1280
1339
 
1281
1340
 
1282
1341
network_format_registry = registry.FormatRegistry()
1325
1384
    created.
1326
1385
 
1327
1386
    Common instance attributes:
1328
 
    _matchingbzrdir - the controldir format that the repository format was
 
1387
    _matchingbzrdir - the bzrdir format that the repository format was
1329
1388
    originally written to work with. This can be used if manually
1330
1389
    constructing a bzrdir and repository, or more commonly for test suite
1331
1390
    parameterization.
1371
1430
    rich_root_data = None
1372
1431
    # Does this format support explicitly versioned directories?
1373
1432
    supports_versioned_directories = None
1374
 
    # Can other repositories be nested into one of this format?
1375
 
    supports_nesting_repositories = None
1376
 
    # Is it possible for revisions to be present without being referenced
1377
 
    # somewhere ?
1378
 
    supports_unreferenced_revisions = None
1379
1433
 
1380
1434
    def __repr__(self):
1381
1435
        return "%s()" % self.__class__.__name__
1387
1441
    def __ne__(self, other):
1388
1442
        return not self == other
1389
1443
 
 
1444
    @classmethod
 
1445
    def find_format(klass, a_bzrdir):
 
1446
        """Return the format for the repository object in a_bzrdir.
 
1447
 
 
1448
        This is used by bzr native formats that have a "format" file in
 
1449
        the repository.  Other methods may be used by different types of
 
1450
        control directory.
 
1451
        """
 
1452
        try:
 
1453
            transport = a_bzrdir.get_repository_transport(None)
 
1454
            format_string = transport.get_bytes("format")
 
1455
            return format_registry.get(format_string)
 
1456
        except errors.NoSuchFile:
 
1457
            raise errors.NoRepositoryPresent(a_bzrdir)
 
1458
        except KeyError:
 
1459
            raise errors.UnknownFormatError(format=format_string,
 
1460
                                            kind='repository')
 
1461
 
 
1462
    @classmethod
 
1463
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
 
1464
    def register_format(klass, format):
 
1465
        format_registry.register(format)
 
1466
 
 
1467
    @classmethod
 
1468
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
 
1469
    def unregister_format(klass, format):
 
1470
        format_registry.remove(format)
 
1471
 
 
1472
    @classmethod
 
1473
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
 
1474
    def get_default_format(klass):
 
1475
        """Return the current default format."""
 
1476
        return format_registry.get_default()
 
1477
 
 
1478
    def get_format_string(self):
 
1479
        """Return the ASCII format string that identifies this format.
 
1480
 
 
1481
        Note that in pre format ?? repositories the format string is
 
1482
        not permitted nor written to disk.
 
1483
        """
 
1484
        raise NotImplementedError(self.get_format_string)
 
1485
 
1390
1486
    def get_format_description(self):
1391
1487
        """Return the short description for this format."""
1392
1488
        raise NotImplementedError(self.get_format_description)
1393
1489
 
1394
 
    def initialize(self, controldir, shared=False):
1395
 
        """Initialize a repository of this format in controldir.
 
1490
    def initialize(self, a_bzrdir, shared=False):
 
1491
        """Initialize a repository of this format in a_bzrdir.
1396
1492
 
1397
 
        :param controldir: The controldir to put the new repository in it.
 
1493
        :param a_bzrdir: The bzrdir to put the new repository in it.
1398
1494
        :param shared: The repository should be initialized as a sharable one.
1399
1495
        :returns: The new repository object.
1400
1496
 
1401
1497
        This may raise UninitializableFormat if shared repository are not
1402
 
        compatible the controldir.
 
1498
        compatible the a_bzrdir.
1403
1499
        """
1404
1500
        raise NotImplementedError(self.initialize)
1405
1501
 
1441
1537
                'Does not support nested trees', target_format,
1442
1538
                from_format=self)
1443
1539
 
1444
 
    def open(self, controldir, _found=False):
1445
 
        """Return an instance of this format for a controldir.
 
1540
    def open(self, a_bzrdir, _found=False):
 
1541
        """Return an instance of this format for the bzrdir a_bzrdir.
1446
1542
 
1447
1543
        _found is a private parameter, do not use it.
1448
1544
        """
1449
1545
        raise NotImplementedError(self.open)
1450
1546
 
1451
 
    def _run_post_repo_init_hooks(self, repository, controldir, shared):
1452
 
        from bzrlib.controldir import ControlDir, RepoInitHookParams
1453
 
        hooks = ControlDir.hooks['post_repo_init']
 
1547
    def _run_post_repo_init_hooks(self, repository, a_bzrdir, shared):
 
1548
        from bzrlib.bzrdir import BzrDir, RepoInitHookParams
 
1549
        hooks = BzrDir.hooks['post_repo_init']
1454
1550
        if not hooks:
1455
1551
            return
1456
 
        params = RepoInitHookParams(repository, self, controldir, shared)
 
1552
        params = RepoInitHookParams(repository, self, a_bzrdir, shared)
1457
1553
        for hook in hooks:
1458
1554
            hook(params)
1459
1555
 
1460
1556
 
1461
 
class RepositoryFormatMetaDir(bzrdir.BzrFormat, RepositoryFormat):
 
1557
class MetaDirRepositoryFormat(RepositoryFormat):
1462
1558
    """Common base class for the new repositories using the metadir layout."""
1463
1559
 
1464
1560
    rich_root_data = False
1465
1561
    supports_tree_reference = False
1466
1562
    supports_external_lookups = False
1467
1563
    supports_leaving_lock = True
1468
 
    supports_nesting_repositories = True
1469
1564
 
1470
1565
    @property
1471
1566
    def _matchingbzrdir(self):
1474
1569
        return matching
1475
1570
 
1476
1571
    def __init__(self):
1477
 
        RepositoryFormat.__init__(self)
1478
 
        bzrdir.BzrFormat.__init__(self)
 
1572
        super(MetaDirRepositoryFormat, self).__init__()
1479
1573
 
1480
1574
    def _create_control_files(self, a_bzrdir):
1481
1575
        """Create the required files and the initial control_files object."""
1505
1599
        finally:
1506
1600
            control_files.unlock()
1507
1601
 
1508
 
    @classmethod
1509
 
    def find_format(klass, a_bzrdir):
1510
 
        """Return the format for the repository object in a_bzrdir.
1511
 
 
1512
 
        This is used by bzr native formats that have a "format" file in
1513
 
        the repository.  Other methods may be used by different types of
1514
 
        control directory.
1515
 
        """
1516
 
        try:
1517
 
            transport = a_bzrdir.get_repository_transport(None)
1518
 
            format_string = transport.get_bytes("format")
1519
 
        except errors.NoSuchFile:
1520
 
            raise errors.NoRepositoryPresent(a_bzrdir)
1521
 
        return klass._find_format(format_registry, 'repository', format_string)
1522
 
 
1523
 
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1524
 
            basedir=None):
1525
 
        RepositoryFormat.check_support_status(self,
1526
 
            allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
1527
 
            basedir=basedir)
1528
 
        bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
1529
 
            recommend_upgrade=recommend_upgrade, basedir=basedir)
 
1602
    def network_name(self):
 
1603
        """Metadir formats have matching disk and network format strings."""
 
1604
        return self.get_format_string()
1530
1605
 
1531
1606
 
1532
1607
# formats which have no format string are not discoverable or independently
1533
1608
# creatable on disk, so are not registered in format_registry.  They're
1534
1609
# all in bzrlib.repofmt.knitreponow.  When an instance of one of these is
1535
 
# needed, it's constructed directly by the ControlDir.  Non-native formats where
 
1610
# needed, it's constructed directly by the BzrDir.  Non-native formats where
1536
1611
# the repository is not separately opened are similar.
1537
1612
 
1538
1613
format_registry.register_lazy(
1649
1724
        self.target.fetch(self.source, revision_id=revision_id)
1650
1725
 
1651
1726
    @needs_write_lock
1652
 
    def fetch(self, revision_id=None, find_ghosts=False):
 
1727
    def fetch(self, revision_id=None, find_ghosts=False,
 
1728
            fetch_spec=None):
1653
1729
        """Fetch the content required to construct revision_id.
1654
1730
 
1655
1731
        The content is copied from self.source to self.target.
1735
1811
        # trigger an assertion if not such
1736
1812
        repo._format.get_format_string()
1737
1813
        self.repo_dir = repo.bzrdir
1738
 
        pb.update(gettext('Moving repository to repository.backup'))
 
1814
        pb.update('Moving repository to repository.backup')
1739
1815
        self.repo_dir.transport.move('repository', 'repository.backup')
1740
1816
        backup_transport =  self.repo_dir.transport.clone('repository.backup')
1741
1817
        repo._format.check_conversion_target(self.target_format)
1742
1818
        self.source_repo = repo._format.open(self.repo_dir,
1743
1819
            _found=True,
1744
1820
            _override_transport=backup_transport)
1745
 
        pb.update(gettext('Creating new repository'))
 
1821
        pb.update('Creating new repository')
1746
1822
        converted = self.target_format.initialize(self.repo_dir,
1747
1823
                                                  self.source_repo.is_shared())
1748
1824
        converted.lock_write()
1749
1825
        try:
1750
 
            pb.update(gettext('Copying content'))
 
1826
            pb.update('Copying content')
1751
1827
            self.source_repo.copy_content_into(converted)
1752
1828
        finally:
1753
1829
            converted.unlock()
1754
 
        pb.update(gettext('Deleting old repository content'))
 
1830
        pb.update('Deleting old repository content')
1755
1831
        self.repo_dir.transport.delete_tree('repository.backup')
1756
 
        ui.ui_factory.note(gettext('repository converted'))
 
1832
        ui.ui_factory.note('repository converted')
1757
1833
        pb.finished()
1758
1834
 
1759
1835
 
1825
1901
        for list_part in self.list_parts:
1826
1902
            full_list.extend(list_part)
1827
1903
        return iter(full_list)
1828
 
 
1829
 
    def __repr__(self):
1830
 
        return "%s.%s(%s)" % (self.__module__, self.__class__.__name__,
1831
 
                              self.list_parts)