~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
180
180
                               even if one is available.
181
181
        """
182
182
        transport.ensure_base()
183
 
        result = self._format.initialize_on_transport(transport)
 
183
        result = self.cloning_metadir().initialize_on_transport(transport)
 
184
        repository_policy = None
184
185
        try:
185
186
            local_repo = self.find_repository()
186
187
        except errors.NoRepositoryPresent:
187
188
            local_repo = None
188
189
        if local_repo:
189
190
            # may need to copy content in
190
 
            if force_new_repo:
191
 
                result_repo = local_repo.clone(
192
 
                    result,
193
 
                    revision_id=revision_id)
194
 
                result_repo.set_make_working_trees(local_repo.make_working_trees())
195
 
            else:
196
 
                try:
197
 
                    result_repo = result.find_repository()
198
 
                    # fetch content this dir needs.
199
 
                    result_repo.fetch(local_repo, revision_id=revision_id)
200
 
                except errors.NoRepositoryPresent:
201
 
                    # needed to make one anyway.
202
 
                    result_repo = local_repo.clone(
203
 
                        result,
204
 
                        revision_id=revision_id)
205
 
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
 
191
            repository_policy = result.determine_repository_policy(
 
192
                force_new_repo)
 
193
            make_working_trees = local_repo.make_working_trees()
 
194
            result_repo = repository_policy.acquire_repository(
 
195
                make_working_trees, local_repo.is_shared())
 
196
            result_repo.fetch(local_repo, revision_id=revision_id)
206
197
        # 1 if there is a branch present
207
198
        #   make sure its content is available in the target repository
208
199
        #   clone it.
209
200
        try:
210
 
            self.open_branch().clone(result, revision_id=revision_id)
 
201
            local_branch = self.open_branch()
211
202
        except errors.NotBranchError:
212
203
            pass
 
204
        else:
 
205
            result_branch = local_branch.clone(result, revision_id=revision_id)
 
206
            if repository_policy is not None:
 
207
                repository_policy.configure_branch(result_branch)
213
208
        try:
214
209
            result_repo = result.find_repository()
215
210
        except errors.NoRepositoryPresent:
356
351
        bzrdir._find_or_create_repository(force_new_repo)
357
352
        return bzrdir.create_branch()
358
353
 
 
354
    def determine_repository_policy(self, force_new_repo=False):
 
355
        """Return an object representing a policy to use.
 
356
 
 
357
        This controls whether a new repository is created, or a shared
 
358
        repository used instead.
 
359
        """
 
360
        def repository_policy(found_bzrdir):
 
361
            stop = False
 
362
            # does it have a repository ?
 
363
            try:
 
364
                repository = found_bzrdir.open_repository()
 
365
            except errors.NoRepositoryPresent:
 
366
                repository = None
 
367
            else:
 
368
                if ((found_bzrdir.root_transport.base !=
 
369
                     self.root_transport.base) and not repository.is_shared()):
 
370
                    repository = None
 
371
                else:
 
372
                    stop = True
 
373
            if not stop:
 
374
                return None, False
 
375
            if repository:
 
376
                return UseExistingRepository(repository), True
 
377
            else:
 
378
                return CreateRepository(self), True
 
379
 
 
380
        if not force_new_repo:
 
381
            policy = self._find_containing(repository_policy)
 
382
            if policy is not None:
 
383
                return policy
 
384
        return CreateRepository(self)
 
385
 
359
386
    def _find_or_create_repository(self, force_new_repo):
360
387
        """Create a new repository if needed, returning the repository."""
361
 
        if force_new_repo:
362
 
            return self.create_repository()
363
 
        try:
364
 
            return self.find_repository()
365
 
        except errors.NoRepositoryPresent:
366
 
            return self.create_repository()
367
 
        
 
388
        policy = self.determine_repository_policy(force_new_repo)
 
389
        return policy.acquire_repository()
 
390
 
368
391
    @staticmethod
369
392
    def create_branch_convenience(base, force_new_repo=False,
370
393
                                  force_new_tree=None, format=None,
508
531
        """
509
532
        raise NotImplementedError(self.destroy_workingtree_metadata)
510
533
 
 
534
    def _find_containing(self, evaluate):
 
535
        """Find something in a containing control directory.
 
536
 
 
537
        This method will scan containing control dirs, until it finds what
 
538
        it is looking for, decides that it will never find it, or runs out
 
539
        of containing control directories to check.
 
540
 
 
541
        It is used to implement find_repository and
 
542
        determine_repository_policy.
 
543
 
 
544
        :param evaluate: A function returning (value, stop).  If stop is True,
 
545
            the value will be returned.
 
546
        """
 
547
        found_bzrdir = self
 
548
        while True:
 
549
            result, stop = evaluate(found_bzrdir)
 
550
            if stop:
 
551
                return result
 
552
            next_transport = found_bzrdir.root_transport.clone('..')
 
553
            if (found_bzrdir.root_transport.base == next_transport.base):
 
554
                # top of the file system
 
555
                return None
 
556
            # find the next containing bzrdir
 
557
            try:
 
558
                found_bzrdir = BzrDir.open_containing_from_transport(
 
559
                    next_transport)[0]
 
560
            except errors.NotBranchError:
 
561
                return None
 
562
 
511
563
    def find_repository(self):
512
564
        """Find the repository that should be used.
513
565
 
515
567
        new branches as well as to hook existing branches up to their
516
568
        repository.
517
569
        """
518
 
        try:
519
 
            return self.open_repository()
520
 
        except errors.NoRepositoryPresent:
521
 
            pass
522
 
        next_transport = self.root_transport.clone('..')
523
 
        while True:
524
 
            # find the next containing bzrdir
525
 
            try:
526
 
                found_bzrdir = BzrDir.open_containing_from_transport(
527
 
                    next_transport)[0]
528
 
            except errors.NotBranchError:
529
 
                # none found
530
 
                raise errors.NoRepositoryPresent(self)
 
570
        def usable_repository(found_bzrdir):
531
571
            # does it have a repository ?
532
572
            try:
533
573
                repository = found_bzrdir.open_repository()
534
574
            except errors.NoRepositoryPresent:
535
 
                next_transport = found_bzrdir.root_transport.clone('..')
536
 
                if (found_bzrdir.root_transport.base == next_transport.base):
537
 
                    # top of the file system
538
 
                    break
539
 
                else:
540
 
                    continue
541
 
            if ((found_bzrdir.root_transport.base ==
542
 
                 self.root_transport.base) or repository.is_shared()):
543
 
                return repository
 
575
                return None, False
 
576
            if found_bzrdir.root_transport.base == self.root_transport.base:
 
577
                return repository, True
 
578
            elif repository.is_shared():
 
579
                return repository, True
544
580
            else:
545
 
                raise errors.NoRepositoryPresent(self)
546
 
        raise errors.NoRepositoryPresent(self)
 
581
                return None, True
 
582
 
 
583
        found_repo = self._find_containing(usable_repository)
 
584
        if found_repo is None:
 
585
            raise errors.NoRepositoryPresent(self)
 
586
        return found_repo
547
587
 
548
588
    def get_branch_reference(self):
549
589
        """Return the referenced URL for the branch in this bzrdir.
1010
1050
        """Pre-splitout bzrdirs do not suffer from stale locks."""
1011
1051
        raise NotImplementedError(self.break_lock)
1012
1052
 
 
1053
    def cloning_metadir(self):
 
1054
        """Produce a metadir suitable for cloning with."""
 
1055
        return self._format.__class__()
 
1056
 
1013
1057
    def clone(self, url, revision_id=None, force_new_repo=False):
1014
1058
        """See BzrDir.clone()."""
1015
1059
        from bzrlib.workingtree import WorkingTreeFormat2
2415
2459
    def initialize_on_transport(self, transport):
2416
2460
        try:
2417
2461
            # hand off the request to the smart server
2418
 
            shared_medium = transport.get_shared_medium()
 
2462
            client_medium = transport.get_smart_medium()
2419
2463
        except errors.NoSmartMedium:
2420
2464
            # TODO: lookup the local format from a server hint.
2421
2465
            local_dir_format = BzrDirMetaFormat1()
2422
2466
            return local_dir_format.initialize_on_transport(transport)
2423
 
        client = _SmartClient(shared_medium)
 
2467
        client = _SmartClient(client_medium, transport.base)
2424
2468
        path = client.remote_path_from_transport(transport)
2425
 
        response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
2426
 
                                                    path)
 
2469
        response = client.call('BzrDirFormat.initialize', path)
2427
2470
        assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2428
2471
        return remote.RemoteBzrDir(transport)
2429
2472
 
2610
2653
        return output
2611
2654
 
2612
2655
 
 
2656
class RepositoryAcquisitionPolicy(object):
 
2657
    """Abstract base class for repository acquisition policies.
 
2658
 
 
2659
    A repository acquisition policy decides how a BzrDir acquires a repository
 
2660
    for a branch that is being created.  The most basic policy decision is
 
2661
    whether to create a new repository or use an existing one.
 
2662
    """
 
2663
 
 
2664
    def configure_branch(self, branch):
 
2665
        """Apply any configuration data from this policy to the branch.
 
2666
 
 
2667
        Default implementation does nothing.
 
2668
        """
 
2669
        pass
 
2670
 
 
2671
    def acquire_repository(self, make_working_trees=None, shared=False):
 
2672
        """Acquire a repository for this bzrdir.
 
2673
 
 
2674
        Implementations may create a new repository or use a pre-exising
 
2675
        repository.
 
2676
        :param make_working_trees: If creating a repository, set
 
2677
            make_working_trees to this value (if non-None)
 
2678
        :param shared: If creating a repository, make it shared if True
 
2679
        :return: A repository
 
2680
        """
 
2681
        raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
 
2682
 
 
2683
 
 
2684
class CreateRepository(RepositoryAcquisitionPolicy):
 
2685
    """A policy of creating a new repository"""
 
2686
 
 
2687
    def __init__(self, bzrdir):
 
2688
        RepositoryAcquisitionPolicy.__init__(self)
 
2689
        self._bzrdir = bzrdir
 
2690
 
 
2691
    def acquire_repository(self, make_working_trees=None, shared=False):
 
2692
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
 
2693
 
 
2694
        Creates the desired repository in the bzrdir we already have.
 
2695
        """
 
2696
        repository = self._bzrdir.create_repository(shared=shared)
 
2697
        if make_working_trees is not None:
 
2698
            repository.set_make_working_trees(make_working_trees)
 
2699
        return repository
 
2700
 
 
2701
 
 
2702
class UseExistingRepository(RepositoryAcquisitionPolicy):
 
2703
    """A policy of reusing an existing repository"""
 
2704
 
 
2705
    def __init__(self, repository):
 
2706
        RepositoryAcquisitionPolicy.__init__(self)
 
2707
        self._repository = repository
 
2708
 
 
2709
    def acquire_repository(self, make_working_trees=None, shared=False):
 
2710
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
 
2711
 
 
2712
        Returns an existing repository to use
 
2713
        """
 
2714
        return self._repository
 
2715
 
 
2716
 
2613
2717
format_registry = BzrDirFormatRegistry()
2614
2718
format_registry.register('weave', BzrDirFormat6,
2615
2719
    'Pre-0.8 format.  Slower than knit and does not'