606
599
# which is newer than a previously supplied older-than version.
607
600
# This indicates that some smart verb call is not guarded
608
601
# appropriately (it should simply not have been tried).
602
raise AssertionError(
610
603
"_remember_remote_is_before(%r) called, but "
611
604
"_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))
605
% (version_tuple, self._remote_version_is_before))
619
606
self._remote_version_is_before = version_tuple
621
608
def protocol_version(self):
733
720
def _read_bytes(self, count):
734
721
"""See SmartClientStreamMedium._read_bytes."""
735
bytes_to_read = min(count, _MAX_READ_SIZE)
736
bytes = self._readable_pipe.read(bytes_to_read)
722
bytes = self._readable_pipe.read(count)
737
723
self._report_activity(len(bytes), 'read')
741
class SSHParams(object):
742
"""A set of parameters for starting a remote bzr via SSH."""
727
class SmartSSHClientMedium(SmartClientStreamMedium):
728
"""A client medium using SSH."""
744
730
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):
731
base=None, vendor=None, bzr_remote_path=None):
761
732
"""Creates a client that will connect on the first use.
763
:param ssh_params: A SSHParams instance.
764
734
:param vendor: An optional override for the ssh vendor to use. See
765
735
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'
737
self._connected = False
739
self._password = password
741
self._username = username
772
742
# SmartClientStreamMedium stores the repr of this object in its
773
743
# _DebugCounter so we have to store all the values used in our repr
774
744
# method before calling the super init.
775
745
SmartClientStreamMedium.__init__(self, base)
746
self._read_from = None
747
self._ssh_connection = None
776
748
self._vendor = vendor
777
self._ssh_connection = None
749
self._write_to = None
750
self._bzr_remote_path = bzr_remote_path
751
# for the benefit of progress making a short description of this
753
self._scheme = 'bzr+ssh'
779
755
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/)" % (
756
return "%s(connected=%r, username=%r, host=%r, port=%r)" % (
785
757
self.__class__.__name__,
787
self._ssh_params.username,
788
self._ssh_params.host,
791
763
def _accept_bytes(self, bytes):
792
764
"""See SmartClientStreamMedium.accept_bytes."""
793
765
self._ensure_connection()
794
self._real_medium.accept_bytes(bytes)
766
self._write_to.write(bytes)
767
self._report_activity(len(bytes), 'write')
796
769
def disconnect(self):
797
770
"""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
771
if not self._connected:
773
self._read_from.close()
774
self._write_to.close()
775
self._ssh_connection.close()
776
self._connected = False
805
778
def _ensure_connection(self):
806
779
"""Connect this medium if not already connected."""
807
if self._real_medium is not None:
809
782
if self._vendor is None:
810
783
vendor = ssh._get_ssh_vendor()
812
785
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',
786
self._ssh_connection = vendor.connect_ssh(self._username,
787
self._password, self._host, self._port,
788
command=[self._bzr_remote_path, 'serve', '--inet',
817
789
'--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))
790
self._read_from, self._write_to = \
791
self._ssh_connection.get_filelike_channels()
792
self._connected = True
831
794
def _flush(self):
832
795
"""See SmartClientStreamMedium._flush()."""
833
self._real_medium._flush()
796
self._write_to.flush()
835
798
def _read_bytes(self, count):
836
799
"""See SmartClientStreamMedium.read_bytes."""
837
if self._real_medium is None:
800
if not self._connected:
838
801
raise errors.MediumNotConnected(self)
839
return self._real_medium.read_bytes(count)
802
bytes_to_read = min(count, _MAX_READ_SIZE)
803
bytes = self._read_from.read(bytes_to_read)
804
self._report_activity(len(bytes), 'read')
842
808
# Port 4155 is the default port for bzr://, registered with IANA.
844
810
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.
813
class SmartTCPClientMedium(SmartClientStreamMedium):
814
"""A client medium using TCP."""
853
def __init__(self, base):
816
def __init__(self, host, port, base):
817
"""Creates a client that will connect on the first use."""
854
818
SmartClientStreamMedium.__init__(self, base)
819
self._connected = False
855
822
self._socket = None
856
self._connected = False
858
824
def _accept_bytes(self, bytes):
859
825
"""See SmartClientMedium.accept_bytes."""
860
826
self._ensure_connection()
861
827
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
829
def disconnect(self):
883
830
"""See SmartClientMedium.disconnect()."""
884
831
if not self._connected:
936
873
(self._host, port, err_msg))
937
874
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.
877
"""See SmartClientStreamMedium._flush().
879
For TCP we do no flushing. We may want to turn off TCP_NODELAY and
880
add a means to do a flush, but that can be done in the future.
883
def _read_bytes(self, count):
884
"""See SmartClientMedium.read_bytes."""
885
if not self._connected:
886
raise errors.MediumNotConnected(self)
887
# We ignore the desired_count because on sockets it's more efficient to
888
# read large chunks (of _MAX_READ_SIZE bytes) at a time.
890
bytes = osutils.until_no_eintr(self._socket.recv, _MAX_READ_SIZE)
891
except socket.error, e:
892
if len(e.args) and e.args[0] == errno.ECONNRESET:
893
# Callers expect an empty string in that case
898
self._report_activity(len(bytes), 'read')
957
902
class SmartClientStreamMediumRequest(SmartClientMediumRequest):