~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-07-11 08:30:47 UTC
  • mfrom: (6015.1.1 trunk)
  • Revision ID: pqm@pqm.ubuntu.com-20110711083047-016iinonq1tbgl6b
(vila) Open trunk as 2.5dev1 (Vincent Ladeuil)

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.
263
226
        get at a repository.
264
227
 
265
228
        :param _unsupported: a private parameter, not part of the api.
 
229
 
266
230
        TODO: static convenience version of this?
267
231
        """
268
232
        raise NotImplementedError(self.open_repository)
351
315
        whether one existed before or not; and a local branch is always
352
316
        created.
353
317
 
354
 
        if revision_id is not None, then the clone operation may tune
355
 
            itself to download less data.
 
318
        :param revision_id: if revision_id is not None, then the clone
 
319
            operation may tune itself to download less data.
356
320
        :param accelerator_tree: A tree which can be used for retrieving file
357
321
            contents more quickly than the revision tree, i.e. a workingtree.
358
322
            The revision tree will be used for cases where accelerator_tree's
364
328
        :param create_tree_if_local: If true, a working-tree will be created
365
329
            when working locally.
366
330
        """
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
 
331
        raise NotImplementedError(self.sprout)
463
332
 
464
333
    def push_branch(self, source, revision_id=None, overwrite=False, 
465
334
        remember=False, create_prefix=False):
481
350
        if br_to is None:
482
351
            # We have a repository but no branch, copy the revisions, and then
483
352
            # create a branch.
 
353
            if revision_id is None:
 
354
                # No revision supplied by the user, default to the branch
 
355
                # revision
 
356
                revision_id = source.last_revision()
484
357
            repository_to.fetch(source.repository, revision_id=revision_id)
485
358
            br_to = source.clone(self, revision_id=revision_id)
486
359
            if source.get_push_location() is None or remember:
542
415
                branch = tree.branch
543
416
        return tree, branch
544
417
 
545
 
 
 
418
    def get_config(self):
 
419
        """Get configuration for this ControlDir."""
 
420
        raise NotImplementedError(self.get_config)
 
421
 
 
422
    def check_conversion_target(self, target_format):
 
423
        """Check that a bzrdir as a whole can be converted to a new format."""
 
424
        raise NotImplementedError(self.check_conversion_target)
 
425
 
 
426
    def clone(self, url, revision_id=None, force_new_repo=False,
 
427
              preserve_stacking=False):
 
428
        """Clone this bzrdir and its contents to url verbatim.
 
429
 
 
430
        :param url: The url create the clone at.  If url's last component does
 
431
            not exist, it will be created.
 
432
        :param revision_id: The tip revision-id to use for any branch or
 
433
            working tree.  If not None, then the clone operation may tune
 
434
            itself to download less data.
 
435
        :param force_new_repo: Do not use a shared repository for the target
 
436
                               even if one is available.
 
437
        :param preserve_stacking: When cloning a stacked branch, stack the
 
438
            new branch on top of the other branch's stacked-on branch.
 
439
        """
 
440
        return self.clone_on_transport(_mod_transport.get_transport(url),
 
441
                                       revision_id=revision_id,
 
442
                                       force_new_repo=force_new_repo,
 
443
                                       preserve_stacking=preserve_stacking)
 
444
 
 
445
    def clone_on_transport(self, transport, revision_id=None,
 
446
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
 
447
        create_prefix=False, use_existing_dir=True, no_tree=False):
 
448
        """Clone this bzrdir and its contents to transport verbatim.
 
449
 
 
450
        :param transport: The transport for the location to produce the clone
 
451
            at.  If the target directory does not exist, it will be created.
 
452
        :param revision_id: The tip revision-id to use for any branch or
 
453
            working tree.  If not None, then the clone operation may tune
 
454
            itself to download less data.
 
455
        :param force_new_repo: Do not use a shared repository for the target,
 
456
                               even if one is available.
 
457
        :param preserve_stacking: When cloning a stacked branch, stack the
 
458
            new branch on top of the other branch's stacked-on branch.
 
459
        :param create_prefix: Create any missing directories leading up to
 
460
            to_transport.
 
461
        :param use_existing_dir: Use an existing directory if one exists.
 
462
        :param no_tree: If set to true prevents creation of a working tree.
 
463
        """
 
464
        raise NotImplementedError(self.clone_on_transport)
 
465
 
 
466
 
 
467
class ControlComponentFormat(object):
 
468
    """A component that can live inside of a .bzr meta directory."""
 
469
 
 
470
    upgrade_recommended = False
 
471
 
 
472
    def get_format_string(self):
 
473
        """Return the format of this format, if usable in meta directories."""
 
474
        raise NotImplementedError(self.get_format_string)
 
475
 
 
476
    def get_format_description(self):
 
477
        """Return the short description for this format."""
 
478
        raise NotImplementedError(self.get_format_description)
 
479
 
 
480
    def is_supported(self):
 
481
        """Is this format supported?
 
482
 
 
483
        Supported formats must be initializable and openable.
 
484
        Unsupported formats may not support initialization or committing or
 
485
        some other features depending on the reason for not being supported.
 
486
        """
 
487
        return True
 
488
 
 
489
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
490
        basedir=None):
 
491
        """Give an error or warning on old formats.
 
492
 
 
493
        :param allow_unsupported: If true, allow opening
 
494
            formats that are strongly deprecated, and which may
 
495
            have limited functionality.
 
496
 
 
497
        :param recommend_upgrade: If true (default), warn
 
498
            the user through the ui object that they may wish
 
499
            to upgrade the object.
 
500
        """
 
501
        if not allow_unsupported and not self.is_supported():
 
502
            # see open_downlevel to open legacy branches.
 
503
            raise errors.UnsupportedFormatError(format=self)
 
504
        if recommend_upgrade and self.upgrade_recommended:
 
505
            ui.ui_factory.recommend_upgrade(
 
506
                self.get_format_description(), basedir)
 
507
 
 
508
 
 
509
class ControlComponentFormatRegistry(registry.FormatRegistry):
 
510
    """A registry for control components (branch, workingtree, repository)."""
 
511
 
 
512
    def __init__(self, other_registry=None):
 
513
        super(ControlComponentFormatRegistry, self).__init__(other_registry)
 
514
        self._extra_formats = []
 
515
 
 
516
    def register(self, format):
 
517
        """Register a new format."""
 
518
        super(ControlComponentFormatRegistry, self).register(
 
519
            format.get_format_string(), format)
 
520
 
 
521
    def remove(self, format):
 
522
        """Remove a registered format."""
 
523
        super(ControlComponentFormatRegistry, self).remove(
 
524
            format.get_format_string())
 
525
 
 
526
    def register_extra(self, format):
 
527
        """Register a format that can not be used in a metadir.
 
528
 
 
529
        This is mainly useful to allow custom repository formats, such as older
 
530
        Bazaar formats and foreign formats, to be tested.
 
531
        """
 
532
        self._extra_formats.append(registry._ObjectGetter(format))
 
533
 
 
534
    def remove_extra(self, format):
 
535
        """Remove an extra format.
 
536
        """
 
537
        self._extra_formats.remove(registry._ObjectGetter(format))
 
538
 
 
539
    def register_extra_lazy(self, module_name, member_name):
 
540
        """Register a format lazily.
 
541
        """
 
542
        self._extra_formats.append(
 
543
            registry._LazyObjectGetter(module_name, member_name))
 
544
 
 
545
    def _get_extra(self):
 
546
        """Return all "extra" formats, not usable in meta directories."""
 
547
        result = []
 
548
        for getter in self._extra_formats:
 
549
            f = getter.get_obj()
 
550
            if callable(f):
 
551
                f = f()
 
552
            result.append(f)
 
553
        return result
 
554
 
 
555
    def _get_all(self):
 
556
        """Return all formats, even those not usable in metadirs.
 
557
        """
 
558
        result = []
 
559
        for name in self.keys():
 
560
            fmt = self.get(name)
 
561
            if callable(fmt):
 
562
                fmt = fmt()
 
563
            result.append(fmt)
 
564
        return result + self._get_extra()
 
565
 
 
566
    def _get_all_modules(self):
 
567
        """Return a set of the modules providing objects."""
 
568
        modules = set()
 
569
        for name in self.keys():
 
570
            modules.add(self._get_module(name))
 
571
        for getter in self._extra_formats:
 
572
            modules.add(getter.get_module())
 
573
        return modules
 
574
 
 
575
 
 
576
class Converter(object):
 
577
    """Converts a disk format object from one format to another."""
 
578
 
 
579
    def convert(self, to_convert, pb):
 
580
        """Perform the conversion of to_convert, giving feedback via pb.
 
581
 
 
582
        :param to_convert: The disk object to convert.
 
583
        :param pb: a progress bar to use for progress information.
 
584
        """
 
585
 
 
586
    def step(self, message):
 
587
        """Update the pb by a step."""
 
588
        self.count +=1
 
589
        self.pb.update(message, self.count, self.total)
546
590
 
547
591
 
548
592
class ControlDirFormat(object):
569
613
    _default_format = None
570
614
    """The default format used for new control directories."""
571
615
 
572
 
    _formats = []
573
 
    """The registered control formats - .bzr, ....
574
 
 
575
 
    This is a list of ControlDirFormat objects.
576
 
    """
577
 
 
578
616
    _server_probers = []
579
617
    """The registered server format probers, e.g. RemoteBzrProber.
580
618
 
592
630
    """
593
631
 
594
632
    supports_workingtrees = True
 
633
    """Whether working trees can exist in control directories of this format.
 
634
    """
 
635
 
 
636
    fixed_components = False
 
637
    """Whether components can not change format independent of the control dir.
 
638
    """
 
639
 
 
640
    upgrade_recommended = False
 
641
    """Whether an upgrade from this format is recommended."""
595
642
 
596
643
    def get_format_description(self):
597
644
        """Return the short description for this format."""
620
667
        """
621
668
        return True
622
669
 
 
670
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
671
        basedir=None):
 
672
        """Give an error or warning on old formats.
 
673
 
 
674
        :param allow_unsupported: If true, allow opening
 
675
            formats that are strongly deprecated, and which may
 
676
            have limited functionality.
 
677
 
 
678
        :param recommend_upgrade: If true (default), warn
 
679
            the user through the ui object that they may wish
 
680
            to upgrade the object.
 
681
        """
 
682
        if not allow_unsupported and not self.is_supported():
 
683
            # see open_downlevel to open legacy branches.
 
684
            raise errors.UnsupportedFormatError(format=self)
 
685
        if recommend_upgrade and self.upgrade_recommended:
 
686
            ui.ui_factory.recommend_upgrade(
 
687
                self.get_format_description(), basedir)
 
688
 
623
689
    def same_model(self, target_format):
624
690
        return (self.repository_format.rich_root_data ==
625
691
            target_format.rich_root_data)
629
695
        """Register a format that does not use '.bzr' for its control dir.
630
696
 
631
697
        """
632
 
        klass._formats.append(format)
 
698
        raise errors.BzrError("ControlDirFormat.register_format() has been "
 
699
            "removed in Bazaar 2.4. Please upgrade your plugins.")
633
700
 
634
701
    @classmethod
635
702
    def register_prober(klass, prober):
661
728
        return self.get_format_description().rstrip()
662
729
 
663
730
    @classmethod
664
 
    def unregister_format(klass, format):
665
 
        klass._formats.remove(format)
666
 
 
667
 
    @classmethod
668
731
    def known_formats(klass):
669
732
        """Return all the known formats.
670
733
        """
671
 
        return set(klass._formats)
 
734
        result = set()
 
735
        for prober_kls in klass._probers + klass._server_probers:
 
736
            result.update(prober_kls.known_formats())
 
737
        return result
672
738
 
673
739
    @classmethod
674
740
    def find_format(klass, transport, _server_formats=True):
696
762
        Subclasses should typically override initialize_on_transport
697
763
        instead of this method.
698
764
        """
699
 
        return self.initialize_on_transport(get_transport(url,
700
 
                                                          possible_transports))
 
765
        return self.initialize_on_transport(
 
766
            _mod_transport.get_transport(url, possible_transports))
 
767
 
701
768
    def initialize_on_transport(self, transport):
702
769
        """Initialize a new controldir in the base directory of a Transport."""
703
770
        raise NotImplementedError(self.initialize_on_transport)
763
830
 
764
831
 
765
832
class Prober(object):
766
 
    """Abstract class that can be used to detect a particular kind of 
 
833
    """Abstract class that can be used to detect a particular kind of
767
834
    control directory.
768
835
 
769
 
    At the moment this just contains a single method to probe a particular 
770
 
    transport, but it may be extended in the future to e.g. avoid 
 
836
    At the moment this just contains a single method to probe a particular
 
837
    transport, but it may be extended in the future to e.g. avoid
771
838
    multiple levels of probing for Subversion repositories.
 
839
 
 
840
    See BzrProber and RemoteBzrProber in bzrlib.bzrdir for the
 
841
    probers that detect .bzr/ directories and Bazaar smart servers,
 
842
    respectively.
 
843
 
 
844
    Probers should be registered using the register_server_prober or
 
845
    register_prober methods on ControlDirFormat.
772
846
    """
773
847
 
774
848
    def probe_transport(self, transport):
781
855
        """
782
856
        raise NotImplementedError(self.probe_transport)
783
857
 
 
858
    @classmethod
 
859
    def known_formats(cls):
 
860
        """Return the control dir formats known by this prober.
 
861
 
 
862
        Multiple probers can return the same formats, so this should
 
863
        return a set.
 
864
 
 
865
        :return: A set of known formats.
 
866
        """
 
867
        raise NotImplementedError(cls.known_formats)
 
868
 
784
869
 
785
870
class ControlDirFormatInfo(object):
786
871
 
795
880
    """Registry of user-selectable ControlDir subformats.
796
881
 
797
882
    Differs from ControlDirFormat._formats in that it provides sub-formats,
798
 
    e.g. ControlDirMeta1 with weave repository.  Also, it's more user-oriented.
 
883
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
799
884
    """
800
885
 
801
886
    def __init__(self):
922
1007
# appear in chronological order and format descriptions can build
923
1008
# on previous ones.
924
1009
format_registry = ControlDirFormatRegistry()
 
1010
 
 
1011
network_format_registry = registry.FormatRegistry()
 
1012
"""Registry of formats indexed by their network name.
 
1013
 
 
1014
The network name for a ControlDirFormat is an identifier that can be used when
 
1015
referring to formats with smart server operations. See
 
1016
ControlDirFormat.network_name() for more detail.
 
1017
"""