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

Reply via email to