/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:
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 .lazy_import import lazy_import
 
17
from __future__ import absolute_import
 
18
 
 
19
from bzrlib.lazy_import import lazy_import
18
20
lazy_import(globals(), """
 
21
import itertools
19
22
import time
20
23
 
21
 
from breezy import (
 
24
from bzrlib import (
22
25
    config,
23
26
    controldir,
24
27
    debug,
 
28
    generate_ids,
25
29
    graph,
 
30
    lockable_files,
 
31
    lockdir,
26
32
    osutils,
27
33
    revision as _mod_revision,
 
34
    testament as _mod_testament,
 
35
    tsort,
28
36
    gpg,
29
37
    )
30
 
from breezy.i18n import gettext
 
38
from bzrlib.bundle import serializer
 
39
from bzrlib.i18n import gettext
31
40
""")
32
41
 
33
 
from . import (
 
42
from bzrlib import (
 
43
    bzrdir,
34
44
    errors,
35
45
    registry,
 
46
    symbol_versioning,
36
47
    ui,
37
48
    )
38
 
from .decorators import only_raises
39
 
from .inter import InterObject
40
 
from .lock import _RelockDebugMixin, LogicalLockResult
41
 
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 (
42
53
    log_exception_quietly, note, mutter, mutter_callsite, warning)
43
54
 
44
55
 
54
65
        errors.InternalBzrError.__init__(self, repo=repo)
55
66
 
56
67
 
57
 
class CannotSetRevisionId(errors.BzrError):
58
 
 
59
 
    _fmt = "Repository format does not support setting revision ids."
60
 
 
61
 
 
62
 
class FetchResult(object):
63
 
    """Result of a fetch operation.
64
 
 
65
 
    :ivar revidmap: For lossy fetches, map from source revid to target revid.
66
 
    :ivar total_fetched: Number of revisions fetched
67
 
    """
68
 
 
69
 
    def __init__(self, total_fetched=None, revidmap=None):
70
 
        self.total_fetched = total_fetched
71
 
        self.revidmap = revidmap
72
 
 
73
 
 
74
68
class CommitBuilder(object):
75
69
    """Provides an interface to build up a commit.
76
70
 
80
74
 
81
75
    # all clients should supply tree roots.
82
76
    record_root_entry = True
 
77
    # whether this commit builder supports the record_entry_contents interface
 
78
    supports_record_entry_contents = False
83
79
    # whether this commit builder will automatically update the branch that is
84
80
    # being committed to
85
81
    updates_branch = False
97
93
        :param revprops: Optional dictionary of revision properties.
98
94
        :param revision_id: Optional revision id.
99
95
        :param lossy: Whether to discard data that can not be natively
100
 
            represented, when pushing to a foreign VCS
 
96
            represented, when pushing to a foreign VCS 
101
97
        """
102
98
        self._config_stack = config_stack
103
99
        self._lossy = lossy
104
100
 
105
101
        if committer is None:
106
102
            self._committer = self._config_stack.get('email')
107
 
        elif not isinstance(committer, str):
108
 
            self._committer = committer.decode()  # throw if non-ascii
 
103
        elif not isinstance(committer, unicode):
 
104
            self._committer = committer.decode() # throw if non-ascii
109
105
        else:
110
106
            self._committer = committer
111
107
 
 
108
        self._new_revision_id = revision_id
112
109
        self.parents = parents
113
110
        self.repository = repository
114
111
 
127
124
        else:
128
125
            self._timezone = int(timezone)
129
126
 
130
 
        self._generate_revision_if_needed(revision_id)
 
127
        self._generate_revision_if_needed()
131
128
 
132
129
    def any_changes(self):
133
130
        """Return True if any entries were changed.
141
138
 
142
139
    def _validate_unicode_text(self, text, context):
143
140
        """Verify things like commit messages don't have bogus characters."""
144
 
        # TODO(jelmer): Make this repository-format specific
145
 
        if u'\r' in text:
 
141
        if '\r' in text:
146
142
            raise ValueError('Invalid value for %s: %r' % (context, text))
147
143
 
148
144
    def _validate_revprops(self, revprops):
149
 
        for key, value in revprops.items():
 
145
        for key, value in revprops.iteritems():
150
146
            # We know that the XML serializers do not round trip '\r'
151
147
            # correctly, so refuse to accept them
152
 
            if not isinstance(value, str):
 
148
            if not isinstance(value, basestring):
153
149
                raise ValueError('revision property (%s) is not a valid'
154
150
                                 ' (unicode) string: %r' % (key, value))
155
 
            # TODO(jelmer): Make this repository-format specific
156
151
            self._validate_unicode_text(value,
157
152
                                        'revision property (%s)' % (key,))
158
153
 
187
182
        """
188
183
        raise NotImplementedError(self.finish_inventory)
189
184
 
190
 
    def _generate_revision_if_needed(self, revision_id):
 
185
    def _gen_revision_id(self):
 
186
        """Return new revision-id."""
 
187
        return generate_ids.gen_revision_id(self._committer, self._timestamp)
 
188
 
 
189
    def _generate_revision_if_needed(self):
191
190
        """Create a revision id if None was supplied.
192
191
 
193
192
        If the repository can not support user-specified revision ids
196
195
 
197
196
        :raises: CannotSetRevisionId
198
197
        """
199
 
        if not self.repository._format.supports_setting_revision_ids:
200
 
            if revision_id is not None:
201
 
                raise CannotSetRevisionId()
202
 
            return
203
 
        if revision_id is None:
 
198
        if self._new_revision_id is None:
204
199
            self._new_revision_id = self._gen_revision_id()
205
200
            self.random_revid = True
206
201
        else:
207
 
            self._new_revision_id = revision_id
208
202
            self.random_revid = False
209
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
 
210
213
    def record_iter_changes(self, tree, basis_revision_id, iter_changes):
211
214
        """Record a new tree via iter_changes.
212
215
 
218
221
            to basis_revision_id. The iterator must not include any items with
219
222
            a current kind of None - missing items must be either filtered out
220
223
            or errored-on beefore record_iter_changes sees the item.
221
 
        :return: A generator of (relpath, fs_hash) tuples for use with
 
224
        :return: A generator of (file_id, relpath, fs_hash) tuples for use with
222
225
            tree._observed_sha1.
223
226
        """
224
227
        raise NotImplementedError(self.record_iter_changes)
238
241
 
239
242
    def __repr__(self):
240
243
        return "RepositoryWriteLockResult(%s, %s)" % (self.repository_token,
241
 
                                                      self.unlock)
242
 
 
243
 
 
244
 
class WriteGroup(object):
245
 
    """Context manager that manages a write group.
246
 
 
247
 
    Raising an exception will result in the write group being aborted.
248
 
    """
249
 
 
250
 
    def __init__(self, repository, suppress_errors=False):
251
 
        self.repository = repository
252
 
        self._suppress_errors = suppress_errors
253
 
 
254
 
    def __enter__(self):
255
 
        self.repository.start_write_group()
256
 
        return self
257
 
 
258
 
    def __exit__(self, exc_type, exc_val, exc_tb):
259
 
        if exc_type:
260
 
            self.repository.abort_write_group(self._suppress_errors)
261
 
            return False
262
 
        else:
263
 
            self.repository.commit_write_group()
 
244
            self.unlock)
264
245
 
265
246
 
266
247
######################################################################
267
248
# Repositories
268
249
 
269
250
 
270
 
class Repository(controldir.ControlComponent, _RelockDebugMixin):
 
251
class Repository(_RelockDebugMixin, controldir.ControlComponent):
271
252
    """Repository holding history for one or more branches.
272
253
 
273
254
    The repository holds and retrieves historical information including
274
255
    revisions and file history.  It's normally accessed only by the Branch,
275
256
    which views a particular line of development through that history.
276
257
 
277
 
    See VersionedFileRepository in breezy.vf_repository for the
 
258
    See VersionedFileRepository in bzrlib.vf_repository for the
278
259
    base class for most Bazaar repositories.
279
260
    """
280
261
 
281
 
    # Does this repository implementation support random access to
282
 
    # items in the tree, or just bulk fetching/pushing of data?
283
 
    supports_random_access = True
284
 
 
285
262
    def abort_write_group(self, suppress_errors=False):
286
263
        """Commit the contents accrued within the current write group.
287
264
 
295
272
            # has an unlock or relock occured ?
296
273
            if suppress_errors:
297
274
                mutter(
298
 
                    '(suppressed) mismatched lock context and write group. %r, %r',
299
 
                    self._write_group, self.get_transaction())
 
275
                '(suppressed) mismatched lock context and write group. %r, %r',
 
276
                self._write_group, self.get_transaction())
300
277
                return
301
278
            raise errors.BzrError(
302
279
                'mismatched lock context and write group. %r, %r' %
303
280
                (self._write_group, self.get_transaction()))
304
281
        try:
305
282
            self._abort_write_group()
306
 
        except Exception as exc:
 
283
        except Exception, exc:
307
284
            self._write_group = None
308
285
            if not suppress_errors:
309
286
                raise
310
287
            mutter('abort_write_group failed')
311
288
            log_exception_quietly()
312
 
            note(gettext('brz: ERROR (ignored): %s'), exc)
 
289
            note(gettext('bzr: ERROR (ignored): %s'), exc)
313
290
        self._write_group = None
314
291
 
315
292
    def _abort_write_group(self):
387
364
        super(Repository, self).__init__()
388
365
        self._format = _format
389
366
        # the following are part of the public API for Repository:
390
 
        self.controldir = controldir
 
367
        self.bzrdir = controldir
391
368
        self.control_files = control_files
392
369
        # for tests
393
370
        self._write_group = None
396
373
 
397
374
    @property
398
375
    def user_transport(self):
399
 
        return self.controldir.user_transport
 
376
        return self.bzrdir.user_transport
400
377
 
401
378
    @property
402
379
    def control_transport(self):
517
494
        """
518
495
        self.control_files.dont_leave_in_place()
519
496
 
 
497
    @needs_read_lock
520
498
    def gather_stats(self, revid=None, committers=None):
521
499
        """Gather statistics from a revision id.
522
500
 
533
511
            revisions: The total revision count in the repository.
534
512
            size: An estimate disk size of the repository in bytes.
535
513
        """
536
 
        with self.lock_read():
537
 
            result = {}
538
 
            if revid and committers:
539
 
                result['committers'] = 0
540
 
            if revid and revid != _mod_revision.NULL_REVISION:
541
 
                graph = self.get_graph()
542
 
                if committers:
543
 
                    all_committers = set()
544
 
                revisions = [r for (r, p) in graph.iter_ancestry([revid])
545
 
                             if r != _mod_revision.NULL_REVISION]
546
 
                last_revision = None
547
 
                if not committers:
548
 
                    # ignore the revisions in the middle - just grab first and last
549
 
                    revisions = revisions[0], revisions[-1]
550
 
                for revision in self.get_revisions(revisions):
551
 
                    if not last_revision:
552
 
                        last_revision = revision
553
 
                    if committers:
554
 
                        all_committers.add(revision.committer)
555
 
                first_revision = revision
556
 
                if committers:
557
 
                    result['committers'] = len(all_committers)
558
 
                result['firstrev'] = (first_revision.timestamp,
559
 
                                      first_revision.timezone)
560
 
                result['latestrev'] = (last_revision.timestamp,
561
 
                                       last_revision.timezone)
562
 
            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
563
540
 
564
541
    def find_branches(self, using=False):
565
542
        """Find branches underneath this repository.
569
546
        :param using: If True, list only branches using this repository.
570
547
        """
571
548
        if using and not self.is_shared():
572
 
            for branch in self.controldir.list_branches():
573
 
                yield branch
574
 
            return
575
 
 
 
549
            return self.bzrdir.list_branches()
576
550
        class Evaluator(object):
577
551
 
578
552
            def __init__(self):
592
566
                value = (controldir.list_branches(), None)
593
567
                return True, value
594
568
 
595
 
        for branches, repository in controldir.ControlDir.find_controldirs(
 
569
        ret = []
 
570
        for branches, repository in controldir.ControlDir.find_bzrdirs(
596
571
                self.user_transport, evaluate=Evaluator()):
597
572
            if branches is not None:
598
 
                for branch in branches:
599
 
                    yield branch
 
573
                ret.extend(branches)
600
574
            if not using and repository is not None:
601
 
                for branch in repository.find_branches():
602
 
                    yield branch
 
575
                ret.extend(repository.find_branches())
 
576
        return ret
603
577
 
 
578
    @needs_read_lock
604
579
    def search_missing_revision_ids(self, other,
605
 
                                    find_ghosts=True, revision_ids=None, if_present_ids=None,
606
 
                                    limit=None):
 
580
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
 
581
            find_ghosts=True, revision_ids=None, if_present_ids=None,
 
582
            limit=None):
607
583
        """Return the revision ids that other has that this does not.
608
584
 
609
585
        These are returned in topological order.
610
586
 
611
 
        revision_ids: only return revision ids included by revision_id.
 
587
        revision_id: only return revision ids included by revision_id.
612
588
        """
613
 
        with self.lock_read():
614
 
            return InterRepository.get(other, self).search_missing_revision_ids(
615
 
                find_ghosts=find_ghosts, revision_ids=revision_ids,
616
 
                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)
617
602
 
618
603
    @staticmethod
619
604
    def open(base):
637
622
        """Commit the contents accrued within the current write group.
638
623
 
639
624
        :seealso: start_write_group.
640
 
 
 
625
        
641
626
        :return: it may return an opaque hint that can be passed to 'pack'.
642
627
        """
643
628
        if self._write_group is not self.get_transaction():
644
629
            # has an unlock or relock occured ?
645
630
            raise errors.BzrError('mismatched lock context %r and '
646
 
                                  'write group %r.' %
647
 
                                  (self.get_transaction(), self._write_group))
 
631
                'write group %r.' %
 
632
                (self.get_transaction(), self._write_group))
648
633
        result = self._commit_write_group()
649
634
        self._write_group = None
650
635
        return result
673
658
        This method is intended to be called after another repository instance
674
659
        (such as one used by a smart server) has inserted data into the
675
660
        repository. On all repositories this will work outside of write groups.
676
 
        Some repository formats (pack and newer for breezy native formats)
 
661
        Some repository formats (pack and newer for bzrlib native formats)
677
662
        support refresh_data inside write groups. If called inside a write
678
663
        group on a repository that does not support refreshing in a write group
679
664
        IsInWriteGroupError will be raised.
692
677
    def _resume_write_group(self, tokens):
693
678
        raise errors.UnsuspendableWriteGroup(self)
694
679
 
695
 
    def fetch(self, source, revision_id=None, find_ghosts=False, lossy=False):
 
680
    def fetch(self, source, revision_id=None, find_ghosts=False):
696
681
        """Fetch the content required to construct revision_id from source.
697
682
 
698
683
        If revision_id is None, then all content is copied.
707
692
        :param revision_id: If specified, all the content needed for this
708
693
            revision ID will be copied to the target.  Fetch will determine for
709
694
            itself which content needs to be copied.
710
 
        :return: A FetchResult object
711
695
        """
712
696
        if self.is_in_write_group():
713
697
            raise errors.InternalBzrError(
716
700
        # TODO: lift out to somewhere common with RemoteRepository
717
701
        # <https://bugs.launchpad.net/bzr/+bug/401646>
718
702
        if (self.has_same_location(source)
719
 
                and self._has_same_fallbacks(source)):
 
703
            and self._has_same_fallbacks(source)):
720
704
            # check that last_revision is in 'from' and then return a
721
705
            # no-operation.
722
706
            if (revision_id is not None and
723
 
                    not _mod_revision.is_null(revision_id)):
 
707
                not _mod_revision.is_null(revision_id)):
724
708
                self.get_revision(revision_id)
725
709
            return 0, []
726
710
        inter = InterRepository.get(source, self)
727
 
        return inter.fetch(
728
 
            revision_id=revision_id, find_ghosts=find_ghosts, lossy=lossy)
 
711
        return inter.fetch(revision_id=revision_id, find_ghosts=find_ghosts)
 
712
 
 
713
    def create_bundle(self, target, base, fileobj, format=None):
 
714
        return serializer.write_bundle(self, target, base, fileobj, format)
729
715
 
730
716
    def get_commit_builder(self, branch, parents, config_stack, timestamp=None,
731
717
                           timezone=None, committer=None, revprops=None,
748
734
    @only_raises(errors.LockNotHeld, errors.LockBroken)
749
735
    def unlock(self):
750
736
        if (self.control_files._lock_count == 1 and
751
 
                self.control_files._lock_mode == 'w'):
 
737
            self.control_files._lock_mode == 'w'):
752
738
            if self._write_group is not None:
753
739
                self.abort_write_group()
754
740
                self.control_files.unlock()
759
745
            for repo in self._fallback_repositories:
760
746
                repo.unlock()
761
747
 
 
748
    @needs_read_lock
762
749
    def clone(self, controldir, revision_id=None):
763
750
        """Clone this repository into controldir using the current format.
764
751
 
767
754
 
768
755
        :return: The newly created destination repository.
769
756
        """
770
 
        with self.lock_read():
771
 
            # TODO: deprecate after 0.16; cloning this with all its settings is
772
 
            # probably not very useful -- mbp 20070423
773
 
            dest_repo = self._create_sprouting_repo(
774
 
                controldir, shared=self.is_shared())
775
 
            self.copy_content_into(dest_repo, revision_id)
776
 
            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
777
763
 
778
764
    def start_write_group(self):
779
765
        """Start a write group in the repository.
782
768
        between file ids and backend store to manage the insertion of data from
783
769
        both fetch and commit operations.
784
770
 
785
 
        A write lock is required around the
786
 
        start_write_group/commit_write_group for the support of lock-requiring
787
 
        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.
788
773
 
789
774
        One can only insert data into a repository inside a write group.
790
775
 
805
790
        entered.
806
791
        """
807
792
 
 
793
    @needs_read_lock
808
794
    def sprout(self, to_bzrdir, revision_id=None):
809
795
        """Create a descendent repository for new development.
810
796
 
811
797
        Unlike clone, this does not copy the settings of the repository.
812
798
        """
813
 
        with self.lock_read():
814
 
            dest_repo = self._create_sprouting_repo(to_bzrdir, shared=False)
815
 
            dest_repo.fetch(self, revision_id=revision_id)
816
 
            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
817
802
 
818
 
    def _create_sprouting_repo(self, a_controldir, shared):
819
 
        if not isinstance(
820
 
                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__):
821
805
            # use target default format.
822
 
            dest_repo = a_controldir.create_repository()
 
806
            dest_repo = a_bzrdir.create_repository()
823
807
        else:
824
808
            # Most control formats need the repository to be specifically
825
809
            # created, but on some old all-in-one formats it's not needed
826
810
            try:
827
 
                dest_repo = self._format.initialize(
828
 
                    a_controldir, shared=shared)
 
811
                dest_repo = self._format.initialize(a_bzrdir, shared=shared)
829
812
            except errors.UninitializableFormat:
830
 
                dest_repo = a_controldir.open_repository()
 
813
                dest_repo = a_bzrdir.open_repository()
831
814
        return dest_repo
832
815
 
 
816
    @needs_read_lock
833
817
    def has_revision(self, revision_id):
834
818
        """True if this repository has a copy of the revision."""
835
 
        with self.lock_read():
836
 
            return revision_id in self.has_revisions((revision_id,))
 
819
        return revision_id in self.has_revisions((revision_id,))
837
820
 
 
821
    @needs_read_lock
838
822
    def has_revisions(self, revision_ids):
839
823
        """Probe to find out the presence of multiple revisions.
840
824
 
843
827
        """
844
828
        raise NotImplementedError(self.has_revisions)
845
829
 
 
830
    @needs_read_lock
846
831
    def get_revision(self, revision_id):
847
832
        """Return the Revision object for a named revision."""
848
 
        with self.lock_read():
849
 
            return self.get_revisions([revision_id])[0]
 
833
        return self.get_revisions([revision_id])[0]
850
834
 
851
835
    def get_revision_reconcile(self, revision_id):
852
836
        """'reconcile' helper routine that allows access to a revision always.
860
844
 
861
845
    def get_revisions(self, revision_ids):
862
846
        """Get many revisions at once.
863
 
 
864
 
        Repositories that need to check data on every revision read should
 
847
        
 
848
        Repositories that need to check data on every revision read should 
865
849
        subclass this method.
866
850
        """
867
 
        revs = {}
868
 
        for revid, rev in self.iter_revisions(revision_ids):
869
 
            if rev is None:
870
 
                raise errors.NoSuchRevision(self, revid)
871
 
            revs[revid] = rev
872
 
        return [revs[revid] for revid in revision_ids]
873
 
 
874
 
    def iter_revisions(self, revision_ids):
875
 
        """Iterate over revision objects.
876
 
 
877
 
        :param revision_ids: An iterable of revisions to examine. None may be
878
 
            passed to request all revisions known to the repository. Note that
879
 
            not all repositories can find unreferenced revisions; for those
880
 
            repositories only referenced ones will be returned.
881
 
        :return: An iterator of (revid, revision) tuples. Absent revisions (
882
 
            those asked for but not available) are returned as (revid, None).
883
 
            N.B.: Revisions are not necessarily yielded in order.
884
 
        """
885
 
        raise NotImplementedError(self.iter_revisions)
886
 
 
887
 
    def get_revision_delta(self, revision_id):
888
 
        """Return the delta for one revision.
889
 
 
890
 
        The delta is relative to the left-hand predecessor of the
891
 
        revision.
892
 
        """
893
 
        with self.lock_read():
894
 
            r = self.get_revision(revision_id)
895
 
            return list(self.get_revision_deltas([r]))[0]
896
 
 
897
 
    def get_revision_deltas(self, revisions, specific_files=None):
 
851
        raise NotImplementedError(self.get_revisions)
 
852
 
 
853
    def get_deltas_for_revisions(self, revisions, specific_fileids=None):
898
854
        """Produce a generator of revision deltas.
899
855
 
900
 
        Note that the input is a sequence of REVISIONS, not revision ids.
 
856
        Note that the input is a sequence of REVISIONS, not revision_ids.
901
857
        Trees will be held in memory until the generator exits.
902
858
        Each delta is relative to the revision's lefthand predecessor.
903
859
 
904
 
        specific_files should exist in the first revision.
905
 
 
906
 
        :param specific_files: if not None, the result is filtered
907
 
          so that only those files, their parents and their
 
860
        :param specific_fileids: if not None, the result is filtered
 
861
          so that only those file-ids, their parents and their
908
862
          children are included.
909
863
        """
910
 
        from .tree import InterTree
911
864
        # Get the revision-ids of interest
912
865
        required_trees = set()
913
866
        for revision in revisions:
914
867
            required_trees.add(revision.revision_id)
915
868
            required_trees.update(revision.parent_ids[:1])
916
869
 
917
 
        trees = {
918
 
            t.get_revision_id(): t
919
 
            for t in self.revision_trees(required_trees)}
 
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))
920
883
 
921
884
        # Calculate the deltas
922
885
        for revision in revisions:
924
887
                old_tree = self.revision_tree(_mod_revision.NULL_REVISION)
925
888
            else:
926
889
                old_tree = trees[revision.parent_ids[0]]
927
 
            intertree = InterTree.get(old_tree, trees[revision.revision_id])
928
 
            yield intertree.compare(specific_files=specific_files)
929
 
            if specific_files is not None:
930
 
                specific_files = [
931
 
                    p for p in intertree.find_source_paths(
932
 
                        specific_files).values()
933
 
                    if p is not None]
934
 
 
 
890
            yield trees[revision.revision_id].changes_from(old_tree)
 
891
 
 
892
    @needs_read_lock
 
893
    def get_revision_delta(self, revision_id, specific_fileids=None):
 
894
        """Return the delta for one revision.
 
895
 
 
896
        The delta is relative to the left-hand predecessor of the
 
897
        revision.
 
898
 
 
899
        :param specific_fileids: if not None, the result is filtered
 
900
          so that only those file-ids, their parents and their
 
901
          children are included.
 
902
        """
 
903
        r = self.get_revision(revision_id)
 
904
        return list(self.get_deltas_for_revisions([r],
 
905
            specific_fileids=specific_fileids))[0]
 
906
 
 
907
    @needs_write_lock
935
908
    def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
936
 
        raise NotImplementedError(self.store_revision_signature)
 
909
        signature = gpg_strategy.sign(plaintext)
 
910
        self.add_signature_text(revision_id, signature)
937
911
 
938
912
    def add_signature_text(self, revision_id, signature):
939
913
        """Store a signature text for a revision.
943
917
        """
944
918
        raise NotImplementedError(self.add_signature_text)
945
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
 
946
933
    def iter_files_bytes(self, desired_files):
947
934
        """Iterate through file versions.
948
935
 
971
958
        partial_history = [known_revid]
972
959
        distance_from_known = known_revno - revno
973
960
        if distance_from_known < 0:
974
 
            raise errors.RevnoOutOfBounds(revno, (0, known_revno))
 
961
            raise ValueError(
 
962
                'requested revno (%d) is later than given known revno (%d)'
 
963
                % (revno, known_revno))
975
964
        try:
976
965
            _iter_for_revno(
977
966
                self, partial_history, stop_index=distance_from_known)
978
 
        except errors.RevisionNotPresent as err:
 
967
        except errors.RevisionNotPresent, err:
979
968
            if err.revision_id == known_revid:
980
969
                # The start revision (known_revid) wasn't found.
981
 
                raise errors.NoSuchRevision(self, known_revid)
 
970
                raise
982
971
            # This is a stacked repository with no fallbacks, or a there's a
983
972
            # left-hand ghost.  Either way, even though the revision named in
984
973
            # the error isn't in this repo, we know it's the next step in this
996
985
        """Return True if this repository is flagged as a shared repository."""
997
986
        raise NotImplementedError(self.is_shared)
998
987
 
 
988
    @needs_write_lock
999
989
    def reconcile(self, other=None, thorough=False):
1000
990
        """Reconcile this repository."""
1001
 
        raise NotImplementedError(self.reconcile)
 
991
        from bzrlib.reconcile import RepoReconciler
 
992
        reconciler = RepoReconciler(self, thorough=thorough)
 
993
        reconciler.reconcile()
 
994
        return reconciler
1002
995
 
1003
996
    def _refresh_data(self):
1004
997
        """Helper called from lock_* to ensure coherency with disk.
1014
1007
        repository.
1015
1008
        """
1016
1009
 
 
1010
    @needs_read_lock
1017
1011
    def revision_tree(self, revision_id):
1018
1012
        """Return Tree for a revision on this branch.
1019
1013
 
1025
1019
        """Return Trees for revisions in this repository.
1026
1020
 
1027
1021
        :param revision_ids: a sequence of revision-ids;
1028
 
          a revision-id may not be None or b'null:'
 
1022
          a revision-id may not be None or 'null:'
1029
1023
        """
1030
1024
        raise NotImplementedError(self.revision_trees)
1031
1025
 
1036
1030
        types it should be a no-op that just returns.
1037
1031
 
1038
1032
        This stub method does not require a lock, but subclasses should use
1039
 
        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
1040
1034
        implicitly lock for the user.
1041
1035
 
1042
1036
        :param hint: If not supplied, the whole repository is packed.
1069
1063
            elif revision_id is None:
1070
1064
                raise ValueError('get_parent_map(None) is not valid')
1071
1065
            else:
1072
 
                query_keys.append((revision_id,))
 
1066
                query_keys.append((revision_id ,))
1073
1067
        vf = self.revisions.without_fallbacks()
1074
 
        for (revision_id,), parent_keys in (
1075
 
                vf.get_parent_map(query_keys).items()):
 
1068
        for ((revision_id,), parent_keys) in \
 
1069
                vf.get_parent_map(query_keys).iteritems():
1076
1070
            if parent_keys:
1077
1071
                result[revision_id] = tuple([parent_revid
1078
 
                                             for (parent_revid,) in parent_keys])
 
1072
                    for (parent_revid,) in parent_keys])
1079
1073
            else:
1080
1074
                result[revision_id] = (_mod_revision.NULL_REVISION,)
1081
1075
        return result
1091
1085
        return graph.CallableToParentsProviderAdapter(
1092
1086
            self._get_parent_map_no_fallbacks)
1093
1087
 
 
1088
    @needs_read_lock
1094
1089
    def get_known_graph_ancestry(self, revision_ids):
1095
1090
        """Return the known graph for a set of revision ids and their ancestors.
1096
1091
        """
1104
1099
        """Return the graph walker for this repository format"""
1105
1100
        parents_provider = self._make_parents_provider()
1106
1101
        if (other_repository is not None and
1107
 
                not self.has_same_location(other_repository)):
 
1102
            not self.has_same_location(other_repository)):
1108
1103
            parents_provider = graph.StackedParentsProvider(
1109
1104
                [parents_provider, other_repository._make_parents_provider()])
1110
1105
        return graph.Graph(parents_provider)
1111
1106
 
 
1107
    @needs_write_lock
1112
1108
    def set_make_working_trees(self, new_value):
1113
1109
        """Set the policy flag for making working trees when creating branches.
1114
1110
 
1124
1120
        """Returns the policy for making working trees on new branches."""
1125
1121
        raise NotImplementedError(self.make_working_trees)
1126
1122
 
 
1123
    @needs_write_lock
1127
1124
    def sign_revision(self, revision_id, gpg_strategy):
1128
 
        raise NotImplementedError(self.sign_revision)
 
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)
1129
1128
 
 
1129
    @needs_read_lock
1130
1130
    def verify_revision_signature(self, revision_id, gpg_strategy):
1131
1131
        """Verify the signature on a revision.
1132
1132
 
1135
1135
 
1136
1136
        :return: gpg.SIGNATURE_VALID or a failed SIGNATURE_ value
1137
1137
        """
1138
 
        raise NotImplementedError(self.verify_revision_signature)
1139
 
 
 
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
1140
1148
    def verify_revision_signatures(self, revision_ids, gpg_strategy):
1141
1149
        """Verify revision signatures for a number of revisions.
1142
1150
 
1144
1152
        :gpg_strategy: the GPGStrategy object to used
1145
1153
        :return: Iterator over tuples with revision id, result and keys
1146
1154
        """
1147
 
        with self.lock_read():
1148
 
            for revid in revision_ids:
1149
 
                (result, key) = self.verify_revision_signature(revid, gpg_strategy)
1150
 
                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
1151
1158
 
1152
1159
    def has_signature_for_revision_id(self, revision_id):
1153
1160
        """Query for a revision signature for revision_id in the repository."""
1166
1173
             will be checked.  Typically the last revision_id of a branch.
1167
1174
        :param callback_refs: A dict of check-refs to resolve and callback
1168
1175
            the check/_check method on the items listed as wanting the ref.
1169
 
            see breezy.check.
1170
 
        :param check_repo: If False do not check the repository contents, just
 
1176
            see bzrlib.check.
 
1177
        :param check_repo: If False do not check the repository contents, just 
1171
1178
            calculate the data callback_refs requires and call them back.
1172
1179
        """
1173
1180
        return self._check(revision_ids=revision_ids, callback_refs=callback_refs,
1174
 
                           check_repo=check_repo)
 
1181
            check_repo=check_repo)
1175
1182
 
1176
1183
    def _check(self, revision_ids=None, callback_refs=None, check_repo=True):
1177
1184
        raise NotImplementedError(self.check)
1190
1197
            if 'format_deprecation' in conf.get('suppress_warnings'):
1191
1198
                return
1192
1199
            warning("Format %s for %s is deprecated -"
1193
 
                    " please use 'brz upgrade' to get better performance"
1194
 
                    % (self._format, self.controldir.transport.base))
 
1200
                    " please use 'bzr upgrade' to get better performance"
 
1201
                    % (self._format, self.bzrdir.transport.base))
1195
1202
        finally:
1196
1203
            _deprecation_warning_done = True
1197
1204
 
1203
1210
        # weave repositories refuse to store revisionids that are non-ascii.
1204
1211
        if revision_id is not None:
1205
1212
            # weaves require ascii revision ids.
1206
 
            if isinstance(revision_id, str):
 
1213
            if isinstance(revision_id, unicode):
1207
1214
                try:
1208
1215
                    revision_id.encode('ascii')
1209
1216
                except UnicodeEncodeError:
1215
1222
                    raise errors.NonAsciiRevisionId(method, self)
1216
1223
 
1217
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
 
1218
1274
class RepositoryFormatRegistry(controldir.ControlComponentFormatRegistry):
1219
1275
    """Repository format registry."""
1220
1276
 
1221
1277
    def get_default(self):
1222
1278
        """Return the current default format."""
1223
 
        return controldir.format_registry.make_controldir('default').repository_format
 
1279
        return controldir.format_registry.make_bzrdir('default').repository_format
1224
1280
 
1225
1281
 
1226
1282
network_format_registry = registry.FormatRegistry()
1269
1325
    created.
1270
1326
 
1271
1327
    Common instance attributes:
1272
 
    _matchingcontroldir - the controldir format that the repository format was
 
1328
    _matchingbzrdir - the controldir format that the repository format was
1273
1329
    originally written to work with. This can be used if manually
1274
1330
    constructing a bzrdir and repository, or more commonly for test suite
1275
1331
    parameterization.
1311
1367
    supports_revision_signatures = True
1312
1368
    # Can the revision graph have incorrect parents?
1313
1369
    revision_graph_can_have_wrong_parents = None
1314
 
    # Does this format support setting revision ids?
1315
 
    supports_setting_revision_ids = True
1316
1370
    # Does this format support rich root data?
1317
1371
    rich_root_data = None
1318
1372
    # Does this format support explicitly versioned directories?
1322
1376
    # Is it possible for revisions to be present without being referenced
1323
1377
    # somewhere ?
1324
1378
    supports_unreferenced_revisions = None
1325
 
    # Does this format store the current Branch.nick in a revision when
1326
 
    # creating commits?
1327
 
    supports_storing_branch_nick = True
1328
 
    # Does the format support overriding the transport to use
1329
 
    supports_overriding_transport = True
1330
 
    # Does the format support setting custom revision properties?
1331
 
    supports_custom_revision_properties = True
1332
 
    # Does the format record per-file revision metadata?
1333
 
    records_per_file_revision = True
1334
1379
 
1335
1380
    def __repr__(self):
1336
1381
        return "%s()" % self.__class__.__name__
1390
1435
            raise errors.BadConversionTarget(
1391
1436
                'Does not support rich root data.', target_format,
1392
1437
                from_format=self)
1393
 
        if (self.supports_tree_reference
1394
 
                and not getattr(target_format, 'supports_tree_reference', False)):
 
1438
        if (self.supports_tree_reference and 
 
1439
            not getattr(target_format, 'supports_tree_reference', False)):
1395
1440
            raise errors.BadConversionTarget(
1396
1441
                'Does not support nested trees', target_format,
1397
1442
                from_format=self)
1404
1449
        raise NotImplementedError(self.open)
1405
1450
 
1406
1451
    def _run_post_repo_init_hooks(self, repository, controldir, shared):
1407
 
        from .controldir import ControlDir, RepoInitHookParams
 
1452
        from bzrlib.controldir import ControlDir, RepoInitHookParams
1408
1453
        hooks = ControlDir.hooks['post_repo_init']
1409
1454
        if not hooks:
1410
1455
            return
1413
1458
            hook(params)
1414
1459
 
1415
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
 
1416
1532
# formats which have no format string are not discoverable or independently
1417
1533
# creatable on disk, so are not registered in format_registry.  They're
1418
 
# 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
1419
1535
# needed, it's constructed directly by the ControlDir.  Non-native formats where
1420
1536
# the repository is not separately opened are similar.
1421
1537
 
1422
1538
format_registry.register_lazy(
1423
 
    b'Bazaar-NG Knit Repository Format 1',
1424
 
    'breezy.bzr.knitrepo',
 
1539
    'Bazaar-NG Knit Repository Format 1',
 
1540
    'bzrlib.repofmt.knitrepo',
1425
1541
    'RepositoryFormatKnit1',
1426
1542
    )
1427
1543
 
1428
1544
format_registry.register_lazy(
1429
 
    b'Bazaar Knit Repository Format 3 (bzr 0.15)\n',
1430
 
    'breezy.bzr.knitrepo',
 
1545
    'Bazaar Knit Repository Format 3 (bzr 0.15)\n',
 
1546
    'bzrlib.repofmt.knitrepo',
1431
1547
    'RepositoryFormatKnit3',
1432
1548
    )
1433
1549
 
1434
1550
format_registry.register_lazy(
1435
 
    b'Bazaar Knit Repository Format 4 (bzr 1.0)\n',
1436
 
    'breezy.bzr.knitrepo',
 
1551
    'Bazaar Knit Repository Format 4 (bzr 1.0)\n',
 
1552
    'bzrlib.repofmt.knitrepo',
1437
1553
    'RepositoryFormatKnit4',
1438
1554
    )
1439
1555
 
1441
1557
# post-subtrees to allow ease of testing.
1442
1558
# NOTE: These are experimental in 0.92. Stable in 1.0 and above
1443
1559
format_registry.register_lazy(
1444
 
    b'Bazaar pack repository format 1 (needs bzr 0.92)\n',
1445
 
    'breezy.bzr.knitpack_repo',
 
1560
    'Bazaar pack repository format 1 (needs bzr 0.92)\n',
 
1561
    'bzrlib.repofmt.knitpack_repo',
1446
1562
    'RepositoryFormatKnitPack1',
1447
1563
    )
1448
1564
format_registry.register_lazy(
1449
 
    b'Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n',
1450
 
    'breezy.bzr.knitpack_repo',
 
1565
    'Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n',
 
1566
    'bzrlib.repofmt.knitpack_repo',
1451
1567
    'RepositoryFormatKnitPack3',
1452
1568
    )
1453
1569
format_registry.register_lazy(
1454
 
    b'Bazaar pack repository format 1 with rich root (needs bzr 1.0)\n',
1455
 
    'breezy.bzr.knitpack_repo',
 
1570
    'Bazaar pack repository format 1 with rich root (needs bzr 1.0)\n',
 
1571
    'bzrlib.repofmt.knitpack_repo',
1456
1572
    'RepositoryFormatKnitPack4',
1457
1573
    )
1458
1574
format_registry.register_lazy(
1459
 
    b'Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n',
1460
 
    'breezy.bzr.knitpack_repo',
 
1575
    'Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n',
 
1576
    'bzrlib.repofmt.knitpack_repo',
1461
1577
    'RepositoryFormatKnitPack5',
1462
1578
    )
1463
1579
format_registry.register_lazy(
1464
 
    b'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6.1)\n',
1465
 
    'breezy.bzr.knitpack_repo',
 
1580
    'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6.1)\n',
 
1581
    'bzrlib.repofmt.knitpack_repo',
1466
1582
    'RepositoryFormatKnitPack5RichRoot',
1467
1583
    )
1468
1584
format_registry.register_lazy(
1469
 
    b'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6)\n',
1470
 
    'breezy.bzr.knitpack_repo',
 
1585
    'Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6)\n',
 
1586
    'bzrlib.repofmt.knitpack_repo',
1471
1587
    'RepositoryFormatKnitPack5RichRootBroken',
1472
1588
    )
1473
1589
format_registry.register_lazy(
1474
 
    b'Bazaar RepositoryFormatKnitPack6 (bzr 1.9)\n',
1475
 
    'breezy.bzr.knitpack_repo',
 
1590
    'Bazaar RepositoryFormatKnitPack6 (bzr 1.9)\n',
 
1591
    'bzrlib.repofmt.knitpack_repo',
1476
1592
    'RepositoryFormatKnitPack6',
1477
1593
    )
1478
1594
format_registry.register_lazy(
1479
 
    b'Bazaar RepositoryFormatKnitPack6RichRoot (bzr 1.9)\n',
1480
 
    'breezy.bzr.knitpack_repo',
 
1595
    'Bazaar RepositoryFormatKnitPack6RichRoot (bzr 1.9)\n',
 
1596
    'bzrlib.repofmt.knitpack_repo',
1481
1597
    'RepositoryFormatKnitPack6RichRoot',
1482
1598
    )
1483
1599
format_registry.register_lazy(
1484
 
    b'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
1485
 
    'breezy.bzr.groupcompress_repo',
 
1600
    'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
 
1601
    'bzrlib.repofmt.groupcompress_repo',
1486
1602
    'RepositoryFormat2a',
1487
1603
    )
1488
1604
 
1489
1605
# Development formats.
1490
1606
# Check their docstrings to see if/when they are obsolete.
1491
1607
format_registry.register_lazy(
1492
 
    (b"Bazaar development format 2 with subtree support "
1493
 
        b"(needs bzr.dev from before 1.8)\n"),
1494
 
    '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',
1495
1611
    'RepositoryFormatPackDevelopment2Subtree',
1496
1612
    )
1497
1613
format_registry.register_lazy(
1498
 
    b'Bazaar development format 8\n',
1499
 
    'breezy.bzr.groupcompress_repo',
 
1614
    'Bazaar development format 8\n',
 
1615
    'bzrlib.repofmt.groupcompress_repo',
1500
1616
    'RepositoryFormat2aSubtree',
1501
1617
    )
1502
1618
 
1516
1632
    _optimisers = []
1517
1633
    """The available optimised InterRepository types."""
1518
1634
 
 
1635
    @needs_write_lock
1519
1636
    def copy_content(self, revision_id=None):
1520
1637
        """Make a complete copy of the content in self into destination.
1521
1638
 
1525
1642
        :param revision_id: Only copy the content needed to construct
1526
1643
                            revision_id and its parents.
1527
1644
        """
1528
 
        with self.lock_write():
1529
 
            try:
1530
 
                self.target.set_make_working_trees(
1531
 
                    self.source.make_working_trees())
1532
 
            except (NotImplementedError, errors.RepositoryUpgradeRequired):
1533
 
                pass
1534
 
            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)
1535
1650
 
1536
 
    def fetch(self, revision_id=None, find_ghosts=False, lossy=False):
 
1651
    @needs_write_lock
 
1652
    def fetch(self, revision_id=None, find_ghosts=False):
1537
1653
        """Fetch the content required to construct revision_id.
1538
1654
 
1539
1655
        The content is copied from self.source to self.target.
1540
1656
 
1541
1657
        :param revision_id: if None all content is copied, if NULL_REVISION no
1542
1658
                            content is copied.
1543
 
        :return: FetchResult
 
1659
        :return: None.
1544
1660
        """
1545
1661
        raise NotImplementedError(self.fetch)
1546
1662
 
1547
 
    def search_missing_revision_ids(
1548
 
            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,
1549
1667
            limit=None):
1550
1668
        """Return the revision ids that source has that target does not.
1551
1669
 
 
1670
        :param revision_id: only return revision ids included by this
 
1671
            revision_id.
1552
1672
        :param revision_ids: return revision ids included by these
1553
1673
            revision_ids.  NoSuchRevision will be raised if any of these
1554
1674
            revisions are not present.
1560
1680
            rather than just finding the surface difference.
1561
1681
        :param limit: Maximum number of revisions to return, topologically
1562
1682
            ordered
1563
 
        :return: A breezy.graph.SearchResult.
 
1683
        :return: A bzrlib.graph.SearchResult.
1564
1684
        """
1565
1685
        raise NotImplementedError(self.search_missing_revision_ids)
1566
1686
 
1574
1694
        try:
1575
1695
            InterRepository._assert_same_model(source, target)
1576
1696
            return True
1577
 
        except errors.IncompatibleRepositories as e:
 
1697
        except errors.IncompatibleRepositories, e:
1578
1698
            return False
1579
1699
 
1580
1700
    @staticmethod
1583
1703
        """
1584
1704
        if source.supports_rich_root() != target.supports_rich_root():
1585
1705
            raise errors.IncompatibleRepositories(source, target,
1586
 
                                                  "different rich-root support")
 
1706
                "different rich-root support")
1587
1707
        if source._serializer != target._serializer:
1588
1708
            raise errors.IncompatibleRepositories(source, target,
1589
 
                                                  "different serializers")
 
1709
                "different serializers")
1590
1710
 
1591
1711
 
1592
1712
class CopyConverter(object):
1608
1728
        :param to_convert: The disk object to convert.
1609
1729
        :param pb: a progress bar to use for progress information.
1610
1730
        """
1611
 
        with ui.ui_factory.nested_progress_bar() as pb:
1612
 
            self.count = 0
1613
 
            self.total = 4
1614
 
            # this is only useful with metadir layouts - separated repo content.
1615
 
            # trigger an assertion if not such
1616
 
            repo._format.get_format_string()
1617
 
            self.repo_dir = repo.controldir
1618
 
            pb.update(gettext('Moving repository to repository.backup'))
1619
 
            self.repo_dir.transport.move('repository', 'repository.backup')
1620
 
            backup_transport = self.repo_dir.transport.clone(
1621
 
                'repository.backup')
1622
 
            repo._format.check_conversion_target(self.target_format)
1623
 
            self.source_repo = repo._format.open(self.repo_dir,
1624
 
                                                 _found=True,
1625
 
                                                 _override_transport=backup_transport)
1626
 
            pb.update(gettext('Creating new repository'))
1627
 
            converted = self.target_format.initialize(self.repo_dir,
1628
 
                                                      self.source_repo.is_shared())
1629
 
            with converted.lock_write():
1630
 
                pb.update(gettext('Copying content'))
1631
 
                self.source_repo.copy_content_into(converted)
1632
 
            pb.update(gettext('Deleting old repository content'))
1633
 
            self.repo_dir.transport.delete_tree('repository.backup')
1634
 
            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()
1635
1758
 
1636
1759
 
1637
1760
def _strip_NULL_ghosts(revision_graph):
1641
1764
        del revision_graph[_mod_revision.NULL_REVISION]
1642
1765
    for key, parents in revision_graph.items():
1643
1766
        revision_graph[key] = tuple(parent for parent in parents if parent
1644
 
                                    in revision_graph)
 
1767
            in revision_graph)
1645
1768
    return revision_graph
1646
1769
 
1647
1770
 
1662
1785
    start_revision = partial_history_cache[-1]
1663
1786
    graph = repo.get_graph()
1664
1787
    iterator = graph.iter_lefthand_ancestry(start_revision,
1665
 
                                            (_mod_revision.NULL_REVISION,))
 
1788
        (_mod_revision.NULL_REVISION,))
1666
1789
    try:
1667
1790
        # skip the last revision in the list
1668
 
        next(iterator)
 
1791
        iterator.next()
1669
1792
        while True:
1670
1793
            if (stop_index is not None and
1671
 
                    len(partial_history_cache) > stop_index):
 
1794
                len(partial_history_cache) > stop_index):
1672
1795
                break
1673
1796
            if partial_history_cache[-1] == stop_revision:
1674
1797
                break
1675
 
            revision_id = next(iterator)
 
1798
            revision_id = iterator.next()
1676
1799
            partial_history_cache.append(revision_id)
1677
1800
    except StopIteration:
1678
1801
        # No more history
1684
1807
 
1685
1808
    Each iterator made from this will reflect the current contents of the lists
1686
1809
    at the time the iterator is made.
1687
 
 
 
1810
    
1688
1811
    This is used by Repository's _make_parents_provider implementation so that
1689
1812
    it is safe to do::
1690
1813