~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

(spiv) Fetch tagged revisions (not just tags) during branch,
 merge and pull. (Andrew Bennetts)

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
from bzrlib import (
30
30
    cleanup,
31
31
    errors,
 
32
    fetch,
32
33
    graph,
33
34
    revision as _mod_revision,
34
35
    transport as _mod_transport,
378
379
               accelerator_tree=None, hardlink=False, stacked=False,
379
380
               source_branch=None, create_tree_if_local=True):
380
381
        add_cleanup = op.add_cleanup
 
382
        fetch_spec_factory = fetch.FetchSpecFactory()
 
383
        if revision_id is not None:
 
384
            fetch_spec_factory.add_revision_ids([revision_id])
 
385
            fetch_spec_factory.source_branch_stop_revision_id = revision_id
381
386
        target_transport = _mod_transport.get_transport(url,
382
387
            possible_transports)
383
388
        target_transport.ensure_base()
384
389
        cloning_format = self.cloning_metadir(stacked)
385
390
        # Create/update the result branch
386
391
        result = cloning_format.initialize_on_transport(target_transport)
 
392
        source_branch, source_repository = self._find_source_repo(
 
393
            add_cleanup, source_branch)
 
394
        fetch_spec_factory.source_branch = source_branch
387
395
        # if a stacked branch wasn't requested, we don't create one
388
396
        # even if the origin was stacked
389
 
        stacked_branch_url = None
390
 
        if source_branch is not None:
391
 
            add_cleanup(source_branch.lock_read().unlock)
392
 
            if stacked:
393
 
                stacked_branch_url = self.root_transport.base
394
 
            source_repository = source_branch.repository
 
397
        if stacked and source_branch is not None:
 
398
            stacked_branch_url = self.root_transport.base
395
399
        else:
396
 
            try:
397
 
                source_branch = self.open_branch()
398
 
                source_repository = source_branch.repository
399
 
                if stacked:
400
 
                    stacked_branch_url = self.root_transport.base
401
 
            except errors.NotBranchError:
402
 
                source_branch = None
403
 
                try:
404
 
                    source_repository = self.open_repository()
405
 
                except errors.NoRepositoryPresent:
406
 
                    source_repository = None
407
 
                else:
408
 
                    add_cleanup(source_repository.lock_read().unlock)
409
 
            else:
410
 
                add_cleanup(source_branch.lock_read().unlock)
 
400
            stacked_branch_url = None
411
401
        repository_policy = result.determine_repository_policy(
412
402
            force_new_repo, stacked_branch_url, require_stacking=stacked)
413
403
        result_repo, is_new_repo = repository_policy.acquire_repository()
414
404
        add_cleanup(result_repo.lock_write().unlock)
415
 
        is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
416
 
        if is_new_repo and revision_id is not None and not is_stacked:
417
 
            fetch_spec = graph.PendingAncestryResult(
418
 
                [revision_id], source_repository)
 
405
        fetch_spec_factory.source_repo = source_repository
 
406
        fetch_spec_factory.target_repo = result_repo
 
407
        if stacked or (len(result_repo._fallback_repositories) != 0):
 
408
            target_repo_kind = fetch.TargetRepoKinds.STACKED
 
409
        elif is_new_repo:
 
410
            target_repo_kind = fetch.TargetRepoKinds.EMPTY
419
411
        else:
420
 
            fetch_spec = None
 
412
            target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
 
413
        fetch_spec_factory.target_repo_kind = target_repo_kind
421
414
        if source_repository is not None:
422
 
            # Fetch while stacked to prevent unstacked fetch from
423
 
            # Branch.sprout.
424
 
            if fetch_spec is None:
425
 
                result_repo.fetch(source_repository, revision_id=revision_id)
426
 
            else:
427
 
                result_repo.fetch(source_repository, fetch_spec=fetch_spec)
 
415
            fetch_spec = fetch_spec_factory.make_fetch_spec()
 
416
            result_repo.fetch(source_repository, fetch_spec=fetch_spec)
428
417
 
429
418
        if source_branch is None:
430
419
            # this is for sprouting a controldir without a branch; is that
455
444
        else:
456
445
            wt = None
457
446
        if recurse == 'down':
 
447
            basis = None
458
448
            if wt is not None:
459
449
                basis = wt.basis_tree()
460
 
                basis.lock_read()
461
 
                subtrees = basis.iter_references()
462
450
            elif result_branch is not None:
463
451
                basis = result_branch.basis_tree()
464
 
                basis.lock_read()
465
 
                subtrees = basis.iter_references()
466
452
            elif source_branch is not None:
467
453
                basis = source_branch.basis_tree()
468
 
                basis.lock_read()
 
454
            if basis is not None:
 
455
                add_cleanup(basis.lock_read().unlock)
469
456
                subtrees = basis.iter_references()
470
457
            else:
471
458
                subtrees = []
472
 
                basis = None
473
 
            try:
474
 
                for path, file_id in subtrees:
475
 
                    target = urlutils.join(url, urlutils.escape(path))
476
 
                    sublocation = source_branch.reference_parent(file_id, path)
477
 
                    sublocation.bzrdir.sprout(target,
478
 
                        basis.get_reference_revision(file_id, path),
479
 
                        force_new_repo=force_new_repo, recurse=recurse,
480
 
                        stacked=stacked)
481
 
            finally:
482
 
                if basis is not None:
483
 
                    basis.unlock()
 
459
            for path, file_id in subtrees:
 
460
                target = urlutils.join(url, urlutils.escape(path))
 
461
                sublocation = source_branch.reference_parent(file_id, path)
 
462
                sublocation.bzrdir.sprout(target,
 
463
                    basis.get_reference_revision(file_id, path),
 
464
                    force_new_repo=force_new_repo, recurse=recurse,
 
465
                    stacked=stacked)
484
466
        return result
485
467
 
 
468
    def _find_source_repo(self, add_cleanup, source_branch):
 
469
        """Find the source branch and repo for a sprout operation.
 
470
        
 
471
        This is helper intended for use by _sprout.
 
472
 
 
473
        :returns: (source_branch, source_repository).  Either or both may be
 
474
            None.  If not None, they will be read-locked (and their unlock(s)
 
475
            scheduled via the add_cleanup param).
 
476
        """
 
477
        if source_branch is not None:
 
478
            add_cleanup(source_branch.lock_read().unlock)
 
479
            return source_branch, source_branch.repository
 
480
        try:
 
481
            source_branch = self.open_branch()
 
482
            source_repository = source_branch.repository
 
483
        except errors.NotBranchError:
 
484
            source_branch = None
 
485
            try:
 
486
                source_repository = self.open_repository()
 
487
            except errors.NoRepositoryPresent:
 
488
                source_repository = None
 
489
            else:
 
490
                add_cleanup(source_repository.lock_read().unlock)
 
491
        else:
 
492
            add_cleanup(source_branch.lock_read().unlock)
 
493
        return source_branch, source_repository
 
494
 
486
495
    def push_branch(self, source, revision_id=None, overwrite=False, 
487
496
        remember=False, create_prefix=False):
488
497
        """Push the source branch into this ControlDir."""