~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

Merge up bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006, 2007, 2008 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
34
34
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
35
35
from bzrlib.config import BranchConfig, TreeConfig
36
36
from bzrlib.decorators import needs_read_lock, needs_write_lock
37
 
from bzrlib.errors import NoSuchRevision
 
37
from bzrlib.errors import (
 
38
    NoSuchRevision,
 
39
    SmartProtocolError,
 
40
    )
38
41
from bzrlib.lockable_files import LockableFiles
39
42
from bzrlib.pack import ContainerPushParser
40
43
from bzrlib.smart import client, vfs
41
44
from bzrlib.symbol_versioning import (
42
45
    deprecated_method,
43
 
    zero_ninetyone,
44
46
    )
45
47
from bzrlib.revision import ensure_null, NULL_REVISION
46
48
from bzrlib.trace import mutter, note, warning
136
138
        return None, self.open_branch()
137
139
 
138
140
    def open_branch(self, _unsupported=False):
139
 
        assert _unsupported == False, 'unsupported flag support not implemented yet.'
 
141
        if _unsupported:
 
142
            raise NotImplementedError('unsupported flag support not implemented yet.')
140
143
        reference_url = self.get_branch_reference()
141
144
        if reference_url is None:
142
145
            # branch at this location.
154
157
        except errors.UnknownSmartMethod:
155
158
            verb = 'BzrDir.find_repository'
156
159
            response = self._client.call(verb, path)
157
 
        assert response[0] in ('ok', 'norepository'), \
158
 
            'unexpected response code %s' % (response,)
159
160
        if response[0] == 'norepository':
160
161
            raise errors.NoRepositoryPresent(self)
 
162
        elif response[0] != 'ok':
 
163
            raise SmartProtocolError('unexpected response %r' 
 
164
                % response)
161
165
        if verb == 'BzrDir.find_repository':
162
166
            # servers that don't support the V2 method don't support external
163
167
            # references either.
164
168
            response = response + ('no', )
165
 
        assert len(response) == 5, 'incorrect response length %s' % (response,)
 
169
        if not (len(response) == 5):
 
170
            raise SmartProtocolError('incorrect response length %s' % (response,))
166
171
        if response[1] == '':
167
172
            format = RemoteRepositoryFormat()
168
173
            format.rich_root_data = (response[2] == 'yes')
226
231
    _matchingbzrdir = RemoteBzrDirFormat
227
232
 
228
233
    def initialize(self, a_bzrdir, shared=False):
229
 
        assert isinstance(a_bzrdir, RemoteBzrDir), \
230
 
            '%r is not a RemoteBzrDir' % (a_bzrdir,)
 
234
        if not isinstance(a_bzrdir, RemoteBzrDir):
 
235
            raise AssertionError('%r is not a RemoteBzrDir' % (a_bzrdir,))
231
236
        return a_bzrdir.create_repository(shared=shared)
232
237
    
233
238
    def open(self, a_bzrdir):
234
 
        assert isinstance(a_bzrdir, RemoteBzrDir)
 
239
        if not isinstance(a_bzrdir, RemoteBzrDir):
 
240
            raise AssertionError('%r is not a RemoteBzrDir' % (a_bzrdir,))
235
241
        return a_bzrdir.open_repository()
236
242
 
237
243
    def get_format_description(self):
371
377
            return {}
372
378
 
373
379
        path = self.bzrdir._path_for_remote_call(self._client)
374
 
        assert type(revision_id) is str
375
380
        response = self._client.call_expecting_body(
376
381
            'Repository.get_revision_graph', path, revision_id)
377
382
        if response[0][0] not in ['ok', 'nosuchrevision']:
390
395
            return revision_graph
391
396
        else:
392
397
            response_body = response[1].read_body_bytes()
393
 
            assert response_body == ''
 
398
            if response_body:
 
399
                raise SmartProtocolError('unexpected response body')
394
400
            raise NoSuchRevision(self, revision_id)
395
401
 
396
402
    def has_revision(self, revision_id):
400
406
            return True
401
407
        path = self.bzrdir._path_for_remote_call(self._client)
402
408
        response = self._client.call('Repository.has_revision', path, revision_id)
403
 
        assert response[0] in ('yes', 'no'), 'unexpected response code %s' % (response,)
 
409
        if response[0] not in ('yes', 'no'):
 
410
            raise SmartProtocolError('unexpected response code %s' % (response,))
404
411
        return response[0] == 'yes'
405
412
 
406
413
    def has_revisions(self, revision_ids):
439
446
            fmt_committers = 'yes'
440
447
        response = self._client.call_expecting_body(
441
448
            'Repository.gather_stats', path, fmt_revid, fmt_committers)
442
 
        assert response[0][0] == 'ok', \
443
 
            'unexpected response code %s' % (response[0],)
 
449
        if response[0][0] != 'ok':
 
450
            raise SmartProtocolError('unexpected response code %s'
 
451
                % (response[0],))
444
452
 
445
453
        body = response[1].read_body_bytes()
446
454
        result = {}
483
491
        """See Repository.is_shared()."""
484
492
        path = self.bzrdir._path_for_remote_call(self._client)
485
493
        response = self._client.call('Repository.is_shared', path)
486
 
        assert response[0] in ('yes', 'no'), 'unexpected response code %s' % (response,)
 
494
        if response[0] not in ('yes', 'no'):
 
495
            raise SmartProtocolError('unexpected response code %s' % (response,))
487
496
        return response[0] == 'yes'
488
497
 
489
498
    def is_write_locked(self):
559
568
        :param repository: The repository to fallback to for non-hpss
560
569
            implemented operations.
561
570
        """
562
 
        assert not isinstance(repository, RemoteRepository)
 
571
        if isinstance(repository, RemoteRepository):
 
572
            raise AssertionError()
563
573
        self._real_repository = repository
564
574
        if self._lock_mode == 'w':
565
575
            # if we are already locked, the real repository must be able to
823
833
            # :- its because we're working with a deprecated server anyway, and
824
834
            # the user will almost certainly have seen a warning about the
825
835
            # server version already.
826
 
            return self.get_revision_graph()
 
836
            rg = self.get_revision_graph()
 
837
            # There is an api discrepency between get_parent_map and
 
838
            # get_revision_graph. Specifically, a "key:()" pair in
 
839
            # get_revision_graph just means a node has no parents. For
 
840
            # "get_parent_map" it means the node is a ghost. So fix up the
 
841
            # graph to correct this.
 
842
            #   https://bugs.launchpad.net/bzr/+bug/214894
 
843
            # There is one other "bug" which is that ghosts in
 
844
            # get_revision_graph() are not returned at all. But we won't worry
 
845
            # about that for now.
 
846
            for node_id, parent_ids in rg.iteritems():
 
847
                if parent_ids == ():
 
848
                    rg[node_id] = (NULL_REVISION,)
 
849
            rg[NULL_REVISION] = ()
 
850
            return rg
827
851
 
828
852
        keys = set(keys)
829
853
        if NULL_REVISION in keys:
1144
1168
        self._dir_mode = None
1145
1169
        self._file_mode = None
1146
1170
 
1147
 
    def get(self, path):
1148
 
        """'get' a remote path as per the LockableFiles interface.
1149
 
 
1150
 
        :param path: the file to 'get'. If this is 'branch.conf', we do not
1151
 
             just retrieve a file, instead we ask the smart server to generate
1152
 
             a configuration for us - which is retrieved as an INI file.
1153
 
        """
1154
 
        if path == 'branch.conf':
1155
 
            path = self.bzrdir._path_for_remote_call(self._client)
1156
 
            response = self._client.call_expecting_body(
1157
 
                'Branch.get_config_file', path)
1158
 
            assert response[0][0] == 'ok', \
1159
 
                'unexpected response code %s' % (response[0],)
1160
 
            return StringIO(response[1].read_body_bytes())
1161
 
        else:
1162
 
            # VFS fallback.
1163
 
            return LockableFiles.get(self, path)
1164
 
 
1165
1171
 
1166
1172
class RemoteBranchFormat(branch.BranchFormat):
1167
1173
 
1176
1182
        return 'Remote BZR Branch'
1177
1183
 
1178
1184
    def open(self, a_bzrdir):
1179
 
        assert isinstance(a_bzrdir, RemoteBzrDir)
1180
1185
        return a_bzrdir.open_branch()
1181
1186
 
1182
1187
    def initialize(self, a_bzrdir):
1183
 
        assert isinstance(a_bzrdir, RemoteBzrDir)
1184
1188
        return a_bzrdir.create_branch()
1185
1189
 
1186
1190
    def supports_tags(self):
1247
1251
        Used before calls to self._real_branch.
1248
1252
        """
1249
1253
        if not self._real_branch:
1250
 
            assert vfs.vfs_enabled()
 
1254
            if not vfs.vfs_enabled():
 
1255
                raise AssertionError('smart server vfs must be enabled '
 
1256
                    'to use vfs implementation')
1251
1257
            self.bzrdir._ensure_real()
1252
1258
            self._real_branch = self.bzrdir._real_bzrdir.open_branch()
1253
1259
            # Give the remote repository the matching real repo.
1320
1326
        if not self._lock_mode:
1321
1327
            remote_tokens = self._remote_lock_write(token)
1322
1328
            self._lock_token, self._repo_lock_token = remote_tokens
1323
 
            assert self._lock_token, 'Remote server did not return a token!'
 
1329
            if not self._lock_token:
 
1330
                raise SmartProtocolError('Remote server did not return a token!')
1324
1331
            # TODO: We really, really, really don't want to call _ensure_real
1325
1332
            # here, but it's the easiest way to ensure coherency between the
1326
1333
            # state of the RemoteBranch and RemoteRepository objects and the
1385
1392
                # Only write-locked branched need to make a remote method call
1386
1393
                # to perfom the unlock.
1387
1394
                return
1388
 
            assert self._lock_token, 'Locked, but no token!'
 
1395
            if not self._lock_token:
 
1396
                raise AssertionError('Locked, but no token!')
1389
1397
            branch_token = self._lock_token
1390
1398
            repo_token = self._repo_lock_token
1391
1399
            self._lock_token = None
1411
1419
        """See Branch.last_revision_info()."""
1412
1420
        path = self.bzrdir._path_for_remote_call(self._client)
1413
1421
        response = self._client.call('Branch.last_revision_info', path)
1414
 
        assert response[0] == 'ok', 'unexpected response code %s' % (response,)
 
1422
        if response[0] != 'ok':
 
1423
            raise SmartProtocolError('unexpected response code %s' % (response,))
1415
1424
        revno = int(response[1])
1416
1425
        last_revision = response[2]
1417
1426
        return (revno, last_revision)
1421
1430
        path = self.bzrdir._path_for_remote_call(self._client)
1422
1431
        response = self._client.call_expecting_body(
1423
1432
            'Branch.revision_history', path)
1424
 
        assert response[0][0] == 'ok', ('unexpected response code %s'
1425
 
                                        % (response[0],))
 
1433
        if response[0][0] != 'ok':
 
1434
            raise SmartProtocolError('unexpected response code %s' % (response,))
1426
1435
        result = response[1].read_body_bytes().split('\x00')
1427
1436
        if result == ['']:
1428
1437
            return []
1443
1452
            path, self._lock_token, self._repo_lock_token, rev_id)
1444
1453
        if response[0] == 'NoSuchRevision':
1445
1454
            raise NoSuchRevision(self, rev_id)
1446
 
        else:
1447
 
            assert response == ('ok',), (
1448
 
                'unexpected response code %r' % (response,))
 
1455
        elif response[0] != 'ok':
 
1456
            raise SmartProtocolError('unexpected response code %s' % (response,))
1449
1457
        self._cache_revision_history(rev_history)
1450
1458
 
1451
1459
    def get_parent(self):
1456
1464
        self._ensure_real()
1457
1465
        return self._real_branch.set_parent(url)
1458
1466
        
1459
 
    def get_config(self):
1460
 
        return RemoteBranchConfig(self)
1461
 
 
1462
1467
    def sprout(self, to_bzrdir, revision_id=None):
1463
1468
        # Like Branch.sprout, except that it sprouts a branch in the default
1464
1469
        # format, because RemoteBranches can't be created at arbitrary URLs.
1495
1500
 
1496
1501
    @needs_write_lock
1497
1502
    def set_last_revision_info(self, revno, revision_id):
1498
 
        assert type(revno) is int
1499
1503
        revision_id = ensure_null(revision_id)
1500
1504
        path = self.bzrdir._path_for_remote_call(self._client)
1501
1505
        try:
1533
1537
            other, stop_revision=stop_revision, overwrite=overwrite)
1534
1538
 
1535
1539
 
1536
 
class RemoteBranchConfig(BranchConfig):
1537
 
 
1538
 
    def username(self):
1539
 
        self.branch._ensure_real()
1540
 
        return self.branch._real_branch.get_config().username()
1541
 
 
1542
 
    def _get_branch_data_config(self):
1543
 
        self.branch._ensure_real()
1544
 
        if self._branch_data_config is None:
1545
 
            self._branch_data_config = TreeConfig(self.branch._real_branch)
1546
 
        return self._branch_data_config
1547
 
 
1548
 
 
1549
1540
def _extract_tar(tar, to_dir):
1550
1541
    """Extract all the contents of a tarfile object.
1551
1542