153
# XXX: The smart server should not depend on the SFTP code being importable.
154
153
from bzrlib.bundle.serializer import write_bundle
155
154
from bzrlib.trace import mutter
156
from bzrlib.transport import local, sftp
155
from bzrlib.transport import local
158
157
# must do this otherwise urllib can't parse the urls properly :(
159
158
for scheme in ['ssh', 'bzr', 'bzr+loopback', 'bzr+ssh']:
336
335
def do_append(self, relpath, mode):
337
old_length = self._backing_transport.append(relpath, StringIO(self._recv_body()),
338
self._deserialise_optional_mode(mode))
336
old_length = self._backing_transport.append_bytes(
337
relpath, self._recv_body(), self._deserialise_optional_mode(mode))
339
338
return SmartServerResponse(('appended', '%d' % old_length))
341
340
def do_delete(self, relpath):
360
359
self._backing_transport.move(rel_from, rel_to)
362
361
def do_put(self, relpath, mode):
363
self._backing_transport.put(relpath,
364
StringIO(self._recv_body()),
362
self._backing_transport.put_bytes(relpath,
365
364
self._deserialise_optional_mode(mode))
367
366
def do_rename(self, rel_from, rel_to):
537
536
### Technically super() here is faulty because Transport's __init__
538
537
### fails to take 2 parameters, and if super were to choose a silly
539
538
### initialisation order things would blow up.
540
super(SmartTransport, self).__init__(server_url)
539
if not url.endswith('/'):
541
super(SmartTransport, self).__init__(url)
542
self._scheme, self._username, self._password, self._host, self._port, self._path = \
543
transport.split_url(url)
541
544
if clone_from is None:
542
545
if client is None:
543
546
self._client = SmartStreamClient(self._connect_to_server)
550
553
# reuse same connection
551
554
self._client = clone_from._client
556
def abspath(self, relpath):
557
"""Return the full url to the given relative path.
559
@param relpath: the relative path or path components
560
@type relpath: str or list
562
return self._unparse_url(self._remote_path(relpath))
553
564
def clone(self, relative_url):
554
565
"""Make a new SmartTransport related to me, sharing the same connection.
624
636
self._translate_error(resp)
626
638
def put_file(self, relpath, upload_file, mode=None):
627
self.put_bytes(relpath, upload_file.read(), mode)
639
# its not ideal to seek back, but currently put_non_atomic_file depends
640
# on transports not reading before failing - which is a faulty
641
# assumption I think - RBC 20060915
642
pos = upload_file.tell()
644
return self.put_bytes(relpath, upload_file.read(), mode)
646
upload_file.seek(pos)
629
649
def put_bytes(self, relpath, upload_contents, mode=None):
630
650
# FIXME: upload_file is probably not safe for non-ascii characters -
637
657
self._translate_error(resp)
639
659
def append_file(self, relpath, from_file, mode=None):
640
self.append_bytes(relpath, from_file.read(), mode)
660
return self.append_bytes(relpath, from_file.read(), mode)
642
662
def append_bytes(self, relpath, bytes, mode=None):
643
663
resp = self._client._call_with_upload(
814
834
def __init__(self, url, clone_from=None):
815
835
super(SmartTCPTransport, self).__init__(url, clone_from)
816
self._scheme, self._username, self._password, self._host, self._port, self._path = \
817
transport.split_url(url)
819
837
self._port = int(self._port)
820
838
except (ValueError, TypeError), e:
841
859
if self._socket is not None:
842
860
self._socket.close()
845
class SmartSSHTransport(SmartTransport):
846
"""Connection to smart server over SSH."""
848
def __init__(self, url, clone_from=None):
849
# TODO: all this probably belongs in the parent class.
850
super(SmartSSHTransport, self).__init__(url, clone_from)
851
self._scheme, self._username, self._password, self._host, self._port, self._path = \
852
transport.split_url(url)
854
if self._port is not None:
855
self._port = int(self._port)
856
except (ValueError, TypeError), e:
857
raise errors.InvalidURL(path=url, extra="invalid port %s" % self._port)
859
def _connect_to_server(self):
860
# XXX: don't hardcode vendor
861
# XXX: cannot pass password to SSHSubprocess yet
862
if self._password is not None:
863
raise errors.InvalidURL("SSH smart transport doesn't handle passwords")
864
self._ssh_connection = sftp.SSHSubprocess(self._host, 'openssh',
865
port=self._port, user=self._username,
866
command=['bzr', 'serve', '--inet'])
867
return self._ssh_connection.get_filelike_channels()
869
def disconnect(self):
870
super(SmartSSHTransport, self).disconnect()
871
self._ssh_connection.close()
863
from bzrlib.transport import sftp
864
except errors.ParamikoNotPresent:
865
# no paramiko, no SSHTransport.
868
class SmartSSHTransport(SmartTransport):
869
"""Connection to smart server over SSH."""
871
def __init__(self, url, clone_from=None):
872
# TODO: all this probably belongs in the parent class.
873
super(SmartSSHTransport, self).__init__(url, clone_from)
875
if self._port is not None:
876
self._port = int(self._port)
877
except (ValueError, TypeError), e:
878
raise errors.InvalidURL(path=url, extra="invalid port %s" % self._port)
880
def _connect_to_server(self):
881
# XXX: don't hardcode vendor
882
# XXX: cannot pass password to SSHSubprocess yet
883
if self._password is not None:
884
raise errors.InvalidURL("SSH smart transport doesn't handle passwords")
885
self._ssh_connection = sftp.SSHSubprocess(self._host, 'openssh',
886
port=self._port, user=self._username,
887
command=['bzr', 'serve', '--inet'])
888
return self._ssh_connection.get_filelike_channels()
890
def disconnect(self):
891
super(SmartSSHTransport, self).disconnect()
892
self._ssh_connection.close()
874
895
def get_test_permutations():