/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Richard Wilbur
  • Date: 2016-02-04 19:07:28 UTC
  • mto: This revision was merged to the branch mainline in revision 6618.
  • Revision ID: richard.wilbur@gmail.com-20160204190728-p0zvfii6zase0fw7
Update COPYING.txt from the original http://www.gnu.org/licenses/gpl-2.0.txt  (Only differences were in whitespace.)  Thanks to Petr Stodulka for pointing out the discrepancy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
from __future__ import absolute_import
18
18
 
19
 
from .lazy_import import lazy_import
 
19
from bzrlib.lazy_import import lazy_import
20
20
lazy_import(globals(), """
21
21
import itertools
22
22
import time
23
23
 
24
 
from breezy import (
 
24
from bzrlib import (
25
25
    config,
26
26
    controldir,
27
27
    debug,
28
28
    generate_ids,
29
29
    graph,
 
30
    lockable_files,
 
31
    lockdir,
30
32
    osutils,
31
33
    revision as _mod_revision,
32
34
    testament as _mod_testament,
 
35
    tsort,
33
36
    gpg,
34
37
    )
35
 
from breezy.bundle import serializer
36
 
from breezy.i18n import gettext
 
38
from bzrlib.bundle import serializer
 
39
from bzrlib.i18n import gettext
37
40
""")
38
41
 
39
 
from . import (
 
42
from bzrlib import (
 
43
    bzrdir,
40
44
    errors,
41
45
    registry,
 
46
    symbol_versioning,
42
47
    ui,
43
48
    )
44
 
from .decorators import only_raises
45
 
from .inter import InterObject
46
 
from .lock import _RelockDebugMixin, LogicalLockResult
47
 
from .sixish import (
48
 
    text_type,
49
 
    viewitems,
50
 
    viewvalues,
51
 
    )
52
 
from .trace import (
 
49
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
 
50
from bzrlib.inter import InterObject
 
51
from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
 
52
from bzrlib.trace import (
53
53
    log_exception_quietly, note, mutter, mutter_callsite, warning)
54
54
 
55
55
 
65
65
        errors.InternalBzrError.__init__(self, repo=repo)
66
66
 
67
67
 
68
 
class CannotSetRevisionId(errors.BzrError):
69
 
 
70
 
    _fmt = "Repository format does not support setting revision ids."
71
 
 
72
 
 
73
68
class CommitBuilder(object):
74
69
    """Provides an interface to build up a commit.
75
70
 
79
74
 
80
75
    # all clients should supply tree roots.
81
76
    record_root_entry = True
 
77
    # whether this commit builder supports the record_entry_contents interface
 
78
    supports_record_entry_contents = False
82
79
    # whether this commit builder will automatically update the branch that is
83
80
    # being committed to
84
81
    updates_branch = False
96
93
        :param revprops: Optional dictionary of revision properties.
97
94
        :param revision_id: Optional revision id.
98
95
        :param lossy: Whether to discard data that can not be natively
99
 
            represented, when pushing to a foreign VCS
 
96
            represented, when pushing to a foreign VCS 
100
97
        """
101
98
        self._config_stack = config_stack
102
99
        self._lossy = lossy
103
100
 
104
101
        if committer is None:
105
102
            self._committer = self._config_stack.get('email')
106
 
        elif not isinstance(committer, text_type):
 
103
        elif not isinstance(committer, unicode):
107
104
            self._committer = committer.decode() # throw if non-ascii
108
105
        else:
109
106
            self._committer = committer
110
107
 
 
108
        self._new_revision_id = revision_id
111
109
        self.parents = parents
112
110
        self.repository = repository
113
111
 
126
124
        else:
127
125
            self._timezone = int(timezone)
128
126
 
129
 
        self._generate_revision_if_needed(revision_id)
 
127
        self._generate_revision_if_needed()
130
128
 
131
129
    def any_changes(self):
132
130
        """Return True if any entries were changed.
144
142
            raise ValueError('Invalid value for %s: %r' % (context, text))
145
143
 
146
144
    def _validate_revprops(self, revprops):
147
 
        for key, value in viewitems(revprops):
 
145
        for key, value in revprops.iteritems():
148
146
            # We know that the XML serializers do not round trip '\r'
149
147
            # correctly, so refuse to accept them
150
 
            if not isinstance(value, (text_type, str)):
 
148
            if not isinstance(value, basestring):
151
149
                raise ValueError('revision property (%s) is not a valid'
152
150
                                 ' (unicode) string: %r' % (key, value))
153
151
            self._validate_unicode_text(value,
188
186
        """Return new revision-id."""
189
187
        return generate_ids.gen_revision_id(self._committer, self._timestamp)
190
188
 
191
 
    def _generate_revision_if_needed(self, revision_id):
 
189
    def _generate_revision_if_needed(self):
192
190
        """Create a revision id if None was supplied.
193
191
 
194
192
        If the repository can not support user-specified revision ids
197
195
 
198
196
        :raises: CannotSetRevisionId
199
197
        """
200
 
        if not self.repository._format.supports_setting_revision_ids:
201
 
            if revision_id is not None:
202
 
                raise CannotSetRevisionId()
203
 
            return
204
 
        if revision_id is None:
 
198
        if self._new_revision_id is None:
205
199
            self._new_revision_id = self._gen_revision_id()
206
200
            self.random_revid = True
207
201
        else:
208
 
            self._new_revision_id = revision_id
209
202
            self.random_revid = False
210
203
 
 
204
    def will_record_deletes(self):
 
205
        """Tell the commit builder that deletes are being notified.
 
206
 
 
207
        This enables the accumulation of an inventory delta; for the resulting
 
208
        commit to be valid, deletes against the basis MUST be recorded via
 
209
        builder.record_delete().
 
210
        """
 
211
        raise NotImplementedError(self.will_record_deletes)
 
212
 
211
213
    def record_iter_changes(self, tree, basis_revision_id, iter_changes):
212
214
        """Record a new tree via iter_changes.
213
215
 
246
248
# Repositories
247
249
 
248
250
 
249
 
class Repository(controldir.ControlComponent, _RelockDebugMixin):
 
251
class Repository(_RelockDebugMixin, controldir.ControlComponent):
250
252
    """Repository holding history for one or more branches.
251
253
 
252
254
    The repository holds and retrieves historical information including
253
255
    revisions and file history.  It's normally accessed only by the Branch,
254
256
    which views a particular line of development through that history.
255
257
 
256
 
    See VersionedFileRepository in breezy.vf_repository for the
 
258
    See VersionedFileRepository in bzrlib.vf_repository for the
257
259
    base class for most Bazaar repositories.
258
260
    """
259
261
 
278
280
                (self._write_group, self.get_transaction()))
279
281
        try:
280
282
            self._abort_write_group()
281
 
        except Exception as exc:
 
283
        except Exception, exc:
282
284
            self._write_group = None
283
285
            if not suppress_errors:
284
286
                raise
285
287
            mutter('abort_write_group failed')
286
288
            log_exception_quietly()
287
 
            note(gettext('brz: ERROR (ignored): %s'), exc)
 
289
            note(gettext('bzr: ERROR (ignored): %s'), exc)
288
290
        self._write_group = None
289
291
 
290
292
    def _abort_write_group(self):
362
364
        super(Repository, self).__init__()
363
365
        self._format = _format
364
366
        # the following are part of the public API for Repository:
365
 
        self.controldir = controldir
 
367
        self.bzrdir = controldir
366
368
        self.control_files = control_files
367
369
        # for tests
368
370
        self._write_group = None
371
373
 
372
374
    @property
373
375
    def user_transport(self):
374
 
        return self.controldir.user_transport
 
376
        return self.bzrdir.user_transport
375
377
 
376
378
    @property
377
379
    def control_transport(self):
492
494
        """
493
495
        self.control_files.dont_leave_in_place()
494
496
 
 
497
    @needs_read_lock
495
498
    def gather_stats(self, revid=None, committers=None):
496
499
        """Gather statistics from a revision id.
497
500
 
508
511
            revisions: The total revision count in the repository.
509
512
            size: An estimate disk size of the repository in bytes.
510
513
        """
511
 
        with self.lock_read():
512
 
            result = {}
513
 
            if revid and committers:
514
 
                result['committers'] = 0
515
 
            if revid and revid != _mod_revision.NULL_REVISION:
516
 
                graph = self.get_graph()
517
 
                if committers:
518
 
                    all_committers = set()
519
 
                revisions = [r for (r, p) in graph.iter_ancestry([revid])
520
 
                            if r != _mod_revision.NULL_REVISION]
521
 
                last_revision = None
522
 
                if not committers:
523
 
                    # ignore the revisions in the middle - just grab first and last
524
 
                    revisions = revisions[0], revisions[-1]
525
 
                for revision in self.get_revisions(revisions):
526
 
                    if not last_revision:
527
 
                        last_revision = revision
528
 
                    if committers:
529
 
                        all_committers.add(revision.committer)
530
 
                first_revision = revision
531
 
                if committers:
532
 
                    result['committers'] = len(all_committers)
533
 
                result['firstrev'] = (first_revision.timestamp,
534
 
                    first_revision.timezone)
535
 
                result['latestrev'] = (last_revision.timestamp,
536
 
                    last_revision.timezone)
537
 
            return result
 
514
        result = {}
 
515
        if revid and committers:
 
516
            result['committers'] = 0
 
517
        if revid and revid != _mod_revision.NULL_REVISION:
 
518
            graph = self.get_graph()
 
519
            if committers:
 
520
                all_committers = set()
 
521
            revisions = [r for (r, p) in graph.iter_ancestry([revid])
 
522
                        if r != _mod_revision.NULL_REVISION]
 
523
            last_revision = None
 
524
            if not committers:
 
525
                # ignore the revisions in the middle - just grab first and last
 
526
                revisions = revisions[0], revisions[-1]
 
527
            for revision in self.get_revisions(revisions):
 
528
                if not last_revision:
 
529
                    last_revision = revision
 
530
                if committers:
 
531
                    all_committers.add(revision.committer)
 
532
            first_revision = revision
 
533
            if committers:
 
534
                result['committers'] = len(all_committers)
 
535
            result['firstrev'] = (first_revision.timestamp,
 
536
                first_revision.timezone)
 
537
            result['latestrev'] = (last_revision.timestamp,
 
538
                last_revision.timezone)
 
539
        return result
538
540
 
539
541
    def find_branches(self, using=False):
540
542
        """Find branches underneath this repository.
544
546
        :param using: If True, list only branches using this repository.
545
547
        """
546
548
        if using and not self.is_shared():
547
 
            return self.controldir.list_branches()
 
549
            return self.bzrdir.list_branches()
548
550
        class Evaluator(object):
549
551
 
550
552
            def __init__(self):
565
567
                return True, value
566
568
 
567
569
        ret = []
568
 
        for branches, repository in controldir.ControlDir.find_controldirs(
 
570
        for branches, repository in controldir.ControlDir.find_bzrdirs(
569
571
                self.user_transport, evaluate=Evaluator()):
570
572
            if branches is not None:
571
573
                ret.extend(branches)
573
575
                ret.extend(repository.find_branches())
574
576
        return ret
575
577
 
 
578
    @needs_read_lock
576
579
    def search_missing_revision_ids(self, other,
 
580
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
577
581
            find_ghosts=True, revision_ids=None, if_present_ids=None,
578
582
            limit=None):
579
583
        """Return the revision ids that other has that this does not.
580
584
 
581
585
        These are returned in topological order.
582
586
 
583
 
        revision_ids: only return revision ids included by revision_id.
 
587
        revision_id: only return revision ids included by revision_id.
584
588
        """
585
 
        with self.lock_read():
586
 
            return InterRepository.get(other, self).search_missing_revision_ids(
587
 
                find_ghosts=find_ghosts, revision_ids=revision_ids,
588
 
                if_present_ids=if_present_ids, limit=limit)
 
589
        if symbol_versioning.deprecated_passed(revision_id):
 
590
            symbol_versioning.warn(
 
591
                'search_missing_revision_ids(revision_id=...) was '
 
592
                'deprecated in 2.4.  Use revision_ids=[...] instead.',
 
593
                DeprecationWarning, stacklevel=3)
 
594
            if revision_ids is not None:
 
595
                raise AssertionError(
 
596
                    'revision_ids is mutually exclusive with revision_id')
 
597
            if revision_id is not None:
 
598
                revision_ids = [revision_id]
 
599
        return InterRepository.get(other, self).search_missing_revision_ids(
 
600
            find_ghosts=find_ghosts, revision_ids=revision_ids,
 
601
            if_present_ids=if_present_ids, limit=limit)
589
602
 
590
603
    @staticmethod
591
604
    def open(base):
645
658
        This method is intended to be called after another repository instance
646
659
        (such as one used by a smart server) has inserted data into the
647
660
        repository. On all repositories this will work outside of write groups.
648
 
        Some repository formats (pack and newer for breezy native formats)
 
661
        Some repository formats (pack and newer for bzrlib native formats)
649
662
        support refresh_data inside write groups. If called inside a write
650
663
        group on a repository that does not support refreshing in a write group
651
664
        IsInWriteGroupError will be raised.
721
734
    @only_raises(errors.LockNotHeld, errors.LockBroken)
722
735
    def unlock(self):
723
736
        if (self.control_files._lock_count == 1 and
724
 
                self.control_files._lock_mode == 'w'):
 
737
            self.control_files._lock_mode == 'w'):
725
738
            if self._write_group is not None:
726
739
                self.abort_write_group()
727
740
                self.control_files.unlock()
732
745
            for repo in self._fallback_repositories:
733
746
                repo.unlock()
734
747
 
 
748
    @needs_read_lock
735
749
    def clone(self, controldir, revision_id=None):
736
750
        """Clone this repository into controldir using the current format.
737
751
 
740
754
 
741
755
        :return: The newly created destination repository.
742
756
        """
743
 
        with self.lock_read():
744
 
            # TODO: deprecate after 0.16; cloning this with all its settings is
745
 
            # probably not very useful -- mbp 20070423
746
 
            dest_repo = self._create_sprouting_repo(
747
 
                controldir, shared=self.is_shared())
748
 
            self.copy_content_into(dest_repo, revision_id)
749
 
            return dest_repo
 
757
        # TODO: deprecate after 0.16; cloning this with all its settings is
 
758
        # probably not very useful -- mbp 20070423
 
759
        dest_repo = self._create_sprouting_repo(
 
760
            controldir, shared=self.is_shared())
 
761
        self.copy_content_into(dest_repo, revision_id)
 
762
        return dest_repo
750
763
 
751
764
    def start_write_group(self):
752
765
        """Start a write group in the repository.
755
768
        between file ids and backend store to manage the insertion of data from
756
769
        both fetch and commit operations.
757
770
 
758
 
        A write lock is required around the
759
 
        start_write_group/commit_write_group for the support of lock-requiring
760
 
        repository formats.
 
771
        A write lock is required around the start_write_group/commit_write_group
 
772
        for the support of lock-requiring repository formats.
761
773
 
762
774
        One can only insert data into a repository inside a write group.
763
775
 
778
790
        entered.
779
791
        """
780
792
 
 
793
    @needs_read_lock
781
794
    def sprout(self, to_bzrdir, revision_id=None):
782
795
        """Create a descendent repository for new development.
783
796
 
784
797
        Unlike clone, this does not copy the settings of the repository.
785
798
        """
786
 
        with self.lock_read():
787
 
            dest_repo = self._create_sprouting_repo(to_bzrdir, shared=False)
788
 
            dest_repo.fetch(self, revision_id=revision_id)
789
 
            return dest_repo
 
799
        dest_repo = self._create_sprouting_repo(to_bzrdir, shared=False)
 
800
        dest_repo.fetch(self, revision_id=revision_id)
 
801
        return dest_repo
790
802
 
791
 
    def _create_sprouting_repo(self, a_controldir, shared):
792
 
        if not isinstance(
793
 
                a_controldir._format, self.controldir._format.__class__):
 
803
    def _create_sprouting_repo(self, a_bzrdir, shared):
 
804
        if not isinstance(a_bzrdir._format, self.bzrdir._format.__class__):
794
805
            # use target default format.
795
 
            dest_repo = a_controldir.create_repository()
 
806
            dest_repo = a_bzrdir.create_repository()
796
807
        else:
797
808
            # Most control formats need the repository to be specifically
798
809
            # created, but on some old all-in-one formats it's not needed
799
810
            try:
800
 
                dest_repo = self._format.initialize(
801
 
                        a_controldir, shared=shared)
 
811
                dest_repo = self._format.initialize(a_bzrdir, shared=shared)
802
812
            except errors.UninitializableFormat:
803
 
                dest_repo = a_controldir.open_repository()
 
813
                dest_repo = a_bzrdir.open_repository()
804
814
        return dest_repo
805
815
 
 
816
    @needs_read_lock
806
817
    def has_revision(self, revision_id):
807
818
        """True if this repository has a copy of the revision."""
808
 
        with self.lock_read():
809
 
            return revision_id in self.has_revisions((revision_id,))
 
819
        return revision_id in self.has_revisions((revision_id,))
810
820
 
 
821
    @needs_read_lock
811
822
    def has_revisions(self, revision_ids):
812
823
        """Probe to find out the presence of multiple revisions.
813
824
 
816
827
        """
817
828
        raise NotImplementedError(self.has_revisions)
818
829
 
 
830
    @needs_read_lock
819
831
    def get_revision(self, revision_id):
820
832
        """Return the Revision object for a named revision."""
821
 
        with self.lock_read():
822
 
            return self.get_revisions([revision_id])[0]
 
833
        return self.get_revisions([revision_id])[0]
823
834
 
824
835
    def get_revision_reconcile(self, revision_id):
825
836
        """'reconcile' helper routine that allows access to a revision always.
833
844
 
834
845
    def get_revisions(self, revision_ids):
835
846
        """Get many revisions at once.
836
 
 
837
 
        Repositories that need to check data on every revision read should
 
847
        
 
848
        Repositories that need to check data on every revision read should 
838
849
        subclass this method.
839
850
        """
840
 
        revs = {}
841
 
        for revid, rev in self.iter_revisions(revision_ids):
842
 
            if rev is None:
843
 
                raise errors.NoSuchRevision(self, revid)
844
 
            revs[revid] = rev
845
 
        return [revs[revid] for revid in revision_ids]
846
 
 
847
 
    def iter_revisions(self, revision_ids):
848
 
        """Iterate over revision objects.
849
 
 
850
 
        :param revision_ids: An iterable of revisions to examine. None may be
851
 
            passed to request all revisions known to the repository. Note that
852
 
            not all repositories can find unreferenced revisions; for those
853
 
            repositories only referenced ones will be returned.
854
 
        :return: An iterator of (revid, revision) tuples. Absent revisions (
855
 
            those asked for but not available) are returned as (revid, None).
856
 
            N.B.: Revisions are not necessarily yielded in order.
857
 
        """
858
 
        raise NotImplementedError(self.iter_revisions)
 
851
        raise NotImplementedError(self.get_revisions)
859
852
 
860
853
    def get_deltas_for_revisions(self, revisions, specific_fileids=None):
861
854
        """Produce a generator of revision deltas.
868
861
          so that only those file-ids, their parents and their
869
862
          children are included.
870
863
        """
871
 
        raise NotImplementedError(self.get_deltas_for_revisions)
872
 
 
 
864
        # Get the revision-ids of interest
 
865
        required_trees = set()
 
866
        for revision in revisions:
 
867
            required_trees.add(revision.revision_id)
 
868
            required_trees.update(revision.parent_ids[:1])
 
869
 
 
870
        # Get the matching filtered trees. Note that it's more
 
871
        # efficient to pass filtered trees to changes_from() rather
 
872
        # than doing the filtering afterwards. changes_from() could
 
873
        # arguably do the filtering itself but it's path-based, not
 
874
        # file-id based, so filtering before or afterwards is
 
875
        # currently easier.
 
876
        if specific_fileids is None:
 
877
            trees = dict((t.get_revision_id(), t) for
 
878
                t in self.revision_trees(required_trees))
 
879
        else:
 
880
            trees = dict((t.get_revision_id(), t) for
 
881
                t in self._filtered_revision_trees(required_trees,
 
882
                specific_fileids))
 
883
 
 
884
        # Calculate the deltas
 
885
        for revision in revisions:
 
886
            if not revision.parent_ids:
 
887
                old_tree = self.revision_tree(_mod_revision.NULL_REVISION)
 
888
            else:
 
889
                old_tree = trees[revision.parent_ids[0]]
 
890
            yield trees[revision.revision_id].changes_from(old_tree)
 
891
 
 
892
    @needs_read_lock
873
893
    def get_revision_delta(self, revision_id, specific_fileids=None):
874
894
        """Return the delta for one revision.
875
895
 
880
900
          so that only those file-ids, their parents and their
881
901
          children are included.
882
902
        """
883
 
        with self.lock_read():
884
 
            r = self.get_revision(revision_id)
885
 
            return list(self.get_deltas_for_revisions(
886
 
                [r], specific_fileids=specific_fileids))[0]
 
903
        r = self.get_revision(revision_id)
 
904
        return list(self.get_deltas_for_revisions([r],
 
905
            specific_fileids=specific_fileids))[0]
887
906
 
 
907
    @needs_write_lock
888
908
    def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
889
 
        with self.lock_write():
890
 
            signature = gpg_strategy.sign(plaintext, gpg.MODE_CLEAR)
891
 
            self.add_signature_text(revision_id, signature)
 
909
        signature = gpg_strategy.sign(plaintext)
 
910
        self.add_signature_text(revision_id, signature)
892
911
 
893
912
    def add_signature_text(self, revision_id, signature):
894
913
        """Store a signature text for a revision.
898
917
        """
899
918
        raise NotImplementedError(self.add_signature_text)
900
919
 
 
920
    def _find_parent_ids_of_revisions(self, revision_ids):
 
921
        """Find all parent ids that are mentioned in the revision graph.
 
922
 
 
923
        :return: set of revisions that are parents of revision_ids which are
 
924
            not part of revision_ids themselves
 
925
        """
 
926
        parent_map = self.get_parent_map(revision_ids)
 
927
        parent_ids = set()
 
928
        map(parent_ids.update, parent_map.itervalues())
 
929
        parent_ids.difference_update(revision_ids)
 
930
        parent_ids.discard(_mod_revision.NULL_REVISION)
 
931
        return parent_ids
 
932
 
901
933
    def iter_files_bytes(self, desired_files):
902
934
        """Iterate through file versions.
903
935
 
932
964
        try:
933
965
            _iter_for_revno(
934
966
                self, partial_history, stop_index=distance_from_known)
935
 
        except errors.RevisionNotPresent as err:
 
967
        except errors.RevisionNotPresent, err:
936
968
            if err.revision_id == known_revid:
937
969
                # The start revision (known_revid) wasn't found.
938
970
                raise
953
985
        """Return True if this repository is flagged as a shared repository."""
954
986
        raise NotImplementedError(self.is_shared)
955
987
 
 
988
    @needs_write_lock
956
989
    def reconcile(self, other=None, thorough=False):
957
990
        """Reconcile this repository."""
958
 
        from .reconcile import RepoReconciler
959
 
        with self.lock_write():
960
 
            reconciler = RepoReconciler(self, thorough=thorough)
961
 
            reconciler.reconcile()
962
 
            return reconciler
 
991
        from bzrlib.reconcile import RepoReconciler
 
992
        reconciler = RepoReconciler(self, thorough=thorough)
 
993
        reconciler.reconcile()
 
994
        return reconciler
963
995
 
964
996
    def _refresh_data(self):
965
997
        """Helper called from lock_* to ensure coherency with disk.
975
1007
        repository.
976
1008
        """
977
1009
 
 
1010
    @needs_read_lock
978
1011
    def revision_tree(self, revision_id):
979
1012
        """Return Tree for a revision on this branch.
980
1013
 
997
1030
        types it should be a no-op that just returns.
998
1031
 
999
1032
        This stub method does not require a lock, but subclasses should use
1000
 
        self.write_lock as this is a long running call it's reasonable to
 
1033
        @needs_write_lock as this is a long running call it's reasonable to
1001
1034
        implicitly lock for the user.
1002
1035
 
1003
1036
        :param hint: If not supplied, the whole repository is packed.
1030
1063
            elif revision_id is None:
1031
1064
                raise ValueError('get_parent_map(None) is not valid')
1032
1065
            else:
1033
 
                query_keys.append((revision_id,))
 
1066
                query_keys.append((revision_id ,))
1034
1067
        vf = self.revisions.without_fallbacks()
1035
 
        for (revision_id,), parent_keys in viewitems(
1036
 
                vf.get_parent_map(query_keys)):
 
1068
        for ((revision_id,), parent_keys) in \
 
1069
                vf.get_parent_map(query_keys).iteritems():
1037
1070
            if parent_keys:
1038
1071
                result[revision_id] = tuple([parent_revid
1039
1072
                    for (parent_revid,) in parent_keys])
1052
1085
        return graph.CallableToParentsProviderAdapter(
1053
1086
            self._get_parent_map_no_fallbacks)
1054
1087
 
 
1088
    @needs_read_lock
1055
1089
    def get_known_graph_ancestry(self, revision_ids):
1056
1090
        """Return the known graph for a set of revision ids and their ancestors.
1057
1091
        """
1070
1104
                [parents_provider, other_repository._make_parents_provider()])
1071
1105
        return graph.Graph(parents_provider)
1072
1106
 
 
1107
    @needs_write_lock
1073
1108
    def set_make_working_trees(self, new_value):
1074
1109
        """Set the policy flag for making working trees when creating branches.
1075
1110
 
1085
1120
        """Returns the policy for making working trees on new branches."""
1086
1121
        raise NotImplementedError(self.make_working_trees)
1087
1122
 
 
1123
    @needs_write_lock
1088
1124
    def sign_revision(self, revision_id, gpg_strategy):
1089
 
        with self.lock_write():
1090
 
            testament = _mod_testament.Testament.from_revision(self, revision_id)
1091
 
            plaintext = testament.as_short_text()
1092
 
            self.store_revision_signature(gpg_strategy, plaintext, revision_id)
 
1125
        testament = _mod_testament.Testament.from_revision(self, revision_id)
 
1126
        plaintext = testament.as_short_text()
 
1127
        self.store_revision_signature(gpg_strategy, plaintext, revision_id)
1093
1128
 
 
1129
    @needs_read_lock
1094
1130
    def verify_revision_signature(self, revision_id, gpg_strategy):
1095
1131
        """Verify the signature on a revision.
1096
1132
 
1099
1135
 
1100
1136
        :return: gpg.SIGNATURE_VALID or a failed SIGNATURE_ value
1101
1137
        """
1102
 
        with self.lock_read():
1103
 
            if not self.has_signature_for_revision_id(revision_id):
1104
 
                return gpg.SIGNATURE_NOT_SIGNED, None
1105
 
            signature = self.get_signature_text(revision_id)
1106
 
 
1107
 
            testament = _mod_testament.Testament.from_revision(self, revision_id)
1108
 
 
1109
 
            (status, key, signed_plaintext) = gpg_strategy.verify(signature)
1110
 
            if testament.as_short_text() != signed_plaintext:
1111
 
                return gpg.SIGNATURE_NOT_VALID, None
1112
 
            return (status, key)
1113
 
 
 
1138
        if not self.has_signature_for_revision_id(revision_id):
 
1139
            return gpg.SIGNATURE_NOT_SIGNED, None
 
1140
        signature = self.get_signature_text(revision_id)
 
1141
 
 
1142
        testament = _mod_testament.Testament.from_revision(self, revision_id)
 
1143
        plaintext = testament.as_short_text()
 
1144
 
 
1145
        return gpg_strategy.verify(signature, plaintext)
 
1146
 
 
1147
    @needs_read_lock
1114
1148
    def verify_revision_signatures(self, revision_ids, gpg_strategy):
1115
1149
        """Verify revision signatures for a number of revisions.
1116
1150
 
1118
1152
        :gpg_strategy: the GPGStrategy object to used
1119
1153
        :return: Iterator over tuples with revision id, result and keys
1120
1154
        """
1121
 
        with self.lock_read():
1122
 
            for revid in revision_ids:
1123
 
                (result, key) = self.verify_revision_signature(revid, gpg_strategy)
1124
 
                yield revid, result, key
 
1155
        for revid in revision_ids:
 
1156
            (result, key) = self.verify_revision_signature(revid, gpg_strategy)
 
1157
            yield revid, result, key
1125
1158
 
1126
1159
    def has_signature_for_revision_id(self, revision_id):
1127
1160
        """Query for a revision signature for revision_id in the repository."""
1140
1173
             will be checked.  Typically the last revision_id of a branch.
1141
1174
        :param callback_refs: A dict of check-refs to resolve and callback
1142
1175
            the check/_check method on the items listed as wanting the ref.
1143
 
            see breezy.check.
 
1176
            see bzrlib.check.
1144
1177
        :param check_repo: If False do not check the repository contents, just 
1145
1178
            calculate the data callback_refs requires and call them back.
1146
1179
        """
1164
1197
            if 'format_deprecation' in conf.get('suppress_warnings'):
1165
1198
                return
1166
1199
            warning("Format %s for %s is deprecated -"
1167
 
                    " please use 'brz upgrade' to get better performance"
1168
 
                    % (self._format, self.controldir.transport.base))
 
1200
                    " please use 'bzr upgrade' to get better performance"
 
1201
                    % (self._format, self.bzrdir.transport.base))
1169
1202
        finally:
1170
1203
            _deprecation_warning_done = True
1171
1204
 
1177
1210
        # weave repositories refuse to store revisionids that are non-ascii.
1178
1211
        if revision_id is not None:
1179
1212
            # weaves require ascii revision ids.
1180
 
            if isinstance(revision_id, text_type):
 
1213
            if isinstance(revision_id, unicode):
1181
1214
                try:
1182
1215
                    revision_id.encode('ascii')
1183
1216
                except UnicodeEncodeError:
1189
1222
                    raise errors.NonAsciiRevisionId(method, self)
1190
1223
 
1191
1224
 
 
1225
class MetaDirRepository(Repository):
 
1226
    """Repositories in the new meta-dir layout.
 
1227
 
 
1228
    :ivar _transport: Transport for access to repository control files,
 
1229
        typically pointing to .bzr/repository.
 
1230
    """
 
1231
 
 
1232
    def __init__(self, _format, a_bzrdir, control_files):
 
1233
        super(MetaDirRepository, self).__init__(_format, a_bzrdir, control_files)
 
1234
        self._transport = control_files._transport
 
1235
 
 
1236
    def is_shared(self):
 
1237
        """Return True if this repository is flagged as a shared repository."""
 
1238
        return self._transport.has('shared-storage')
 
1239
 
 
1240
    @needs_write_lock
 
1241
    def set_make_working_trees(self, new_value):
 
1242
        """Set the policy flag for making working trees when creating branches.
 
1243
 
 
1244
        This only applies to branches that use this repository.
 
1245
 
 
1246
        The default is 'True'.
 
1247
        :param new_value: True to restore the default, False to disable making
 
1248
                          working trees.
 
1249
        """
 
1250
        if new_value:
 
1251
            try:
 
1252
                self._transport.delete('no-working-trees')
 
1253
            except errors.NoSuchFile:
 
1254
                pass
 
1255
        else:
 
1256
            self._transport.put_bytes('no-working-trees', '',
 
1257
                mode=self.bzrdir._get_file_mode())
 
1258
 
 
1259
    def make_working_trees(self):
 
1260
        """Returns the policy for making working trees on new branches."""
 
1261
        return not self._transport.has('no-working-trees')
 
1262
 
 
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
 
1192
1274
class RepositoryFormatRegistry(controldir.ControlComponentFormatRegistry):
1193
1275
    """Repository format registry."""
1194
1276
 
1195
1277
    def get_default(self):
1196
1278
        """Return the current default format."""
1197
 
        return controldir.format_registry.make_controldir('default').repository_format
 
1279
        return controldir.format_registry.make_bzrdir('default').repository_format
1198
1280
 
1199
1281
 
1200
1282
network_format_registry = registry.FormatRegistry()
1243
1325
    created.
1244
1326
 
1245
1327
    Common instance attributes:
1246
 
    _matchingcontroldir - the controldir format that the repository format was
 
1328
    _matchingbzrdir - the controldir format that the repository format was
1247
1329
    originally written to work with. This can be used if manually
1248
1330
    constructing a bzrdir and repository, or more commonly for test suite
1249
1331
    parameterization.
1285
1367
    supports_revision_signatures = True
1286
1368
    # Can the revision graph have incorrect parents?
1287
1369
    revision_graph_can_have_wrong_parents = None
1288
 
    # Does this format support setting revision ids?
1289
 
    supports_setting_revision_ids = True
1290
1370
    # Does this format support rich root data?
1291
1371
    rich_root_data = None
1292
1372
    # Does this format support explicitly versioned directories?
1296
1376
    # Is it possible for revisions to be present without being referenced
1297
1377
    # somewhere ?
1298
1378
    supports_unreferenced_revisions = None
1299
 
    # Does this format store the current Branch.nick in a revision when
1300
 
    # creating commits?
1301
 
    supports_storing_branch_nick = True
1302
 
    # Does the format support overriding the transport to use
1303
 
    supports_overriding_transport = True
1304
 
    # Does the format support setting custom revision properties?
1305
 
    supports_custom_revision_properties = True
1306
 
    # Does the format record per-file revision metadata?
1307
 
    records_per_file_revision = True
1308
1379
 
1309
1380
    def __repr__(self):
1310
1381
        return "%s()" % self.__class__.__name__
1378
1449
        raise NotImplementedError(self.open)
1379
1450
 
1380
1451
    def _run_post_repo_init_hooks(self, repository, controldir, shared):
1381
 
        from .controldir import ControlDir, RepoInitHookParams
 
1452
        from bzrlib.controldir import ControlDir, RepoInitHookParams
1382
1453
        hooks = ControlDir.hooks['post_repo_init']
1383
1454
        if not hooks:
1384
1455
            return
1387
1458
            hook(params)
1388
1459
 
1389
1460
 
 
1461
class RepositoryFormatMetaDir(bzrdir.BzrFormat, RepositoryFormat):
 
1462
    """Common base class for the new repositories using the metadir layout."""
 
1463
 
 
1464
    rich_root_data = False
 
1465
    supports_tree_reference = False
 
1466
    supports_external_lookups = False
 
1467
    supports_leaving_lock = True
 
1468
    supports_nesting_repositories = True
 
1469
 
 
1470
    @property
 
1471
    def _matchingbzrdir(self):
 
1472
        matching = bzrdir.BzrDirMetaFormat1()
 
1473
        matching.repository_format = self
 
1474
        return matching
 
1475
 
 
1476
    def __init__(self):
 
1477
        RepositoryFormat.__init__(self)
 
1478
        bzrdir.BzrFormat.__init__(self)
 
1479
 
 
1480
    def _create_control_files(self, a_bzrdir):
 
1481
        """Create the required files and the initial control_files object."""
 
1482
        # FIXME: RBC 20060125 don't peek under the covers
 
1483
        # NB: no need to escape relative paths that are url safe.
 
1484
        repository_transport = a_bzrdir.get_repository_transport(self)
 
1485
        control_files = lockable_files.LockableFiles(repository_transport,
 
1486
                                'lock', lockdir.LockDir)
 
1487
        control_files.create_lock()
 
1488
        return control_files
 
1489
 
 
1490
    def _upload_blank_content(self, a_bzrdir, dirs, files, utf8_files, shared):
 
1491
        """Upload the initial blank content."""
 
1492
        control_files = self._create_control_files(a_bzrdir)
 
1493
        control_files.lock_write()
 
1494
        transport = control_files._transport
 
1495
        if shared == True:
 
1496
            utf8_files += [('shared-storage', '')]
 
1497
        try:
 
1498
            transport.mkdir_multi(dirs, mode=a_bzrdir._get_dir_mode())
 
1499
            for (filename, content_stream) in files:
 
1500
                transport.put_file(filename, content_stream,
 
1501
                    mode=a_bzrdir._get_file_mode())
 
1502
            for (filename, content_bytes) in utf8_files:
 
1503
                transport.put_bytes_non_atomic(filename, content_bytes,
 
1504
                    mode=a_bzrdir._get_file_mode())
 
1505
        finally:
 
1506
            control_files.unlock()
 
1507
 
 
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)
 
1530
 
 
1531
 
1390
1532
# formats which have no format string are not discoverable or independently
1391
1533
# creatable on disk, so are not registered in format_registry.  They're
1392
 
# all in breezy.bzr.knitreponow.  When an instance of one of these is
 
1534
# all in bzrlib.repofmt.knitreponow.  When an instance of one of these is
1393
1535
# needed, it's constructed directly by the ControlDir.  Non-native formats where
1394
1536
# the repository is not separately opened are similar.
1395
1537
 
1396
1538
format_registry.register_lazy(
1397
 
    b'Bazaar-NG Knit Repository Format 1',
1398
 
    'breezy.bzr.knitrepo',
 
1539
    'Bazaar-NG Knit Repository Format 1',
 
1540
    'bzrlib.repofmt.knitrepo',
1399
1541
    'RepositoryFormatKnit1',
1400
1542
    )
1401
1543
 
1402
1544
format_registry.register_lazy(
1403
 
    b'Bazaar Knit Repository Format 3 (bzr 0.15)\n',
1404
 
    'breezy.bzr.knitrepo',
 
1545
    'Bazaar Knit Repository Format 3 (bzr 0.15)\n',
 
1546
    'bzrlib.repofmt.knitrepo',
1405
1547
    'RepositoryFormatKnit3',
1406
1548
    )
1407
1549
 
1408
1550
format_registry.register_lazy(
1409
 
    b'Bazaar Knit Repository Format 4 (bzr 1.0)\n',
1410
 
    'breezy.bzr.knitrepo',
 
1551
    'Bazaar Knit Repository Format 4 (bzr 1.0)\n',
 
1552
    'bzrlib.repofmt.knitrepo',
1411
1553
    'RepositoryFormatKnit4',
1412
1554
    )
1413
1555
 
1415
1557
# post-subtrees to allow ease of testing.
1416
1558
# NOTE: These are experimental in 0.92. Stable in 1.0 and above
1417
1559
format_registry.register_lazy(
1418
 
    b'Bazaar pack repository format 1 (needs bzr 0.92)\n',
1419
 
    'breezy.bzr.knitpack_repo',
 
1560
    'Bazaar pack repository format 1 (needs bzr 0.92)\n',
 
1561
    'bzrlib.repofmt.knitpack_repo',
1420
1562
    'RepositoryFormatKnitPack1',
1421
1563
    )
1422
1564
format_registry.register_lazy(
1423
 
    b'Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n',
1424
 
    'breezy.bzr.knitpack_repo',
 
1565
    'Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n',
 
1566
    'bzrlib.repofmt.knitpack_repo',
1425
1567
    'RepositoryFormatKnitPack3',
1426
1568
    )
1427
1569
format_registry.register_lazy(
1428
 
    b'Bazaar pack repository format 1 with rich root (needs bzr 1.0)\n',
1429
 
    'breezy.bzr.knitpack_repo',
 
1570
    'Bazaar pack repository format 1 with rich root (needs bzr 1.0)\n',
 
1571
    'bzrlib.repofmt.knitpack_repo',
1430
1572
    'RepositoryFormatKnitPack4',
1431
1573
    )
1432
1574
format_registry.register_lazy(
1433
 
    b'Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n',
1434
 
    'breezy.bzr.knitpack_repo',
 
1575
    'Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n',
 
1576
    'bzrlib.repofmt.knitpack_repo',
1435
1577
    'RepositoryFormatKnitPack5',
1436
1578
    )
1437
1579
format_registry.register_lazy(
1438
 
    b'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6.1)\n',
1439
 
    'breezy.bzr.knitpack_repo',
 
1580
    'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6.1)\n',
 
1581
    'bzrlib.repofmt.knitpack_repo',
1440
1582
    'RepositoryFormatKnitPack5RichRoot',
1441
1583
    )
1442
1584
format_registry.register_lazy(
1443
 
    b'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6)\n',
1444
 
    'breezy.bzr.knitpack_repo',
 
1585
    'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6)\n',
 
1586
    'bzrlib.repofmt.knitpack_repo',
1445
1587
    'RepositoryFormatKnitPack5RichRootBroken',
1446
1588
    )
1447
1589
format_registry.register_lazy(
1448
 
    b'Bazaar RepositoryFormatKnitPack6 (bzr 1.9)\n',
1449
 
    'breezy.bzr.knitpack_repo',
 
1590
    'Bazaar RepositoryFormatKnitPack6 (bzr 1.9)\n',
 
1591
    'bzrlib.repofmt.knitpack_repo',
1450
1592
    'RepositoryFormatKnitPack6',
1451
1593
    )
1452
1594
format_registry.register_lazy(
1453
 
    b'Bazaar RepositoryFormatKnitPack6RichRoot (bzr 1.9)\n',
1454
 
    'breezy.bzr.knitpack_repo',
 
1595
    'Bazaar RepositoryFormatKnitPack6RichRoot (bzr 1.9)\n',
 
1596
    'bzrlib.repofmt.knitpack_repo',
1455
1597
    'RepositoryFormatKnitPack6RichRoot',
1456
1598
    )
1457
1599
format_registry.register_lazy(
1458
 
    b'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
1459
 
    'breezy.bzr.groupcompress_repo',
 
1600
    'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
 
1601
    'bzrlib.repofmt.groupcompress_repo',
1460
1602
    'RepositoryFormat2a',
1461
1603
    )
1462
1604
 
1463
1605
# Development formats.
1464
1606
# Check their docstrings to see if/when they are obsolete.
1465
1607
format_registry.register_lazy(
1466
 
    (b"Bazaar development format 2 with subtree support "
1467
 
        b"(needs bzr.dev from before 1.8)\n"),
1468
 
    'breezy.bzr.knitpack_repo',
 
1608
    ("Bazaar development format 2 with subtree support "
 
1609
        "(needs bzr.dev from before 1.8)\n"),
 
1610
    'bzrlib.repofmt.knitpack_repo',
1469
1611
    'RepositoryFormatPackDevelopment2Subtree',
1470
1612
    )
1471
1613
format_registry.register_lazy(
1472
 
    b'Bazaar development format 8\n',
1473
 
    'breezy.bzr.groupcompress_repo',
 
1614
    'Bazaar development format 8\n',
 
1615
    'bzrlib.repofmt.groupcompress_repo',
1474
1616
    'RepositoryFormat2aSubtree',
1475
1617
    )
1476
1618
 
1490
1632
    _optimisers = []
1491
1633
    """The available optimised InterRepository types."""
1492
1634
 
 
1635
    @needs_write_lock
1493
1636
    def copy_content(self, revision_id=None):
1494
1637
        """Make a complete copy of the content in self into destination.
1495
1638
 
1499
1642
        :param revision_id: Only copy the content needed to construct
1500
1643
                            revision_id and its parents.
1501
1644
        """
1502
 
        with self.lock_write():
1503
 
            try:
1504
 
                self.target.set_make_working_trees(
1505
 
                    self.source.make_working_trees())
1506
 
            except NotImplementedError:
1507
 
                pass
1508
 
            self.target.fetch(self.source, revision_id=revision_id)
 
1645
        try:
 
1646
            self.target.set_make_working_trees(self.source.make_working_trees())
 
1647
        except NotImplementedError:
 
1648
            pass
 
1649
        self.target.fetch(self.source, revision_id=revision_id)
1509
1650
 
 
1651
    @needs_write_lock
1510
1652
    def fetch(self, revision_id=None, find_ghosts=False):
1511
1653
        """Fetch the content required to construct revision_id.
1512
1654
 
1518
1660
        """
1519
1661
        raise NotImplementedError(self.fetch)
1520
1662
 
1521
 
    def search_missing_revision_ids(
1522
 
            self, find_ghosts=True, revision_ids=None, if_present_ids=None,
 
1663
    @needs_read_lock
 
1664
    def search_missing_revision_ids(self,
 
1665
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
 
1666
            find_ghosts=True, revision_ids=None, if_present_ids=None,
1523
1667
            limit=None):
1524
1668
        """Return the revision ids that source has that target does not.
1525
1669
 
 
1670
        :param revision_id: only return revision ids included by this
 
1671
            revision_id.
1526
1672
        :param revision_ids: return revision ids included by these
1527
1673
            revision_ids.  NoSuchRevision will be raised if any of these
1528
1674
            revisions are not present.
1534
1680
            rather than just finding the surface difference.
1535
1681
        :param limit: Maximum number of revisions to return, topologically
1536
1682
            ordered
1537
 
        :return: A breezy.graph.SearchResult.
 
1683
        :return: A bzrlib.graph.SearchResult.
1538
1684
        """
1539
1685
        raise NotImplementedError(self.search_missing_revision_ids)
1540
1686
 
1548
1694
        try:
1549
1695
            InterRepository._assert_same_model(source, target)
1550
1696
            return True
1551
 
        except errors.IncompatibleRepositories as e:
 
1697
        except errors.IncompatibleRepositories, e:
1552
1698
            return False
1553
1699
 
1554
1700
    @staticmethod
1582
1728
        :param to_convert: The disk object to convert.
1583
1729
        :param pb: a progress bar to use for progress information.
1584
1730
        """
1585
 
        with ui.ui_factory.nested_progress_bar() as pb:
1586
 
            self.count = 0
1587
 
            self.total = 4
1588
 
            # this is only useful with metadir layouts - separated repo content.
1589
 
            # trigger an assertion if not such
1590
 
            repo._format.get_format_string()
1591
 
            self.repo_dir = repo.controldir
1592
 
            pb.update(gettext('Moving repository to repository.backup'))
1593
 
            self.repo_dir.transport.move('repository', 'repository.backup')
1594
 
            backup_transport =  self.repo_dir.transport.clone('repository.backup')
1595
 
            repo._format.check_conversion_target(self.target_format)
1596
 
            self.source_repo = repo._format.open(self.repo_dir,
1597
 
                _found=True,
1598
 
                _override_transport=backup_transport)
1599
 
            pb.update(gettext('Creating new repository'))
1600
 
            converted = self.target_format.initialize(self.repo_dir,
1601
 
                                                      self.source_repo.is_shared())
1602
 
            converted.lock_write()
1603
 
            try:
1604
 
                pb.update(gettext('Copying content'))
1605
 
                self.source_repo.copy_content_into(converted)
1606
 
            finally:
1607
 
                converted.unlock()
1608
 
            pb.update(gettext('Deleting old repository content'))
1609
 
            self.repo_dir.transport.delete_tree('repository.backup')
1610
 
            ui.ui_factory.note(gettext('repository converted'))
 
1731
        pb = ui.ui_factory.nested_progress_bar()
 
1732
        self.count = 0
 
1733
        self.total = 4
 
1734
        # this is only useful with metadir layouts - separated repo content.
 
1735
        # trigger an assertion if not such
 
1736
        repo._format.get_format_string()
 
1737
        self.repo_dir = repo.bzrdir
 
1738
        pb.update(gettext('Moving repository to repository.backup'))
 
1739
        self.repo_dir.transport.move('repository', 'repository.backup')
 
1740
        backup_transport =  self.repo_dir.transport.clone('repository.backup')
 
1741
        repo._format.check_conversion_target(self.target_format)
 
1742
        self.source_repo = repo._format.open(self.repo_dir,
 
1743
            _found=True,
 
1744
            _override_transport=backup_transport)
 
1745
        pb.update(gettext('Creating new repository'))
 
1746
        converted = self.target_format.initialize(self.repo_dir,
 
1747
                                                  self.source_repo.is_shared())
 
1748
        converted.lock_write()
 
1749
        try:
 
1750
            pb.update(gettext('Copying content'))
 
1751
            self.source_repo.copy_content_into(converted)
 
1752
        finally:
 
1753
            converted.unlock()
 
1754
        pb.update(gettext('Deleting old repository content'))
 
1755
        self.repo_dir.transport.delete_tree('repository.backup')
 
1756
        ui.ui_factory.note(gettext('repository converted'))
 
1757
        pb.finished()
1611
1758
 
1612
1759
 
1613
1760
def _strip_NULL_ghosts(revision_graph):
1615
1762
    # Filter ghosts, and null:
1616
1763
    if _mod_revision.NULL_REVISION in revision_graph:
1617
1764
        del revision_graph[_mod_revision.NULL_REVISION]
1618
 
    for key, parents in viewitems(revision_graph):
 
1765
    for key, parents in revision_graph.items():
1619
1766
        revision_graph[key] = tuple(parent for parent in parents if parent
1620
1767
            in revision_graph)
1621
1768
    return revision_graph
1641
1788
        (_mod_revision.NULL_REVISION,))
1642
1789
    try:
1643
1790
        # skip the last revision in the list
1644
 
        next(iterator)
 
1791
        iterator.next()
1645
1792
        while True:
1646
1793
            if (stop_index is not None and
1647
1794
                len(partial_history_cache) > stop_index):
1648
1795
                break
1649
1796
            if partial_history_cache[-1] == stop_revision:
1650
1797
                break
1651
 
            revision_id = next(iterator)
 
1798
            revision_id = iterator.next()
1652
1799
            partial_history_cache.append(revision_id)
1653
1800
    except StopIteration:
1654
1801
        # No more history
1660
1807
 
1661
1808
    Each iterator made from this will reflect the current contents of the lists
1662
1809
    at the time the iterator is made.
1663
 
 
 
1810
    
1664
1811
    This is used by Repository's _make_parents_provider implementation so that
1665
1812
    it is safe to do::
1666
1813