/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

  • Committer: Vincent Ladeuil
  • Date: 2011-07-06 09:22:00 UTC
  • mfrom: (6008 +trunk)
  • mto: (6012.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6013.
  • Revision ID: v.ladeuil+lp@free.fr-20110706092200-7iai2mwzc0sqdsvf
MergingĀ inĀ trunk

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,
31
30
    errors,
32
 
    graph,
33
31
    revision as _mod_revision,
34
32
    transport as _mod_transport,
35
 
    urlutils,
 
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
 
    local,
45
 
    )
46
38
 
47
39
""")
48
40
 
82
74
        return self.user_transport.base
83
75
 
84
76
 
 
77
 
85
78
class ControlDir(ControlComponent):
86
79
    """A control directory.
87
80
 
140
133
        """
141
134
        raise NotImplementedError(self.needs_format_conversion)
142
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
 
143
144
    def destroy_repository(self):
144
145
        """Destroy the repository in this ControlDir."""
145
146
        raise NotImplementedError(self.destroy_repository)
206
207
            raise errors.NoColocatedBranchSupport(self)
207
208
        return None
208
209
 
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
 
 
248
210
    def open_branch(self, name=None, unsupported=False,
249
211
                    ignore_fallbacks=False):
250
212
        """Open the branch object at this ControlDir if one is present.
264
226
        get at a repository.
265
227
 
266
228
        :param _unsupported: a private parameter, not part of the api.
 
229
 
267
230
        TODO: static convenience version of this?
268
231
        """
269
232
        raise NotImplementedError(self.open_repository)
352
315
        whether one existed before or not; and a local branch is always
353
316
        created.
354
317
 
355
 
        if revision_id is not None, then the clone operation may tune
356
 
            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.
357
320
        :param accelerator_tree: A tree which can be used for retrieving file
358
321
            contents more quickly than the revision tree, i.e. a workingtree.
359
322
            The revision tree will be used for cases where accelerator_tree's
365
328
        :param create_tree_if_local: If true, a working-tree will be created
366
329
            when working locally.
367
330
        """
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 = _mod_transport.get_transport(url,
382
 
            possible_transports)
383
 
        target_transport.ensure_base()
384
 
        cloning_format = self.cloning_metadir(stacked)
385
 
        # Create/update the result branch
386
 
        result = cloning_format.initialize_on_transport(target_transport)
387
 
        # if a stacked branch wasn't requested, we don't create one
388
 
        # even if the origin was stacked
389
 
        stacked_branch_url = None
390
 
        if source_branch is not None:
391
 
            add_cleanup(source_branch.lock_read().unlock)
392
 
            if stacked:
393
 
                stacked_branch_url = self.root_transport.base
394
 
            source_repository = source_branch.repository
395
 
        else:
396
 
            try:
397
 
                source_branch = self.open_branch()
398
 
                source_repository = source_branch.repository
399
 
                if stacked:
400
 
                    stacked_branch_url = self.root_transport.base
401
 
            except errors.NotBranchError:
402
 
                source_branch = None
403
 
                try:
404
 
                    source_repository = self.open_repository()
405
 
                except errors.NoRepositoryPresent:
406
 
                    source_repository = None
407
 
                else:
408
 
                    add_cleanup(source_repository.lock_read().unlock)
409
 
            else:
410
 
                add_cleanup(source_branch.lock_read().unlock)
411
 
        repository_policy = result.determine_repository_policy(
412
 
            force_new_repo, stacked_branch_url, require_stacking=stacked)
413
 
        result_repo, is_new_repo = repository_policy.acquire_repository()
414
 
        add_cleanup(result_repo.lock_write().unlock)
415
 
        is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
416
 
        if is_new_repo and revision_id is not None and not is_stacked:
417
 
            fetch_spec = graph.PendingAncestryResult(
418
 
                [revision_id], source_repository)
419
 
        else:
420
 
            fetch_spec = None
421
 
        if source_repository is not None:
422
 
            # Fetch while stacked to prevent unstacked fetch from
423
 
            # Branch.sprout.
424
 
            if fetch_spec is None:
425
 
                result_repo.fetch(source_repository, revision_id=revision_id)
426
 
            else:
427
 
                result_repo.fetch(source_repository, fetch_spec=fetch_spec)
428
 
 
429
 
        if source_branch is None:
430
 
            # this is for sprouting a controldir without a branch; is that
431
 
            # actually useful?
432
 
            # Not especially, but it's part of the contract.
433
 
            result_branch = result.create_branch()
434
 
        else:
435
 
            result_branch = source_branch.sprout(result,
436
 
                revision_id=revision_id, repository_policy=repository_policy,
437
 
                repository=result_repo)
438
 
        mutter("created new branch %r" % (result_branch,))
439
 
 
440
 
        # Create/update the result working tree
441
 
        if (create_tree_if_local and
442
 
            isinstance(target_transport, local.LocalTransport) and
443
 
            (result_repo is None or result_repo.make_working_trees())):
444
 
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
445
 
                hardlink=hardlink, from_branch=result_branch)
446
 
            wt.lock_write()
447
 
            try:
448
 
                if wt.path2id('') is None:
449
 
                    try:
450
 
                        wt.set_root_id(self.open_workingtree.get_root_id())
451
 
                    except errors.NoWorkingTree:
452
 
                        pass
453
 
            finally:
454
 
                wt.unlock()
455
 
        else:
456
 
            wt = None
457
 
        if recurse == 'down':
458
 
            if wt is not None:
459
 
                basis = wt.basis_tree()
460
 
                basis.lock_read()
461
 
                subtrees = basis.iter_references()
462
 
            elif result_branch is not None:
463
 
                basis = result_branch.basis_tree()
464
 
                basis.lock_read()
465
 
                subtrees = basis.iter_references()
466
 
            elif source_branch is not None:
467
 
                basis = source_branch.basis_tree()
468
 
                basis.lock_read()
469
 
                subtrees = basis.iter_references()
470
 
            else:
471
 
                subtrees = []
472
 
                basis = None
473
 
            try:
474
 
                for path, file_id in subtrees:
475
 
                    target = urlutils.join(url, urlutils.escape(path))
476
 
                    sublocation = source_branch.reference_parent(file_id, path)
477
 
                    sublocation.bzrdir.sprout(target,
478
 
                        basis.get_reference_revision(file_id, path),
479
 
                        force_new_repo=force_new_repo, recurse=recurse,
480
 
                        stacked=stacked)
481
 
            finally:
482
 
                if basis is not None:
483
 
                    basis.unlock()
484
 
        return result
 
331
        raise NotImplementedError(self.sprout)
485
332
 
486
333
    def push_branch(self, source, revision_id=None, overwrite=False, 
487
334
        remember=False, create_prefix=False):
597
444
 
598
445
    def clone_on_transport(self, transport, revision_id=None,
599
446
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
600
 
        create_prefix=False, use_existing_dir=True):
 
447
        create_prefix=False, use_existing_dir=True, no_tree=False):
601
448
        """Clone this bzrdir and its contents to transport verbatim.
602
449
 
603
450
        :param transport: The transport for the location to produce the clone
612
459
        :param create_prefix: Create any missing directories leading up to
613
460
            to_transport.
614
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.
615
463
        """
616
464
        raise NotImplementedError(self.clone_on_transport)
617
465
 
618
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)
 
590
 
 
591
 
619
592
class ControlDirFormat(object):
620
593
    """An encapsulation of the initialization and open routines for a format.
621
594
 
640
613
    _default_format = None
641
614
    """The default format used for new control directories."""
642
615
 
643
 
    _formats = []
644
 
    """The registered control formats - .bzr, ....
645
 
 
646
 
    This is a list of ControlDirFormat objects.
647
 
    """
648
 
 
649
616
    _server_probers = []
650
617
    """The registered server format probers, e.g. RemoteBzrProber.
651
618
 
663
630
    """
664
631
 
665
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."""
666
642
 
667
643
    def get_format_description(self):
668
644
        """Return the short description for this format."""
691
667
        """
692
668
        return True
693
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
 
694
689
    def same_model(self, target_format):
695
690
        return (self.repository_format.rich_root_data ==
696
691
            target_format.rich_root_data)
700
695
        """Register a format that does not use '.bzr' for its control dir.
701
696
 
702
697
        """
703
 
        klass._formats.append(format)
 
698
        raise errors.BzrError("ControlDirFormat.register_format() has been "
 
699
            "removed in Bazaar 2.4. Please upgrade your plugins.")
704
700
 
705
701
    @classmethod
706
702
    def register_prober(klass, prober):
732
728
        return self.get_format_description().rstrip()
733
729
 
734
730
    @classmethod
735
 
    def unregister_format(klass, format):
736
 
        klass._formats.remove(format)
737
 
 
738
 
    @classmethod
739
731
    def known_formats(klass):
740
732
        """Return all the known formats.
741
733
        """
742
 
        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
743
738
 
744
739
    @classmethod
745
740
    def find_format(klass, transport, _server_formats=True):
835
830
 
836
831
 
837
832
class Prober(object):
838
 
    """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
839
834
    control directory.
840
835
 
841
 
    At the moment this just contains a single method to probe a particular 
842
 
    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
843
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.
844
846
    """
845
847
 
846
848
    def probe_transport(self, transport):
853
855
        """
854
856
        raise NotImplementedError(self.probe_transport)
855
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
 
856
869
 
857
870
class ControlDirFormatInfo(object):
858
871
 
867
880
    """Registry of user-selectable ControlDir subformats.
868
881
 
869
882
    Differs from ControlDirFormat._formats in that it provides sub-formats,
870
 
    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.
871
884
    """
872
885
 
873
886
    def __init__(self):