606
597
# which is newer than a previously supplied older-than version.
607
598
# This indicates that some smart verb call is not guarded
608
599
# appropriately (it should simply not have been tried).
600
raise AssertionError(
610
601
"_remember_remote_is_before(%r) called, but "
611
602
"_remember_remote_is_before(%r) was called previously."
612
, version_tuple, self._remote_version_is_before)
613
if 'hpss' in debug.debug_flags:
614
ui.ui_factory.show_warning(
615
"_remember_remote_is_before(%r) called, but "
616
"_remember_remote_is_before(%r) was called previously."
617
% (version_tuple, self._remote_version_is_before))
603
% (version_tuple, self._remote_version_is_before))
619
604
self._remote_version_is_before = version_tuple
621
606
def protocol_version(self):
733
718
def _read_bytes(self, count):
734
719
"""See SmartClientStreamMedium._read_bytes."""
735
bytes_to_read = min(count, _MAX_READ_SIZE)
736
bytes = self._readable_pipe.read(bytes_to_read)
720
bytes = self._readable_pipe.read(count)
737
721
self._report_activity(len(bytes), 'read')
741
class SSHParams(object):
742
"""A set of parameters for starting a remote bzr via SSH."""
725
class SmartSSHClientMedium(SmartClientStreamMedium):
726
"""A client medium using SSH."""
744
728
def __init__(self, host, port=None, username=None, password=None,
745
bzr_remote_path='bzr'):
748
self.username = username
749
self.password = password
750
self.bzr_remote_path = bzr_remote_path
753
class SmartSSHClientMedium(SmartClientStreamMedium):
754
"""A client medium using SSH.
756
It delegates IO to a SmartClientSocketMedium or
757
SmartClientAlreadyConnectedSocketMedium (depending on platform).
760
def __init__(self, base, ssh_params, vendor=None):
729
base=None, vendor=None, bzr_remote_path=None):
761
730
"""Creates a client that will connect on the first use.
763
:param ssh_params: A SSHParams instance.
764
732
:param vendor: An optional override for the ssh vendor to use. See
765
733
bzrlib.transport.ssh for details on ssh vendors.
767
self._real_medium = None
768
self._ssh_params = ssh_params
769
# for the benefit of progress making a short description of this
771
self._scheme = 'bzr+ssh'
735
self._connected = False
737
self._password = password
739
self._username = username
772
740
# SmartClientStreamMedium stores the repr of this object in its
773
741
# _DebugCounter so we have to store all the values used in our repr
774
742
# method before calling the super init.
775
743
SmartClientStreamMedium.__init__(self, base)
744
self._read_from = None
745
self._ssh_connection = None
776
746
self._vendor = vendor
777
self._ssh_connection = None
747
self._write_to = None
748
self._bzr_remote_path = bzr_remote_path
749
# for the benefit of progress making a short description of this
751
self._scheme = 'bzr+ssh'
779
753
def __repr__(self):
780
if self._ssh_params.port is None:
783
maybe_port = ':%s' % self._ssh_params.port
784
return "%s(%s://%s@%s%s/)" % (
754
return "%s(connected=%r, username=%r, host=%r, port=%r)" % (
785
755
self.__class__.__name__,
787
self._ssh_params.username,
788
self._ssh_params.host,
791
761
def _accept_bytes(self, bytes):
792
762
"""See SmartClientStreamMedium.accept_bytes."""
793
763
self._ensure_connection()
794
self._real_medium.accept_bytes(bytes)
764
self._write_to.write(bytes)
765
self._report_activity(len(bytes), 'write')
796
767
def disconnect(self):
797
768
"""See SmartClientMedium.disconnect()."""
798
if self._real_medium is not None:
799
self._real_medium.disconnect()
800
self._real_medium = None
801
if self._ssh_connection is not None:
802
self._ssh_connection.close()
803
self._ssh_connection = None
769
if not self._connected:
771
self._read_from.close()
772
self._write_to.close()
773
self._ssh_connection.close()
774
self._connected = False
805
776
def _ensure_connection(self):
806
777
"""Connect this medium if not already connected."""
807
if self._real_medium is not None:
809
780
if self._vendor is None:
810
781
vendor = ssh._get_ssh_vendor()
812
783
vendor = self._vendor
813
self._ssh_connection = vendor.connect_ssh(self._ssh_params.username,
814
self._ssh_params.password, self._ssh_params.host,
815
self._ssh_params.port,
816
command=[self._ssh_params.bzr_remote_path, 'serve', '--inet',
784
self._ssh_connection = vendor.connect_ssh(self._username,
785
self._password, self._host, self._port,
786
command=[self._bzr_remote_path, 'serve', '--inet',
817
787
'--directory=/', '--allow-writes'])
818
io_kind, io_object = self._ssh_connection.get_sock_or_pipes()
819
if io_kind == 'socket':
820
self._real_medium = SmartClientAlreadyConnectedSocketMedium(
821
self.base, io_object)
822
elif io_kind == 'pipes':
823
read_from, write_to = io_object
824
self._real_medium = SmartSimplePipesClientMedium(
825
read_from, write_to, self.base)
827
raise AssertionError(
828
"Unexpected io_kind %r from %r"
829
% (io_kind, self._ssh_connection))
788
self._read_from, self._write_to = \
789
self._ssh_connection.get_filelike_channels()
790
self._connected = True
831
792
def _flush(self):
832
793
"""See SmartClientStreamMedium._flush()."""
833
self._real_medium._flush()
794
self._write_to.flush()
835
796
def _read_bytes(self, count):
836
797
"""See SmartClientStreamMedium.read_bytes."""
837
if self._real_medium is None:
798
if not self._connected:
838
799
raise errors.MediumNotConnected(self)
839
return self._real_medium.read_bytes(count)
800
bytes_to_read = min(count, _MAX_READ_SIZE)
801
bytes = self._read_from.read(bytes_to_read)
802
self._report_activity(len(bytes), 'read')
842
806
# Port 4155 is the default port for bzr://, registered with IANA.
844
808
BZR_DEFAULT_PORT = 4155
847
class SmartClientSocketMedium(SmartClientStreamMedium):
848
"""A client medium using a socket.
850
This class isn't usable directly. Use one of its subclasses instead.
811
class SmartTCPClientMedium(SmartClientStreamMedium):
812
"""A client medium using TCP."""
853
def __init__(self, base):
814
def __init__(self, host, port, base):
815
"""Creates a client that will connect on the first use."""
854
816
SmartClientStreamMedium.__init__(self, base)
817
self._connected = False
855
820
self._socket = None
856
self._connected = False
858
822
def _accept_bytes(self, bytes):
859
823
"""See SmartClientMedium.accept_bytes."""
860
824
self._ensure_connection()
861
825
osutils.send_all(self._socket, bytes, self._report_activity)
863
def _ensure_connection(self):
864
"""Connect this medium if not already connected."""
865
raise NotImplementedError(self._ensure_connection)
868
"""See SmartClientStreamMedium._flush().
870
For sockets we do no flushing. For TCP sockets we may want to turn off
871
TCP_NODELAY and add a means to do a flush, but that can be done in the
875
def _read_bytes(self, count):
876
"""See SmartClientMedium.read_bytes."""
877
if not self._connected:
878
raise errors.MediumNotConnected(self)
879
return osutils.read_bytes_from_socket(
880
self._socket, self._report_activity)
882
827
def disconnect(self):
883
828
"""See SmartClientMedium.disconnect()."""
884
829
if not self._connected:
936
871
(self._host, port, err_msg))
937
872
self._connected = True
940
class SmartClientAlreadyConnectedSocketMedium(SmartClientSocketMedium):
941
"""A client medium for an already connected socket.
943
Note that this class will assume it "owns" the socket, so it will close it
944
when its disconnect method is called.
947
def __init__(self, base, sock):
948
SmartClientSocketMedium.__init__(self, base)
950
self._connected = True
952
def _ensure_connection(self):
953
# Already connected, by definition! So nothing to do.
875
"""See SmartClientStreamMedium._flush().
877
For TCP we do no flushing. We may want to turn off TCP_NODELAY and
878
add a means to do a flush, but that can be done in the future.
881
def _read_bytes(self, count):
882
"""See SmartClientMedium.read_bytes."""
883
if not self._connected:
884
raise errors.MediumNotConnected(self)
885
return _read_bytes_from_socket(
886
self._socket.recv, count, self._report_activity)
957
889
class SmartClientStreamMediumRequest(SmartClientMediumRequest):