~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

(gz) Fix test failure on alpha by correcting format string for
 gc_chk_sha1_record (Martin [gz])

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,
34
36
    urlutils,
35
37
    )
36
38
from bzrlib.push import (
37
39
    PushResult,
38
40
    )
 
41
from bzrlib.trace import (
 
42
    mutter,
 
43
    )
 
44
from bzrlib.transport import (
 
45
    local,
 
46
    )
39
47
 
40
48
""")
41
49
 
145
153
        """Destroy the repository in this ControlDir."""
146
154
        raise NotImplementedError(self.destroy_repository)
147
155
 
148
 
    def create_branch(self, name=None, repository=None,
149
 
                      append_revisions_only=None):
 
156
    def create_branch(self, name=None, repository=None):
150
157
        """Create a branch in this ControlDir.
151
158
 
152
159
        :param name: Name of the colocated branch to create, None for
153
160
            the default branch.
154
 
        :param append_revisions_only: Whether this branch should only allow
155
 
            appending new revisions to its history.
156
161
 
157
162
        The controldirs format will control what branch format is created.
158
163
        For more control see BranchFormatXX.create(a_controldir).
196
201
        """
197
202
        raise NotImplementedError(self.destroy_workingtree_metadata)
198
203
 
199
 
    def find_branch_format(self, name=None):
200
 
        """Find the branch 'format' for this bzrdir.
201
 
 
202
 
        This might be a synthetic object for e.g. RemoteBranch and SVN.
203
 
        """
204
 
        raise NotImplementedError(self.find_branch_format)
205
 
 
206
204
    def get_branch_reference(self, name=None):
207
205
        """Return the referenced URL for the branch in this controldir.
208
206
 
217
215
            raise errors.NoColocatedBranchSupport(self)
218
216
        return None
219
217
 
 
218
    def get_branch_transport(self, branch_format, name=None):
 
219
        """Get the transport for use by branch format in this ControlDir.
 
220
 
 
221
        Note that bzr dirs that do not support format strings will raise
 
222
        IncompatibleFormat if the branch format they are given has
 
223
        a format string, and vice versa.
 
224
 
 
225
        If branch_format is None, the transport is returned with no
 
226
        checking. If it is not None, then the returned transport is
 
227
        guaranteed to point to an existing directory ready for use.
 
228
        """
 
229
        raise NotImplementedError(self.get_branch_transport)
 
230
 
 
231
    def get_repository_transport(self, repository_format):
 
232
        """Get the transport for use by repository format in this ControlDir.
 
233
 
 
234
        Note that bzr dirs that do not support format strings will raise
 
235
        IncompatibleFormat if the repository format they are given has
 
236
        a format string, and vice versa.
 
237
 
 
238
        If repository_format is None, the transport is returned with no
 
239
        checking. If it is not None, then the returned transport is
 
240
        guaranteed to point to an existing directory ready for use.
 
241
        """
 
242
        raise NotImplementedError(self.get_repository_transport)
 
243
 
 
244
    def get_workingtree_transport(self, tree_format):
 
245
        """Get the transport for use by workingtree format in this ControlDir.
 
246
 
 
247
        Note that bzr dirs that do not support format strings will raise
 
248
        IncompatibleFormat if the workingtree format they are given has a
 
249
        format string, and vice versa.
 
250
 
 
251
        If workingtree_format is None, the transport is returned with no
 
252
        checking. If it is not None, then the returned transport is
 
253
        guaranteed to point to an existing directory ready for use.
 
254
        """
 
255
        raise NotImplementedError(self.get_workingtree_transport)
 
256
 
220
257
    def open_branch(self, name=None, unsupported=False,
221
258
                    ignore_fallbacks=False):
222
259
        """Open the branch object at this ControlDir if one is present.
236
273
        get at a repository.
237
274
 
238
275
        :param _unsupported: a private parameter, not part of the api.
239
 
 
240
276
        TODO: static convenience version of this?
241
277
        """
242
278
        raise NotImplementedError(self.open_repository)
276
312
        except errors.NotBranchError:
277
313
            return False
278
314
 
279
 
    def _get_selected_branch(self):
280
 
        """Return the name of the branch selected by the user.
281
 
 
282
 
        :return: Name of the branch selected by the user, or None.
283
 
        """
284
 
        branch = self.root_transport.get_segment_parameters().get("branch")
285
 
        if branch is not None:
286
 
            branch = urlutils.unescape(branch)
287
 
        return branch
288
 
 
289
315
    def has_workingtree(self):
290
316
        """Tell if this controldir contains a working tree.
291
317
 
335
361
        whether one existed before or not; and a local branch is always
336
362
        created.
337
363
 
338
 
        :param revision_id: if revision_id is not None, then the clone
339
 
            operation may tune itself to download less data.
 
364
        if revision_id is not None, then the clone operation may tune
 
365
            itself to download less data.
340
366
        :param accelerator_tree: A tree which can be used for retrieving file
341
367
            contents more quickly than the revision tree, i.e. a workingtree.
342
368
            The revision tree will be used for cases where accelerator_tree's
348
374
        :param create_tree_if_local: If true, a working-tree will be created
349
375
            when working locally.
350
376
        """
351
 
        raise NotImplementedError(self.sprout)
 
377
        operation = cleanup.OperationWithCleanups(self._sprout)
 
378
        return operation.run(url, revision_id=revision_id,
 
379
            force_new_repo=force_new_repo, recurse=recurse,
 
380
            possible_transports=possible_transports,
 
381
            accelerator_tree=accelerator_tree, hardlink=hardlink,
 
382
            stacked=stacked, source_branch=source_branch,
 
383
            create_tree_if_local=create_tree_if_local)
 
384
 
 
385
    def _sprout(self, op, url, revision_id=None, force_new_repo=False,
 
386
               recurse='down', possible_transports=None,
 
387
               accelerator_tree=None, hardlink=False, stacked=False,
 
388
               source_branch=None, create_tree_if_local=True):
 
389
        add_cleanup = op.add_cleanup
 
390
        fetch_spec_factory = fetch.FetchSpecFactory()
 
391
        if revision_id is not None:
 
392
            fetch_spec_factory.add_revision_ids([revision_id])
 
393
            fetch_spec_factory.source_branch_stop_revision_id = revision_id
 
394
        target_transport = _mod_transport.get_transport(url,
 
395
            possible_transports)
 
396
        target_transport.ensure_base()
 
397
        cloning_format = self.cloning_metadir(stacked)
 
398
        # Create/update the result branch
 
399
        result = cloning_format.initialize_on_transport(target_transport)
 
400
        source_branch, source_repository = self._find_source_repo(
 
401
            add_cleanup, source_branch)
 
402
        fetch_spec_factory.source_branch = source_branch
 
403
        # if a stacked branch wasn't requested, we don't create one
 
404
        # even if the origin was stacked
 
405
        if stacked and source_branch is not None:
 
406
            stacked_branch_url = self.root_transport.base
 
407
        else:
 
408
            stacked_branch_url = None
 
409
        repository_policy = result.determine_repository_policy(
 
410
            force_new_repo, stacked_branch_url, require_stacking=stacked)
 
411
        result_repo, is_new_repo = repository_policy.acquire_repository()
 
412
        add_cleanup(result_repo.lock_write().unlock)
 
413
        fetch_spec_factory.source_repo = source_repository
 
414
        fetch_spec_factory.target_repo = result_repo
 
415
        if stacked or (len(result_repo._fallback_repositories) != 0):
 
416
            target_repo_kind = fetch.TargetRepoKinds.STACKED
 
417
        elif is_new_repo:
 
418
            target_repo_kind = fetch.TargetRepoKinds.EMPTY
 
419
        else:
 
420
            target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
 
421
        fetch_spec_factory.target_repo_kind = target_repo_kind
 
422
        if source_repository is not None:
 
423
            fetch_spec = fetch_spec_factory.make_fetch_spec()
 
424
            result_repo.fetch(source_repository, fetch_spec=fetch_spec)
 
425
 
 
426
        if source_branch is None:
 
427
            # this is for sprouting a controldir without a branch; is that
 
428
            # actually useful?
 
429
            # Not especially, but it's part of the contract.
 
430
            result_branch = result.create_branch()
 
431
        else:
 
432
            result_branch = source_branch.sprout(result,
 
433
                revision_id=revision_id, repository_policy=repository_policy,
 
434
                repository=result_repo)
 
435
        mutter("created new branch %r" % (result_branch,))
 
436
 
 
437
        # Create/update the result working tree
 
438
        if (create_tree_if_local and
 
439
            isinstance(target_transport, local.LocalTransport) and
 
440
            (result_repo is None or result_repo.make_working_trees())):
 
441
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
 
442
                hardlink=hardlink, from_branch=result_branch)
 
443
            wt.lock_write()
 
444
            try:
 
445
                if wt.path2id('') is None:
 
446
                    try:
 
447
                        wt.set_root_id(self.open_workingtree.get_root_id())
 
448
                    except errors.NoWorkingTree:
 
449
                        pass
 
450
            finally:
 
451
                wt.unlock()
 
452
        else:
 
453
            wt = None
 
454
        if recurse == 'down':
 
455
            basis = None
 
456
            if wt is not None:
 
457
                basis = wt.basis_tree()
 
458
            elif result_branch is not None:
 
459
                basis = result_branch.basis_tree()
 
460
            elif source_branch is not None:
 
461
                basis = source_branch.basis_tree()
 
462
            if basis is not None:
 
463
                add_cleanup(basis.lock_read().unlock)
 
464
                subtrees = basis.iter_references()
 
465
            else:
 
466
                subtrees = []
 
467
            for path, file_id in subtrees:
 
468
                target = urlutils.join(url, urlutils.escape(path))
 
469
                sublocation = source_branch.reference_parent(file_id, path)
 
470
                sublocation.bzrdir.sprout(target,
 
471
                    basis.get_reference_revision(file_id, path),
 
472
                    force_new_repo=force_new_repo, recurse=recurse,
 
473
                    stacked=stacked)
 
474
        return result
 
475
 
 
476
    def _find_source_repo(self, add_cleanup, source_branch):
 
477
        """Find the source branch and repo for a sprout operation.
 
478
        
 
479
        This is helper intended for use by _sprout.
 
480
 
 
481
        :returns: (source_branch, source_repository).  Either or both may be
 
482
            None.  If not None, they will be read-locked (and their unlock(s)
 
483
            scheduled via the add_cleanup param).
 
484
        """
 
485
        if source_branch is not None:
 
486
            add_cleanup(source_branch.lock_read().unlock)
 
487
            return source_branch, source_branch.repository
 
488
        try:
 
489
            source_branch = self.open_branch()
 
490
            source_repository = source_branch.repository
 
491
        except errors.NotBranchError:
 
492
            source_branch = None
 
493
            try:
 
494
                source_repository = self.open_repository()
 
495
            except errors.NoRepositoryPresent:
 
496
                source_repository = None
 
497
            else:
 
498
                add_cleanup(source_repository.lock_read().unlock)
 
499
        else:
 
500
            add_cleanup(source_branch.lock_read().unlock)
 
501
        return source_branch, source_repository
352
502
 
353
503
    def push_branch(self, source, revision_id=None, overwrite=False, 
354
504
        remember=False, create_prefix=False):
370
520
        if br_to is None:
371
521
            # We have a repository but no branch, copy the revisions, and then
372
522
            # create a branch.
373
 
            if revision_id is None:
374
 
                # No revision supplied by the user, default to the branch
375
 
                # revision
376
 
                revision_id = source.last_revision()
377
523
            repository_to.fetch(source.repository, revision_id=revision_id)
378
524
            br_to = source.clone(self, revision_id=revision_id)
379
525
            if source.get_push_location() is None or remember:
487
633
class ControlComponentFormat(object):
488
634
    """A component that can live inside of a .bzr meta directory."""
489
635
 
490
 
    upgrade_recommended = False
491
 
 
492
636
    def get_format_string(self):
493
637
        """Return the format of this format, if usable in meta directories."""
494
638
        raise NotImplementedError(self.get_format_string)
497
641
        """Return the short description for this format."""
498
642
        raise NotImplementedError(self.get_format_description)
499
643
 
500
 
    def is_supported(self):
501
 
        """Is this format supported?
502
 
 
503
 
        Supported formats must be initializable and openable.
504
 
        Unsupported formats may not support initialization or committing or
505
 
        some other features depending on the reason for not being supported.
506
 
        """
507
 
        return True
508
 
 
509
 
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
510
 
        basedir=None):
511
 
        """Give an error or warning on old formats.
512
 
 
513
 
        :param allow_unsupported: If true, allow opening
514
 
            formats that are strongly deprecated, and which may
515
 
            have limited functionality.
516
 
 
517
 
        :param recommend_upgrade: If true (default), warn
518
 
            the user through the ui object that they may wish
519
 
            to upgrade the object.
520
 
        """
521
 
        if not allow_unsupported and not self.is_supported():
522
 
            # see open_downlevel to open legacy branches.
523
 
            raise errors.UnsupportedFormatError(format=self)
524
 
        if recommend_upgrade and self.upgrade_recommended:
525
 
            ui.ui_factory.recommend_upgrade(
526
 
                self.get_format_description(), basedir)
527
 
 
528
644
 
529
645
class ControlComponentFormatRegistry(registry.FormatRegistry):
530
646
    """A registry for control components (branch, workingtree, repository)."""
593
709
        return modules
594
710
 
595
711
 
596
 
class Converter(object):
597
 
    """Converts a disk format object from one format to another."""
598
 
 
599
 
    def convert(self, to_convert, pb):
600
 
        """Perform the conversion of to_convert, giving feedback via pb.
601
 
 
602
 
        :param to_convert: The disk object to convert.
603
 
        :param pb: a progress bar to use for progress information.
604
 
        """
605
 
 
606
 
    def step(self, message):
607
 
        """Update the pb by a step."""
608
 
        self.count +=1
609
 
        self.pb.update(message, self.count, self.total)
610
 
 
611
 
 
612
712
class ControlDirFormat(object):
613
713
    """An encapsulation of the initialization and open routines for a format.
614
714
 
633
733
    _default_format = None
634
734
    """The default format used for new control directories."""
635
735
 
 
736
    _formats = []
 
737
    """The registered control formats - .bzr, ....
 
738
 
 
739
    This is a list of ControlDirFormat objects.
 
740
    """
 
741
 
636
742
    _server_probers = []
637
743
    """The registered server format probers, e.g. RemoteBzrProber.
638
744
 
657
763
    """Whether components can not change format independent of the control dir.
658
764
    """
659
765
 
660
 
    upgrade_recommended = False
661
 
    """Whether an upgrade from this format is recommended."""
662
 
 
663
766
    def get_format_description(self):
664
767
        """Return the short description for this format."""
665
768
        raise NotImplementedError(self.get_format_description)
681
784
    def is_supported(self):
682
785
        """Is this format supported?
683
786
 
684
 
        Supported formats must be openable.
 
787
        Supported formats must be initializable and openable.
685
788
        Unsupported formats may not support initialization or committing or
686
789
        some other features depending on the reason for not being supported.
687
790
        """
688
791
        return True
689
792
 
690
 
    def is_initializable(self):
691
 
        """Whether new control directories of this format can be initialized.
692
 
        """
693
 
        return self.is_supported()
694
 
 
695
 
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
696
 
        basedir=None):
697
 
        """Give an error or warning on old formats.
698
 
 
699
 
        :param allow_unsupported: If true, allow opening
700
 
            formats that are strongly deprecated, and which may
701
 
            have limited functionality.
702
 
 
703
 
        :param recommend_upgrade: If true (default), warn
704
 
            the user through the ui object that they may wish
705
 
            to upgrade the object.
706
 
        """
707
 
        if not allow_unsupported and not self.is_supported():
708
 
            # see open_downlevel to open legacy branches.
709
 
            raise errors.UnsupportedFormatError(format=self)
710
 
        if recommend_upgrade and self.upgrade_recommended:
711
 
            ui.ui_factory.recommend_upgrade(
712
 
                self.get_format_description(), basedir)
713
 
 
714
793
    def same_model(self, target_format):
715
794
        return (self.repository_format.rich_root_data ==
716
795
            target_format.rich_root_data)
720
799
        """Register a format that does not use '.bzr' for its control dir.
721
800
 
722
801
        """
723
 
        raise errors.BzrError("ControlDirFormat.register_format() has been "
724
 
            "removed in Bazaar 2.4. Please upgrade your plugins.")
 
802
        klass._formats.append(format)
725
803
 
726
804
    @classmethod
727
805
    def register_prober(klass, prober):
753
831
        return self.get_format_description().rstrip()
754
832
 
755
833
    @classmethod
 
834
    def unregister_format(klass, format):
 
835
        klass._formats.remove(format)
 
836
 
 
837
    @classmethod
756
838
    def known_formats(klass):
757
839
        """Return all the known formats.
758
840
        """
759
 
        result = set()
760
 
        for prober_kls in klass._probers + klass._server_probers:
761
 
            result.update(prober_kls.known_formats())
762
 
        return result
 
841
        return set(klass._formats)
763
842
 
764
843
    @classmethod
765
844
    def find_format(klass, transport, _server_formats=True):
855
934
 
856
935
 
857
936
class Prober(object):
858
 
    """Abstract class that can be used to detect a particular kind of
 
937
    """Abstract class that can be used to detect a particular kind of 
859
938
    control directory.
860
939
 
861
 
    At the moment this just contains a single method to probe a particular
862
 
    transport, but it may be extended in the future to e.g. avoid
 
940
    At the moment this just contains a single method to probe a particular 
 
941
    transport, but it may be extended in the future to e.g. avoid 
863
942
    multiple levels of probing for Subversion repositories.
864
 
 
865
 
    See BzrProber and RemoteBzrProber in bzrlib.bzrdir for the
866
 
    probers that detect .bzr/ directories and Bazaar smart servers,
867
 
    respectively.
868
 
 
869
 
    Probers should be registered using the register_server_prober or
870
 
    register_prober methods on ControlDirFormat.
871
943
    """
872
944
 
873
945
    def probe_transport(self, transport):
880
952
        """
881
953
        raise NotImplementedError(self.probe_transport)
882
954
 
883
 
    @classmethod
884
 
    def known_formats(cls):
885
 
        """Return the control dir formats known by this prober.
886
 
 
887
 
        Multiple probers can return the same formats, so this should
888
 
        return a set.
889
 
 
890
 
        :return: A set of known formats.
891
 
        """
892
 
        raise NotImplementedError(cls.known_formats)
893
 
 
894
955
 
895
956
class ControlDirFormatInfo(object):
896
957