~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

  • Committer: Gordon Tyler
  • Date: 2011-01-21 23:51:15 UTC
  • mto: This revision was merged to the branch mainline in revision 5632.
  • Revision ID: gordon@doxxx.net-20110121235115-9sdqamejot1h0481
Replace usage of format function from python 2.6 with our own very simple formatting function.

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,
30
31
    errors,
 
32
    graph,
31
33
    revision as _mod_revision,
32
 
    transport as _mod_transport,
33
 
    ui,
 
34
    urlutils,
34
35
    )
35
36
from bzrlib.push import (
36
37
    PushResult,
37
38
    )
 
39
from bzrlib.trace import (
 
40
    mutter,
 
41
    )
 
42
from bzrlib.transport import (
 
43
    get_transport,
 
44
    local,
 
45
    )
38
46
 
39
47
""")
40
48
 
74
82
        return self.user_transport.base
75
83
 
76
84
 
77
 
 
78
85
class ControlDir(ControlComponent):
79
86
    """A control directory.
80
87
 
133
140
        """
134
141
        raise NotImplementedError(self.needs_format_conversion)
135
142
 
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
 
 
144
143
    def destroy_repository(self):
145
144
        """Destroy the repository in this ControlDir."""
146
145
        raise NotImplementedError(self.destroy_repository)
207
206
            raise errors.NoColocatedBranchSupport(self)
208
207
        return None
209
208
 
 
209
    def get_branch_transport(self, branch_format, name=None):
 
210
        """Get the transport for use by branch format in this ControlDir.
 
211
 
 
212
        Note that bzr dirs that do not support format strings will raise
 
213
        IncompatibleFormat if the branch format they are given has
 
214
        a format string, and vice versa.
 
215
 
 
216
        If branch_format is None, the transport is returned with no
 
217
        checking. If it is not None, then the returned transport is
 
218
        guaranteed to point to an existing directory ready for use.
 
219
        """
 
220
        raise NotImplementedError(self.get_branch_transport)
 
221
 
 
222
    def get_repository_transport(self, repository_format):
 
223
        """Get the transport for use by repository format in this ControlDir.
 
224
 
 
225
        Note that bzr dirs that do not support format strings will raise
 
226
        IncompatibleFormat if the repository format they are given has
 
227
        a format string, and vice versa.
 
228
 
 
229
        If repository_format is None, the transport is returned with no
 
230
        checking. If it is not None, then the returned transport is
 
231
        guaranteed to point to an existing directory ready for use.
 
232
        """
 
233
        raise NotImplementedError(self.get_repository_transport)
 
234
 
 
235
    def get_workingtree_transport(self, tree_format):
 
236
        """Get the transport for use by workingtree format in this ControlDir.
 
237
 
 
238
        Note that bzr dirs that do not support format strings will raise
 
239
        IncompatibleFormat if the workingtree format they are given has a
 
240
        format string, and vice versa.
 
241
 
 
242
        If workingtree_format is None, the transport is returned with no
 
243
        checking. If it is not None, then the returned transport is
 
244
        guaranteed to point to an existing directory ready for use.
 
245
        """
 
246
        raise NotImplementedError(self.get_workingtree_transport)
 
247
 
210
248
    def open_branch(self, name=None, unsupported=False,
211
249
                    ignore_fallbacks=False):
212
250
        """Open the branch object at this ControlDir if one is present.
327
365
        :param create_tree_if_local: If true, a working-tree will be created
328
366
            when working locally.
329
367
        """
330
 
        raise NotImplementedError(self.sprout)
 
368
        operation = cleanup.OperationWithCleanups(self._sprout)
 
369
        return operation.run(url, revision_id=revision_id,
 
370
            force_new_repo=force_new_repo, recurse=recurse,
 
371
            possible_transports=possible_transports,
 
372
            accelerator_tree=accelerator_tree, hardlink=hardlink,
 
373
            stacked=stacked, source_branch=source_branch,
 
374
            create_tree_if_local=create_tree_if_local)
 
375
 
 
376
    def _sprout(self, op, url, revision_id=None, force_new_repo=False,
 
377
               recurse='down', possible_transports=None,
 
378
               accelerator_tree=None, hardlink=False, stacked=False,
 
379
               source_branch=None, create_tree_if_local=True):
 
380
        add_cleanup = op.add_cleanup
 
381
        target_transport = get_transport(url, possible_transports)
 
382
        target_transport.ensure_base()
 
383
        cloning_format = self.cloning_metadir(stacked)
 
384
        # Create/update the result branch
 
385
        result = cloning_format.initialize_on_transport(target_transport)
 
386
        # if a stacked branch wasn't requested, we don't create one
 
387
        # even if the origin was stacked
 
388
        stacked_branch_url = None
 
389
        if source_branch is not None:
 
390
            add_cleanup(source_branch.lock_read().unlock)
 
391
            if stacked:
 
392
                stacked_branch_url = self.root_transport.base
 
393
            source_repository = source_branch.repository
 
394
        else:
 
395
            try:
 
396
                source_branch = self.open_branch()
 
397
                source_repository = source_branch.repository
 
398
                if stacked:
 
399
                    stacked_branch_url = self.root_transport.base
 
400
            except errors.NotBranchError:
 
401
                source_branch = None
 
402
                try:
 
403
                    source_repository = self.open_repository()
 
404
                except errors.NoRepositoryPresent:
 
405
                    source_repository = None
 
406
                else:
 
407
                    add_cleanup(source_repository.lock_read().unlock)
 
408
            else:
 
409
                add_cleanup(source_branch.lock_read().unlock)
 
410
        repository_policy = result.determine_repository_policy(
 
411
            force_new_repo, stacked_branch_url, require_stacking=stacked)
 
412
        result_repo, is_new_repo = repository_policy.acquire_repository()
 
413
        add_cleanup(result_repo.lock_write().unlock)
 
414
        is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
 
415
        if is_new_repo and revision_id is not None and not is_stacked:
 
416
            fetch_spec = graph.PendingAncestryResult(
 
417
                [revision_id], source_repository)
 
418
        else:
 
419
            fetch_spec = None
 
420
        if source_repository is not None:
 
421
            # Fetch while stacked to prevent unstacked fetch from
 
422
            # Branch.sprout.
 
423
            if fetch_spec is None:
 
424
                result_repo.fetch(source_repository, revision_id=revision_id)
 
425
            else:
 
426
                result_repo.fetch(source_repository, fetch_spec=fetch_spec)
 
427
 
 
428
        if source_branch is None:
 
429
            # this is for sprouting a controldir without a branch; is that
 
430
            # actually useful?
 
431
            # Not especially, but it's part of the contract.
 
432
            result_branch = result.create_branch()
 
433
        else:
 
434
            result_branch = source_branch.sprout(result,
 
435
                revision_id=revision_id, repository_policy=repository_policy,
 
436
                repository=result_repo)
 
437
        mutter("created new branch %r" % (result_branch,))
 
438
 
 
439
        # Create/update the result working tree
 
440
        if (create_tree_if_local and
 
441
            isinstance(target_transport, local.LocalTransport) and
 
442
            (result_repo is None or result_repo.make_working_trees())):
 
443
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
 
444
                hardlink=hardlink, from_branch=result_branch)
 
445
            wt.lock_write()
 
446
            try:
 
447
                if wt.path2id('') is None:
 
448
                    try:
 
449
                        wt.set_root_id(self.open_workingtree.get_root_id())
 
450
                    except errors.NoWorkingTree:
 
451
                        pass
 
452
            finally:
 
453
                wt.unlock()
 
454
        else:
 
455
            wt = None
 
456
        if recurse == 'down':
 
457
            if wt is not None:
 
458
                basis = wt.basis_tree()
 
459
                basis.lock_read()
 
460
                subtrees = basis.iter_references()
 
461
            elif result_branch is not None:
 
462
                basis = result_branch.basis_tree()
 
463
                basis.lock_read()
 
464
                subtrees = basis.iter_references()
 
465
            elif source_branch is not None:
 
466
                basis = source_branch.basis_tree()
 
467
                basis.lock_read()
 
468
                subtrees = basis.iter_references()
 
469
            else:
 
470
                subtrees = []
 
471
                basis = None
 
472
            try:
 
473
                for path, file_id in subtrees:
 
474
                    target = urlutils.join(url, urlutils.escape(path))
 
475
                    sublocation = source_branch.reference_parent(file_id, path)
 
476
                    sublocation.bzrdir.sprout(target,
 
477
                        basis.get_reference_revision(file_id, path),
 
478
                        force_new_repo=force_new_repo, recurse=recurse,
 
479
                        stacked=stacked)
 
480
            finally:
 
481
                if basis is not None:
 
482
                    basis.unlock()
 
483
        return result
331
484
 
332
485
    def push_branch(self, source, revision_id=None, overwrite=False, 
333
486
        remember=False, create_prefix=False):
349
502
        if br_to is None:
350
503
            # We have a repository but no branch, copy the revisions, and then
351
504
            # 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()
356
505
            repository_to.fetch(source.repository, revision_id=revision_id)
357
506
            br_to = source.clone(self, revision_id=revision_id)
358
507
            if source.get_push_location() is None or remember:
436
585
        :param preserve_stacking: When cloning a stacked branch, stack the
437
586
            new branch on top of the other branch's stacked-on branch.
438
587
        """
439
 
        return self.clone_on_transport(_mod_transport.get_transport(url),
 
588
        return self.clone_on_transport(get_transport(url),
440
589
                                       revision_id=revision_id,
441
590
                                       force_new_repo=force_new_repo,
442
591
                                       preserve_stacking=preserve_stacking)
443
592
 
444
593
    def clone_on_transport(self, transport, revision_id=None,
445
594
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
446
 
        create_prefix=False, use_existing_dir=True, no_tree=False):
 
595
        create_prefix=False, use_existing_dir=True):
447
596
        """Clone this bzrdir and its contents to transport verbatim.
448
597
 
449
598
        :param transport: The transport for the location to produce the clone
458
607
        :param create_prefix: Create any missing directories leading up to
459
608
            to_transport.
460
609
        :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
610
        """
463
611
        raise NotImplementedError(self.clone_on_transport)
464
612
 
465
613
 
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
 
 
591
614
class ControlDirFormat(object):
592
615
    """An encapsulation of the initialization and open routines for a format.
593
616
 
612
635
    _default_format = None
613
636
    """The default format used for new control directories."""
614
637
 
 
638
    _formats = []
 
639
    """The registered control formats - .bzr, ....
 
640
 
 
641
    This is a list of ControlDirFormat objects.
 
642
    """
 
643
 
615
644
    _server_probers = []
616
645
    """The registered server format probers, e.g. RemoteBzrProber.
617
646
 
629
658
    """
630
659
 
631
660
    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
661
 
642
662
    def get_format_description(self):
643
663
        """Return the short description for this format."""
666
686
        """
667
687
        return True
668
688
 
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
 
 
688
689
    def same_model(self, target_format):
689
690
        return (self.repository_format.rich_root_data ==
690
691
            target_format.rich_root_data)
694
695
        """Register a format that does not use '.bzr' for its control dir.
695
696
 
696
697
        """
697
 
        raise errors.BzrError("ControlDirFormat.register_format() has been "
698
 
            "removed in Bazaar 2.4. Please upgrade your plugins.")
 
698
        klass._formats.append(format)
699
699
 
700
700
    @classmethod
701
701
    def register_prober(klass, prober):
727
727
        return self.get_format_description().rstrip()
728
728
 
729
729
    @classmethod
 
730
    def unregister_format(klass, format):
 
731
        klass._formats.remove(format)
 
732
 
 
733
    @classmethod
730
734
    def known_formats(klass):
731
735
        """Return all the known formats.
732
736
        """
733
 
        result = set()
734
 
        for prober_kls in klass._probers + klass._server_probers:
735
 
            result.update(prober_kls.known_formats())
736
 
        return result
 
737
        return set(klass._formats)
737
738
 
738
739
    @classmethod
739
740
    def find_format(klass, transport, _server_formats=True):
761
762
        Subclasses should typically override initialize_on_transport
762
763
        instead of this method.
763
764
        """
764
 
        return self.initialize_on_transport(
765
 
            _mod_transport.get_transport(url, possible_transports))
766
 
 
 
765
        return self.initialize_on_transport(get_transport(url,
 
766
                                                          possible_transports))
767
767
    def initialize_on_transport(self, transport):
768
768
        """Initialize a new controldir in the base directory of a Transport."""
769
769
        raise NotImplementedError(self.initialize_on_transport)
829
829
 
830
830
 
831
831
class Prober(object):
832
 
    """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 
833
833
    control directory.
834
834
 
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
 
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 
837
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.
845
838
    """
846
839
 
847
840
    def probe_transport(self, transport):
854
847
        """
855
848
        raise NotImplementedError(self.probe_transport)
856
849
 
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
 
 
868
850
 
869
851
class ControlDirFormatInfo(object):
870
852
 
879
861
    """Registry of user-selectable ControlDir subformats.
880
862
 
881
863
    Differs from ControlDirFormat._formats in that it provides sub-formats,
882
 
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
 
864
    e.g. ControlDirMeta1 with weave repository.  Also, it's more user-oriented.
883
865
    """
884
866
 
885
867
    def __init__(self):