~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Jelmer Vernooij
  • Date: 2011-01-11 04:33:12 UTC
  • mto: (5582.12.2 weave-plugin)
  • mto: This revision was merged to the branch mainline in revision 5718.
  • Revision ID: jelmer@samba.org-20110111043312-g4wx6iuf9662f36d
Move weave formats into bzrlib.plugins.weave_fmt.

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
    lockdir,
40
40
    lru_cache,
41
41
    osutils,
 
42
    pyutils,
42
43
    revision as _mod_revision,
43
44
    static_tuple,
44
45
    symbol_versioning,
52
53
from bzrlib.testament import Testament
53
54
""")
54
55
 
 
56
import sys
55
57
from bzrlib import (
56
58
    errors,
57
59
    registry,
113
115
 
114
116
        if committer is None:
115
117
            self._committer = self._config.username()
 
118
        elif not isinstance(committer, unicode):
 
119
            self._committer = committer.decode() # throw if non-ascii
116
120
        else:
117
121
            self._committer = committer
118
122
 
434
438
            else:
435
439
                # we don't need to commit this, because the caller already
436
440
                # determined that an existing revision of this file is
437
 
                # appropriate. If its not being considered for committing then
 
441
                # appropriate. If it's not being considered for committing then
438
442
                # it and all its parents to the root must be unaltered so
439
443
                # no-change against the basis.
440
444
                if ie.revision == self._new_revision_id:
756
760
                    # after iter_changes examines and decides it has changed,
757
761
                    # we will unconditionally record a new version even if some
758
762
                    # other process reverts it while commit is running (with
759
 
                    # the revert happening after iter_changes did it's
 
763
                    # the revert happening after iter_changes did its
760
764
                    # examination).
761
765
                    if change[7][1]:
762
766
                        entry.executable = True
945
949
        pointing to .bzr/repository.
946
950
    """
947
951
 
948
 
    # What class to use for a CommitBuilder. Often its simpler to change this
 
952
    # What class to use for a CommitBuilder. Often it's simpler to change this
949
953
    # in a Repository class subclass rather than to override
950
954
    # get_commit_builder.
951
955
    _commit_builder_class = CommitBuilder
2511
2515
            ancestors will be traversed.
2512
2516
        """
2513
2517
        graph = self.get_graph()
2514
 
        next_id = revision_id
2515
 
        while True:
2516
 
            if next_id in (None, _mod_revision.NULL_REVISION):
2517
 
                return
2518
 
            try:
2519
 
                parents = graph.get_parent_map([next_id])[next_id]
2520
 
            except KeyError:
2521
 
                raise errors.RevisionNotPresent(next_id, self)
2522
 
            yield next_id
2523
 
            if len(parents) == 0:
2524
 
                return
2525
 
            else:
2526
 
                next_id = parents[0]
 
2518
        stop_revisions = (None, _mod_revision.NULL_REVISION)
 
2519
        return graph.iter_lefthand_ancestry(revision_id, stop_revisions)
2527
2520
 
2528
2521
    def is_shared(self):
2529
2522
        """Return True if this repository is flagged as a shared repository."""
2630
2623
        types it should be a no-op that just returns.
2631
2624
 
2632
2625
        This stub method does not require a lock, but subclasses should use
2633
 
        @needs_write_lock as this is a long running call its reasonable to
 
2626
        @needs_write_lock as this is a long running call it's reasonable to
2634
2627
        implicitly lock for the user.
2635
2628
 
2636
2629
        :param hint: If not supplied, the whole repository is packed.
2829
2822
        raise NotImplementedError(self.revision_graph_can_have_wrong_parents)
2830
2823
 
2831
2824
 
2832
 
# remove these delegates a while after bzr 0.15
2833
 
def __make_delegated(name, from_module):
2834
 
    def _deprecated_repository_forwarder():
2835
 
        symbol_versioning.warn('%s moved to %s in bzr 0.15'
2836
 
            % (name, from_module),
2837
 
            DeprecationWarning,
2838
 
            stacklevel=2)
2839
 
        m = __import__(from_module, globals(), locals(), [name])
2840
 
        try:
2841
 
            return getattr(m, name)
2842
 
        except AttributeError:
2843
 
            raise AttributeError('module %s has no name %s'
2844
 
                    % (m, name))
2845
 
    globals()[name] = _deprecated_repository_forwarder
2846
 
 
2847
 
for _name in [
2848
 
        'AllInOneRepository',
2849
 
        'WeaveMetaDirRepository',
2850
 
        'PreSplitOutRepositoryFormat',
2851
 
        'RepositoryFormat4',
2852
 
        'RepositoryFormat5',
2853
 
        'RepositoryFormat6',
2854
 
        'RepositoryFormat7',
2855
 
        ]:
2856
 
    __make_delegated(_name, 'bzrlib.repofmt.weaverepo')
2857
 
 
2858
 
for _name in [
2859
 
        'KnitRepository',
2860
 
        'RepositoryFormatKnit',
2861
 
        'RepositoryFormatKnit1',
2862
 
        ]:
2863
 
    __make_delegated(_name, 'bzrlib.repofmt.knitrepo')
2864
 
 
2865
 
 
2866
2825
def install_revision(repository, rev, revision_tree):
2867
2826
    """Install all revision data into a repository."""
2868
2827
    install_revisions(repository, [(rev, revision_tree, None)])
3272
3231
        return self.get_format_string()
3273
3232
 
3274
3233
 
3275
 
# Pre-0.8 formats that don't have a disk format string (because they are
3276
 
# versioned by the matching control directory). We use the control directories
3277
 
# disk format string as a key for the network_name because they meet the
3278
 
# constraints (simple string, unique, immutable).
3279
 
network_format_registry.register_lazy(
3280
 
    "Bazaar-NG branch, format 5\n",
3281
 
    'bzrlib.repofmt.weaverepo',
3282
 
    'RepositoryFormat5',
3283
 
)
3284
 
network_format_registry.register_lazy(
3285
 
    "Bazaar-NG branch, format 6\n",
3286
 
    'bzrlib.repofmt.weaverepo',
3287
 
    'RepositoryFormat6',
3288
 
)
3289
 
 
3290
3234
# formats which have no format string are not discoverable or independently
3291
3235
# creatable on disk, so are not registered in format_registry.  They're
3292
 
# all in bzrlib.repofmt.weaverepo now.  When an instance of one of these is
 
3236
# all in bzrlib.repofmt.knitreponow.  When an instance of one of these is
3293
3237
# needed, it's constructed directly by the BzrDir.  Non-native formats where
3294
3238
# the repository is not separately opened are similar.
3295
3239
 
3296
3240
format_registry.register_lazy(
3297
 
    'Bazaar-NG Repository format 7',
3298
 
    'bzrlib.repofmt.weaverepo',
3299
 
    'RepositoryFormat7'
3300
 
    )
3301
 
 
3302
 
format_registry.register_lazy(
3303
3241
    'Bazaar-NG Knit Repository Format 1',
3304
3242
    'bzrlib.repofmt.knitrepo',
3305
3243
    'RepositoryFormatKnit1',
3360
3298
    'bzrlib.repofmt.pack_repo',
3361
3299
    'RepositoryFormatKnitPack6RichRoot',
3362
3300
    )
 
3301
format_registry.register_lazy(
 
3302
    'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
 
3303
    'bzrlib.repofmt.groupcompress_repo',
 
3304
    'RepositoryFormat2a',
 
3305
    )
3363
3306
 
3364
3307
# Development formats.
3365
 
# Obsolete but kept pending a CHK based subtree format.
 
3308
# Check their docstrings to see if/when they are obsolete.
3366
3309
format_registry.register_lazy(
3367
3310
    ("Bazaar development format 2 with subtree support "
3368
3311
        "(needs bzr.dev from before 1.8)\n"),
3369
3312
    'bzrlib.repofmt.pack_repo',
3370
3313
    'RepositoryFormatPackDevelopment2Subtree',
3371
3314
    )
3372
 
 
3373
 
# 1.14->1.16 go below here
3374
 
format_registry.register_lazy(
3375
 
    'Bazaar development format - group compression and chk inventory'
3376
 
        ' (needs bzr.dev from 1.14)\n',
3377
 
    'bzrlib.repofmt.groupcompress_repo',
3378
 
    'RepositoryFormatCHK1',
3379
 
    )
3380
 
 
3381
 
format_registry.register_lazy(
3382
 
    'Bazaar development format - chk repository with bencode revision '
3383
 
        'serialization (needs bzr.dev from 1.16)\n',
3384
 
    'bzrlib.repofmt.groupcompress_repo',
3385
 
    'RepositoryFormatCHK2',
3386
 
    )
3387
 
format_registry.register_lazy(
3388
 
    'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
3389
 
    'bzrlib.repofmt.groupcompress_repo',
3390
 
    'RepositoryFormat2a',
 
3315
format_registry.register_lazy(
 
3316
    'Bazaar development format 8\n',
 
3317
    'bzrlib.repofmt.groupcompress_repo',
 
3318
    'RepositoryFormat2aSubtree',
3391
3319
    )
3392
3320
 
3393
3321
 
3571
3499
        return InterRepository._same_model(source, target)
3572
3500
 
3573
3501
 
3574
 
class InterWeaveRepo(InterSameDataRepository):
3575
 
    """Optimised code paths between Weave based repositories.
3576
 
 
3577
 
    This should be in bzrlib/repofmt/weaverepo.py but we have not yet
3578
 
    implemented lazy inter-object optimisation.
3579
 
    """
3580
 
 
3581
 
    @classmethod
3582
 
    def _get_repo_format_to_test(self):
3583
 
        from bzrlib.repofmt import weaverepo
3584
 
        return weaverepo.RepositoryFormat7()
3585
 
 
3586
 
    @staticmethod
3587
 
    def is_compatible(source, target):
3588
 
        """Be compatible with known Weave formats.
3589
 
 
3590
 
        We don't test for the stores being of specific types because that
3591
 
        could lead to confusing results, and there is no need to be
3592
 
        overly general.
3593
 
        """
3594
 
        from bzrlib.repofmt.weaverepo import (
3595
 
                RepositoryFormat5,
3596
 
                RepositoryFormat6,
3597
 
                RepositoryFormat7,
3598
 
                )
3599
 
        try:
3600
 
            return (isinstance(source._format, (RepositoryFormat5,
3601
 
                                                RepositoryFormat6,
3602
 
                                                RepositoryFormat7)) and
3603
 
                    isinstance(target._format, (RepositoryFormat5,
3604
 
                                                RepositoryFormat6,
3605
 
                                                RepositoryFormat7)))
3606
 
        except AttributeError:
3607
 
            return False
3608
 
 
3609
 
    @needs_write_lock
3610
 
    def copy_content(self, revision_id=None):
3611
 
        """See InterRepository.copy_content()."""
3612
 
        # weave specific optimised path:
3613
 
        try:
3614
 
            self.target.set_make_working_trees(self.source.make_working_trees())
3615
 
        except (errors.RepositoryUpgradeRequired, NotImplemented):
3616
 
            pass
3617
 
        # FIXME do not peek!
3618
 
        if self.source._transport.listable():
3619
 
            pb = ui.ui_factory.nested_progress_bar()
3620
 
            try:
3621
 
                self.target.texts.insert_record_stream(
3622
 
                    self.source.texts.get_record_stream(
3623
 
                        self.source.texts.keys(), 'topological', False))
3624
 
                pb.update('Copying inventory', 0, 1)
3625
 
                self.target.inventories.insert_record_stream(
3626
 
                    self.source.inventories.get_record_stream(
3627
 
                        self.source.inventories.keys(), 'topological', False))
3628
 
                self.target.signatures.insert_record_stream(
3629
 
                    self.source.signatures.get_record_stream(
3630
 
                        self.source.signatures.keys(),
3631
 
                        'unordered', True))
3632
 
                self.target.revisions.insert_record_stream(
3633
 
                    self.source.revisions.get_record_stream(
3634
 
                        self.source.revisions.keys(),
3635
 
                        'topological', True))
3636
 
            finally:
3637
 
                pb.finished()
3638
 
        else:
3639
 
            self.target.fetch(self.source, revision_id=revision_id)
3640
 
 
3641
 
    @needs_read_lock
3642
 
    def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3643
 
        """See InterRepository.missing_revision_ids()."""
3644
 
        # we want all revisions to satisfy revision_id in source.
3645
 
        # but we don't want to stat every file here and there.
3646
 
        # we want then, all revisions other needs to satisfy revision_id
3647
 
        # checked, but not those that we have locally.
3648
 
        # so the first thing is to get a subset of the revisions to
3649
 
        # satisfy revision_id in source, and then eliminate those that
3650
 
        # we do already have.
3651
 
        # this is slow on high latency connection to self, but as this
3652
 
        # disk format scales terribly for push anyway due to rewriting
3653
 
        # inventory.weave, this is considered acceptable.
3654
 
        # - RBC 20060209
3655
 
        if revision_id is not None:
3656
 
            source_ids = self.source.get_ancestry(revision_id)
3657
 
            if source_ids[0] is not None:
3658
 
                raise AssertionError()
3659
 
            source_ids.pop(0)
3660
 
        else:
3661
 
            source_ids = self.source._all_possible_ids()
3662
 
        source_ids_set = set(source_ids)
3663
 
        # source_ids is the worst possible case we may need to pull.
3664
 
        # now we want to filter source_ids against what we actually
3665
 
        # have in target, but don't try to check for existence where we know
3666
 
        # we do not have a revision as that would be pointless.
3667
 
        target_ids = set(self.target._all_possible_ids())
3668
 
        possibly_present_revisions = target_ids.intersection(source_ids_set)
3669
 
        actually_present_revisions = set(
3670
 
            self.target._eliminate_revisions_not_present(possibly_present_revisions))
3671
 
        required_revisions = source_ids_set.difference(actually_present_revisions)
3672
 
        if revision_id is not None:
3673
 
            # we used get_ancestry to determine source_ids then we are assured all
3674
 
            # revisions referenced are present as they are installed in topological order.
3675
 
            # and the tip revision was validated by get_ancestry.
3676
 
            result_set = required_revisions
3677
 
        else:
3678
 
            # if we just grabbed the possibly available ids, then
3679
 
            # we only have an estimate of whats available and need to validate
3680
 
            # that against the revision records.
3681
 
            result_set = set(
3682
 
                self.source._eliminate_revisions_not_present(required_revisions))
3683
 
        return self.source.revision_ids_to_search_result(result_set)
3684
 
 
3685
 
 
3686
 
class InterKnitRepo(InterSameDataRepository):
3687
 
    """Optimised code paths between Knit based repositories."""
3688
 
 
3689
 
    @classmethod
3690
 
    def _get_repo_format_to_test(self):
3691
 
        from bzrlib.repofmt import knitrepo
3692
 
        return knitrepo.RepositoryFormatKnit1()
3693
 
 
3694
 
    @staticmethod
3695
 
    def is_compatible(source, target):
3696
 
        """Be compatible with known Knit formats.
3697
 
 
3698
 
        We don't test for the stores being of specific types because that
3699
 
        could lead to confusing results, and there is no need to be
3700
 
        overly general.
3701
 
        """
3702
 
        from bzrlib.repofmt.knitrepo import RepositoryFormatKnit
3703
 
        try:
3704
 
            are_knits = (isinstance(source._format, RepositoryFormatKnit) and
3705
 
                isinstance(target._format, RepositoryFormatKnit))
3706
 
        except AttributeError:
3707
 
            return False
3708
 
        return are_knits and InterRepository._same_model(source, target)
3709
 
 
3710
 
    @needs_read_lock
3711
 
    def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
3712
 
        """See InterRepository.missing_revision_ids()."""
3713
 
        if revision_id is not None:
3714
 
            source_ids = self.source.get_ancestry(revision_id)
3715
 
            if source_ids[0] is not None:
3716
 
                raise AssertionError()
3717
 
            source_ids.pop(0)
3718
 
        else:
3719
 
            source_ids = self.source.all_revision_ids()
3720
 
        source_ids_set = set(source_ids)
3721
 
        # source_ids is the worst possible case we may need to pull.
3722
 
        # now we want to filter source_ids against what we actually
3723
 
        # have in target, but don't try to check for existence where we know
3724
 
        # we do not have a revision as that would be pointless.
3725
 
        target_ids = set(self.target.all_revision_ids())
3726
 
        possibly_present_revisions = target_ids.intersection(source_ids_set)
3727
 
        actually_present_revisions = set(
3728
 
            self.target._eliminate_revisions_not_present(possibly_present_revisions))
3729
 
        required_revisions = source_ids_set.difference(actually_present_revisions)
3730
 
        if revision_id is not None:
3731
 
            # we used get_ancestry to determine source_ids then we are assured all
3732
 
            # revisions referenced are present as they are installed in topological order.
3733
 
            # and the tip revision was validated by get_ancestry.
3734
 
            result_set = required_revisions
3735
 
        else:
3736
 
            # if we just grabbed the possibly available ids, then
3737
 
            # we only have an estimate of whats available and need to validate
3738
 
            # that against the revision records.
3739
 
            result_set = set(
3740
 
                self.source._eliminate_revisions_not_present(required_revisions))
3741
 
        return self.source.revision_ids_to_search_result(result_set)
3742
 
 
3743
 
 
3744
3502
class InterDifferingSerializer(InterRepository):
3745
3503
 
3746
3504
    @classmethod
3848
3606
                basis_id, delta, current_revision_id, parents_parents)
3849
3607
            cache[current_revision_id] = parent_tree
3850
3608
 
3851
 
    def _fetch_batch(self, revision_ids, basis_id, cache, a_graph=None):
 
3609
    def _fetch_batch(self, revision_ids, basis_id, cache):
3852
3610
        """Fetch across a few revisions.
3853
3611
 
3854
3612
        :param revision_ids: The revisions to copy
3855
3613
        :param basis_id: The revision_id of a tree that must be in cache, used
3856
3614
            as a basis for delta when no other base is available
3857
3615
        :param cache: A cache of RevisionTrees that we can use.
3858
 
        :param a_graph: A Graph object to determine the heads() of the
3859
 
            rich-root data stream.
3860
3616
        :return: The revision_id of the last converted tree. The RevisionTree
3861
3617
            for it will be in cache
3862
3618
        """
3930
3686
        if root_keys_to_create:
3931
3687
            root_stream = _mod_fetch._new_root_data_stream(
3932
3688
                root_keys_to_create, self._revision_id_to_root_id, parent_map,
3933
 
                self.source, graph=a_graph)
 
3689
                self.source)
3934
3690
            to_texts.insert_record_stream(root_stream)
3935
3691
        to_texts.insert_record_stream(from_texts.get_record_stream(
3936
3692
            text_keys, self.target._format._fetch_order,
3993
3749
        cache[basis_id] = basis_tree
3994
3750
        del basis_tree # We don't want to hang on to it here
3995
3751
        hints = []
3996
 
        if self._converting_to_rich_root and len(revision_ids) > 100:
3997
 
            a_graph = _mod_fetch._get_rich_root_heads_graph(self.source,
3998
 
                                                            revision_ids)
3999
 
        else:
4000
 
            a_graph = None
 
3752
        a_graph = None
4001
3753
 
4002
3754
        for offset in range(0, len(revision_ids), batch_size):
4003
3755
            self.target.start_write_group()
4005
3757
                pb.update('Transferring revisions', offset,
4006
3758
                          len(revision_ids))
4007
3759
                batch = revision_ids[offset:offset+batch_size]
4008
 
                basis_id = self._fetch_batch(batch, basis_id, cache,
4009
 
                                             a_graph=a_graph)
 
3760
                basis_id = self._fetch_batch(batch, basis_id, cache)
4010
3761
            except:
4011
3762
                self.source._safe_to_return_from_cache = False
4012
3763
                self.target.abort_write_group()
4078
3829
            basis_id = first_rev.parent_ids[0]
4079
3830
            # only valid as a basis if the target has it
4080
3831
            self.target.get_revision(basis_id)
4081
 
            # Try to get a basis tree - if its a ghost it will hit the
 
3832
            # Try to get a basis tree - if it's a ghost it will hit the
4082
3833
            # NoSuchRevision case.
4083
3834
            basis_tree = self.source.revision_tree(basis_id)
4084
3835
        except (IndexError, errors.NoSuchRevision):
4089
3840
 
4090
3841
InterRepository.register_optimiser(InterDifferingSerializer)
4091
3842
InterRepository.register_optimiser(InterSameDataRepository)
4092
 
InterRepository.register_optimiser(InterWeaveRepo)
4093
 
InterRepository.register_optimiser(InterKnitRepo)
4094
3843
 
4095
3844
 
4096
3845
class CopyConverter(object):