~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

  • Committer: Andrew Bennetts
  • Date: 2011-02-14 12:03:05 UTC
  • mto: This revision was merged to the branch mainline in revision 5664.
  • Revision ID: andrew.bennetts@canonical.com-20110214120305-7l7iu1h6f13voeo7
Add release note.

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
    fetch,
 
33
    graph,
31
34
    revision as _mod_revision,
32
35
    transport as _mod_transport,
33
 
    ui,
 
36
    urlutils,
34
37
    )
35
38
from bzrlib.push import (
36
39
    PushResult,
37
40
    )
 
41
from bzrlib.trace import (
 
42
    mutter,
 
43
    )
 
44
from bzrlib.transport import (
 
45
    local,
 
46
    )
38
47
 
39
48
""")
40
49
 
74
83
        return self.user_transport.base
75
84
 
76
85
 
77
 
 
78
86
class ControlDir(ControlComponent):
79
87
    """A control directory.
80
88
 
133
141
        """
134
142
        raise NotImplementedError(self.needs_format_conversion)
135
143
 
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
144
    def destroy_repository(self):
145
145
        """Destroy the repository in this ControlDir."""
146
146
        raise NotImplementedError(self.destroy_repository)
207
207
            raise errors.NoColocatedBranchSupport(self)
208
208
        return None
209
209
 
 
210
    def get_branch_transport(self, branch_format, name=None):
 
211
        """Get the transport for use by branch format in this ControlDir.
 
212
 
 
213
        Note that bzr dirs that do not support format strings will raise
 
214
        IncompatibleFormat if the branch format they are given has
 
215
        a format string, and vice versa.
 
216
 
 
217
        If branch_format is None, the transport is returned with no
 
218
        checking. If it is not None, then the returned transport is
 
219
        guaranteed to point to an existing directory ready for use.
 
220
        """
 
221
        raise NotImplementedError(self.get_branch_transport)
 
222
 
 
223
    def get_repository_transport(self, repository_format):
 
224
        """Get the transport for use by repository format in this ControlDir.
 
225
 
 
226
        Note that bzr dirs that do not support format strings will raise
 
227
        IncompatibleFormat if the repository format they are given has
 
228
        a format string, and vice versa.
 
229
 
 
230
        If repository_format is None, the transport is returned with no
 
231
        checking. If it is not None, then the returned transport is
 
232
        guaranteed to point to an existing directory ready for use.
 
233
        """
 
234
        raise NotImplementedError(self.get_repository_transport)
 
235
 
 
236
    def get_workingtree_transport(self, tree_format):
 
237
        """Get the transport for use by workingtree format in this ControlDir.
 
238
 
 
239
        Note that bzr dirs that do not support format strings will raise
 
240
        IncompatibleFormat if the workingtree format they are given has a
 
241
        format string, and vice versa.
 
242
 
 
243
        If workingtree_format is None, the transport is returned with no
 
244
        checking. If it is not None, then the returned transport is
 
245
        guaranteed to point to an existing directory ready for use.
 
246
        """
 
247
        raise NotImplementedError(self.get_workingtree_transport)
 
248
 
210
249
    def open_branch(self, name=None, unsupported=False,
211
250
                    ignore_fallbacks=False):
212
251
        """Open the branch object at this ControlDir if one is present.
327
366
        :param create_tree_if_local: If true, a working-tree will be created
328
367
            when working locally.
329
368
        """
330
 
        raise NotImplementedError(self.sprout)
 
369
        operation = cleanup.OperationWithCleanups(self._sprout)
 
370
        return operation.run(url, revision_id=revision_id,
 
371
            force_new_repo=force_new_repo, recurse=recurse,
 
372
            possible_transports=possible_transports,
 
373
            accelerator_tree=accelerator_tree, hardlink=hardlink,
 
374
            stacked=stacked, source_branch=source_branch,
 
375
            create_tree_if_local=create_tree_if_local)
 
376
 
 
377
    def _sprout(self, op, url, revision_id=None, force_new_repo=False,
 
378
               recurse='down', possible_transports=None,
 
379
               accelerator_tree=None, hardlink=False, stacked=False,
 
380
               source_branch=None, create_tree_if_local=True):
 
381
        add_cleanup = op.add_cleanup
 
382
        fetch_spec_factory = fetch.FetchSpecFactory()
 
383
        if revision_id is not None:
 
384
            fetch_spec_factory.add_revision_ids([revision_id])
 
385
            fetch_spec_factory.source_branch_stop_revision_id = revision_id
 
386
        target_transport = _mod_transport.get_transport(url,
 
387
            possible_transports)
 
388
        target_transport.ensure_base()
 
389
        cloning_format = self.cloning_metadir(stacked)
 
390
        # Create/update the result branch
 
391
        result = cloning_format.initialize_on_transport(target_transport)
 
392
        source_branch, source_repository = self._find_source_repo(
 
393
            add_cleanup, source_branch)
 
394
        fetch_spec_factory.source_branch = source_branch
 
395
        # if a stacked branch wasn't requested, we don't create one
 
396
        # even if the origin was stacked
 
397
        if stacked and source_branch is not None:
 
398
            stacked_branch_url = self.root_transport.base
 
399
        else:
 
400
            stacked_branch_url = None
 
401
        repository_policy = result.determine_repository_policy(
 
402
            force_new_repo, stacked_branch_url, require_stacking=stacked)
 
403
        result_repo, is_new_repo = repository_policy.acquire_repository()
 
404
        add_cleanup(result_repo.lock_write().unlock)
 
405
        fetch_spec_factory.source_repo = source_repository
 
406
        fetch_spec_factory.target_repo = result_repo
 
407
        if stacked or (len(result_repo._fallback_repositories) != 0):
 
408
            target_repo_kind = fetch.TargetRepoKinds.STACKED
 
409
        elif is_new_repo:
 
410
            target_repo_kind = fetch.TargetRepoKinds.EMPTY
 
411
        else:
 
412
            target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
 
413
        fetch_spec_factory.target_repo_kind = target_repo_kind
 
414
        if source_repository is not None:
 
415
            fetch_spec = fetch_spec_factory.make_fetch_spec()
 
416
            result_repo.fetch(source_repository, fetch_spec=fetch_spec)
 
417
 
 
418
        if source_branch is None:
 
419
            # this is for sprouting a controldir without a branch; is that
 
420
            # actually useful?
 
421
            # Not especially, but it's part of the contract.
 
422
            result_branch = result.create_branch()
 
423
        else:
 
424
            result_branch = source_branch.sprout(result,
 
425
                revision_id=revision_id, repository_policy=repository_policy,
 
426
                repository=result_repo)
 
427
        mutter("created new branch %r" % (result_branch,))
 
428
 
 
429
        # Create/update the result working tree
 
430
        if (create_tree_if_local and
 
431
            isinstance(target_transport, local.LocalTransport) and
 
432
            (result_repo is None or result_repo.make_working_trees())):
 
433
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
 
434
                hardlink=hardlink, from_branch=result_branch)
 
435
            wt.lock_write()
 
436
            try:
 
437
                if wt.path2id('') is None:
 
438
                    try:
 
439
                        wt.set_root_id(self.open_workingtree.get_root_id())
 
440
                    except errors.NoWorkingTree:
 
441
                        pass
 
442
            finally:
 
443
                wt.unlock()
 
444
        else:
 
445
            wt = None
 
446
        if recurse == 'down':
 
447
            basis = None
 
448
            if wt is not None:
 
449
                basis = wt.basis_tree()
 
450
            elif result_branch is not None:
 
451
                basis = result_branch.basis_tree()
 
452
            elif source_branch is not None:
 
453
                basis = source_branch.basis_tree()
 
454
            if basis is not None:
 
455
                add_cleanup(basis.lock_read().unlock)
 
456
                subtrees = basis.iter_references()
 
457
            else:
 
458
                subtrees = []
 
459
            for path, file_id in subtrees:
 
460
                target = urlutils.join(url, urlutils.escape(path))
 
461
                sublocation = source_branch.reference_parent(file_id, path)
 
462
                sublocation.bzrdir.sprout(target,
 
463
                    basis.get_reference_revision(file_id, path),
 
464
                    force_new_repo=force_new_repo, recurse=recurse,
 
465
                    stacked=stacked)
 
466
        return result
 
467
 
 
468
    def _find_source_repo(self, add_cleanup, source_branch):
 
469
        """Find the source branch and repo for a sprout operation.
 
470
        
 
471
        This is helper intended for use by _sprout.
 
472
 
 
473
        :returns: (source_branch, source_repository).  Either or both may be
 
474
            None.  If not None, they will be read-locked (and their unlock(s)
 
475
            scheduled via the add_cleanup param).
 
476
        """
 
477
        if source_branch is not None:
 
478
            add_cleanup(source_branch.lock_read().unlock)
 
479
            return source_branch, source_branch.repository
 
480
        try:
 
481
            source_branch = self.open_branch()
 
482
            source_repository = source_branch.repository
 
483
        except errors.NotBranchError:
 
484
            source_branch = None
 
485
            try:
 
486
                source_repository = self.open_repository()
 
487
            except errors.NoRepositoryPresent:
 
488
                source_repository = None
 
489
            else:
 
490
                add_cleanup(source_repository.lock_read().unlock)
 
491
        else:
 
492
            add_cleanup(source_branch.lock_read().unlock)
 
493
        return source_branch, source_repository
331
494
 
332
495
    def push_branch(self, source, revision_id=None, overwrite=False, 
333
496
        remember=False, create_prefix=False):
349
512
        if br_to is None:
350
513
            # We have a repository but no branch, copy the revisions, and then
351
514
            # 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
515
            repository_to.fetch(source.repository, revision_id=revision_id)
357
516
            br_to = source.clone(self, revision_id=revision_id)
358
517
            if source.get_push_location() is None or remember:
443
602
 
444
603
    def clone_on_transport(self, transport, revision_id=None,
445
604
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
446
 
        create_prefix=False, use_existing_dir=True, no_tree=False):
 
605
        create_prefix=False, use_existing_dir=True):
447
606
        """Clone this bzrdir and its contents to transport verbatim.
448
607
 
449
608
        :param transport: The transport for the location to produce the clone
458
617
        :param create_prefix: Create any missing directories leading up to
459
618
            to_transport.
460
619
        :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
620
        """
463
621
        raise NotImplementedError(self.clone_on_transport)
464
622
 
465
623
 
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
624
class ControlDirFormat(object):
592
625
    """An encapsulation of the initialization and open routines for a format.
593
626
 
612
645
    _default_format = None
613
646
    """The default format used for new control directories."""
614
647
 
 
648
    _formats = []
 
649
    """The registered control formats - .bzr, ....
 
650
 
 
651
    This is a list of ControlDirFormat objects.
 
652
    """
 
653
 
615
654
    _server_probers = []
616
655
    """The registered server format probers, e.g. RemoteBzrProber.
617
656
 
629
668
    """
630
669
 
631
670
    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
671
 
642
672
    def get_format_description(self):
643
673
        """Return the short description for this format."""
666
696
        """
667
697
        return True
668
698
 
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
699
    def same_model(self, target_format):
689
700
        return (self.repository_format.rich_root_data ==
690
701
            target_format.rich_root_data)
694
705
        """Register a format that does not use '.bzr' for its control dir.
695
706
 
696
707
        """
697
 
        raise errors.BzrError("ControlDirFormat.register_format() has been "
698
 
            "removed in Bazaar 2.4. Please upgrade your plugins.")
 
708
        klass._formats.append(format)
699
709
 
700
710
    @classmethod
701
711
    def register_prober(klass, prober):
727
737
        return self.get_format_description().rstrip()
728
738
 
729
739
    @classmethod
 
740
    def unregister_format(klass, format):
 
741
        klass._formats.remove(format)
 
742
 
 
743
    @classmethod
730
744
    def known_formats(klass):
731
745
        """Return all the known formats.
732
746
        """
733
 
        result = set()
734
 
        for prober_kls in klass._probers + klass._server_probers:
735
 
            result.update(prober_kls.known_formats())
736
 
        return result
 
747
        return set(klass._formats)
737
748
 
738
749
    @classmethod
739
750
    def find_format(klass, transport, _server_formats=True):
829
840
 
830
841
 
831
842
class Prober(object):
832
 
    """Abstract class that can be used to detect a particular kind of
 
843
    """Abstract class that can be used to detect a particular kind of 
833
844
    control directory.
834
845
 
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
 
846
    At the moment this just contains a single method to probe a particular 
 
847
    transport, but it may be extended in the future to e.g. avoid 
837
848
    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
849
    """
846
850
 
847
851
    def probe_transport(self, transport):
854
858
        """
855
859
        raise NotImplementedError(self.probe_transport)
856
860
 
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
861
 
869
862
class ControlDirFormatInfo(object):
870
863
 
879
872
    """Registry of user-selectable ControlDir subformats.
880
873
 
881
874
    Differs from ControlDirFormat._formats in that it provides sub-formats,
882
 
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
 
875
    e.g. ControlDirMeta1 with weave repository.  Also, it's more user-oriented.
883
876
    """
884
877
 
885
878
    def __init__(self):