~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

  • Committer: John Arbash Meinel
  • Date: 2011-05-11 11:35:28 UTC
  • mto: This revision was merged to the branch mainline in revision 5851.
  • Revision ID: john@arbash-meinel.com-20110511113528-qepibuwxicjrbb2h
Break compatibility with python <2.6.

This includes auditing the code for places where we were doing
explicit 'sys.version' checks and removing them as appropriate.

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:
542
414
                branch = tree.branch
543
415
        return tree, branch
544
416
 
545
 
 
 
417
    def get_config(self):
 
418
        """Get configuration for this ControlDir."""
 
419
        raise NotImplementedError(self.get_config)
 
420
 
 
421
    def check_conversion_target(self, target_format):
 
422
        """Check that a bzrdir as a whole can be converted to a new format."""
 
423
        raise NotImplementedError(self.check_conversion_target)
 
424
 
 
425
    def clone(self, url, revision_id=None, force_new_repo=False,
 
426
              preserve_stacking=False):
 
427
        """Clone this bzrdir and its contents to url verbatim.
 
428
 
 
429
        :param url: The url create the clone at.  If url's last component does
 
430
            not exist, it will be created.
 
431
        :param revision_id: The tip revision-id to use for any branch or
 
432
            working tree.  If not None, then the clone operation may tune
 
433
            itself to download less data.
 
434
        :param force_new_repo: Do not use a shared repository for the target
 
435
                               even if one is available.
 
436
        :param preserve_stacking: When cloning a stacked branch, stack the
 
437
            new branch on top of the other branch's stacked-on branch.
 
438
        """
 
439
        return self.clone_on_transport(_mod_transport.get_transport(url),
 
440
                                       revision_id=revision_id,
 
441
                                       force_new_repo=force_new_repo,
 
442
                                       preserve_stacking=preserve_stacking)
 
443
 
 
444
    def clone_on_transport(self, transport, revision_id=None,
 
445
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
 
446
        create_prefix=False, use_existing_dir=True, no_tree=False):
 
447
        """Clone this bzrdir and its contents to transport verbatim.
 
448
 
 
449
        :param transport: The transport for the location to produce the clone
 
450
            at.  If the target directory does not exist, it will be created.
 
451
        :param revision_id: The tip revision-id to use for any branch or
 
452
            working tree.  If not None, then the clone operation may tune
 
453
            itself to download less data.
 
454
        :param force_new_repo: Do not use a shared repository for the target,
 
455
                               even if one is available.
 
456
        :param preserve_stacking: When cloning a stacked branch, stack the
 
457
            new branch on top of the other branch's stacked-on branch.
 
458
        :param create_prefix: Create any missing directories leading up to
 
459
            to_transport.
 
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.
 
462
        """
 
463
        raise NotImplementedError(self.clone_on_transport)
 
464
 
 
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)
546
589
 
547
590
 
548
591
class ControlDirFormat(object):
562
605
    object will be created every system load.
563
606
 
564
607
    :cvar colocated_branches: Whether this formats supports colocated branches.
 
608
    :cvar supports_workingtrees: This control directory can co-exist with a
 
609
        working tree.
565
610
    """
566
611
 
567
612
    _default_format = None
568
613
    """The default format used for new control directories."""
569
614
 
570
 
    _formats = []
571
 
    """The registered control formats - .bzr, ....
572
 
 
573
 
    This is a list of ControlDirFormat objects.
574
 
    """
575
 
 
576
615
    _server_probers = []
577
616
    """The registered server format probers, e.g. RemoteBzrProber.
578
617
 
589
628
    """Whether co-located branches are supported for this control dir format.
590
629
    """
591
630
 
 
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."""
 
641
 
592
642
    def get_format_description(self):
593
643
        """Return the short description for this format."""
594
644
        raise NotImplementedError(self.get_format_description)
616
666
        """
617
667
        return True
618
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
 
619
688
    def same_model(self, target_format):
620
689
        return (self.repository_format.rich_root_data ==
621
690
            target_format.rich_root_data)
625
694
        """Register a format that does not use '.bzr' for its control dir.
626
695
 
627
696
        """
628
 
        klass._formats.append(format)
 
697
        raise errors.BzrError("ControlDirFormat.register_format() has been "
 
698
            "removed in Bazaar 2.4. Please upgrade your plugins.")
629
699
 
630
700
    @classmethod
631
701
    def register_prober(klass, prober):
657
727
        return self.get_format_description().rstrip()
658
728
 
659
729
    @classmethod
660
 
    def unregister_format(klass, format):
661
 
        klass._formats.remove(format)
662
 
 
663
 
    @classmethod
664
730
    def known_formats(klass):
665
731
        """Return all the known formats.
666
732
        """
667
 
        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
668
737
 
669
738
    @classmethod
670
739
    def find_format(klass, transport, _server_formats=True):
692
761
        Subclasses should typically override initialize_on_transport
693
762
        instead of this method.
694
763
        """
695
 
        return self.initialize_on_transport(get_transport(url,
696
 
                                                          possible_transports))
 
764
        return self.initialize_on_transport(
 
765
            _mod_transport.get_transport(url, possible_transports))
 
766
 
697
767
    def initialize_on_transport(self, transport):
698
768
        """Initialize a new controldir in the base directory of a Transport."""
699
769
        raise NotImplementedError(self.initialize_on_transport)
759
829
 
760
830
 
761
831
class Prober(object):
762
 
    """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
763
833
    control directory.
764
834
 
765
 
    At the moment this just contains a single method to probe a particular 
766
 
    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
767
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.
768
845
    """
769
846
 
770
847
    def probe_transport(self, transport):
777
854
        """
778
855
        raise NotImplementedError(self.probe_transport)
779
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
 
780
868
 
781
869
class ControlDirFormatInfo(object):
782
870
 
791
879
    """Registry of user-selectable ControlDir subformats.
792
880
 
793
881
    Differs from ControlDirFormat._formats in that it provides sub-formats,
794
 
    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.
795
883
    """
796
884
 
797
885
    def __init__(self):
918
1006
# appear in chronological order and format descriptions can build
919
1007
# on previous ones.
920
1008
format_registry = ControlDirFormatRegistry()
 
1009
 
 
1010
network_format_registry = registry.FormatRegistry()
 
1011
"""Registry of formats indexed by their network name.
 
1012
 
 
1013
The network name for a ControlDirFormat is an identifier that can be used when
 
1014
referring to formats with smart server operations. See
 
1015
ControlDirFormat.network_name() for more detail.
 
1016
"""