~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

  • Committer: Andrew Bennetts
  • Date: 2011-04-08 03:31:54 UTC
  • mfrom: (5766 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5767.
  • Revision ID: andrew.bennetts@canonical.com-20110408033154-la08nghd4391sw5m
Merge latest lp:bzr, move our new release notes entries to the current release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
import textwrap
28
28
 
29
29
from bzrlib import (
30
 
    cleanup,
31
30
    errors,
32
 
    fetch,
33
31
    revision as _mod_revision,
34
32
    transport as _mod_transport,
35
 
    urlutils,
 
33
    ui,
36
34
    )
37
35
from bzrlib.push import (
38
36
    PushResult,
39
37
    )
40
 
from bzrlib.trace import (
41
 
    mutter,
42
 
    )
43
 
from bzrlib.transport import (
44
 
    local,
45
 
    )
46
38
 
47
39
""")
48
40
 
82
74
        return self.user_transport.base
83
75
 
84
76
 
 
77
 
85
78
class ControlDir(ControlComponent):
86
79
    """A control directory.
87
80
 
334
327
        :param create_tree_if_local: If true, a working-tree will be created
335
328
            when working locally.
336
329
        """
337
 
        operation = cleanup.OperationWithCleanups(self._sprout)
338
 
        return operation.run(url, revision_id=revision_id,
339
 
            force_new_repo=force_new_repo, recurse=recurse,
340
 
            possible_transports=possible_transports,
341
 
            accelerator_tree=accelerator_tree, hardlink=hardlink,
342
 
            stacked=stacked, source_branch=source_branch,
343
 
            create_tree_if_local=create_tree_if_local)
344
 
 
345
 
    def _sprout(self, op, url, revision_id=None, force_new_repo=False,
346
 
               recurse='down', possible_transports=None,
347
 
               accelerator_tree=None, hardlink=False, stacked=False,
348
 
               source_branch=None, create_tree_if_local=True):
349
 
        add_cleanup = op.add_cleanup
350
 
        fetch_spec_factory = fetch.FetchSpecFactory()
351
 
        if revision_id is not None:
352
 
            fetch_spec_factory.add_revision_ids([revision_id])
353
 
            fetch_spec_factory.source_branch_stop_revision_id = revision_id
354
 
        target_transport = _mod_transport.get_transport(url,
355
 
            possible_transports)
356
 
        target_transport.ensure_base()
357
 
        cloning_format = self.cloning_metadir(stacked)
358
 
        # Create/update the result branch
359
 
        result = cloning_format.initialize_on_transport(target_transport)
360
 
        source_branch, source_repository = self._find_source_repo(
361
 
            add_cleanup, source_branch)
362
 
        fetch_spec_factory.source_branch = source_branch
363
 
        # if a stacked branch wasn't requested, we don't create one
364
 
        # even if the origin was stacked
365
 
        if stacked and source_branch is not None:
366
 
            stacked_branch_url = self.root_transport.base
367
 
        else:
368
 
            stacked_branch_url = None
369
 
        repository_policy = result.determine_repository_policy(
370
 
            force_new_repo, stacked_branch_url, require_stacking=stacked)
371
 
        result_repo, is_new_repo = repository_policy.acquire_repository()
372
 
        add_cleanup(result_repo.lock_write().unlock)
373
 
        fetch_spec_factory.source_repo = source_repository
374
 
        fetch_spec_factory.target_repo = result_repo
375
 
        if stacked or (len(result_repo._fallback_repositories) != 0):
376
 
            target_repo_kind = fetch.TargetRepoKinds.STACKED
377
 
        elif is_new_repo:
378
 
            target_repo_kind = fetch.TargetRepoKinds.EMPTY
379
 
        else:
380
 
            target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
381
 
        fetch_spec_factory.target_repo_kind = target_repo_kind
382
 
        if source_repository is not None:
383
 
            fetch_spec = fetch_spec_factory.make_fetch_spec()
384
 
            result_repo.fetch(source_repository, fetch_spec=fetch_spec)
385
 
 
386
 
        if source_branch is None:
387
 
            # this is for sprouting a controldir without a branch; is that
388
 
            # actually useful?
389
 
            # Not especially, but it's part of the contract.
390
 
            result_branch = result.create_branch()
391
 
        else:
392
 
            result_branch = source_branch.sprout(result,
393
 
                revision_id=revision_id, repository_policy=repository_policy,
394
 
                repository=result_repo)
395
 
        mutter("created new branch %r" % (result_branch,))
396
 
 
397
 
        # Create/update the result working tree
398
 
        if (create_tree_if_local and
399
 
            isinstance(target_transport, local.LocalTransport) and
400
 
            (result_repo is None or result_repo.make_working_trees())):
401
 
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
402
 
                hardlink=hardlink, from_branch=result_branch)
403
 
            wt.lock_write()
404
 
            try:
405
 
                if wt.path2id('') is None:
406
 
                    try:
407
 
                        wt.set_root_id(self.open_workingtree.get_root_id())
408
 
                    except errors.NoWorkingTree:
409
 
                        pass
410
 
            finally:
411
 
                wt.unlock()
412
 
        else:
413
 
            wt = None
414
 
        if recurse == 'down':
415
 
            basis = None
416
 
            if wt is not None:
417
 
                basis = wt.basis_tree()
418
 
            elif result_branch is not None:
419
 
                basis = result_branch.basis_tree()
420
 
            elif source_branch is not None:
421
 
                basis = source_branch.basis_tree()
422
 
            if basis is not None:
423
 
                add_cleanup(basis.lock_read().unlock)
424
 
                subtrees = basis.iter_references()
425
 
            else:
426
 
                subtrees = []
427
 
            for path, file_id in subtrees:
428
 
                target = urlutils.join(url, urlutils.escape(path))
429
 
                sublocation = source_branch.reference_parent(file_id, path)
430
 
                sublocation.bzrdir.sprout(target,
431
 
                    basis.get_reference_revision(file_id, path),
432
 
                    force_new_repo=force_new_repo, recurse=recurse,
433
 
                    stacked=stacked)
434
 
        return result
435
 
 
436
 
    def _find_source_repo(self, add_cleanup, source_branch):
437
 
        """Find the source branch and repo for a sprout operation.
438
 
        
439
 
        This is helper intended for use by _sprout.
440
 
 
441
 
        :returns: (source_branch, source_repository).  Either or both may be
442
 
            None.  If not None, they will be read-locked (and their unlock(s)
443
 
            scheduled via the add_cleanup param).
444
 
        """
445
 
        if source_branch is not None:
446
 
            add_cleanup(source_branch.lock_read().unlock)
447
 
            return source_branch, source_branch.repository
448
 
        try:
449
 
            source_branch = self.open_branch()
450
 
            source_repository = source_branch.repository
451
 
        except errors.NotBranchError:
452
 
            source_branch = None
453
 
            try:
454
 
                source_repository = self.open_repository()
455
 
            except errors.NoRepositoryPresent:
456
 
                source_repository = None
457
 
            else:
458
 
                add_cleanup(source_repository.lock_read().unlock)
459
 
        else:
460
 
            add_cleanup(source_branch.lock_read().unlock)
461
 
        return source_branch, source_repository
 
330
        raise NotImplementedError(self.sprout)
462
331
 
463
332
    def push_branch(self, source, revision_id=None, overwrite=False, 
464
333
        remember=False, create_prefix=False):
480
349
        if br_to is None:
481
350
            # We have a repository but no branch, copy the revisions, and then
482
351
            # create a branch.
 
352
            if revision_id is None:
 
353
                # No revision supplied by the user, default to the branch
 
354
                # revision
 
355
                revision_id = source.last_revision()
483
356
            repository_to.fetch(source.repository, revision_id=revision_id)
484
357
            br_to = source.clone(self, revision_id=revision_id)
485
358
            if source.get_push_location() is None or remember:
593
466
class ControlComponentFormat(object):
594
467
    """A component that can live inside of a .bzr meta directory."""
595
468
 
 
469
    upgrade_recommended = False
 
470
 
596
471
    def get_format_string(self):
597
472
        """Return the format of this format, if usable in meta directories."""
598
473
        raise NotImplementedError(self.get_format_string)
601
476
        """Return the short description for this format."""
602
477
        raise NotImplementedError(self.get_format_description)
603
478
 
 
479
    def is_supported(self):
 
480
        """Is this format supported?
 
481
 
 
482
        Supported formats must be initializable and openable.
 
483
        Unsupported formats may not support initialization or committing or
 
484
        some other features depending on the reason for not being supported.
 
485
        """
 
486
        return True
 
487
 
 
488
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
489
        basedir=None):
 
490
        """Give an error or warning on old formats.
 
491
 
 
492
        :param allow_unsupported: If true, allow opening
 
493
            formats that are strongly deprecated, and which may
 
494
            have limited functionality.
 
495
 
 
496
        :param recommend_upgrade: If true (default), warn
 
497
            the user through the ui object that they may wish
 
498
            to upgrade the object.
 
499
        """
 
500
        if not allow_unsupported and not self.is_supported():
 
501
            # see open_downlevel to open legacy branches.
 
502
            raise errors.UnsupportedFormatError(format=self)
 
503
        if recommend_upgrade and self.upgrade_recommended:
 
504
            ui.ui_factory.recommend_upgrade(
 
505
                self.get_format_description(), basedir)
 
506
 
604
507
 
605
508
class ControlComponentFormatRegistry(registry.FormatRegistry):
606
509
    """A registry for control components (branch, workingtree, repository)."""
733
636
    """Whether components can not change format independent of the control dir.
734
637
    """
735
638
 
 
639
    upgrade_recommended = False
 
640
    """Whether an upgrade from this format is recommended."""
 
641
 
736
642
    def get_format_description(self):
737
643
        """Return the short description for this format."""
738
644
        raise NotImplementedError(self.get_format_description)
760
666
        """
761
667
        return True
762
668
 
 
669
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
670
        basedir=None):
 
671
        """Give an error or warning on old formats.
 
672
 
 
673
        :param allow_unsupported: If true, allow opening
 
674
            formats that are strongly deprecated, and which may
 
675
            have limited functionality.
 
676
 
 
677
        :param recommend_upgrade: If true (default), warn
 
678
            the user through the ui object that they may wish
 
679
            to upgrade the object.
 
680
        """
 
681
        if not allow_unsupported and not self.is_supported():
 
682
            # see open_downlevel to open legacy branches.
 
683
            raise errors.UnsupportedFormatError(format=self)
 
684
        if recommend_upgrade and self.upgrade_recommended:
 
685
            ui.ui_factory.recommend_upgrade(
 
686
                self.get_format_description(), basedir)
 
687
 
763
688
    def same_model(self, target_format):
764
689
        return (self.repository_format.rich_root_data ==
765
690
            target_format.rich_root_data)