~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-07-16 07:54:18 UTC
  • mfrom: (3537.3.5 stacking)
  • Revision ID: pqm@pqm.ubuntu.com-20080716075418-xbachkqt622m73v1
(mbp) post-merge review cleanups for stacking

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
 
40
40
import bzrlib
41
41
from bzrlib import (
 
42
    config,
42
43
    errors,
43
44
    graph,
44
45
    lockable_files,
156
157
                format.get_format_description(),
157
158
                basedir)
158
159
 
159
 
    def clone(self, url, revision_id=None, force_new_repo=False):
 
160
    def clone(self, url, revision_id=None, force_new_repo=False,
 
161
              preserve_stacking=False):
160
162
        """Clone this bzrdir and its contents to url verbatim.
161
163
 
162
 
        If url's last component does not exist, it will be created.
163
 
 
164
 
        if revision_id is not None, then the clone operation may tune
 
164
        :param url: The url create the clone at.  If url's last component does
 
165
            not exist, it will be created.
 
166
        :param revision_id: The tip revision-id to use for any branch or
 
167
            working tree.  If not None, then the clone operation may tune
165
168
            itself to download less data.
166
 
        :param force_new_repo: Do not use a shared repository for the target 
 
169
        :param force_new_repo: Do not use a shared repository for the target
167
170
                               even if one is available.
 
171
        :param preserve_stacking: When cloning a stacked branch, stack the
 
172
            new branch on top of the other branch's stacked-on branch.
168
173
        """
169
174
        return self.clone_on_transport(get_transport(url),
170
175
                                       revision_id=revision_id,
171
 
                                       force_new_repo=force_new_repo)
 
176
                                       force_new_repo=force_new_repo,
 
177
                                       preserve_stacking=preserve_stacking)
172
178
 
173
179
    def clone_on_transport(self, transport, revision_id=None,
174
 
                           force_new_repo=False):
 
180
                           force_new_repo=False, preserve_stacking=False):
175
181
        """Clone this bzrdir and its contents to transport verbatim.
176
182
 
177
 
        If the target directory does not exist, it will be created.
178
 
 
179
 
        if revision_id is not None, then the clone operation may tune
 
183
        :param transport: The transport for the location to produce the clone
 
184
            at.  If the target directory does not exist, it will be created.
 
185
        :param revision_id: The tip revision-id to use for any branch or
 
186
            working tree.  If not None, then the clone operation may tune
180
187
            itself to download less data.
181
 
        :param force_new_repo: Do not use a shared repository for the target 
 
188
        :param force_new_repo: Do not use a shared repository for the target,
182
189
                               even if one is available.
 
190
        :param preserve_stacking: When cloning a stacked branch, stack the
 
191
            new branch on top of the other branch's stacked-on branch.
183
192
        """
184
193
        transport.ensure_base()
185
194
        result = self.cloning_metadir().initialize_on_transport(transport)
186
195
        repository_policy = None
 
196
        stack_on = None
187
197
        try:
188
198
            local_repo = self.find_repository()
189
199
        except errors.NoRepositoryPresent:
190
200
            local_repo = None
 
201
        try:
 
202
            local_branch = self.open_branch()
 
203
        except errors.NotBranchError:
 
204
            local_branch = None
 
205
        else:
 
206
            # enable fallbacks when branch is not a branch reference
 
207
            if local_branch.repository.has_same_location(local_repo):
 
208
                local_repo = local_branch.repository
 
209
            if preserve_stacking:
 
210
                try:
 
211
                    stack_on = local_branch.get_stacked_on_url()
 
212
                except (errors.UnstackableBranchFormat,
 
213
                        errors.UnstackableRepositoryFormat,
 
214
                        errors.NotStacked):
 
215
                    pass
 
216
 
191
217
        if local_repo:
192
218
            # may need to copy content in
193
219
            repository_policy = result.determine_repository_policy(
194
 
                force_new_repo)
 
220
                force_new_repo, stack_on)
195
221
            make_working_trees = local_repo.make_working_trees()
196
222
            result_repo = repository_policy.acquire_repository(
197
223
                make_working_trees, local_repo.is_shared())
198
224
            result_repo.fetch(local_repo, revision_id=revision_id)
 
225
        else:
 
226
            result_repo = None
199
227
        # 1 if there is a branch present
200
228
        #   make sure its content is available in the target repository
201
229
        #   clone it.
202
 
        try:
203
 
            local_branch = self.open_branch()
204
 
        except errors.NotBranchError:
205
 
            pass
206
 
        else:
 
230
        if local_branch is not None:
207
231
            result_branch = local_branch.clone(result, revision_id=revision_id)
208
232
            if repository_policy is not None:
209
233
                repository_policy.configure_branch(result_branch)
210
 
        try:
211
 
            result_repo = result.find_repository()
212
 
        except errors.NoRepositoryPresent:
213
 
            result_repo = None
214
234
        if result_repo is None or result_repo.make_working_trees():
215
235
            try:
216
236
                self.open_workingtree().clone(result)
352
372
        bzrdir._find_or_create_repository(force_new_repo)
353
373
        return bzrdir.create_branch()
354
374
 
355
 
    def determine_repository_policy(self, force_new_repo=False):
 
375
    def determine_repository_policy(self, force_new_repo=False, stack_on=None,
 
376
                                    stack_on_pwd=None, require_stacking=False):
356
377
        """Return an object representing a policy to use.
357
378
 
358
379
        This controls whether a new repository is created, or a shared
359
380
        repository used instead.
 
381
 
 
382
        If stack_on is supplied, will not seek a containing shared repo.
 
383
        :param force_new_repo: If True, require a new repository to be created.
 
384
        :param stack_on: If supplied, the location to stack on.  If not
 
385
            supplied, a default_stack_on location may be used.
 
386
        :param stack_on_pwd: If stack_on is relative, the location it is
 
387
            relative to.
360
388
        """
361
389
        def repository_policy(found_bzrdir):
 
390
            stack_on = None
 
391
            stack_on_pwd = None
 
392
            config = found_bzrdir.get_config()
362
393
            stop = False
 
394
            if config is not None:
 
395
                stack_on = config.get_default_stack_on()
 
396
                if stack_on is not None:
 
397
                    stack_on_pwd = found_bzrdir.root_transport.base
 
398
                    stop = True
 
399
                    note('Using default stacking branch %s at %s', stack_on,
 
400
                         stack_on_pwd)
363
401
            # does it have a repository ?
364
402
            try:
365
403
                repository = found_bzrdir.open_repository()
374
412
            if not stop:
375
413
                return None, False
376
414
            if repository:
377
 
                return UseExistingRepository(repository), True
 
415
                return UseExistingRepository(repository, stack_on,
 
416
                    stack_on_pwd, require_stacking=require_stacking), True
378
417
            else:
379
 
                return CreateRepository(self), True
 
418
                return CreateRepository(self, stack_on, stack_on_pwd,
 
419
                    require_stacking=require_stacking), True
380
420
 
381
421
        if not force_new_repo:
382
 
            policy = self._find_containing(repository_policy)
383
 
            if policy is not None:
384
 
                return policy
385
 
        return CreateRepository(self)
 
422
            if stack_on is None:
 
423
                policy = self._find_containing(repository_policy)
 
424
                if policy is not None:
 
425
                    return policy
 
426
            else:
 
427
                try:
 
428
                    return UseExistingRepository(self.open_repository(),
 
429
                        stack_on, stack_on_pwd,
 
430
                        require_stacking=require_stacking)
 
431
                except errors.NoRepositoryPresent:
 
432
                    pass
 
433
        return CreateRepository(self, stack_on, stack_on_pwd,
 
434
                                require_stacking=require_stacking)
386
435
 
387
436
    def _find_or_create_repository(self, force_new_repo):
388
437
        """Create a new repository if needed, returning the repository."""
649
698
        guaranteed to point to an existing directory ready for use.
650
699
        """
651
700
        raise NotImplementedError(self.get_workingtree_transport)
652
 
        
 
701
 
 
702
    def get_config(self):
 
703
        if getattr(self, '_get_config', None) is None:
 
704
            return None
 
705
        return self._get_config()
 
706
 
653
707
    def __init__(self, _transport, _format):
654
708
        """Initialize a Bzr control dir object.
655
709
        
1017
1071
            except errors.NoRepositoryPresent:
1018
1072
                source_repository = None
1019
1073
            stacked_branch_url = None
1020
 
        if force_new_repo:
1021
 
            result_repo = None
1022
 
        else:
1023
 
            try:
1024
 
                result_repo = result.find_repository()
1025
 
            except errors.NoRepositoryPresent:
1026
 
                result_repo = None
1027
 
 
1028
 
        # Create/update the result repository as required
1029
 
        if source_repository is None:
1030
 
            if result_repo is None:
1031
 
                # no repo available, make a new one
1032
 
                result.create_repository()
1033
 
        elif stacked_branch_url is not None:
1034
 
            if result_repo is None:
1035
 
                result_repo = source_repository._format.initialize(result)
1036
 
            stacked_dir = BzrDir.open(stacked_branch_url)
1037
 
            try:
1038
 
                stacked_repo = stacked_dir.open_branch().repository
1039
 
            except errors.NotBranchError:
1040
 
                stacked_repo = stacked_dir.open_repository()
1041
 
            result_repo.add_fallback_repository(stacked_repo)
1042
 
            result_repo.fetch(source_repository, revision_id=revision_id)
1043
 
        elif result_repo is None:
1044
 
            # have source, and want to make a new target repo
1045
 
            result_repo = source_repository.sprout(result,
1046
 
                                                   revision_id=revision_id)
1047
 
        else:
1048
 
            # Fetch needed content into target.
1049
 
            # Would rather do it this way ...
1050
 
            # source_repository.copy_content_into(result_repo,
1051
 
            #                                     revision_id=revision_id)
1052
 
            # so we can override the copy method
 
1074
        repository_policy = result.determine_repository_policy(
 
1075
            force_new_repo, stacked_branch_url, require_stacking=stacked)
 
1076
        result_repo = repository_policy.acquire_repository()
 
1077
        if source_repository is not None:
1053
1078
            result_repo.fetch(source_repository, revision_id=revision_id)
1054
1079
 
1055
1080
        # Create/update the result branch
1058
1083
                revision_id=revision_id)
1059
1084
        else:
1060
1085
            result_branch = result.create_branch()
1061
 
        if stacked_branch_url is not None:
1062
 
            result_branch.set_stacked_on(stacked_branch_url)
 
1086
        repository_policy.configure_branch(result_branch)
1063
1087
 
1064
1088
        # Create/update the result working tree
1065
1089
        if isinstance(target_transport, LocalTransport) and (
1122
1146
        """Produce a metadir suitable for cloning with."""
1123
1147
        return self._format.__class__()
1124
1148
 
1125
 
    def clone(self, url, revision_id=None, force_new_repo=False):
1126
 
        """See BzrDir.clone()."""
 
1149
    def clone(self, url, revision_id=None, force_new_repo=False,
 
1150
              preserve_stacking=False):
 
1151
        """See BzrDir.clone().
 
1152
 
 
1153
        force_new_repo has no effect, since this family of formats always
 
1154
        require a new repository.
 
1155
        preserve_stacking has no effect, since no source branch using this
 
1156
        family of formats can be stacked, so there is no stacking to preserve.
 
1157
        """
1127
1158
        from bzrlib.workingtree import WorkingTreeFormat2
1128
1159
        self._make_tail(url)
1129
1160
        result = self._format._initialize_for_clone(url)
1484
1515
            basedir=self.root_transport.base)
1485
1516
        return format.open(self, _found=True)
1486
1517
 
 
1518
    def _get_config(self):
 
1519
        return config.BzrDirConfig(self.transport)
 
1520
 
1487
1521
 
1488
1522
class BzrDirFormat(object):
1489
1523
    """An encapsulation of the initialization and open routines for a format.
2734
2768
    for a branch that is being created.  The most basic policy decision is
2735
2769
    whether to create a new repository or use an existing one.
2736
2770
    """
 
2771
    def __init__(self, stack_on, stack_on_pwd, require_stacking):
 
2772
        """Constructor.
 
2773
 
 
2774
        :param stack_on: A location to stack on
 
2775
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2776
            relative to.
 
2777
        :param require_stacking: If True, it is a failure to not stack.
 
2778
        """
 
2779
        self._stack_on = stack_on
 
2780
        self._stack_on_pwd = stack_on_pwd
 
2781
        self._require_stacking = require_stacking
2737
2782
 
2738
2783
    def configure_branch(self, branch):
2739
2784
        """Apply any configuration data from this policy to the branch.
2740
2785
 
2741
 
        Default implementation does nothing.
 
2786
        Default implementation sets repository stacking.
2742
2787
        """
2743
 
        pass
 
2788
        if self._stack_on is None:
 
2789
            return
 
2790
        if self._stack_on_pwd is None:
 
2791
            stack_on = self._stack_on
 
2792
        else:
 
2793
            try:
 
2794
                stack_on = urlutils.rebase_url(self._stack_on,
 
2795
                    self._stack_on_pwd,
 
2796
                    branch.bzrdir.root_transport.base)
 
2797
            except errors.InvalidRebaseURLs:
 
2798
                stack_on = self._get_full_stack_on()
 
2799
        try:
 
2800
            branch.set_stacked_on_url(stack_on)
 
2801
        except errors.UnstackableBranchFormat:
 
2802
            if self._require_stacking:
 
2803
                raise
 
2804
 
 
2805
    def _get_full_stack_on(self):
 
2806
        """Get a fully-qualified URL for the stack_on location."""
 
2807
        if self._stack_on is None:
 
2808
            return None
 
2809
        if self._stack_on_pwd is None:
 
2810
            return self._stack_on
 
2811
        else:
 
2812
            return urlutils.join(self._stack_on_pwd, self._stack_on)
 
2813
 
 
2814
    def _add_fallback(self, repository):
 
2815
        """Add a fallback to the supplied repository, if stacking is set."""
 
2816
        stack_on = self._get_full_stack_on()
 
2817
        if stack_on is None:
 
2818
            return
 
2819
        stacked_dir = BzrDir.open(stack_on)
 
2820
        try:
 
2821
            stacked_repo = stacked_dir.open_branch().repository
 
2822
        except errors.NotBranchError:
 
2823
            stacked_repo = stacked_dir.open_repository()
 
2824
        try:
 
2825
            repository.add_fallback_repository(stacked_repo)
 
2826
        except errors.UnstackableRepositoryFormat:
 
2827
            if self._require_stacking:
 
2828
                raise
2744
2829
 
2745
2830
    def acquire_repository(self, make_working_trees=None, shared=False):
2746
2831
        """Acquire a repository for this bzrdir.
2758
2843
class CreateRepository(RepositoryAcquisitionPolicy):
2759
2844
    """A policy of creating a new repository"""
2760
2845
 
2761
 
    def __init__(self, bzrdir):
2762
 
        RepositoryAcquisitionPolicy.__init__(self)
 
2846
    def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
 
2847
                 require_stacking=False):
 
2848
        """
 
2849
        Constructor.
 
2850
        :param bzrdir: The bzrdir to create the repository on.
 
2851
        :param stack_on: A location to stack on
 
2852
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2853
            relative to.
 
2854
        """
 
2855
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
 
2856
                                             require_stacking)
2763
2857
        self._bzrdir = bzrdir
2764
2858
 
2765
2859
    def acquire_repository(self, make_working_trees=None, shared=False):
2768
2862
        Creates the desired repository in the bzrdir we already have.
2769
2863
        """
2770
2864
        repository = self._bzrdir.create_repository(shared=shared)
 
2865
        self._add_fallback(repository)
2771
2866
        if make_working_trees is not None:
2772
2867
            repository.set_make_working_trees(make_working_trees)
2773
2868
        return repository
2776
2871
class UseExistingRepository(RepositoryAcquisitionPolicy):
2777
2872
    """A policy of reusing an existing repository"""
2778
2873
 
2779
 
    def __init__(self, repository):
2780
 
        RepositoryAcquisitionPolicy.__init__(self)
 
2874
    def __init__(self, repository, stack_on=None, stack_on_pwd=None,
 
2875
                 require_stacking=False):
 
2876
        """Constructor.
 
2877
 
 
2878
        :param repository: The repository to use.
 
2879
        :param stack_on: A location to stack on
 
2880
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2881
            relative to.
 
2882
        """
 
2883
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
 
2884
                                             require_stacking)
2781
2885
        self._repository = repository
2782
2886
 
2783
2887
    def acquire_repository(self, make_working_trees=None, shared=False):
2785
2889
 
2786
2890
        Returns an existing repository to use
2787
2891
        """
 
2892
        self._add_fallback(self._repository)
2788
2893
        return self._repository
2789
2894
 
2790
2895