~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: 2011-04-19 04:37:48 UTC
  • mfrom: (5741.3.8 506265-command-deprecation)
  • Revision ID: pqm@pqm.ubuntu.com-20110419043748-qq4lsmc50cckqzp7
(mbp) Deprecate 'bzr clone' and 'bzr get' (bug 506265) (Martin Pool)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2010 Canonical Ltd
 
1
# Copyright (C) 2010, 2011 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
28
28
 
29
29
from bzrlib import (
30
30
    errors,
31
 
    graph,
32
 
    registry,
33
31
    revision as _mod_revision,
34
 
    symbol_versioning,
35
 
    urlutils,
 
32
    transport as _mod_transport,
 
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
 
    get_transport,
45
 
    local,
46
 
    )
47
38
 
48
39
""")
49
40
 
 
41
from bzrlib import registry
 
42
 
50
43
 
51
44
class ControlComponent(object):
52
45
    """Abstract base class for control directory components.
81
74
        return self.user_transport.base
82
75
 
83
76
 
 
77
 
84
78
class ControlDir(ControlComponent):
85
79
    """A control directory.
86
80
 
139
133
        """
140
134
        raise NotImplementedError(self.needs_format_conversion)
141
135
 
 
136
    def create_repository(self, shared=False):
 
137
        """Create a new repository in this control directory.
 
138
 
 
139
        :param shared: If a shared repository should be created
 
140
        :return: The newly created repository
 
141
        """
 
142
        raise NotImplementedError(self.create_repository)
 
143
 
142
144
    def destroy_repository(self):
143
145
        """Destroy the repository in this ControlDir."""
144
146
        raise NotImplementedError(self.destroy_repository)
145
147
 
146
 
    def create_branch(self, name=None):
 
148
    def create_branch(self, name=None, repository=None):
147
149
        """Create a branch in this ControlDir.
148
150
 
149
151
        :param name: Name of the colocated branch to create, None for
205
207
            raise errors.NoColocatedBranchSupport(self)
206
208
        return None
207
209
 
208
 
    def get_branch_transport(self, branch_format, name=None):
209
 
        """Get the transport for use by branch format in this ControlDir.
210
 
 
211
 
        Note that bzr dirs that do not support format strings will raise
212
 
        IncompatibleFormat if the branch format they are given has
213
 
        a format string, and vice versa.
214
 
 
215
 
        If branch_format is None, the transport is returned with no
216
 
        checking. If it is not None, then the returned transport is
217
 
        guaranteed to point to an existing directory ready for use.
218
 
        """
219
 
        raise NotImplementedError(self.get_branch_transport)
220
 
 
221
 
    def get_repository_transport(self, repository_format):
222
 
        """Get the transport for use by repository format in this ControlDir.
223
 
 
224
 
        Note that bzr dirs that do not support format strings will raise
225
 
        IncompatibleFormat if the repository format they are given has
226
 
        a format string, and vice versa.
227
 
 
228
 
        If repository_format is None, the transport is returned with no
229
 
        checking. If it is not None, then the returned transport is
230
 
        guaranteed to point to an existing directory ready for use.
231
 
        """
232
 
        raise NotImplementedError(self.get_repository_transport)
233
 
 
234
 
    def get_workingtree_transport(self, tree_format):
235
 
        """Get the transport for use by workingtree format in this ControlDir.
236
 
 
237
 
        Note that bzr dirs that do not support format strings will raise
238
 
        IncompatibleFormat if the workingtree format they are given has a
239
 
        format string, and vice versa.
240
 
 
241
 
        If workingtree_format is None, the transport is returned with no
242
 
        checking. If it is not None, then the returned transport is
243
 
        guaranteed to point to an existing directory ready for use.
244
 
        """
245
 
        raise NotImplementedError(self.get_workingtree_transport)
246
 
 
247
210
    def open_branch(self, name=None, unsupported=False,
248
211
                    ignore_fallbacks=False):
249
212
        """Open the branch object at this ControlDir if one is present.
364
327
        :param create_tree_if_local: If true, a working-tree will be created
365
328
            when working locally.
366
329
        """
367
 
        target_transport = get_transport(url, possible_transports)
368
 
        target_transport.ensure_base()
369
 
        cloning_format = self.cloning_metadir(stacked)
370
 
        # Create/update the result branch
371
 
        result = cloning_format.initialize_on_transport(target_transport)
372
 
        # if a stacked branch wasn't requested, we don't create one
373
 
        # even if the origin was stacked
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
379
 
        else:
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
391
 
        repository_policy = result.determine_repository_policy(
392
 
            force_new_repo, stacked_branch_url, require_stacking=stacked)
393
 
        result_repo, is_new_repo = repository_policy.acquire_repository()
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)
398
 
        else:
399
 
            fetch_spec = None
400
 
        if source_repository is not None:
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)
407
 
 
408
 
        if source_branch is None:
409
 
            # this is for sprouting a controldir without a branch; is that
410
 
            # actually useful?
411
 
            # Not especially, but it's part of the contract.
412
 
            result_branch = result.create_branch()
413
 
        else:
414
 
            result_branch = source_branch.sprout(result,
415
 
                revision_id=revision_id, repository_policy=repository_policy)
416
 
        mutter("created new branch %r" % (result_branch,))
417
 
 
418
 
        # Create/update the result working tree
419
 
        if (create_tree_if_local and
420
 
            isinstance(target_transport, local.LocalTransport) and
421
 
            (result_repo is None or result_repo.make_working_trees())):
422
 
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
423
 
                hardlink=hardlink)
424
 
            wt.lock_write()
425
 
            try:
426
 
                if wt.path2id('') is None:
427
 
                    try:
428
 
                        wt.set_root_id(self.open_workingtree.get_root_id())
429
 
                    except errors.NoWorkingTree:
430
 
                        pass
431
 
            finally:
432
 
                wt.unlock()
433
 
        else:
434
 
            wt = None
435
 
        if recurse == 'down':
436
 
            if wt is not None:
437
 
                basis = wt.basis_tree()
438
 
                basis.lock_read()
439
 
                subtrees = basis.iter_references()
440
 
            elif result_branch is not None:
441
 
                basis = result_branch.basis_tree()
442
 
                basis.lock_read()
443
 
                subtrees = basis.iter_references()
444
 
            elif source_branch is not None:
445
 
                basis = source_branch.basis_tree()
446
 
                basis.lock_read()
447
 
                subtrees = basis.iter_references()
448
 
            else:
449
 
                subtrees = []
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()
462
 
        return result
 
330
        raise NotImplementedError(self.sprout)
463
331
 
464
332
    def push_branch(self, source, revision_id=None, overwrite=False, 
465
333
        remember=False, create_prefix=False):
481
349
        if br_to is None:
482
350
            # We have a repository but no branch, copy the revisions, and then
483
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()
484
356
            repository_to.fetch(source.repository, revision_id=revision_id)
485
357
            br_to = source.clone(self, revision_id=revision_id)
486
358
            if source.get_push_location() is None or remember:
564
436
        :param preserve_stacking: When cloning a stacked branch, stack the
565
437
            new branch on top of the other branch's stacked-on branch.
566
438
        """
567
 
        return self.clone_on_transport(get_transport(url),
 
439
        return self.clone_on_transport(_mod_transport.get_transport(url),
568
440
                                       revision_id=revision_id,
569
441
                                       force_new_repo=force_new_repo,
570
442
                                       preserve_stacking=preserve_stacking)
571
443
 
572
444
    def clone_on_transport(self, transport, revision_id=None,
573
445
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
574
 
        create_prefix=False, use_existing_dir=True):
 
446
        create_prefix=False, use_existing_dir=True, no_tree=False):
575
447
        """Clone this bzrdir and its contents to transport verbatim.
576
448
 
577
449
        :param transport: The transport for the location to produce the clone
586
458
        :param create_prefix: Create any missing directories leading up to
587
459
            to_transport.
588
460
        :param use_existing_dir: Use an existing directory if one exists.
 
461
        :param no_tree: If set to true prevents creation of a working tree.
589
462
        """
590
463
        raise NotImplementedError(self.clone_on_transport)
591
464
 
592
465
 
 
466
class ControlComponentFormat(object):
 
467
    """A component that can live inside of a .bzr meta directory."""
 
468
 
 
469
    upgrade_recommended = False
 
470
 
 
471
    def get_format_string(self):
 
472
        """Return the format of this format, if usable in meta directories."""
 
473
        raise NotImplementedError(self.get_format_string)
 
474
 
 
475
    def get_format_description(self):
 
476
        """Return the short description for this format."""
 
477
        raise NotImplementedError(self.get_format_description)
 
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
 
 
507
 
 
508
class ControlComponentFormatRegistry(registry.FormatRegistry):
 
509
    """A registry for control components (branch, workingtree, repository)."""
 
510
 
 
511
    def __init__(self, other_registry=None):
 
512
        super(ControlComponentFormatRegistry, self).__init__(other_registry)
 
513
        self._extra_formats = []
 
514
 
 
515
    def register(self, format):
 
516
        """Register a new format."""
 
517
        super(ControlComponentFormatRegistry, self).register(
 
518
            format.get_format_string(), format)
 
519
 
 
520
    def remove(self, format):
 
521
        """Remove a registered format."""
 
522
        super(ControlComponentFormatRegistry, self).remove(
 
523
            format.get_format_string())
 
524
 
 
525
    def register_extra(self, format):
 
526
        """Register a format that can not be used in a metadir.
 
527
 
 
528
        This is mainly useful to allow custom repository formats, such as older
 
529
        Bazaar formats and foreign formats, to be tested.
 
530
        """
 
531
        self._extra_formats.append(registry._ObjectGetter(format))
 
532
 
 
533
    def remove_extra(self, format):
 
534
        """Remove an extra format.
 
535
        """
 
536
        self._extra_formats.remove(registry._ObjectGetter(format))
 
537
 
 
538
    def register_extra_lazy(self, module_name, member_name):
 
539
        """Register a format lazily.
 
540
        """
 
541
        self._extra_formats.append(
 
542
            registry._LazyObjectGetter(module_name, member_name))
 
543
 
 
544
    def _get_extra(self):
 
545
        """Return all "extra" formats, not usable in meta directories."""
 
546
        result = []
 
547
        for getter in self._extra_formats:
 
548
            f = getter.get_obj()
 
549
            if callable(f):
 
550
                f = f()
 
551
            result.append(f)
 
552
        return result
 
553
 
 
554
    def _get_all(self):
 
555
        """Return all formats, even those not usable in metadirs.
 
556
        """
 
557
        result = []
 
558
        for name in self.keys():
 
559
            fmt = self.get(name)
 
560
            if callable(fmt):
 
561
                fmt = fmt()
 
562
            result.append(fmt)
 
563
        return result + self._get_extra()
 
564
 
 
565
    def _get_all_modules(self):
 
566
        """Return a set of the modules providing objects."""
 
567
        modules = set()
 
568
        for name in self.keys():
 
569
            modules.add(self._get_module(name))
 
570
        for getter in self._extra_formats:
 
571
            modules.add(getter.get_module())
 
572
        return modules
 
573
 
 
574
 
 
575
class Converter(object):
 
576
    """Converts a disk format object from one format to another."""
 
577
 
 
578
    def convert(self, to_convert, pb):
 
579
        """Perform the conversion of to_convert, giving feedback via pb.
 
580
 
 
581
        :param to_convert: The disk object to convert.
 
582
        :param pb: a progress bar to use for progress information.
 
583
        """
 
584
 
 
585
    def step(self, message):
 
586
        """Update the pb by a step."""
 
587
        self.count +=1
 
588
        self.pb.update(message, self.count, self.total)
 
589
 
 
590
 
593
591
class ControlDirFormat(object):
594
592
    """An encapsulation of the initialization and open routines for a format.
595
593
 
614
612
    _default_format = None
615
613
    """The default format used for new control directories."""
616
614
 
617
 
    _formats = []
618
 
    """The registered control formats - .bzr, ....
619
 
 
620
 
    This is a list of ControlDirFormat objects.
621
 
    """
622
 
 
623
615
    _server_probers = []
624
616
    """The registered server format probers, e.g. RemoteBzrProber.
625
617
 
637
629
    """
638
630
 
639
631
    supports_workingtrees = True
 
632
    """Whether working trees can exist in control directories of this format.
 
633
    """
 
634
 
 
635
    fixed_components = False
 
636
    """Whether components can not change format independent of the control dir.
 
637
    """
 
638
 
 
639
    upgrade_recommended = False
 
640
    """Whether an upgrade from this format is recommended."""
640
641
 
641
642
    def get_format_description(self):
642
643
        """Return the short description for this format."""
665
666
        """
666
667
        return True
667
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
 
668
688
    def same_model(self, target_format):
669
689
        return (self.repository_format.rich_root_data ==
670
690
            target_format.rich_root_data)
674
694
        """Register a format that does not use '.bzr' for its control dir.
675
695
 
676
696
        """
677
 
        klass._formats.append(format)
 
697
        raise errors.BzrError("ControlDirFormat.register_format() has been "
 
698
            "removed in Bazaar 2.4. Please upgrade your plugins.")
678
699
 
679
700
    @classmethod
680
701
    def register_prober(klass, prober):
706
727
        return self.get_format_description().rstrip()
707
728
 
708
729
    @classmethod
709
 
    def unregister_format(klass, format):
710
 
        klass._formats.remove(format)
711
 
 
712
 
    @classmethod
713
730
    def known_formats(klass):
714
731
        """Return all the known formats.
715
732
        """
716
 
        return set(klass._formats)
 
733
        result = set()
 
734
        for prober_kls in klass._probers + klass._server_probers:
 
735
            result.update(prober_kls.known_formats())
 
736
        return result
717
737
 
718
738
    @classmethod
719
739
    def find_format(klass, transport, _server_formats=True):
741
761
        Subclasses should typically override initialize_on_transport
742
762
        instead of this method.
743
763
        """
744
 
        return self.initialize_on_transport(get_transport(url,
745
 
                                                          possible_transports))
 
764
        return self.initialize_on_transport(
 
765
            _mod_transport.get_transport(url, possible_transports))
 
766
 
746
767
    def initialize_on_transport(self, transport):
747
768
        """Initialize a new controldir in the base directory of a Transport."""
748
769
        raise NotImplementedError(self.initialize_on_transport)
808
829
 
809
830
 
810
831
class Prober(object):
811
 
    """Abstract class that can be used to detect a particular kind of 
 
832
    """Abstract class that can be used to detect a particular kind of
812
833
    control directory.
813
834
 
814
 
    At the moment this just contains a single method to probe a particular 
815
 
    transport, but it may be extended in the future to e.g. avoid 
 
835
    At the moment this just contains a single method to probe a particular
 
836
    transport, but it may be extended in the future to e.g. avoid
816
837
    multiple levels of probing for Subversion repositories.
 
838
 
 
839
    See BzrProber and RemoteBzrProber in bzrlib.bzrdir for the
 
840
    probers that detect .bzr/ directories and Bazaar smart servers,
 
841
    respectively.
 
842
 
 
843
    Probers should be registered using the register_server_prober or
 
844
    register_prober methods on ControlDirFormat.
817
845
    """
818
846
 
819
847
    def probe_transport(self, transport):
826
854
        """
827
855
        raise NotImplementedError(self.probe_transport)
828
856
 
 
857
    @classmethod
 
858
    def known_formats(cls):
 
859
        """Return the control dir formats known by this prober.
 
860
 
 
861
        Multiple probers can return the same formats, so this should
 
862
        return a set.
 
863
 
 
864
        :return: A set of known formats.
 
865
        """
 
866
        raise NotImplementedError(cls.known_formats)
 
867
 
829
868
 
830
869
class ControlDirFormatInfo(object):
831
870
 
840
879
    """Registry of user-selectable ControlDir subformats.
841
880
 
842
881
    Differs from ControlDirFormat._formats in that it provides sub-formats,
843
 
    e.g. ControlDirMeta1 with weave repository.  Also, it's more user-oriented.
 
882
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
844
883
    """
845
884
 
846
885
    def __init__(self):