~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-11-08 13:45:51 UTC
  • mfrom: (5532.1.1 trunk)
  • Revision ID: pqm@pqm.ubuntu.com-20101108134551-sxvk77ehmegkrwmm
(vila) Fix news entry

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2010, 2011 Canonical Ltd
 
1
# Copyright (C) 2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
27
27
import textwrap
28
28
 
29
29
from bzrlib import (
30
 
    cleanup,
31
30
    errors,
32
 
    fetch,
33
31
    graph,
 
32
    registry,
34
33
    revision as _mod_revision,
35
 
    transport as _mod_transport,
 
34
    symbol_versioning,
36
35
    urlutils,
37
36
    )
38
37
from bzrlib.push import (
42
41
    mutter,
43
42
    )
44
43
from bzrlib.transport import (
 
44
    get_transport,
45
45
    local,
46
46
    )
47
47
 
48
48
""")
49
49
 
50
 
from bzrlib import registry
51
 
 
52
50
 
53
51
class ControlComponent(object):
54
52
    """Abstract base class for control directory components.
145
143
        """Destroy the repository in this ControlDir."""
146
144
        raise NotImplementedError(self.destroy_repository)
147
145
 
148
 
    def create_branch(self, name=None, repository=None):
 
146
    def create_branch(self, name=None):
149
147
        """Create a branch in this ControlDir.
150
148
 
151
149
        :param name: Name of the colocated branch to create, None for
366
364
        :param create_tree_if_local: If true, a working-tree will be created
367
365
            when working locally.
368
366
        """
369
 
        operation = cleanup.OperationWithCleanups(self._sprout)
370
 
        return operation.run(url, revision_id=revision_id,
371
 
            force_new_repo=force_new_repo, recurse=recurse,
372
 
            possible_transports=possible_transports,
373
 
            accelerator_tree=accelerator_tree, hardlink=hardlink,
374
 
            stacked=stacked, source_branch=source_branch,
375
 
            create_tree_if_local=create_tree_if_local)
376
 
 
377
 
    def _sprout(self, op, url, revision_id=None, force_new_repo=False,
378
 
               recurse='down', possible_transports=None,
379
 
               accelerator_tree=None, hardlink=False, stacked=False,
380
 
               source_branch=None, create_tree_if_local=True):
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
386
 
        target_transport = _mod_transport.get_transport(url,
387
 
            possible_transports)
 
367
        target_transport = get_transport(url, possible_transports)
388
368
        target_transport.ensure_base()
389
369
        cloning_format = self.cloning_metadir(stacked)
390
370
        # Create/update the result branch
391
371
        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
395
372
        # if a stacked branch wasn't requested, we don't create one
396
373
        # even if the origin was stacked
397
 
        if stacked and source_branch is not None:
398
 
            stacked_branch_url = self.root_transport.base
 
374
        stacked_branch_url = None
 
375
        if source_branch is not None:
 
376
            if stacked:
 
377
                stacked_branch_url = self.root_transport.base
 
378
            source_repository = source_branch.repository
399
379
        else:
400
 
            stacked_branch_url = None
 
380
            try:
 
381
                source_branch = self.open_branch()
 
382
                source_repository = source_branch.repository
 
383
                if stacked:
 
384
                    stacked_branch_url = self.root_transport.base
 
385
            except errors.NotBranchError:
 
386
                source_branch = None
 
387
                try:
 
388
                    source_repository = self.open_repository()
 
389
                except errors.NoRepositoryPresent:
 
390
                    source_repository = None
401
391
        repository_policy = result.determine_repository_policy(
402
392
            force_new_repo, stacked_branch_url, require_stacking=stacked)
403
393
        result_repo, is_new_repo = repository_policy.acquire_repository()
404
 
        add_cleanup(result_repo.lock_write().unlock)
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
 
394
        is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
 
395
        if is_new_repo and revision_id is not None and not is_stacked:
 
396
            fetch_spec = graph.PendingAncestryResult(
 
397
                [revision_id], source_repository)
411
398
        else:
412
 
            target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
413
 
        fetch_spec_factory.target_repo_kind = target_repo_kind
 
399
            fetch_spec = None
414
400
        if source_repository is not None:
415
 
            fetch_spec = fetch_spec_factory.make_fetch_spec()
416
 
            result_repo.fetch(source_repository, fetch_spec=fetch_spec)
 
401
            # Fetch while stacked to prevent unstacked fetch from
 
402
            # Branch.sprout.
 
403
            if fetch_spec is None:
 
404
                result_repo.fetch(source_repository, revision_id=revision_id)
 
405
            else:
 
406
                result_repo.fetch(source_repository, fetch_spec=fetch_spec)
417
407
 
418
408
        if source_branch is None:
419
409
            # this is for sprouting a controldir without a branch; is that
422
412
            result_branch = result.create_branch()
423
413
        else:
424
414
            result_branch = source_branch.sprout(result,
425
 
                revision_id=revision_id, repository_policy=repository_policy,
426
 
                repository=result_repo)
 
415
                revision_id=revision_id, repository_policy=repository_policy)
427
416
        mutter("created new branch %r" % (result_branch,))
428
417
 
429
418
        # Create/update the result working tree
431
420
            isinstance(target_transport, local.LocalTransport) and
432
421
            (result_repo is None or result_repo.make_working_trees())):
433
422
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
434
 
                hardlink=hardlink, from_branch=result_branch)
 
423
                hardlink=hardlink)
435
424
            wt.lock_write()
436
425
            try:
437
426
                if wt.path2id('') is None:
444
433
        else:
445
434
            wt = None
446
435
        if recurse == 'down':
447
 
            basis = None
448
436
            if wt is not None:
449
437
                basis = wt.basis_tree()
 
438
                basis.lock_read()
 
439
                subtrees = basis.iter_references()
450
440
            elif result_branch is not None:
451
441
                basis = result_branch.basis_tree()
 
442
                basis.lock_read()
 
443
                subtrees = basis.iter_references()
452
444
            elif source_branch is not None:
453
445
                basis = source_branch.basis_tree()
454
 
            if basis is not None:
455
 
                add_cleanup(basis.lock_read().unlock)
 
446
                basis.lock_read()
456
447
                subtrees = basis.iter_references()
457
448
            else:
458
449
                subtrees = []
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)
 
450
                basis = None
 
451
            try:
 
452
                for path, file_id in subtrees:
 
453
                    target = urlutils.join(url, urlutils.escape(path))
 
454
                    sublocation = source_branch.reference_parent(file_id, path)
 
455
                    sublocation.bzrdir.sprout(target,
 
456
                        basis.get_reference_revision(file_id, path),
 
457
                        force_new_repo=force_new_repo, recurse=recurse,
 
458
                        stacked=stacked)
 
459
            finally:
 
460
                if basis is not None:
 
461
                    basis.unlock()
466
462
        return result
467
463
 
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
 
 
495
464
    def push_branch(self, source, revision_id=None, overwrite=False, 
496
465
        remember=False, create_prefix=False):
497
466
        """Push the source branch into this ControlDir."""
595
564
        :param preserve_stacking: When cloning a stacked branch, stack the
596
565
            new branch on top of the other branch's stacked-on branch.
597
566
        """
598
 
        return self.clone_on_transport(_mod_transport.get_transport(url),
 
567
        return self.clone_on_transport(get_transport(url),
599
568
                                       revision_id=revision_id,
600
569
                                       force_new_repo=force_new_repo,
601
570
                                       preserve_stacking=preserve_stacking)
602
571
 
603
572
    def clone_on_transport(self, transport, revision_id=None,
604
573
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
605
 
        create_prefix=False, use_existing_dir=True, no_tree=False):
 
574
        create_prefix=False, use_existing_dir=True):
606
575
        """Clone this bzrdir and its contents to transport verbatim.
607
576
 
608
577
        :param transport: The transport for the location to produce the clone
617
586
        :param create_prefix: Create any missing directories leading up to
618
587
            to_transport.
619
588
        :param use_existing_dir: Use an existing directory if one exists.
620
 
        :param no_tree: If set to true prevents creation of a working tree.
621
589
        """
622
590
        raise NotImplementedError(self.clone_on_transport)
623
591
 
773
741
        Subclasses should typically override initialize_on_transport
774
742
        instead of this method.
775
743
        """
776
 
        return self.initialize_on_transport(
777
 
            _mod_transport.get_transport(url, possible_transports))
778
 
 
 
744
        return self.initialize_on_transport(get_transport(url,
 
745
                                                          possible_transports))
779
746
    def initialize_on_transport(self, transport):
780
747
        """Initialize a new controldir in the base directory of a Transport."""
781
748
        raise NotImplementedError(self.initialize_on_transport)