Revision: 140
Author: janne.t.harkonen
Date: Thu Aug 16 04:17:12 2012
Log: cleanup command execution
http://code.google.com/p/robotframework-sshlibrary/source/detail?r=140
Added:
/trunk/src/SSHLibrary/core.py
Deleted:
/trunk/src/SSHLibrary/client.py
Modified:
/trunk/src/SSHLibrary/__init__.py
/trunk/src/SSHLibrary/javaclient.py
/trunk/src/SSHLibrary/pythonclient.py
=======================================
--- /dev/null
+++ /trunk/src/SSHLibrary/core.py Thu Aug 16 04:17:12 2012
@@ -0,0 +1,88 @@
+# Copyright 2008-2010 Nokia Siemens Networks Oyj
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+class AuthenticationException(RuntimeError):
+ pass
+
+
+class Command(object):
+ """Base class for remote commands."""
+
+ def __init__(self, command):
+ self._command = command
+ self._session = None
+
+ def run_in(self, session):
+ """Run this command in given SSH session.
+
+ :param session: a session in an already open SSH connection
+ """
+ self._session = session
+ self._execute()
+
+ def read_outputs(self):
+ """Return outputs of this command.
+
+ :return: a 3-tuple of stdout, stderr and return code.
+ """
+ return self._read_outputs()
+
+
+class SSHClient(object):
+
+ def __init__(self, host, port, prompt):
+ self.host = host
+ self.port = port
+ self.prompt = prompt
+ self.shell = None
+ self.client = self._create_client()
+ self._commands = []
+
+ def execute_command(self, command, return_stdout, return_stderr,
+ return_rc):
+ self.start_command(command)
+ return self.read_command_output(return_stdout, return_stderr,
+ return_rc)
+
+ def start_command(self, command):
+ self._commands.append(self._start_command(command))
+
+ def read_command_output(self, return_stdout, return_stderr, return_rc):
+ stdout, stderr, rc = self._commands.pop().read_outputs()
+ ret = []
+ if return_stdout:
+ ret.append(stdout.rstrip('\n'))
+ if return_stderr:
+ ret.append(stderr.rstrip('\n'))
+ if return_rc:
+ ret.append(rc)
+ if len(ret) == 1:
+ return ret[0]
+ return ret
+
+ def put_file(self, source, dest, mode, newline_char):
+ remotefile = self._create_remote_file(dest, mode)
+ localfile = open(source, 'rb')
+ position = 0
+ while True:
+ data = localfile.read(4096)
+ if not data:
+ break
+ if newline_char and '\n' in data:
+ data = data.replace('\n', newline_char)
+ self._write_to_remote_file(remotefile, data, position)
+ position += len(data)
+ self._close_remote_file(remotefile)
+ localfile.close()
=======================================
--- /trunk/src/SSHLibrary/client.py Thu Aug 16 04:16:56 2012
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2008-2010 Nokia Siemens Networks Oyj
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-class AuthenticationException(RuntimeError):
- pass
-
-
-class SSHLibraryClient(object):
-
- def __init__(self, host, port, prompt):
- self.host = host
- self.port = port
- self.prompt = prompt
- self.shell = None
- self.client = self._create_client()
-
- def execute_command(self, command, return_stdout, return_stderr,
- return_rc):
- stdout, stderr, rc = self._execute_command(command)
- return self._return_outputs(stdout, stderr, rc, return_stdout,
- return_stderr, return_rc)
-
- def _return_outputs(self, stdout, stderr, rc, return_stdout,
return_stderr,
- return_rc):
- ret = []
- print return_stdout, return_stderr, return_rc
- if return_stdout:
- ret.append(self._process_output(stdout))
- if return_stderr:
- ret.append(self._process_output(stderr))
- if return_rc:
- ret.append(rc)
- if len(ret) == 1:
- return ret[0]
- return ret
-
- def read_command_output(self, return_stdout, return_stderr, return_rc):
- stdout, stderr, rc = self._read_command_output()
- return self._return_outputs(stdout, stderr, rc, return_stdout,
- return_stderr, return_rc)
-
- def _process_output(self, text):
- if text.endswith('\n'):
- return text[:-1]
- return text
-
- def put_file(self, source, dest, mode, newline_char):
- remotefile = self._create_remote_file(dest, mode)
- localfile = open(source, 'rb')
- position = 0
- while True:
- data = localfile.read(4096)
- if not data:
- break
- if newline_char and '\n' in data:
- data = data.replace('\n', newline_char)
- self._write_to_remote_file(remotefile, data, position)
- position += len(data)
- self._close_remote_file(remotefile)
- localfile.close()
=======================================
--- /trunk/src/SSHLibrary/__init__.py Thu Aug 16 04:16:56 2012
+++ /trunk/src/SSHLibrary/__init__.py Thu Aug 16 04:17:12 2012
@@ -23,9 +23,9 @@
from connectioncache import ConnectionCache
from client import AuthenticationException
if utils.is_jython:
- from javaclient import SSHClient
+ from javaclient import JavaSSHClient as SSHClient
else:
- from pythonclient import SSHClient
+ from pythonclient import PythonSSHClient as SSHClient
from version import VERSION
__version__ = VERSION
@@ -367,20 +367,17 @@
Command must have been started using `Start Command` before this
keyword can be used.
- Examples:
- | Start Command | some command |
- | ${out}= | Read Command Output |
| | |
- | ${err}= | Read Command Output | stderr | #stderr is
returned | |
- | ${out} | ${err}= | Read Command Output |
both | #stdout and stderr are returned |
+ See `Execute Command` for examples about how the return value can
+ be configured using `return_stdout`, `return_stderr` and
`return_rc`.
"""
self._info("Reading output of command '%s'" % self._command)
opts = self._output_options(return_stdout, return_stderr,
return_rc)
return self._client.read_command_output(*opts)
def _output_options(self, stdout, stderr, rc):
+ # Handle legacy options for configuring returned outputs
if not isinstance(stdout, basestring):
return stdout, stderr, rc
- # Handle legacy options for configuring returned outputs
stdout = stdout.lower()
if stdout == 'stderr':
return False, True, rc
=======================================
--- /trunk/src/SSHLibrary/javaclient.py Thu Aug 16 04:16:56 2012
+++ /trunk/src/SSHLibrary/javaclient.py Thu Aug 16 04:17:12 2012
@@ -23,10 +23,10 @@
raise ImportError('Importing Trilead SSH classes failed. '
'Make sure you have the Trilead jar file in
CLASSPATH.')
-from client import SSHLibraryClient, AuthenticationException
+from core import SSHClient, Command, AuthenticationException
-class SSHClient(SSHLibraryClient):
+class JavaSSHClient(SSHClient):
def _create_client(self):
client = Connection(self.host, self.port)
@@ -50,34 +50,10 @@
def close(self):
self.client.close()
- def _execute_command(self, command):
- session = self._start_command(command)
- return self._read_command_output(session)
-
- def _read_command_output(self, session=None):
- session = session or self.sess
- stdout = self._read_from_stream(session.getStdout())
- stderr = self._read_from_stream(session.getStderr())
- rc = session.getExitStatus()
- session.close()
- return stdout, stderr, rc
-
def _start_command(self, command):
- session = self.client.openSession()
- session.execCommand(command)
- return session
-
- def _read_from_stream(self, stream):
- reader = BufferedReader(InputStreamReader(StreamGobbler(stream)))
- result = ''
- line = reader.readLine()
- while line is not None:
- result += line + '\n'
- line = reader.readLine()
- return result
-
- def start_command(self, command):
- self.sess = self._start_command(command)
+ cmd = RemoteCommand(command)
+ cmd.run_in(self.client.openSession())
+ return cmd
def open_shell(self, term_type, width, height):
self.shell = self.client.openSession()
@@ -166,3 +142,25 @@
self.sftp_client.closeFile(remotefile)
localfile.flush()
localfile.close()
+
+
+class RemoteCommand(Command):
+
+ def _execute(self):
+ self._session.execCommand(self._command)
+
+ def _read_outputs(self):
+ stdout = self._read_from_stream(self._session.getStdout())
+ stderr = self._read_from_stream(self._session.getStderr())
+ rc = self._session.getExitStatus()
+ self._session.close()
+ return stdout, stderr, rc
+
+ def _read_from_stream(self, stream):
+ reader = BufferedReader(InputStreamReader(StreamGobbler(stream)))
+ result = ''
+ line = reader.readLine()
+ while line is not None:
+ result += line + '\n'
+ line = reader.readLine()
+ return result
=======================================
--- /trunk/src/SSHLibrary/pythonclient.py Thu Aug 16 04:16:56 2012
+++ /trunk/src/SSHLibrary/pythonclient.py Thu Aug 16 04:17:12 2012
@@ -22,7 +22,7 @@
'Ensure that paramiko and pycrypto modules are installed.'
)
-from client import SSHLibraryClient, AuthenticationException
+from core import SSHClient, Command, AuthenticationException
# There doesn't seem to be a simpler way to increase banner timeout
@@ -36,8 +36,7 @@
paramiko.transport.Transport.start_client = _monkey_patched_start_client
-class SSHClient(SSHLibraryClient):
-
+class PythonSSHClient(SSHClient):
enable_ssh_logging = staticmethod(lambda path:
paramiko.util.log_to_file(path))
@@ -59,23 +58,10 @@
def close(self):
self.client.close()
- def _execute_command(self, command):
- channel, stdout, stderr = self._start_command(command)
- return stdout.read(), stderr.read(), channel.recv_exit_status()
-
def _start_command(self, command):
- channel = self.client.get_transport().open_session()
- channel.exec_command(command)
- stdout = channel.makefile('rb', -1)
- stderr = channel.makefile_stderr('rb', -1)
- return channel, stdout, stderr
-
- def start_command(self, command):
- self.channel, self.stdout, self.stderr =
self._start_command(command)
-
- def _read_command_output(self):
- return self.stdout.read(), self.stderr.read(), \
- self.channel.recv_exit_status()
+ cmd = RemoteCommand(command)
+ cmd.run_in(self.client.get_transport().open_session())
+ return cmd
def open_shell(self, term_type, width, height):
self.shell = self.client.invoke_shell(term_type, width, height)
@@ -127,9 +113,23 @@
remotefile.close()
def listfiles(self, path):
- return[ getattr(fileinfo, 'filename', '?') for fileinfo
+ return [getattr(fileinfo, 'filename', '?') for fileinfo
in self.sftp_client.listdir_attr(path)
- if stat.S_ISREG(fileinfo.st_mode) or
stat.S_IFMT(fileinfo.st_mode) == 0 ]
+ if stat.S_ISREG(fileinfo.st_mode) or
+ stat.S_IFMT(fileinfo.st_mode) == 0]
def get_file(self, source, dest):
self.sftp_client.get(source, dest)
+
+
+class RemoteCommand(Command):
+
+ def _execute(self):
+ self._session.exec_command(self._command)
+
+ def _read_outputs(self):
+ stdout = self._session.makefile('rb', -1).read()
+ stderr = self._session.makefile_stderr('rb', -1).read()
+ rc = self._session.recv_exit_status()
+ self._session.close()
+ return stdout, stderr, rc