~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

(gz) Remove bzrlib/util/elementtree/ package (Martin Packman)

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
 
17
19
from bzrlib.lazy_import import lazy_import
18
20
lazy_import(globals(), """
19
21
import itertools
20
22
import time
21
23
 
22
24
from bzrlib import (
23
 
    bzrdir,
24
25
    config,
25
26
    controldir,
26
27
    debug,
32
33
    revision as _mod_revision,
33
34
    testament as _mod_testament,
34
35
    tsort,
 
36
    gpg,
35
37
    )
36
38
from bzrlib.bundle import serializer
 
39
from bzrlib.i18n import gettext
37
40
""")
38
41
 
39
42
from bzrlib import (
 
43
    bzrdir,
40
44
    errors,
41
45
    registry,
42
46
    symbol_versioning,
72
76
    record_root_entry = True
73
77
    # whether this commit builder supports the record_entry_contents interface
74
78
    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
75
82
 
76
 
    def __init__(self, repository, parents, config, timestamp=None,
 
83
    def __init__(self, repository, parents, config_stack, timestamp=None,
77
84
                 timezone=None, committer=None, revprops=None,
78
85
                 revision_id=None, lossy=False):
79
86
        """Initiate a CommitBuilder.
88
95
        :param lossy: Whether to discard data that can not be natively
89
96
            represented, when pushing to a foreign VCS 
90
97
        """
91
 
        self._config = config
 
98
        self._config_stack = config_stack
92
99
        self._lossy = lossy
93
100
 
94
101
        if committer is None:
95
 
            self._committer = self._config.username()
 
102
            self._committer = self._config_stack.get('email')
96
103
        elif not isinstance(committer, unicode):
97
104
            self._committer = committer.decode() # throw if non-ascii
98
105
        else:
279
286
                raise
280
287
            mutter('abort_write_group failed')
281
288
            log_exception_quietly()
282
 
            note('bzr: ERROR (ignored): %s', exc)
 
289
            note(gettext('bzr: ERROR (ignored): %s'), exc)
283
290
        self._write_group = None
284
291
 
285
292
    def _abort_write_group(self):
339
346
        """
340
347
        self.control_files.break_lock()
341
348
 
342
 
    @needs_read_lock
343
 
    def _eliminate_revisions_not_present(self, revision_ids):
344
 
        """Check every revision id in revision_ids to see if we have it.
345
 
 
346
 
        Returns a set of the present revisions.
347
 
        """
348
 
        result = []
349
 
        graph = self.get_graph()
350
 
        parent_map = graph.get_parent_map(revision_ids)
351
 
        # The old API returned a list, should this actually be a set?
352
 
        return parent_map.keys()
353
 
 
354
349
    @staticmethod
355
 
    def create(a_bzrdir):
356
 
        """Construct the current default format repository in a_bzrdir."""
357
 
        return RepositoryFormat.get_default_format().initialize(a_bzrdir)
 
350
    def create(controldir):
 
351
        """Construct the current default format repository in controldir."""
 
352
        return RepositoryFormat.get_default_format().initialize(controldir)
358
353
 
359
 
    def __init__(self, _format, a_bzrdir, control_files):
 
354
    def __init__(self, _format, controldir, control_files):
360
355
        """instantiate a Repository.
361
356
 
362
357
        :param _format: The format of the repository on disk.
363
 
        :param a_bzrdir: The BzrDir of the repository.
 
358
        :param controldir: The ControlDir of the repository.
364
359
        :param control_files: Control files to use for locking, etc.
365
360
        """
366
361
        # In the future we will have a single api for all stores for
369
364
        super(Repository, self).__init__()
370
365
        self._format = _format
371
366
        # the following are part of the public API for Repository:
372
 
        self.bzrdir = a_bzrdir
 
367
        self.bzrdir = controldir
373
368
        self.control_files = control_files
374
 
        self._transport = control_files._transport
375
 
        self.base = self._transport.base
376
369
        # for tests
377
370
        self._write_group = None
378
371
        # Additional places to query for data.
416
409
        """
417
410
        if self.__class__ is not other.__class__:
418
411
            return False
419
 
        return (self._transport.base == other._transport.base)
 
412
        return (self.control_url == other.control_url)
420
413
 
421
414
    def is_in_write_group(self):
422
415
        """Return True if there is an open write group.
522
515
        if revid and committers:
523
516
            result['committers'] = 0
524
517
        if revid and revid != _mod_revision.NULL_REVISION:
 
518
            graph = self.get_graph()
525
519
            if committers:
526
520
                all_committers = set()
527
 
            revisions = self.get_ancestry(revid)
528
 
            # pop the leading None
529
 
            revisions.pop(0)
530
 
            first_revision = None
 
521
            revisions = [r for (r, p) in graph.iter_ancestry([revid])
 
522
                        if r != _mod_revision.NULL_REVISION]
 
523
            last_revision = None
531
524
            if not committers:
532
525
                # ignore the revisions in the middle - just grab first and last
533
526
                revisions = revisions[0], revisions[-1]
534
527
            for revision in self.get_revisions(revisions):
535
 
                if not first_revision:
536
 
                    first_revision = revision
 
528
                if not last_revision:
 
529
                    last_revision = revision
537
530
                if committers:
538
531
                    all_committers.add(revision.committer)
539
 
            last_revision = revision
 
532
            first_revision = revision
540
533
            if committers:
541
534
                result['committers'] = len(all_committers)
542
535
            result['firstrev'] = (first_revision.timestamp,
559
552
            def __init__(self):
560
553
                self.first_call = True
561
554
 
562
 
            def __call__(self, bzrdir):
563
 
                # On the first call, the parameter is always the bzrdir
 
555
            def __call__(self, controldir):
 
556
                # On the first call, the parameter is always the controldir
564
557
                # containing the current repo.
565
558
                if not self.first_call:
566
559
                    try:
567
 
                        repository = bzrdir.open_repository()
 
560
                        repository = controldir.open_repository()
568
561
                    except errors.NoRepositoryPresent:
569
562
                        pass
570
563
                    else:
571
564
                        return False, ([], repository)
572
565
                self.first_call = False
573
 
                value = (bzrdir.list_branches(), None)
 
566
                value = (controldir.list_branches(), None)
574
567
                return True, value
575
568
 
576
569
        ret = []
577
 
        for branches, repository in bzrdir.BzrDir.find_bzrdirs(
 
570
        for branches, repository in controldir.ControlDir.find_bzrdirs(
578
571
                self.user_transport, evaluate=Evaluator()):
579
572
            if branches is not None:
580
573
                ret.extend(branches)
614
607
        For instance, if the repository is at URL/.bzr/repository,
615
608
        Repository.open(URL) -> a Repository instance.
616
609
        """
617
 
        control = bzrdir.BzrDir.open(base)
 
610
        control = controldir.ControlDir.open(base)
618
611
        return control.open_repository()
619
612
 
620
613
    def copy_content_into(self, destination, revision_id=None):
651
644
        """
652
645
 
653
646
    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
        """
654
653
        raise errors.UnsuspendableWriteGroup(self)
655
654
 
656
655
    def refresh_data(self):
678
677
    def _resume_write_group(self, tokens):
679
678
        raise errors.UnsuspendableWriteGroup(self)
680
679
 
681
 
    def fetch(self, source, revision_id=None, find_ghosts=False,
682
 
            fetch_spec=None):
 
680
    def fetch(self, source, revision_id=None, find_ghosts=False):
683
681
        """Fetch the content required to construct revision_id from source.
684
682
 
685
 
        If revision_id is None and fetch_spec is None, then all content is
686
 
        copied.
 
683
        If revision_id is None, then all content is copied.
687
684
 
688
685
        fetch() may not be used when the repository is in a write group -
689
686
        either finish the current write group before using fetch, or use
695
692
        :param revision_id: If specified, all the content needed for this
696
693
            revision ID will be copied to the target.  Fetch will determine for
697
694
            itself which content needs to be copied.
698
 
        :param fetch_spec: If specified, a SearchResult or
699
 
            PendingAncestryResult that describes which revisions to copy.  This
700
 
            allows copying multiple heads at once.  Mutually exclusive with
701
 
            revision_id.
702
695
        """
703
 
        if fetch_spec is not None and revision_id is not None:
704
 
            raise AssertionError(
705
 
                "fetch_spec and revision_id are mutually exclusive.")
706
696
        if self.is_in_write_group():
707
697
            raise errors.InternalBzrError(
708
698
                "May not fetch while in a write group.")
710
700
        # TODO: lift out to somewhere common with RemoteRepository
711
701
        # <https://bugs.launchpad.net/bzr/+bug/401646>
712
702
        if (self.has_same_location(source)
713
 
            and fetch_spec is None
714
703
            and self._has_same_fallbacks(source)):
715
704
            # check that last_revision is in 'from' and then return a
716
705
            # no-operation.
719
708
                self.get_revision(revision_id)
720
709
            return 0, []
721
710
        inter = InterRepository.get(source, self)
722
 
        return inter.fetch(revision_id=revision_id,
723
 
            find_ghosts=find_ghosts, fetch_spec=fetch_spec)
 
711
        return inter.fetch(revision_id=revision_id, find_ghosts=find_ghosts)
724
712
 
725
713
    def create_bundle(self, target, base, fileobj, format=None):
726
714
        return serializer.write_bundle(self, target, base, fileobj, format)
727
715
 
728
 
    def get_commit_builder(self, branch, parents, config, timestamp=None,
 
716
    def get_commit_builder(self, branch, parents, config_stack, timestamp=None,
729
717
                           timezone=None, committer=None, revprops=None,
730
718
                           revision_id=None, lossy=False):
731
719
        """Obtain a CommitBuilder for this repository.
732
720
 
733
721
        :param branch: Branch to commit to.
734
722
        :param parents: Revision ids of the parents of the new revision.
735
 
        :param config: Configuration to use.
 
723
        :param config_stack: Configuration stack to use.
736
724
        :param timestamp: Optional timestamp recorded for commit.
737
725
        :param timezone: Optional timezone for timestamp.
738
726
        :param committer: Optional committer to set for commit.
758
746
                repo.unlock()
759
747
 
760
748
    @needs_read_lock
761
 
    def clone(self, a_bzrdir, revision_id=None):
762
 
        """Clone this repository into a_bzrdir using the current format.
 
749
    def clone(self, controldir, revision_id=None):
 
750
        """Clone this repository into controldir using the current format.
763
751
 
764
752
        Currently no check is made that the format of this repository and
765
753
        the bzrdir format are compatible. FIXME RBC 20060201.
768
756
        """
769
757
        # TODO: deprecate after 0.16; cloning this with all its settings is
770
758
        # probably not very useful -- mbp 20070423
771
 
        dest_repo = self._create_sprouting_repo(a_bzrdir, shared=self.is_shared())
 
759
        dest_repo = self._create_sprouting_repo(
 
760
            controldir, shared=self.is_shared())
772
761
        self.copy_content_into(dest_repo, revision_id)
773
762
        return dest_repo
774
763
 
941
930
        parent_ids.discard(_mod_revision.NULL_REVISION)
942
931
        return parent_ids
943
932
 
944
 
    def fileids_altered_by_revision_ids(self, revision_ids):
945
 
        """Find the file ids and versions affected by revisions.
946
 
 
947
 
        :param revisions: an iterable containing revision ids.
948
 
        :return: a dictionary mapping altered file-ids to an iterable of
949
 
            revision_ids. Each altered file-ids has the exact revision_ids
950
 
            that altered it listed explicitly.
951
 
        """
952
 
        raise NotImplementedError(self.fileids_altered_by_revision_ids)
953
 
 
954
933
    def iter_files_bytes(self, desired_files):
955
934
        """Iterate through file versions.
956
935
 
1002
981
            raise AssertionError('_iter_for_revno returned too much history')
1003
982
        return (True, partial_history[-1])
1004
983
 
 
984
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
1005
985
    def iter_reverse_revision_history(self, revision_id):
1006
986
        """Iterate backwards through revision ids in the lefthand history
1007
987
 
1055
1035
        raise NotImplementedError(self.revision_trees)
1056
1036
 
1057
1037
    @needs_read_lock
 
1038
    @symbol_versioning.deprecated_method(
 
1039
        symbol_versioning.deprecated_in((2, 4, 0)))
1058
1040
    def get_ancestry(self, revision_id, topo_sorted=True):
1059
1041
        """Return a list of revision-ids integrated by a revision.
1060
1042
 
1064
1046
 
1065
1047
        This is topologically sorted.
1066
1048
        """
 
1049
        if 'evil' in debug.debug_flags:
 
1050
            mutter_callsite(2, "get_ancestry is linear with history.")
1067
1051
        if _mod_revision.is_null(revision_id):
1068
1052
            return [None]
1069
1053
        if not self.has_revision(revision_id):
1165
1149
                [parents_provider, other_repository._make_parents_provider()])
1166
1150
        return graph.Graph(parents_provider)
1167
1151
 
1168
 
    def revision_ids_to_search_result(self, result_set):
1169
 
        """Convert a set of revision ids to a graph SearchResult."""
1170
 
        result_parents = set()
1171
 
        for parents in self.get_graph().get_parent_map(
1172
 
            result_set).itervalues():
1173
 
            result_parents.update(parents)
1174
 
        included_keys = result_set.intersection(result_parents)
1175
 
        start_keys = result_set.difference(included_keys)
1176
 
        exclude_keys = result_parents.difference(result_set)
1177
 
        result = graph.SearchResult(start_keys, exclude_keys,
1178
 
            len(result_set), result_set)
1179
 
        return result
1180
 
 
1181
1152
    @needs_write_lock
1182
1153
    def set_make_working_trees(self, new_value):
1183
1154
        """Set the policy flag for making working trees when creating branches.
1200
1171
        plaintext = testament.as_short_text()
1201
1172
        self.store_revision_signature(gpg_strategy, plaintext, revision_id)
1202
1173
 
 
1174
    @needs_read_lock
 
1175
    def verify_revision_signature(self, revision_id, gpg_strategy):
 
1176
        """Verify the signature on a revision.
 
1177
        
 
1178
        :param revision_id: the revision to verify
 
1179
        :gpg_strategy: the GPGStrategy object to used
 
1180
        
 
1181
        :return: gpg.SIGNATURE_VALID or a failed SIGNATURE_ value
 
1182
        """
 
1183
        if not self.has_signature_for_revision_id(revision_id):
 
1184
            return gpg.SIGNATURE_NOT_SIGNED, None
 
1185
        signature = self.get_signature_text(revision_id)
 
1186
 
 
1187
        testament = _mod_testament.Testament.from_revision(self, revision_id)
 
1188
        plaintext = testament.as_short_text()
 
1189
 
 
1190
        return gpg_strategy.verify(signature, plaintext)
 
1191
 
1203
1192
    def has_signature_for_revision_id(self, revision_id):
1204
1193
        """Query for a revision signature for revision_id in the repository."""
1205
1194
        raise NotImplementedError(self.has_signature_for_revision_id)
1304
1293
        """Returns the policy for making working trees on new branches."""
1305
1294
        return not self._transport.has('no-working-trees')
1306
1295
 
 
1296
    @needs_write_lock
 
1297
    def update_feature_flags(self, updated_flags):
 
1298
        """Update the feature flags for this branch.
 
1299
 
 
1300
        :param updated_flags: Dictionary mapping feature names to necessities
 
1301
            A necessity can be None to indicate the feature should be removed
 
1302
        """
 
1303
        self._format._update_feature_flags(updated_flags)
 
1304
        self.control_transport.put_bytes('format', self._format.as_string())
 
1305
 
1307
1306
 
1308
1307
class RepositoryFormatRegistry(controldir.ControlComponentFormatRegistry):
1309
1308
    """Repository format registry."""
1310
1309
 
1311
1310
    def get_default(self):
1312
1311
        """Return the current default format."""
1313
 
        from bzrlib import bzrdir
1314
 
        return bzrdir.format_registry.make_bzrdir('default').repository_format
 
1312
        return controldir.format_registry.make_bzrdir('default').repository_format
1315
1313
 
1316
1314
 
1317
1315
network_format_registry = registry.FormatRegistry()
1360
1358
    created.
1361
1359
 
1362
1360
    Common instance attributes:
1363
 
    _matchingbzrdir - the bzrdir format that the repository format was
 
1361
    _matchingbzrdir - the controldir format that the repository format was
1364
1362
    originally written to work with. This can be used if manually
1365
1363
    constructing a bzrdir and repository, or more commonly for test suite
1366
1364
    parameterization.
1404
1402
    revision_graph_can_have_wrong_parents = None
1405
1403
    # Does this format support rich root data?
1406
1404
    rich_root_data = None
 
1405
    # Does this format support explicitly versioned directories?
 
1406
    supports_versioned_directories = None
 
1407
    # Can other repositories be nested into one of this format?
 
1408
    supports_nesting_repositories = None
 
1409
    # Is it possible for revisions to be present without being referenced
 
1410
    # somewhere ?
 
1411
    supports_unreferenced_revisions = None
1407
1412
 
1408
1413
    def __repr__(self):
1409
1414
        return "%s()" % self.__class__.__name__
1416
1421
        return not self == other
1417
1422
 
1418
1423
    @classmethod
1419
 
    def find_format(klass, a_bzrdir):
1420
 
        """Return the format for the repository object in a_bzrdir.
1421
 
 
1422
 
        This is used by bzr native formats that have a "format" file in
1423
 
        the repository.  Other methods may be used by different types of
1424
 
        control directory.
1425
 
        """
1426
 
        try:
1427
 
            transport = a_bzrdir.get_repository_transport(None)
1428
 
            format_string = transport.get_bytes("format")
1429
 
            return format_registry.get(format_string)
1430
 
        except errors.NoSuchFile:
1431
 
            raise errors.NoRepositoryPresent(a_bzrdir)
1432
 
        except KeyError:
1433
 
            raise errors.UnknownFormatError(format=format_string,
1434
 
                                            kind='repository')
1435
 
 
1436
 
    @classmethod
1437
1424
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
1438
1425
    def register_format(klass, format):
1439
1426
        format_registry.register(format)
1449
1436
        """Return the current default format."""
1450
1437
        return format_registry.get_default()
1451
1438
 
1452
 
    def get_format_string(self):
1453
 
        """Return the ASCII format string that identifies this format.
1454
 
 
1455
 
        Note that in pre format ?? repositories the format string is
1456
 
        not permitted nor written to disk.
1457
 
        """
1458
 
        raise NotImplementedError(self.get_format_string)
1459
 
 
1460
1439
    def get_format_description(self):
1461
1440
        """Return the short description for this format."""
1462
1441
        raise NotImplementedError(self.get_format_description)
1463
1442
 
1464
 
    def initialize(self, a_bzrdir, shared=False):
1465
 
        """Initialize a repository of this format in a_bzrdir.
 
1443
    def initialize(self, controldir, shared=False):
 
1444
        """Initialize a repository of this format in controldir.
1466
1445
 
1467
 
        :param a_bzrdir: The bzrdir to put the new repository in it.
 
1446
        :param controldir: The controldir to put the new repository in it.
1468
1447
        :param shared: The repository should be initialized as a sharable one.
1469
1448
        :returns: The new repository object.
1470
1449
 
1471
1450
        This may raise UninitializableFormat if shared repository are not
1472
 
        compatible the a_bzrdir.
 
1451
        compatible the controldir.
1473
1452
        """
1474
1453
        raise NotImplementedError(self.initialize)
1475
1454
 
1511
1490
                'Does not support nested trees', target_format,
1512
1491
                from_format=self)
1513
1492
 
1514
 
    def open(self, a_bzrdir, _found=False):
1515
 
        """Return an instance of this format for the bzrdir a_bzrdir.
 
1493
    def open(self, controldir, _found=False):
 
1494
        """Return an instance of this format for a controldir.
1516
1495
 
1517
1496
        _found is a private parameter, do not use it.
1518
1497
        """
1519
1498
        raise NotImplementedError(self.open)
1520
1499
 
1521
 
    def _run_post_repo_init_hooks(self, repository, a_bzrdir, shared):
1522
 
        from bzrlib.bzrdir import BzrDir, RepoInitHookParams
1523
 
        hooks = BzrDir.hooks['post_repo_init']
 
1500
    def _run_post_repo_init_hooks(self, repository, controldir, shared):
 
1501
        from bzrlib.controldir import ControlDir, RepoInitHookParams
 
1502
        hooks = ControlDir.hooks['post_repo_init']
1524
1503
        if not hooks:
1525
1504
            return
1526
 
        params = RepoInitHookParams(repository, self, a_bzrdir, shared)
 
1505
        params = RepoInitHookParams(repository, self, controldir, shared)
1527
1506
        for hook in hooks:
1528
1507
            hook(params)
1529
1508
 
1530
1509
 
1531
 
class MetaDirRepositoryFormat(RepositoryFormat):
 
1510
class RepositoryFormatMetaDir(bzrdir.BzrFormat, RepositoryFormat):
1532
1511
    """Common base class for the new repositories using the metadir layout."""
1533
1512
 
1534
1513
    rich_root_data = False
1535
1514
    supports_tree_reference = False
1536
1515
    supports_external_lookups = False
1537
1516
    supports_leaving_lock = True
 
1517
    supports_nesting_repositories = True
1538
1518
 
1539
1519
    @property
1540
1520
    def _matchingbzrdir(self):
1543
1523
        return matching
1544
1524
 
1545
1525
    def __init__(self):
1546
 
        super(MetaDirRepositoryFormat, self).__init__()
 
1526
        RepositoryFormat.__init__(self)
 
1527
        bzrdir.BzrFormat.__init__(self)
1547
1528
 
1548
1529
    def _create_control_files(self, a_bzrdir):
1549
1530
        """Create the required files and the initial control_files object."""
1573
1554
        finally:
1574
1555
            control_files.unlock()
1575
1556
 
1576
 
    def network_name(self):
1577
 
        """Metadir formats have matching disk and network format strings."""
1578
 
        return self.get_format_string()
 
1557
    @classmethod
 
1558
    def find_format(klass, a_bzrdir):
 
1559
        """Return the format for the repository object in a_bzrdir.
 
1560
 
 
1561
        This is used by bzr native formats that have a "format" file in
 
1562
        the repository.  Other methods may be used by different types of
 
1563
        control directory.
 
1564
        """
 
1565
        try:
 
1566
            transport = a_bzrdir.get_repository_transport(None)
 
1567
            format_string = transport.get_bytes("format")
 
1568
        except errors.NoSuchFile:
 
1569
            raise errors.NoRepositoryPresent(a_bzrdir)
 
1570
        return klass._find_format(format_registry, 'repository', format_string)
 
1571
 
 
1572
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
1573
            basedir=None):
 
1574
        RepositoryFormat.check_support_status(self,
 
1575
            allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
 
1576
            basedir=basedir)
 
1577
        bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
 
1578
            recommend_upgrade=recommend_upgrade, basedir=basedir)
1579
1579
 
1580
1580
 
1581
1581
# formats which have no format string are not discoverable or independently
1582
1582
# creatable on disk, so are not registered in format_registry.  They're
1583
1583
# all in bzrlib.repofmt.knitreponow.  When an instance of one of these is
1584
 
# needed, it's constructed directly by the BzrDir.  Non-native formats where
 
1584
# needed, it's constructed directly by the ControlDir.  Non-native formats where
1585
1585
# the repository is not separately opened are similar.
1586
1586
 
1587
1587
format_registry.register_lazy(
1698
1698
        self.target.fetch(self.source, revision_id=revision_id)
1699
1699
 
1700
1700
    @needs_write_lock
1701
 
    def fetch(self, revision_id=None, find_ghosts=False,
1702
 
            fetch_spec=None):
 
1701
    def fetch(self, revision_id=None, find_ghosts=False):
1703
1702
        """Fetch the content required to construct revision_id.
1704
1703
 
1705
1704
        The content is copied from self.source to self.target.
1785
1784
        # trigger an assertion if not such
1786
1785
        repo._format.get_format_string()
1787
1786
        self.repo_dir = repo.bzrdir
1788
 
        pb.update('Moving repository to repository.backup')
 
1787
        pb.update(gettext('Moving repository to repository.backup'))
1789
1788
        self.repo_dir.transport.move('repository', 'repository.backup')
1790
1789
        backup_transport =  self.repo_dir.transport.clone('repository.backup')
1791
1790
        repo._format.check_conversion_target(self.target_format)
1792
1791
        self.source_repo = repo._format.open(self.repo_dir,
1793
1792
            _found=True,
1794
1793
            _override_transport=backup_transport)
1795
 
        pb.update('Creating new repository')
 
1794
        pb.update(gettext('Creating new repository'))
1796
1795
        converted = self.target_format.initialize(self.repo_dir,
1797
1796
                                                  self.source_repo.is_shared())
1798
1797
        converted.lock_write()
1799
1798
        try:
1800
 
            pb.update('Copying content')
 
1799
            pb.update(gettext('Copying content'))
1801
1800
            self.source_repo.copy_content_into(converted)
1802
1801
        finally:
1803
1802
            converted.unlock()
1804
 
        pb.update('Deleting old repository content')
 
1803
        pb.update(gettext('Deleting old repository content'))
1805
1804
        self.repo_dir.transport.delete_tree('repository.backup')
1806
 
        ui.ui_factory.note('repository converted')
 
1805
        ui.ui_factory.note(gettext('repository converted'))
1807
1806
        pb.finished()
1808
1807
 
1809
1808
 
1833
1832
        it is encountered, history extension will stop.
1834
1833
    """
1835
1834
    start_revision = partial_history_cache[-1]
1836
 
    iterator = repo.iter_reverse_revision_history(start_revision)
 
1835
    graph = repo.get_graph()
 
1836
    iterator = graph.iter_lefthand_ancestry(start_revision,
 
1837
        (_mod_revision.NULL_REVISION,))
1837
1838
    try:
1838
 
        #skip the last revision in the list
 
1839
        # skip the last revision in the list
1839
1840
        iterator.next()
1840
1841
        while True:
1841
1842
            if (stop_index is not None and
1873
1874
        for list_part in self.list_parts:
1874
1875
            full_list.extend(list_part)
1875
1876
        return iter(full_list)
 
1877
 
 
1878
    def __repr__(self):
 
1879
        return "%s.%s(%s)" % (self.__module__, self.__class__.__name__,
 
1880
                              self.list_parts)