~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

merge trunk

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,
 
32
    transport as _mod_transport,
 
33
    ui,
35
34
    urlutils,
36
35
    )
37
36
from bzrlib.push import (
38
37
    PushResult,
39
38
    )
40
 
from bzrlib.trace import (
41
 
    mutter,
42
 
    )
43
39
from bzrlib.transport import (
44
 
    get_transport,
45
40
    local,
46
41
    )
47
42
 
48
43
""")
49
44
 
 
45
from bzrlib import registry
 
46
 
50
47
 
51
48
class ControlComponent(object):
52
49
    """Abstract base class for control directory components.
81
78
        return self.user_transport.base
82
79
 
83
80
 
 
81
 
84
82
class ControlDir(ControlComponent):
85
83
    """A control directory.
86
84
 
139
137
        """
140
138
        raise NotImplementedError(self.needs_format_conversion)
141
139
 
 
140
    def create_repository(self, shared=False):
 
141
        """Create a new repository in this control directory.
 
142
 
 
143
        :param shared: If a shared repository should be created
 
144
        :return: The newly created repository
 
145
        """
 
146
        raise NotImplementedError(self.create_repository)
 
147
 
142
148
    def destroy_repository(self):
143
149
        """Destroy the repository in this ControlDir."""
144
150
        raise NotImplementedError(self.destroy_repository)
145
151
 
146
 
    def create_branch(self, name=None):
 
152
    def create_branch(self, name=None, repository=None):
147
153
        """Create a branch in this ControlDir.
148
154
 
149
155
        :param name: Name of the colocated branch to create, None for
205
211
            raise errors.NoColocatedBranchSupport(self)
206
212
        return None
207
213
 
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
214
    def open_branch(self, name=None, unsupported=False,
248
215
                    ignore_fallbacks=False):
249
216
        """Open the branch object at this ControlDir if one is present.
364
331
        :param create_tree_if_local: If true, a working-tree will be created
365
332
            when working locally.
366
333
        """
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
 
334
        raise NotImplementedError(self.sprout)
463
335
 
464
336
    def push_branch(self, source, revision_id=None, overwrite=False, 
465
337
        remember=False, create_prefix=False):
481
353
        if br_to is None:
482
354
            # We have a repository but no branch, copy the revisions, and then
483
355
            # create a branch.
 
356
            if revision_id is None:
 
357
                # No revision supplied by the user, default to the branch
 
358
                # revision
 
359
                revision_id = source.last_revision()
484
360
            repository_to.fetch(source.repository, revision_id=revision_id)
485
361
            br_to = source.clone(self, revision_id=revision_id)
486
362
            if source.get_push_location() is None or remember:
564
440
        :param preserve_stacking: When cloning a stacked branch, stack the
565
441
            new branch on top of the other branch's stacked-on branch.
566
442
        """
567
 
        return self.clone_on_transport(get_transport(url),
 
443
        return self.clone_on_transport(_mod_transport.get_transport(url),
568
444
                                       revision_id=revision_id,
569
445
                                       force_new_repo=force_new_repo,
570
446
                                       preserve_stacking=preserve_stacking)
571
447
 
572
448
    def clone_on_transport(self, transport, revision_id=None,
573
449
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
574
 
        create_prefix=False, use_existing_dir=True):
 
450
        create_prefix=False, use_existing_dir=True, no_tree=False):
575
451
        """Clone this bzrdir and its contents to transport verbatim.
576
452
 
577
453
        :param transport: The transport for the location to produce the clone
586
462
        :param create_prefix: Create any missing directories leading up to
587
463
            to_transport.
588
464
        :param use_existing_dir: Use an existing directory if one exists.
 
465
        :param no_tree: If set to true prevents creation of a working tree.
589
466
        """
590
467
        raise NotImplementedError(self.clone_on_transport)
591
468
 
592
469
 
 
470
class ControlComponentFormat(object):
 
471
    """A component that can live inside of a .bzr meta directory."""
 
472
 
 
473
    upgrade_recommended = False
 
474
 
 
475
    def get_format_string(self):
 
476
        """Return the format of this format, if usable in meta directories."""
 
477
        raise NotImplementedError(self.get_format_string)
 
478
 
 
479
    def get_format_description(self):
 
480
        """Return the short description for this format."""
 
481
        raise NotImplementedError(self.get_format_description)
 
482
 
 
483
    def is_supported(self):
 
484
        """Is this format supported?
 
485
 
 
486
        Supported formats must be initializable and openable.
 
487
        Unsupported formats may not support initialization or committing or
 
488
        some other features depending on the reason for not being supported.
 
489
        """
 
490
        return True
 
491
 
 
492
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
493
        basedir=None):
 
494
        """Give an error or warning on old formats.
 
495
 
 
496
        :param allow_unsupported: If true, allow opening
 
497
            formats that are strongly deprecated, and which may
 
498
            have limited functionality.
 
499
 
 
500
        :param recommend_upgrade: If true (default), warn
 
501
            the user through the ui object that they may wish
 
502
            to upgrade the object.
 
503
        """
 
504
        if not allow_unsupported and not self.is_supported():
 
505
            # see open_downlevel to open legacy branches.
 
506
            raise errors.UnsupportedFormatError(format=self)
 
507
        if recommend_upgrade and self.upgrade_recommended:
 
508
            ui.ui_factory.recommend_upgrade(
 
509
                self.get_format_description(), basedir)
 
510
 
 
511
 
 
512
class ControlComponentFormatRegistry(registry.FormatRegistry):
 
513
    """A registry for control components (branch, workingtree, repository)."""
 
514
 
 
515
    def __init__(self, other_registry=None):
 
516
        super(ControlComponentFormatRegistry, self).__init__(other_registry)
 
517
        self._extra_formats = []
 
518
 
 
519
    def register(self, format):
 
520
        """Register a new format."""
 
521
        super(ControlComponentFormatRegistry, self).register(
 
522
            format.get_format_string(), format)
 
523
 
 
524
    def remove(self, format):
 
525
        """Remove a registered format."""
 
526
        super(ControlComponentFormatRegistry, self).remove(
 
527
            format.get_format_string())
 
528
 
 
529
    def register_extra(self, format):
 
530
        """Register a format that can not be used in a metadir.
 
531
 
 
532
        This is mainly useful to allow custom repository formats, such as older
 
533
        Bazaar formats and foreign formats, to be tested.
 
534
        """
 
535
        self._extra_formats.append(registry._ObjectGetter(format))
 
536
 
 
537
    def remove_extra(self, format):
 
538
        """Remove an extra format.
 
539
        """
 
540
        self._extra_formats.remove(registry._ObjectGetter(format))
 
541
 
 
542
    def register_extra_lazy(self, module_name, member_name):
 
543
        """Register a format lazily.
 
544
        """
 
545
        self._extra_formats.append(
 
546
            registry._LazyObjectGetter(module_name, member_name))
 
547
 
 
548
    def _get_extra(self):
 
549
        """Return all "extra" formats, not usable in meta directories."""
 
550
        result = []
 
551
        for getter in self._extra_formats:
 
552
            f = getter.get_obj()
 
553
            if callable(f):
 
554
                f = f()
 
555
            result.append(f)
 
556
        return result
 
557
 
 
558
    def _get_all(self):
 
559
        """Return all formats, even those not usable in metadirs.
 
560
        """
 
561
        result = []
 
562
        for name in self.keys():
 
563
            fmt = self.get(name)
 
564
            if callable(fmt):
 
565
                fmt = fmt()
 
566
            result.append(fmt)
 
567
        return result + self._get_extra()
 
568
 
 
569
    def _get_all_modules(self):
 
570
        """Return a set of the modules providing objects."""
 
571
        modules = set()
 
572
        for name in self.keys():
 
573
            modules.add(self._get_module(name))
 
574
        for getter in self._extra_formats:
 
575
            modules.add(getter.get_module())
 
576
        return modules
 
577
 
 
578
 
 
579
class Converter(object):
 
580
    """Converts a disk format object from one format to another."""
 
581
 
 
582
    def convert(self, to_convert, pb):
 
583
        """Perform the conversion of to_convert, giving feedback via pb.
 
584
 
 
585
        :param to_convert: The disk object to convert.
 
586
        :param pb: a progress bar to use for progress information.
 
587
        """
 
588
 
 
589
    def step(self, message):
 
590
        """Update the pb by a step."""
 
591
        self.count +=1
 
592
        self.pb.update(message, self.count, self.total)
 
593
 
 
594
 
593
595
class ControlDirFormat(object):
594
596
    """An encapsulation of the initialization and open routines for a format.
595
597
 
614
616
    _default_format = None
615
617
    """The default format used for new control directories."""
616
618
 
617
 
    _formats = []
618
 
    """The registered control formats - .bzr, ....
619
 
 
620
 
    This is a list of ControlDirFormat objects.
621
 
    """
622
 
 
623
619
    _server_probers = []
624
620
    """The registered server format probers, e.g. RemoteBzrProber.
625
621
 
637
633
    """
638
634
 
639
635
    supports_workingtrees = True
 
636
    """Whether working trees can exist in control directories of this format.
 
637
    """
 
638
 
 
639
    fixed_components = False
 
640
    """Whether components can not change format independent of the control dir.
 
641
    """
 
642
 
 
643
    upgrade_recommended = False
 
644
    """Whether an upgrade from this format is recommended."""
640
645
 
641
646
    def get_format_description(self):
642
647
        """Return the short description for this format."""
665
670
        """
666
671
        return True
667
672
 
 
673
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
674
        basedir=None):
 
675
        """Give an error or warning on old formats.
 
676
 
 
677
        :param allow_unsupported: If true, allow opening
 
678
            formats that are strongly deprecated, and which may
 
679
            have limited functionality.
 
680
 
 
681
        :param recommend_upgrade: If true (default), warn
 
682
            the user through the ui object that they may wish
 
683
            to upgrade the object.
 
684
        """
 
685
        if not allow_unsupported and not self.is_supported():
 
686
            # see open_downlevel to open legacy branches.
 
687
            raise errors.UnsupportedFormatError(format=self)
 
688
        if recommend_upgrade and self.upgrade_recommended:
 
689
            ui.ui_factory.recommend_upgrade(
 
690
                self.get_format_description(), basedir)
 
691
 
668
692
    def same_model(self, target_format):
669
693
        return (self.repository_format.rich_root_data ==
670
694
            target_format.rich_root_data)
674
698
        """Register a format that does not use '.bzr' for its control dir.
675
699
 
676
700
        """
677
 
        klass._formats.append(format)
 
701
        raise errors.BzrError("ControlDirFormat.register_format() has been "
 
702
            "removed in Bazaar 2.4. Please upgrade your plugins.")
678
703
 
679
704
    @classmethod
680
705
    def register_prober(klass, prober):
706
731
        return self.get_format_description().rstrip()
707
732
 
708
733
    @classmethod
709
 
    def unregister_format(klass, format):
710
 
        klass._formats.remove(format)
711
 
 
712
 
    @classmethod
713
734
    def known_formats(klass):
714
735
        """Return all the known formats.
715
736
        """
716
 
        return set(klass._formats)
 
737
        result = set()
 
738
        for prober_kls in klass._probers + klass._server_probers:
 
739
            result.update(prober_kls.known_formats())
 
740
        return result
717
741
 
718
742
    @classmethod
719
743
    def find_format(klass, transport, _server_formats=True):
741
765
        Subclasses should typically override initialize_on_transport
742
766
        instead of this method.
743
767
        """
744
 
        return self.initialize_on_transport(get_transport(url,
745
 
                                                          possible_transports))
 
768
        return self.initialize_on_transport(
 
769
            _mod_transport.get_transport(url, possible_transports))
 
770
 
746
771
    def initialize_on_transport(self, transport):
747
772
        """Initialize a new controldir in the base directory of a Transport."""
748
773
        raise NotImplementedError(self.initialize_on_transport)
808
833
 
809
834
 
810
835
class Prober(object):
811
 
    """Abstract class that can be used to detect a particular kind of 
 
836
    """Abstract class that can be used to detect a particular kind of
812
837
    control directory.
813
838
 
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 
 
839
    At the moment this just contains a single method to probe a particular
 
840
    transport, but it may be extended in the future to e.g. avoid
816
841
    multiple levels of probing for Subversion repositories.
 
842
 
 
843
    See BzrProber and RemoteBzrProber in bzrlib.bzrdir for the
 
844
    probers that detect .bzr/ directories and Bazaar smart servers,
 
845
    respectively.
 
846
 
 
847
    Probers should be registered using the register_server_prober or
 
848
    register_prober methods on ControlDirFormat.
817
849
    """
818
850
 
819
851
    def probe_transport(self, transport):
826
858
        """
827
859
        raise NotImplementedError(self.probe_transport)
828
860
 
 
861
    @classmethod
 
862
    def known_formats(cls):
 
863
        """Return the control dir formats known by this prober.
 
864
 
 
865
        Multiple probers can return the same formats, so this should
 
866
        return a set.
 
867
 
 
868
        :return: A set of known formats.
 
869
        """
 
870
        raise NotImplementedError(cls.known_formats)
 
871
 
829
872
 
830
873
class ControlDirFormatInfo(object):
831
874
 
840
883
    """Registry of user-selectable ControlDir subformats.
841
884
 
842
885
    Differs from ControlDirFormat._formats in that it provides sub-formats,
843
 
    e.g. ControlDirMeta1 with weave repository.  Also, it's more user-oriented.
 
886
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
844
887
    """
845
888
 
846
889
    def __init__(self):