~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: John Arbash Meinel
  • Date: 2007-04-28 15:04:17 UTC
  • mfrom: (2466 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2566.
  • Revision ID: john@arbash-meinel.com-20070428150417-trp3pi0pzd411pu4
[merge] bzr.dev 2466

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
# TODO: remove unittest dependency; put that stuff inside the test suite
24
24
 
25
 
# TODO: The Format probe_transport seems a bit redundant with just trying to
26
 
# open the bzrdir. -- mbp
27
 
#
28
25
# TODO: Can we move specific formats into separate modules to make this file
29
26
# smaller?
30
27
 
44
41
    lockable_files,
45
42
    lockdir,
46
43
    registry,
 
44
    remote,
47
45
    revision as _mod_revision,
48
46
    symbol_versioning,
49
47
    ui,
58
56
    sha_strings,
59
57
    sha_string,
60
58
    )
 
59
from bzrlib.smart.client import _SmartClient
 
60
from bzrlib.smart import protocol
61
61
from bzrlib.store.revision.text import TextRevisionStore
62
62
from bzrlib.store.text import TextStore
63
63
from bzrlib.store.versioned import WeaveStore
94
94
        If there is a tree, the tree is opened and break_lock() called.
95
95
        Otherwise, branch is tried, and finally repository.
96
96
        """
 
97
        # XXX: This seems more like a UI function than something that really
 
98
        # belongs in this class.
97
99
        try:
98
100
            thing_to_unlock = self.open_workingtree()
99
101
        except (errors.NotLocalUrl, errors.NoWorkingTree):
413
415
                    break
414
416
                else:
415
417
                    continue
416
 
            if ((found_bzrdir.root_transport.base == 
 
418
            if ((found_bzrdir.root_transport.base ==
417
419
                 self.root_transport.base) or repository.is_shared()):
418
420
                return repository
419
421
            else:
420
422
                raise errors.NoRepositoryPresent(self)
421
423
        raise errors.NoRepositoryPresent(self)
422
424
 
 
425
    def get_branch_reference(self):
 
426
        """Return the referenced URL for the branch in this bzrdir.
 
427
 
 
428
        :raises NotBranchError: If there is no Branch.
 
429
        :return: The URL the branch in this bzrdir references if it is a
 
430
            reference branch, or None for regular branches.
 
431
        """
 
432
        return None
 
433
 
423
434
    def get_branch_transport(self, branch_format):
424
435
        """Get the transport for use by branch format in this BzrDir.
425
436
 
517
528
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
518
529
 
519
530
    @staticmethod
520
 
    def open_from_transport(transport, _unsupported=False):
 
531
    def open_from_transport(transport, _unsupported=False,
 
532
                            _server_formats=True):
521
533
        """Open a bzrdir within a particular directory.
522
534
 
523
535
        :param transport: Transport containing the bzrdir.
526
538
        base = transport.base
527
539
 
528
540
        def find_format(transport):
529
 
            return transport, BzrDirFormat.find_format(transport)
 
541
            return transport, BzrDirFormat.find_format(
 
542
                transport, _server_formats=_server_formats)
530
543
 
531
544
        def redirected(transport, e, redirection_notice):
532
545
            qualified_source = e.get_source_url()
598
611
                return result, urlutils.unescape(a_transport.relpath(url))
599
612
            except errors.NotBranchError, e:
600
613
                pass
601
 
            new_t = a_transport.clone('..')
 
614
            try:
 
615
                new_t = a_transport.clone('..')
 
616
            except errors.InvalidURLJoin:
 
617
                # reached the root, whatever that may be
 
618
                raise errors.NotBranchError(path=url)
602
619
            if new_t.base == a_transport.base:
603
620
                # reached the root, whatever that may be
604
621
                raise errors.NotBranchError(path=url)
636
653
        """
637
654
        raise NotImplementedError(self.open_repository)
638
655
 
639
 
    def open_workingtree(self, _unsupported=False):
 
656
    def open_workingtree(self, _unsupported=False,
 
657
            recommend_upgrade=True):
640
658
        """Open the workingtree object at this BzrDir if one is present.
641
 
        
642
 
        TODO: static convenience version of this?
 
659
 
 
660
        :param recommend_upgrade: Optional keyword parameter, when True (the
 
661
            default), emit through the ui module a recommendation that the user
 
662
            upgrade the working tree when the workingtree being opened is old
 
663
            (but still fully supported).
643
664
        """
644
665
        raise NotImplementedError(self.open_workingtree)
645
666
 
673
694
            return False
674
695
 
675
696
    def _cloning_metadir(self):
 
697
        """Produce a metadir suitable for cloning with"""
676
698
        result_format = self._format.__class__()
677
699
        try:
678
700
            try:
681
703
            except errors.NotBranchError:
682
704
                source_branch = None
683
705
                source_repository = self.open_repository()
684
 
            result_format.repository_format = source_repository._format
685
706
        except errors.NoRepositoryPresent:
686
707
            source_repository = None
 
708
        else:
 
709
            # XXX TODO: This isinstance is here because we have not implemented
 
710
            # the fix recommended in bug # 103195 - to delegate this choice the
 
711
            # repository itself.
 
712
            repo_format = source_repository._format
 
713
            if not isinstance(repo_format, remote.RemoteRepositoryFormat):
 
714
                result_format.repository_format = repo_format
687
715
        try:
688
716
            # TODO: Couldn't we just probe for the format in these cases,
689
717
            # rather than opening the whole tree?  It would be a little
754
782
            result.create_repository()
755
783
        elif source_repository is not None and result_repo is None:
756
784
            # have source, and want to make a new target repo
757
 
            # we don't clone the repo because that preserves attributes
758
 
            # like is_shared(), and we have not yet implemented a 
759
 
            # repository sprout().
760
 
            result_repo = result.create_repository()
761
 
        if result_repo is not None:
 
785
            result_repo = source_repository.sprout(result, revision_id=revision_id)
 
786
        else:
762
787
            # fetch needed content into target.
763
788
            if source_repository is not None:
 
789
                # would rather do 
 
790
                # source_repository.copy_content_into(result_repo, revision_id=revision_id)
 
791
                # so we can override the copy method
764
792
                result_repo.fetch(source_repository, revision_id=revision_id)
765
793
        if source_branch is not None:
766
794
            source_branch.sprout(result, revision_id=revision_id)
1044
1072
    def destroy_workingtree_metadata(self):
1045
1073
        self.transport.delete_tree('checkout')
1046
1074
 
 
1075
    def find_branch_format(self):
 
1076
        """Find the branch 'format' for this bzrdir.
 
1077
 
 
1078
        This might be a synthetic object for e.g. RemoteBranch and SVN.
 
1079
        """
 
1080
        from bzrlib.branch import BranchFormat
 
1081
        return BranchFormat.find_format(self)
 
1082
 
1047
1083
    def _get_mkdir_mode(self):
1048
1084
        """Figure out the mode to use when creating a bzrdir subdir."""
1049
1085
        temp_control = lockable_files.LockableFiles(self.transport, '',
1050
1086
                                     lockable_files.TransportLock)
1051
1087
        return temp_control._dir_mode
1052
1088
 
 
1089
    def get_branch_reference(self):
 
1090
        """See BzrDir.get_branch_reference()."""
 
1091
        from bzrlib.branch import BranchFormat
 
1092
        format = BranchFormat.find_format(self)
 
1093
        return format.get_reference(self)
 
1094
 
1053
1095
    def get_branch_transport(self, branch_format):
1054
1096
        """See BzrDir.get_branch_transport()."""
1055
1097
        if branch_format is None:
1126
1168
 
1127
1169
    def open_branch(self, unsupported=False):
1128
1170
        """See BzrDir.open_branch."""
1129
 
        from bzrlib.branch import BranchFormat
1130
 
        format = BranchFormat.find_format(self)
 
1171
        format = self.find_branch_format()
1131
1172
        self._check_supported(format, unsupported)
1132
1173
        return format.open(self, _found=True)
1133
1174
 
1178
1219
    This is a list of BzrDirFormat objects.
1179
1220
    """
1180
1221
 
 
1222
    _control_server_formats = []
 
1223
    """The registered control server formats, e.g. RemoteBzrDirs.
 
1224
 
 
1225
    This is a list of BzrDirFormat objects.
 
1226
    """
 
1227
 
1181
1228
    _lock_file_name = 'branch-lock'
1182
1229
 
1183
1230
    # _lock_class must be set in subclasses to the lock type, typ.
1184
1231
    # TransportLock or LockDir
1185
1232
 
1186
1233
    @classmethod
1187
 
    def find_format(klass, transport):
 
1234
    def find_format(klass, transport, _server_formats=True):
1188
1235
        """Return the format present at transport."""
1189
 
        for format in klass._control_formats:
 
1236
        if _server_formats:
 
1237
            formats = klass._control_server_formats + klass._control_formats
 
1238
        else:
 
1239
            formats = klass._control_formats
 
1240
        for format in formats:
1190
1241
            try:
1191
1242
                return format.probe_transport(transport)
1192
1243
            except errors.NotBranchError:
1196
1247
 
1197
1248
    @classmethod
1198
1249
    def probe_transport(klass, transport):
1199
 
        """Return the .bzrdir style transport present at URL."""
 
1250
        """Return the .bzrdir style format present in a directory."""
1200
1251
        try:
1201
1252
            format_string = transport.get(".bzr/branch-format").read()
1202
1253
        except errors.NoSuchFile:
1342
1393
        klass._control_formats.append(format)
1343
1394
 
1344
1395
    @classmethod
 
1396
    def register_control_server_format(klass, format):
 
1397
        """Register a control format for client-server environments.
 
1398
 
 
1399
        These formats will be tried before ones registered with
 
1400
        register_control_format.  This gives implementations that decide to the
 
1401
        chance to grab it before anything looks at the contents of the format
 
1402
        file.
 
1403
        """
 
1404
        klass._control_server_formats.append(format)
 
1405
 
 
1406
    @classmethod
1345
1407
    @symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1346
1408
    def set_default_format(klass, format):
1347
1409
        klass._set_default_format(format)
1641
1703
    easy to identify.
1642
1704
    """
1643
1705
 
1644
 
    def __init__(self, transport_server, transport_readonly_server, formats):
 
1706
    def __init__(self, vfs_factory, transport_server, transport_readonly_server,
 
1707
        formats):
 
1708
        """Create an object to adapt tests.
 
1709
 
 
1710
        :param vfs_server: A factory to create a Transport Server which has
 
1711
            all the VFS methods working, and is writable.
 
1712
        """
 
1713
        self._vfs_factory = vfs_factory
1645
1714
        self._transport_server = transport_server
1646
1715
        self._transport_readonly_server = transport_readonly_server
1647
1716
        self._formats = formats
1650
1719
        result = unittest.TestSuite()
1651
1720
        for format in self._formats:
1652
1721
            new_test = deepcopy(test)
 
1722
            new_test.vfs_transport_factory = self._vfs_factory
1653
1723
            new_test.transport_server = self._transport_server
1654
1724
            new_test.transport_readonly_server = self._transport_readonly_server
1655
1725
            new_test.bzrdir_format = format
2149
2219
        return to_convert
2150
2220
 
2151
2221
 
 
2222
# This is not in remote.py because it's small, and needs to be registered.
 
2223
# Putting it in remote.py creates a circular import problem.
 
2224
# we can make it a lazy object if the control formats is turned into something
 
2225
# like a registry.
 
2226
class RemoteBzrDirFormat(BzrDirMetaFormat1):
 
2227
    """Format representing bzrdirs accessed via a smart server"""
 
2228
 
 
2229
    def get_format_description(self):
 
2230
        return 'bzr remote bzrdir'
 
2231
    
 
2232
    @classmethod
 
2233
    def probe_transport(klass, transport):
 
2234
        """Return a RemoteBzrDirFormat object if it looks possible."""
 
2235
        try:
 
2236
            client = transport.get_smart_client()
 
2237
        except (NotImplementedError, AttributeError,
 
2238
                errors.TransportNotPossible):
 
2239
            # no smart server, so not a branch for this format type.
 
2240
            raise errors.NotBranchError(path=transport.base)
 
2241
        else:
 
2242
            # Send a 'hello' request in protocol version one, and decline to
 
2243
            # open it if the server doesn't support our required version (2) so
 
2244
            # that the VFS-based transport will do it.
 
2245
            request = client.get_request()
 
2246
            smart_protocol = protocol.SmartClientRequestProtocolOne(request)
 
2247
            server_version = smart_protocol.query_version()
 
2248
            if server_version != 2:
 
2249
                raise errors.NotBranchError(path=transport.base)
 
2250
            return klass()
 
2251
 
 
2252
    def initialize_on_transport(self, transport):
 
2253
        try:
 
2254
            # hand off the request to the smart server
 
2255
            medium = transport.get_smart_medium()
 
2256
        except errors.NoSmartMedium:
 
2257
            # TODO: lookup the local format from a server hint.
 
2258
            local_dir_format = BzrDirMetaFormat1()
 
2259
            return local_dir_format.initialize_on_transport(transport)
 
2260
        client = _SmartClient(medium)
 
2261
        path = client.remote_path_from_transport(transport)
 
2262
        response = _SmartClient(medium).call('BzrDirFormat.initialize', path)
 
2263
        assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
 
2264
        return remote.RemoteBzrDir(transport)
 
2265
 
 
2266
    def _open(self, transport):
 
2267
        return remote.RemoteBzrDir(transport)
 
2268
 
 
2269
    def __eq__(self, other):
 
2270
        if not isinstance(other, RemoteBzrDirFormat):
 
2271
            return False
 
2272
        return self.get_format_description() == other.get_format_description()
 
2273
 
 
2274
 
 
2275
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
 
2276
 
 
2277
 
2152
2278
class BzrDirFormatInfo(object):
2153
2279
 
2154
2280
    def __init__(self, native, deprecated, hidden):