~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

After adding a pseudo-failure update the stored test count again

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
 
from bzrlib.transport import (
44
 
    get_transport,
45
 
    local,
46
 
    )
47
39
 
48
40
""")
49
41
 
 
42
from bzrlib import registry
 
43
 
50
44
 
51
45
class ControlComponent(object):
52
46
    """Abstract base class for control directory components.
81
75
        return self.user_transport.base
82
76
 
83
77
 
 
78
 
84
79
class ControlDir(ControlComponent):
85
80
    """A control directory.
86
81
 
139
134
        """
140
135
        raise NotImplementedError(self.needs_format_conversion)
141
136
 
 
137
    def create_repository(self, shared=False):
 
138
        """Create a new repository in this control directory.
 
139
 
 
140
        :param shared: If a shared repository should be created
 
141
        :return: The newly created repository
 
142
        """
 
143
        raise NotImplementedError(self.create_repository)
 
144
 
142
145
    def destroy_repository(self):
143
146
        """Destroy the repository in this ControlDir."""
144
147
        raise NotImplementedError(self.destroy_repository)
145
148
 
146
 
    def create_branch(self, name=None):
 
149
    def create_branch(self, name=None, repository=None,
 
150
                      append_revisions_only=None):
147
151
        """Create a branch in this ControlDir.
148
152
 
149
153
        :param name: Name of the colocated branch to create, None for
150
154
            the default branch.
 
155
        :param append_revisions_only: Whether this branch should only allow
 
156
            appending new revisions to its history.
151
157
 
152
158
        The controldirs format will control what branch format is created.
153
159
        For more control see BranchFormatXX.create(a_controldir).
191
197
        """
192
198
        raise NotImplementedError(self.destroy_workingtree_metadata)
193
199
 
 
200
    def find_branch_format(self, name=None):
 
201
        """Find the branch 'format' for this bzrdir.
 
202
 
 
203
        This might be a synthetic object for e.g. RemoteBranch and SVN.
 
204
        """
 
205
        raise NotImplementedError(self.find_branch_format)
 
206
 
194
207
    def get_branch_reference(self, name=None):
195
208
        """Return the referenced URL for the branch in this controldir.
196
209
 
205
218
            raise errors.NoColocatedBranchSupport(self)
206
219
        return None
207
220
 
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
221
    def open_branch(self, name=None, unsupported=False,
248
222
                    ignore_fallbacks=False):
249
223
        """Open the branch object at this ControlDir if one is present.
263
237
        get at a repository.
264
238
 
265
239
        :param _unsupported: a private parameter, not part of the api.
 
240
 
266
241
        TODO: static convenience version of this?
267
242
        """
268
243
        raise NotImplementedError(self.open_repository)
302
277
        except errors.NotBranchError:
303
278
            return False
304
279
 
 
280
    def _get_selected_branch(self):
 
281
        """Return the name of the branch selected by the user.
 
282
 
 
283
        :return: Name of the branch selected by the user, or None.
 
284
        """
 
285
        branch = self.root_transport.get_segment_parameters().get("branch")
 
286
        if branch is not None:
 
287
            branch = urlutils.unescape(branch)
 
288
        return branch
 
289
 
305
290
    def has_workingtree(self):
306
291
        """Tell if this controldir contains a working tree.
307
292
 
351
336
        whether one existed before or not; and a local branch is always
352
337
        created.
353
338
 
354
 
        if revision_id is not None, then the clone operation may tune
355
 
            itself to download less data.
 
339
        :param revision_id: if revision_id is not None, then the clone
 
340
            operation may tune itself to download less data.
356
341
        :param accelerator_tree: A tree which can be used for retrieving file
357
342
            contents more quickly than the revision tree, i.e. a workingtree.
358
343
            The revision tree will be used for cases where accelerator_tree's
364
349
        :param create_tree_if_local: If true, a working-tree will be created
365
350
            when working locally.
366
351
        """
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
 
352
        raise NotImplementedError(self.sprout)
463
353
 
464
354
    def push_branch(self, source, revision_id=None, overwrite=False, 
465
355
        remember=False, create_prefix=False):
481
371
        if br_to is None:
482
372
            # We have a repository but no branch, copy the revisions, and then
483
373
            # create a branch.
 
374
            if revision_id is None:
 
375
                # No revision supplied by the user, default to the branch
 
376
                # revision
 
377
                revision_id = source.last_revision()
484
378
            repository_to.fetch(source.repository, revision_id=revision_id)
485
379
            br_to = source.clone(self, revision_id=revision_id)
486
380
            if source.get_push_location() is None or remember:
564
458
        :param preserve_stacking: When cloning a stacked branch, stack the
565
459
            new branch on top of the other branch's stacked-on branch.
566
460
        """
567
 
        return self.clone_on_transport(get_transport(url),
 
461
        return self.clone_on_transport(_mod_transport.get_transport(url),
568
462
                                       revision_id=revision_id,
569
463
                                       force_new_repo=force_new_repo,
570
464
                                       preserve_stacking=preserve_stacking)
571
465
 
572
466
    def clone_on_transport(self, transport, revision_id=None,
573
467
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
574
 
        create_prefix=False, use_existing_dir=True):
 
468
        create_prefix=False, use_existing_dir=True, no_tree=False):
575
469
        """Clone this bzrdir and its contents to transport verbatim.
576
470
 
577
471
        :param transport: The transport for the location to produce the clone
586
480
        :param create_prefix: Create any missing directories leading up to
587
481
            to_transport.
588
482
        :param use_existing_dir: Use an existing directory if one exists.
 
483
        :param no_tree: If set to true prevents creation of a working tree.
589
484
        """
590
485
        raise NotImplementedError(self.clone_on_transport)
591
486
 
592
487
 
 
488
class ControlComponentFormat(object):
 
489
    """A component that can live inside of a .bzr meta directory."""
 
490
 
 
491
    upgrade_recommended = False
 
492
 
 
493
    def get_format_string(self):
 
494
        """Return the format of this format, if usable in meta directories."""
 
495
        raise NotImplementedError(self.get_format_string)
 
496
 
 
497
    def get_format_description(self):
 
498
        """Return the short description for this format."""
 
499
        raise NotImplementedError(self.get_format_description)
 
500
 
 
501
    def is_supported(self):
 
502
        """Is this format supported?
 
503
 
 
504
        Supported formats must be initializable and openable.
 
505
        Unsupported formats may not support initialization or committing or
 
506
        some other features depending on the reason for not being supported.
 
507
        """
 
508
        return True
 
509
 
 
510
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
511
        basedir=None):
 
512
        """Give an error or warning on old formats.
 
513
 
 
514
        :param allow_unsupported: If true, allow opening
 
515
            formats that are strongly deprecated, and which may
 
516
            have limited functionality.
 
517
 
 
518
        :param recommend_upgrade: If true (default), warn
 
519
            the user through the ui object that they may wish
 
520
            to upgrade the object.
 
521
        """
 
522
        if not allow_unsupported and not self.is_supported():
 
523
            # see open_downlevel to open legacy branches.
 
524
            raise errors.UnsupportedFormatError(format=self)
 
525
        if recommend_upgrade and self.upgrade_recommended:
 
526
            ui.ui_factory.recommend_upgrade(
 
527
                self.get_format_description(), basedir)
 
528
 
 
529
 
 
530
class ControlComponentFormatRegistry(registry.FormatRegistry):
 
531
    """A registry for control components (branch, workingtree, repository)."""
 
532
 
 
533
    def __init__(self, other_registry=None):
 
534
        super(ControlComponentFormatRegistry, self).__init__(other_registry)
 
535
        self._extra_formats = []
 
536
 
 
537
    def register(self, format):
 
538
        """Register a new format."""
 
539
        super(ControlComponentFormatRegistry, self).register(
 
540
            format.get_format_string(), format)
 
541
 
 
542
    def remove(self, format):
 
543
        """Remove a registered format."""
 
544
        super(ControlComponentFormatRegistry, self).remove(
 
545
            format.get_format_string())
 
546
 
 
547
    def register_extra(self, format):
 
548
        """Register a format that can not be used in a metadir.
 
549
 
 
550
        This is mainly useful to allow custom repository formats, such as older
 
551
        Bazaar formats and foreign formats, to be tested.
 
552
        """
 
553
        self._extra_formats.append(registry._ObjectGetter(format))
 
554
 
 
555
    def remove_extra(self, format):
 
556
        """Remove an extra format.
 
557
        """
 
558
        self._extra_formats.remove(registry._ObjectGetter(format))
 
559
 
 
560
    def register_extra_lazy(self, module_name, member_name):
 
561
        """Register a format lazily.
 
562
        """
 
563
        self._extra_formats.append(
 
564
            registry._LazyObjectGetter(module_name, member_name))
 
565
 
 
566
    def _get_extra(self):
 
567
        """Return all "extra" formats, not usable in meta directories."""
 
568
        result = []
 
569
        for getter in self._extra_formats:
 
570
            f = getter.get_obj()
 
571
            if callable(f):
 
572
                f = f()
 
573
            result.append(f)
 
574
        return result
 
575
 
 
576
    def _get_all(self):
 
577
        """Return all formats, even those not usable in metadirs.
 
578
        """
 
579
        result = []
 
580
        for name in self.keys():
 
581
            fmt = self.get(name)
 
582
            if callable(fmt):
 
583
                fmt = fmt()
 
584
            result.append(fmt)
 
585
        return result + self._get_extra()
 
586
 
 
587
    def _get_all_modules(self):
 
588
        """Return a set of the modules providing objects."""
 
589
        modules = set()
 
590
        for name in self.keys():
 
591
            modules.add(self._get_module(name))
 
592
        for getter in self._extra_formats:
 
593
            modules.add(getter.get_module())
 
594
        return modules
 
595
 
 
596
 
 
597
class Converter(object):
 
598
    """Converts a disk format object from one format to another."""
 
599
 
 
600
    def convert(self, to_convert, pb):
 
601
        """Perform the conversion of to_convert, giving feedback via pb.
 
602
 
 
603
        :param to_convert: The disk object to convert.
 
604
        :param pb: a progress bar to use for progress information.
 
605
        """
 
606
 
 
607
    def step(self, message):
 
608
        """Update the pb by a step."""
 
609
        self.count +=1
 
610
        self.pb.update(message, self.count, self.total)
 
611
 
 
612
 
593
613
class ControlDirFormat(object):
594
614
    """An encapsulation of the initialization and open routines for a format.
595
615
 
614
634
    _default_format = None
615
635
    """The default format used for new control directories."""
616
636
 
617
 
    _formats = []
618
 
    """The registered control formats - .bzr, ....
619
 
 
620
 
    This is a list of ControlDirFormat objects.
621
 
    """
622
 
 
623
637
    _server_probers = []
624
638
    """The registered server format probers, e.g. RemoteBzrProber.
625
639
 
637
651
    """
638
652
 
639
653
    supports_workingtrees = True
 
654
    """Whether working trees can exist in control directories of this format.
 
655
    """
 
656
 
 
657
    fixed_components = False
 
658
    """Whether components can not change format independent of the control dir.
 
659
    """
 
660
 
 
661
    upgrade_recommended = False
 
662
    """Whether an upgrade from this format is recommended."""
640
663
 
641
664
    def get_format_description(self):
642
665
        """Return the short description for this format."""
665
688
        """
666
689
        return True
667
690
 
 
691
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
692
        basedir=None):
 
693
        """Give an error or warning on old formats.
 
694
 
 
695
        :param allow_unsupported: If true, allow opening
 
696
            formats that are strongly deprecated, and which may
 
697
            have limited functionality.
 
698
 
 
699
        :param recommend_upgrade: If true (default), warn
 
700
            the user through the ui object that they may wish
 
701
            to upgrade the object.
 
702
        """
 
703
        if not allow_unsupported and not self.is_supported():
 
704
            # see open_downlevel to open legacy branches.
 
705
            raise errors.UnsupportedFormatError(format=self)
 
706
        if recommend_upgrade and self.upgrade_recommended:
 
707
            ui.ui_factory.recommend_upgrade(
 
708
                self.get_format_description(), basedir)
 
709
 
668
710
    def same_model(self, target_format):
669
711
        return (self.repository_format.rich_root_data ==
670
712
            target_format.rich_root_data)
674
716
        """Register a format that does not use '.bzr' for its control dir.
675
717
 
676
718
        """
677
 
        klass._formats.append(format)
 
719
        raise errors.BzrError("ControlDirFormat.register_format() has been "
 
720
            "removed in Bazaar 2.4. Please upgrade your plugins.")
678
721
 
679
722
    @classmethod
680
723
    def register_prober(klass, prober):
706
749
        return self.get_format_description().rstrip()
707
750
 
708
751
    @classmethod
709
 
    def unregister_format(klass, format):
710
 
        klass._formats.remove(format)
711
 
 
712
 
    @classmethod
713
752
    def known_formats(klass):
714
753
        """Return all the known formats.
715
754
        """
716
 
        return set(klass._formats)
 
755
        result = set()
 
756
        for prober_kls in klass._probers + klass._server_probers:
 
757
            result.update(prober_kls.known_formats())
 
758
        return result
717
759
 
718
760
    @classmethod
719
761
    def find_format(klass, transport, _server_formats=True):
741
783
        Subclasses should typically override initialize_on_transport
742
784
        instead of this method.
743
785
        """
744
 
        return self.initialize_on_transport(get_transport(url,
745
 
                                                          possible_transports))
 
786
        return self.initialize_on_transport(
 
787
            _mod_transport.get_transport(url, possible_transports))
 
788
 
746
789
    def initialize_on_transport(self, transport):
747
790
        """Initialize a new controldir in the base directory of a Transport."""
748
791
        raise NotImplementedError(self.initialize_on_transport)
808
851
 
809
852
 
810
853
class Prober(object):
811
 
    """Abstract class that can be used to detect a particular kind of 
 
854
    """Abstract class that can be used to detect a particular kind of
812
855
    control directory.
813
856
 
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 
 
857
    At the moment this just contains a single method to probe a particular
 
858
    transport, but it may be extended in the future to e.g. avoid
816
859
    multiple levels of probing for Subversion repositories.
 
860
 
 
861
    See BzrProber and RemoteBzrProber in bzrlib.bzrdir for the
 
862
    probers that detect .bzr/ directories and Bazaar smart servers,
 
863
    respectively.
 
864
 
 
865
    Probers should be registered using the register_server_prober or
 
866
    register_prober methods on ControlDirFormat.
817
867
    """
818
868
 
819
869
    def probe_transport(self, transport):
826
876
        """
827
877
        raise NotImplementedError(self.probe_transport)
828
878
 
 
879
    @classmethod
 
880
    def known_formats(cls):
 
881
        """Return the control dir formats known by this prober.
 
882
 
 
883
        Multiple probers can return the same formats, so this should
 
884
        return a set.
 
885
 
 
886
        :return: A set of known formats.
 
887
        """
 
888
        raise NotImplementedError(cls.known_formats)
 
889
 
829
890
 
830
891
class ControlDirFormatInfo(object):
831
892
 
840
901
    """Registry of user-selectable ControlDir subformats.
841
902
 
842
903
    Differs from ControlDirFormat._formats in that it provides sub-formats,
843
 
    e.g. ControlDirMeta1 with weave repository.  Also, it's more user-oriented.
 
904
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
844
905
    """
845
906
 
846
907
    def __init__(self):