1
# Copyright (C) 2006-2010 Canonical Ltd
1
# Copyright (C) 2006 Canonical Ltd
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
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""RemoteTransport client for the smart-server.
36
36
from bzrlib.smart import client, medium
37
from bzrlib.symbol_versioning import (
37
from bzrlib.symbol_versioning import (deprecated_method, one_four)
42
40
class _SmartStat(object):
55
53
The connection has a notion of the current directory to which it's
56
54
connected; this is incorporated in filenames passed to the server.
58
This supports some higher-level RPC operations and can also be treated
56
This supports some higher-level RPC operations and can also be treated
59
57
like a Transport to do file-like operations.
61
59
The connection can be made over a tcp socket, an ssh pipe or a series of
69
67
# IMPORTANT FOR IMPLEMENTORS: RemoteTransport MUST NOT be given encoding
70
68
# responsibilities: Put those on SmartClient or similar. This is vital for
71
69
# the ability to support multiple versions of the smart protocol over time:
72
# RemoteTransport is an adapter from the Transport object model to the
70
# RemoteTransport is an adapter from the Transport object model to the
73
71
# SmartClient model, not an encoder.
75
73
# FIXME: the medium parameter should be private, only the tests requires
92
90
should only be used for testing purposes; normally this is
93
91
determined from the medium.
95
super(RemoteTransport, self).__init__(
96
url, _from_transport=_from_transport)
93
super(RemoteTransport, self).__init__(url,
94
_from_transport=_from_transport)
98
96
# The medium is the connection, except when we need to share it with
99
97
# other objects (RemoteBzrDir, RemoteRepository etc). In these cases
100
98
# what we want to share is really the shared connection.
102
if (_from_transport is not None
103
and isinstance(_from_transport, RemoteTransport)):
104
_client = _from_transport._client
105
elif _from_transport is None:
100
if _from_transport is None:
106
101
# If no _from_transport is specified, we need to intialize the
108
103
credentials = None
139
134
return None, None
141
def _report_activity(self, bytes, direction):
142
"""See Transport._report_activity.
144
Does nothing; the smart medium will report activity triggered by a
149
136
def is_readonly(self):
150
137
"""Smart server transport can do read/write file operations."""
168
155
def get_smart_medium(self):
169
156
return self._get_connection()
158
@deprecated_method(one_four)
159
def get_shared_medium(self):
160
return self._get_shared_connection()
171
162
def _remote_path(self, relpath):
172
163
"""Returns the Unicode version of the absolute path for relpath."""
173
return urlutils.URL._combine_paths(self._parsed_url.path, relpath)
164
return self._combine_paths(self._path, relpath)
175
166
def _call(self, method, *args):
176
167
resp = self._call2(method, *args)
301
292
def append_file(self, relpath, from_file, mode=None):
302
293
return self.append_bytes(relpath, from_file.read(), mode)
304
295
def append_bytes(self, relpath, bytes, mode=None):
305
296
resp = self._call_with_body_bytes(
430
421
def _ensure_ok(self, resp):
431
422
if resp[0] != 'ok':
432
423
raise errors.UnexpectedSmartServerResponse(resp)
434
425
def _translate_error(self, err, relpath=None):
435
426
remote._translate_error(err, path=relpath)
437
428
def disconnect(self):
438
m = self.get_smart_medium()
429
self.get_smart_medium().disconnect()
442
431
def stat(self, relpath):
443
432
resp = self._call2('stat', self._remote_path(relpath))
477
466
class RemoteTCPTransport(RemoteTransport):
478
467
"""Connection to smart server over plain tcp.
480
469
This is essentially just a factory to get 'RemoteTransport(url,
481
470
SmartTCPClientMedium).
484
473
def _build_medium(self):
485
474
client_medium = medium.SmartTCPClientMedium(
486
self._parsed_url.host, self._parsed_url.port, self.base)
475
self._host, self._port, self.base)
487
476
return client_medium, None
497
486
def _build_medium(self):
498
487
client_medium = medium.SmartTCPClientMedium(
499
self._parsed_url.host, self._parsed_url.port, self.base)
488
self._host, self._port, self.base)
500
489
client_medium._protocol_version = 2
501
490
client_medium._remember_remote_is_before((1, 6))
502
491
return client_medium, None
512
501
def _build_medium(self):
513
502
location_config = config.LocationConfig(self.base)
514
503
bzr_remote_path = location_config.get_bzr_remote_path()
515
user = self._parsed_url.user
517
506
auth = config.AuthenticationConfig()
518
user = auth.get_user('ssh', self._parsed_url.host,
519
self._parsed_url.port)
520
ssh_params = medium.SSHParams(self._parsed_url.host,
521
self._parsed_url.port, user, self._parsed_url.password,
523
client_medium = medium.SmartSSHClientMedium(self.base, ssh_params)
524
return client_medium, (user, self._parsed_url.password)
507
user = auth.get_user('ssh', self._host, self._port)
508
client_medium = medium.SmartSSHClientMedium(self._host, self._port,
509
user, self._password, self.base,
510
bzr_remote_path=bzr_remote_path)
511
return client_medium, (user, self._password)
527
514
class RemoteHTTPTransport(RemoteTransport):
528
515
"""Just a way to connect between a bzr+http:// url and http://.
530
517
This connection operates slightly differently than the RemoteSSHTransport.
531
518
It uses a plain http:// transport underneath, which defines what remote
532
519
.bzr/smart URL we are connected to. From there, all paths that are sent are
541
528
# url only for an intial construction (when the url came from the
543
530
http_url = base[len('bzr+'):]
544
self._http_transport = transport.get_transport_from_url(http_url)
531
self._http_transport = transport.get_transport(http_url)
546
533
self._http_transport = http_transport
547
534
super(RemoteHTTPTransport, self).__init__(
593
580
return redirected
596
class HintingSSHTransport(transport.Transport):
597
"""Simple transport that handles ssh:// and points out bzr+ssh://."""
599
def __init__(self, url):
600
raise errors.UnsupportedProtocol(url,
601
'bzr supports bzr+ssh to operate over ssh, use "bzr+%s".' % url)
604
583
def get_test_permutations():
605
584
"""Return (transport, server) permutations for testing."""
606
585
### We may need a little more test framework support to construct an
607
586
### appropriate RemoteTransport in the future.
608
from bzrlib.tests import test_server
609
return [(RemoteTCPTransport, test_server.SmartTCPServer_for_testing)]
587
from bzrlib.smart import server
588
return [(RemoteTCPTransport, server.SmartTCPServer_for_testing)]