Revision: 173
Author:   janne.t.harkonen
Date:     Wed Aug 29 05:46:34 2012
Log:      cleaner module structure
http://code.google.com/p/robotframework-sshlibrary/source/detail?r=173

Added:
 /trunk/src/SSHLibrary/abstractclient.py
Deleted:
 /trunk/src/SSHLibrary/core.py
Modified:
 /trunk/src/SSHLibrary/client.py
 /trunk/src/SSHLibrary/javaclient.py
 /trunk/src/SSHLibrary/library.py
 /trunk/src/SSHLibrary/pythonclient.py

=======================================
--- /dev/null
+++ /trunk/src/SSHLibrary/abstractclient.py     Wed Aug 29 05:46:34 2012
@@ -0,0 +1,427 @@
+#  Copyright 2008-2012 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.
+
+from __future__ import with_statement
+
+import os
+import re
+import time
+import glob
+
+from robot import utils
+
+from .config import (Configuration, StringEntry, TimeEntry, IntegerEntry,
+        NewlineEntry)
+
+
+class SSHClientException(RuntimeError):
+    pass
+
+
+class ClientConfig(Configuration):
+
+    def __init__(self, host, alias=None, port=22, timeout=3, newline='LF',
+                 prompt=None, term_type='vt100', width=80, height=24):
+        Configuration.__init__(self,
+                host=StringEntry(host),
+                alias=StringEntry(alias),
+                port=IntegerEntry(port),
+                timeout=TimeEntry(timeout),
+                newline=NewlineEntry(newline),
+                prompt=StringEntry(prompt),
+                term_type=StringEntry(term_type),
+                width=IntegerEntry(width),
+                height=IntegerEntry(height))
+
+
+class AbstractSSHClient(object):
+    """A base class for SSH client implementations, defines the public API
+
+ Subclasses provide the tool/language specific concrete implementations.
+    """
+
+    def __init__(self, host, alias=None, port=22, timeout=3, newline='LF',
+                 prompt=None, term_type='vt100', width=80, height=24):
+        """Create new SSHClient based on arguments."""
+        self.config = ClientConfig(host, alias, port, timeout, newline,
+                                   prompt, term_type, width, height)
+        self.client = self._create_client()
+        self._commands = []
+
+    @property
+    def host(self):
+        return self.config.host
+
+    @property
+    def port(self):
+        return self.config.port
+
+    @staticmethod
+    def enable_logging(path):
+        """Log SSH events to file.
+
+        :param path: A filename where the log events are written
+        :returns: Whether logging was succesfully enabled.
+        """
+        raise NotImplementedError
+
+    def login(self, username, password):
+        """Login using given credentials.
+
+        :param str username: username to log in with
+        :param str password: password for `username`
+ :returns: If prompt is defined, read and return output until prompt.
+            Otherwise all output is read and returned.
+        """
+        try:
+            self._login(username, password)
+        except SSHClientException:
+            msg = 'Authentication failed for user: %s' % username
+            raise SSHClientException(msg)
+        return self._finalize_login()
+
+    def login_with_public_key(self, username, keyfile, password):
+        """Login using given credentials.
+
+        :param str username: username to log in with
+        :param str keyfile: path to a valid OpenSSH keyfile
+        :param str password: password used in unlocking the keyfile
+ :returns: If prompt is defined, read and return output until prompt.
+            Otherwise all output is read and returned.
+        """
+        self._verify_key_file(keyfile)
+        try:
+            self._login_with_public_key(username, keyfile, password)
+        except SSHClientException:
+            msg = 'Login with public key failed for user: %s' % username
+            raise SSHClientException(msg)
+        return self._finalize_login()
+
+    def _finalize_login(self):
+        self.open_shell()
+ return self.read_until_prompt() if self.config.prompt else self.read()
+
+    def _verify_key_file(self, keyfile):
+        if not os.path.exists(keyfile):
+            raise SSHClientException("Given key file '%s' does not exist" %
+                                     keyfile)
+        try:
+            open(keyfile).close()
+        except IOError:
+ raise SSHClientException("Could not read key file '%s'" % keyfile)
+
+    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 write(self, text, add_newline=False):
+        """Write `text` in shell session.
+
+        :param str text: the text to be written, must be ASCII.
+ :param bool add_newline: if True, a newline will be added to `text`.
+        """
+        self._ensure_prompt_is_set()
+        try:
+            text = str(text)
+        except UnicodeError:
+ raise SSHClientException('Invalid input, only ASCII characters '
+                                     'are allowed. Got: %s' % text)
+        if add_newline:
+            text += self.config.newline
+        self._write(text)
+
+    def read(self):
+        """Read and return currently available output."""
+        return self._read()
+
+    def read_char(self):
+        """Read and return a single character from current session."""
+        return self._read_char()
+
+    def read_until(self, expected):
+        """Read and return from the output until expected.
+
+        :param str expected: text to look for in the output
+        :raises SSHClientException: if expected is not found in output when
+            timeout expires.
+
+        timeout is defined with :py:meth:`open_connection()`
+        """
+        return self._read_until(lambda s: expected in s, expected)
+
+    def read_until_newline(self):
+ """Read and return from the output up to the first newline character.
+
+        :raises SSHClientException: if newline is not found in output when
+            timeout expires.
+
+        timeout is defined with :py:meth:`open_connection()`
+        """
+        return self.read_until(self.config.newline)
+
+    def read_until_prompt(self):
+        """Read and return from the output until prompt.
+
+        :raises SSHClientException: if prompt is not set or it is not found
+            in output when timeout expires.
+
+        prompt and timeout are defined with :py:meth:`open_connection()`
+        """
+        self._ensure_prompt_is_set()
+        return self.read_until(self.config.prompt)
+
+    def read_until_regexp(self, regexp):
+        """Read and return from the output until regexp matches.
+
+ :param regexp: a pattern or a compiled regexp obect used for matching
+        :raises SSHClientException: if match is not found in output when
+            timeout expires.
+
+        timeout is defined with :py:meth:`open_connection()`
+        """
+        if isinstance(regexp, basestring):
+            regexp = re.compile(regexp)
+        return self._read_until(lambda s: regexp.search(s), regexp.pattern)
+
+    def write_until_expected(self, text, expected, timeout, interval):
+        """Write text until expected output appears or timeout expires.
+
+        :param str text: Text to be written using #write_bare().
+        :param str expected: Text to look for in the output.
+        :param int timeout: The timeout during which `expected` must appear
+            in the output. Can be defined either as seconds or as a Robot
+            Framework time string, e.g. 1 minute 20 seconds.
+        :param int interval: Time to wait between repeated writings. Can be
+            defined similarly as `timeout`.
+        """
+        timeout = TimeEntry(timeout)
+        interval = TimeEntry(interval)
+        starttime = time.time()
+        while time.time() - starttime < timeout.value:
+            self.write(text)
+            try:
+                return self._read_until(lambda s: expected in s,
+                                        expected, timeout=interval.value)
+            except SSHClientException:
+                pass
+        raise SSHClientException("No match found for '%s' in %s."
+                                 % (expected, timeout))
+
+    def _read_until(self, matcher, expected, timeout=None):
+        ret = ''
+ timeout = TimeEntry(timeout) if timeout else self.config.get('timeout')
+        start_time = time.time()
+        while time.time() < float(timeout.value) + start_time:
+            ret += self._read_char()
+            if matcher(ret):
+                return ret
+ raise SSHClientException("No match found for '%s' in %s\nOutput:\n%s"
+                                 % (expected, timeout, ret))
+
+    def _ensure_prompt_is_set(self):
+        if not self.config.prompt:
+            raise SSHClientException('Prompt is not set.')
+
+    def put_file(self, source, destination='.', mode='0744',
+                 newline='default', path_separator='/'):
+        """Put file(s) from localhost to remote host.
+
+        :param source: Local file path. May be a simple pattern containing
+            '*' and '?', in which case all matching files are tranferred
+        :param destintation: Remote path. If many files are transferred,
+            must be a directory. Defaults to users home directory.
+        :param mode: File permissions for the remote file. Defined as a
+            Unix file format string, e.g. '0600'
+        :param newline: Newline character to be used in the remote file.
+            Default is 'LF', i.e. the line feed character.
+        :param path_separator: The path separator on the remote machine.
+            Must be defined if the remote machine runs Windows.
+        """
+        sftp_client = self._create_sftp_client()
+        sources, destinations = sftp_client.put_file(
+                source, destination, mode, newline, path_separator)
+        sftp_client.close()
+        return sources, destinations
+
+    def get_file(self, source, destination='.', path_separator='/'):
+        """Get file(s) from the remote host to localhost.
+
+        :param source: Remote file path. May be a simple pattern containing
+            '*' and '?', in which case all matching files are tranferred
+            :param destintation: Local path. If many files are transferred,
+            must be a directory. Defaults to current working directory.
+        :param path_separator: The path separator on the remote machine.
+            Must be defined if the remote machine runs Windows.
+        """
+        sftp_client = self._create_sftp_client()
+        sources, destinations = sftp_client.get_file(
+                source, destination, path_separator)
+        sftp_client.close()
+        return sources, destinations
+
+
+class AbstractSFTPClient(object):
+
+    def __init__(self, ssh_client):
+        self._client = self._create_client(ssh_client)
+        self._homedir = self._resolve_homedir()
+
+    def close(self):
+        self._client.close()
+
+    def get_file(self, sources, destination, path_separator='/'):
+        remotefiles = self._get_get_file_sources(sources, path_separator)
+ localfiles = self._get_get_file_destinations(remotefiles, destination)
+        for src, dst in zip(remotefiles, localfiles):
+            self._get_file(src, dst)
+        return remotefiles, localfiles
+
+    def _get_get_file_sources(self, source, path_separator):
+        if path_separator in source:
+            path, pattern = source.rsplit(path_separator, 1)
+        else:
+            path, pattern = '', source
+        if not path:
+            path = '.'
+        sourcefiles = []
+        for filename in self._listfiles(path):
+            if utils.matches(filename, pattern):
+                if path:
+                    filename = path_separator.join([path, filename])
+                sourcefiles.append(filename)
+        if not sourcefiles:
+            msg = "There were no source files matching '%s'" % source
+            raise SSHClientException(msg)
+        return sourcefiles
+
+    def _get_get_file_destinations(self, sourcefiles, dest):
+        if dest == '.':
+            dest += os.sep
+        is_dir = dest.endswith(os.sep)
+        if not is_dir and len(sourcefiles) > 1:
+ msg = 'Cannot copy multiple source files to one destination file.'
+            raise SSHClientException(msg)
+        dest = os.path.abspath(dest.replace('/', os.sep))
+        self._create_missing_local_dirs(dest, is_dir)
+        if is_dir:
+            return [os.path.join(dest, os.path.split(name)[1])
+                    for name in sourcefiles]
+        return [dest]
+
+    def _create_missing_local_dirs(self, dest, is_dir):
+        if not is_dir:
+            dest = os.path.dirname(dest)
+        if not os.path.exists(dest):
+            os.makedirs(dest)
+
+    def put_file(self, sources, destination, mode, newline,
+                  path_separator='/'):
+        mode = int(mode, 8)
+        newline = {'CRLF': '\r\n', 'LF': '\n'}.get(newline.upper(), None)
+        localfiles = self._get_put_file_sources(sources)
+        remotefiles, remotedir = self._get_put_file_destinations(
+                    localfiles, destination, path_separator)
+        self._create_missing_remote_path(remotedir)
+        for src, dst in zip(localfiles, remotefiles):
+            self._put_file(src, dst, mode, newline)
+        return localfiles, remotefiles
+
+    def _put_file(self, source, dest, mode, newline_char):
+        remotefile = self._create_remote_file(dest, mode)
+        with open(source, 'rb') as localfile:
+            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)
+
+    def _parse_path_elements(self, dest, path_separator):
+        def _isabs(path):
+            if dest.startswith(path_separator):
+                return True
+            if path_separator == '\\' and path[1:3] == ':\\':
+                return True
+            return False
+        if not _isabs(dest):
+            dest = path_separator.join([self._homedir, dest])
+        return dest.rsplit(path_separator, 1)
+
+    def _get_put_file_sources(self, source):
+        sources = [f for f in glob.glob(source.replace('/', os.sep))
+                   if os.path.isfile(f)]
+        if not sources:
+            msg = "There are no source files matching '%s'" % source
+            raise SSHClientException(msg)
+        return sources
+
+    def _get_put_file_destinations(self, sources, dest, path_separator):
+        dest = dest.split(':')[-1].replace('\\', '/')
+        if dest == '.':
+            dest = self._homedir + '/'
+        if len(sources) > 1 and dest[-1] != '/':
+            raise ValueError('It is not possible to copy multiple source '
+                             'files to one destination file.')
+        dirpath, filename = self._parse_path_elements(dest, path_separator)
+        if filename:
+            files = [path_separator.join([dirpath, filename])]
+        else:
+            files = [path_separator.join([dirpath, os.path.split(path)[1]])
+                     for path in sources]
+        return files, dirpath
+
+
+class AbstractCommand(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()
=======================================
--- /trunk/src/SSHLibrary/core.py       Sun Aug 26 21:30:21 2012
+++ /dev/null
@@ -1,70 +0,0 @@
-#  Copyright 2008-2012 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.
-
-
-from config import (Configuration, StringEntry, TimeEntry, IntegerEntry,
-        NewlineEntry, LogLevelEntry)
-
-
-class SSHClientException(RuntimeError):
-    pass
-
-
-class DefaultConfig(Configuration):
-
-    def __init__(self, timeout, newline, prompt, log_level):
-        Configuration.__init__(self,
-                timeout=TimeEntry(timeout or 3),
-                newline=NewlineEntry(newline or 'LF'),
-                prompt=StringEntry(prompt),
-                log_level=LogLevelEntry(log_level or 'INFO'))
-
-
-class ClientConfig(Configuration):
-
-    def __init__(self, host, alias=None, port=22, timeout=3, newline='LF',
-                 prompt=None, term_type='vt100', width=80, height=24):
-        Configuration.__init__(self,
-                host=StringEntry(host),
-                alias=StringEntry(alias),
-                port=IntegerEntry(port),
-                timeout=TimeEntry(timeout),
-                newline=NewlineEntry(newline),
-                prompt=StringEntry(prompt),
-                term_type=StringEntry(term_type),
-                width=IntegerEntry(width),
-                height=IntegerEntry(height))
-
-
-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()
=======================================
--- /trunk/src/SSHLibrary/client.py     Wed Aug 29 05:46:22 2012
+++ /trunk/src/SSHLibrary/client.py     Wed Aug 29 05:46:34 2012
@@ -12,392 +12,9 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.

-from __future__ import with_statement
-
 import sys
-import os
-import re
-import time
-import glob

-from robot import utils
-
-from .core import ClientConfig, SSHClientException, TimeEntry
-
-
-def SSHClient(host, alias=None, port=22, timeout=3, newline='LF', prompt=None,
-              term_type='vt100', width=80, height=24):
-    """Create new SSH client with given configuration options.
-
-    :returns: Platform specific implementation of `AbstracSSHClient`
-    """
- return _SSHClientClass()(ClientConfig(host, alias, port, timeout, newline, - prompt, term_type, width, height))
-
-
-def _SSHClientClass():
-    if sys.platform.startswith('java'):
-        from javaclient import JavaSSHClient
-        return JavaSSHClient
-    from pythonclient import PythonSSHClient
-    return PythonSSHClient
-
-
-class AbstractSSHClient(object):
-    """A base class for SSH client implementations, defines the public API
-
- Subclasses provide the tool/language specific concrete implementations.
-    """
-
-    def __init__(self, config):
-        """Create new SSHClient.
-
-        :param ClientConfig config: the configuration used by this client
-        """
-        self.config = config
-        self.client = self._create_client()
-        self._commands = []
-
-    @property
-    def host(self):
-        return self.config.host
-
-    @property
-    def port(self):
-        return self.config.port
-
-    @staticmethod
-    def enable_logging(path):
-        """Log SSH events to file.
-
-        :param path: A filename where the log events are written
-        :returns: Whether logging was succesfully enabled.
-        """
-        _SSHClientClass().enable_logging(path)
-
-    def login(self, username, password):
-        """Login using given credentials.
-
-        :param str username: username to log in with
-        :param str password: password for `username`
- :returns: If prompt is defined, read and return output until prompt.
-            Otherwise all output is read and returned.
-        """
-        try:
-            self._login(username, password)
-        except SSHClientException:
-            msg = 'Authentication failed for user: %s' % username
-            raise SSHClientException(msg)
-        return self._finalize_login()
-
-    def login_with_public_key(self, username, keyfile, password):
-        """Login using given credentials.
-
-        :param str username: username to log in with
-        :param str keyfile: path to a valid OpenSSH keyfile
-        :param str password: password used in unlocking the keyfile
- :returns: If prompt is defined, read and return output until prompt.
-            Otherwise all output is read and returned.
-        """
-        self._verify_key_file(keyfile)
-        try:
-            self._login_with_public_key(username, keyfile, password)
-        except SSHClientException:
-            msg = 'Login with public key failed for user: %s' % username
-            raise SSHClientException(msg)
-        return self._finalize_login()
-
-    def _finalize_login(self):
-        self.open_shell()
- return self.read_until_prompt() if self.config.prompt else self.read()
-
-    def _verify_key_file(self, keyfile):
-        if not os.path.exists(keyfile):
-            raise SSHClientException("Given key file '%s' does not exist" %
-                                     keyfile)
-        try:
-            open(keyfile).close()
-        except IOError:
- raise SSHClientException("Could not read key file '%s'" % keyfile)
-
-    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 write(self, text, add_newline=False):
-        """Write `text` in shell session.
-
-        :param str text: the text to be written, must be ASCII.
- :param bool add_newline: if True, a newline will be added to `text`.
-        """
-        self._ensure_prompt_is_set()
-        try:
-            text = str(text)
-        except UnicodeError:
- raise SSHClientException('Invalid input, only ASCII characters '
-                                     'are allowed. Got: %s' % text)
-        if add_newline:
-            text += self.config.newline
-        self._write(text)
-
-    def read(self):
-        """Read and return currently available output."""
-        return self._read()
-
-    def read_char(self):
-        """Read and return a single character from current session."""
-        return self._read_char()
-
-    def read_until(self, expected):
-        """Read and return from the output until expected.
-
-        :param str expected: text to look for in the output
-        :raises SSHClientException: if expected is not found in output when
-            timeout expires.
-
-        timeout is defined with :py:meth:`open_connection()`
-        """
-        return self._read_until(lambda s: expected in s, expected)
-
-    def read_until_newline(self):
- """Read and return from the output up to the first newline character.
-
-        :raises SSHClientException: if newline is not found in output when
-            timeout expires.
-
-        timeout is defined with :py:meth:`open_connection()`
-        """
-        return self.read_until(self.config.newline)
-
-    def read_until_prompt(self):
-        """Read and return from the output until prompt.
-
-        :raises SSHClientException: if prompt is not set or it is not found
-            in output when timeout expires.
-
-        prompt and timeout are defined with :py:meth:`open_connection()`
-        """
-        self._ensure_prompt_is_set()
-        return self.read_until(self.config.prompt)
-
-    def read_until_regexp(self, regexp):
-        """Read and return from the output until regexp matches.
-
- :param regexp: a pattern or a compiled regexp obect used for matching
-        :raises SSHClientException: if match is not found in output when
-            timeout expires.
-
-        timeout is defined with :py:meth:`open_connection()`
-        """
-        if isinstance(regexp, basestring):
-            regexp = re.compile(regexp)
-        return self._read_until(lambda s: regexp.search(s), regexp.pattern)
-
-    def write_until_expected(self, text, expected, timeout, interval):
-        """Write text until expected output appears or timeout expires.
-
-        :param str text: Text to be written using #write_bare().
-        :param str expected: Text to look for in the output.
-        :param int timeout: The timeout during which `expected` must appear
-            in the output. Can be defined either as seconds or as a Robot
-            Framework time string, e.g. 1 minute 20 seconds.
-        :param int interval: Time to wait between repeated writings. Can be
-            defined similarly as `timeout`.
-        """
-        timeout = TimeEntry(timeout)
-        interval = TimeEntry(interval)
-        starttime = time.time()
-        while time.time() - starttime < timeout.value:
-            self.write(text)
-            try:
-                return self._read_until(lambda s: expected in s,
-                                        expected, timeout=interval.value)
-            except SSHClientException:
-                pass
-        raise SSHClientException("No match found for '%s' in %s."
-                                 % (expected, timeout))
-
-    def _read_until(self, matcher, expected, timeout=None):
-        ret = ''
- timeout = TimeEntry(timeout) if timeout else self.config.get('timeout')
-        start_time = time.time()
-        while time.time() < float(timeout.value) + start_time:
-            ret += self._read_char()
-            if matcher(ret):
-                return ret
- raise SSHClientException("No match found for '%s' in %s\nOutput:\n%s"
-                                 % (expected, timeout, ret))
-
-    def _ensure_prompt_is_set(self):
-        if not self.config.prompt:
-            raise SSHClientException('Prompt is not set.')
-
-    def put_file(self, source, destination='.', mode='0744',
-                 newline='default', path_separator='/'):
-        """Put file(s) from localhost to remote host.
-
-        :param source: Local file path. May be a simple pattern containing
-            '*' and '?', in which case all matching files are tranferred
-        :param destintation: Remote path. If many files are transferred,
-            must be a directory. Defaults to users home directory.
-        :param mode: File permissions for the remote file. Defined as a
-            Unix file format string, e.g. '0600'
-        :param newline: Newline character to be used in the remote file.
-            Default is 'LF', i.e. the line feed character.
-        :param path_separator: The path separator on the remote machine.
-            Must be defined if the remote machine runs Windows.
-        """
-        sftp_client = self._create_sftp_client()
-        sources, destinations = sftp_client.put_file(
-                source, destination, mode, newline, path_separator)
-        sftp_client.close()
-        return sources, destinations
-
-    def get_file(self, source, destination='.', path_separator='/'):
-        """Get file(s) from the remote host to localhost.
-
-        :param source: Remote file path. May be a simple pattern containing
-            '*' and '?', in which case all matching files are tranferred
-            :param destintation: Local path. If many files are transferred,
-            must be a directory. Defaults to current working directory.
-        :param path_separator: The path separator on the remote machine.
-            Must be defined if the remote machine runs Windows.
-        """
-        sftp_client = self._create_sftp_client()
-        sources, destinations = sftp_client.get_file(
-                source, destination, path_separator)
-        sftp_client.close()
-        return sources, destinations
-
-
-class AbstractSFTPClient(object):
-
-    def __init__(self, ssh_client):
-        self._client = self._create_client(ssh_client)
-        self._homedir = self._resolve_homedir()
-
-    def close(self):
-        self._client.close()
-
-    def get_file(self, sources, destination, path_separator='/'):
-        remotefiles = self._get_get_file_sources(sources, path_separator)
- localfiles = self._get_get_file_destinations(remotefiles, destination)
-        for src, dst in zip(remotefiles, localfiles):
-            self._get_file(src, dst)
-        return remotefiles, localfiles
-
-    def _get_get_file_sources(self, source, path_separator):
-        if path_separator in source:
-            path, pattern = source.rsplit(path_separator, 1)
-        else:
-            path, pattern = '', source
-        if not path:
-            path = '.'
-        sourcefiles = []
-        for filename in self._listfiles(path):
-            if utils.matches(filename, pattern):
-                if path:
-                    filename = path_separator.join([path, filename])
-                sourcefiles.append(filename)
-        if not sourcefiles:
-            msg = "There were no source files matching '%s'" % source
-            raise SSHClientException(msg)
-        return sourcefiles
-
-    def _get_get_file_destinations(self, sourcefiles, dest):
-        if dest == '.':
-            dest += os.sep
-        is_dir = dest.endswith(os.sep)
-        if not is_dir and len(sourcefiles) > 1:
- msg = 'Cannot copy multiple source files to one destination file.'
-            raise SSHClientException(msg)
-        dest = os.path.abspath(dest.replace('/', os.sep))
-        self._create_missing_local_dirs(dest, is_dir)
-        if is_dir:
-            return [os.path.join(dest, os.path.split(name)[1])
-                    for name in sourcefiles]
-        return [dest]
-
-    def _create_missing_local_dirs(self, dest, is_dir):
-        if not is_dir:
-            dest = os.path.dirname(dest)
-        if not os.path.exists(dest):
-            os.makedirs(dest)
-
-    def put_file(self, sources, destination, mode, newline,
-                  path_separator='/'):
-        mode = int(mode, 8)
-        newline = {'CRLF': '\r\n', 'LF': '\n'}.get(newline.upper(), None)
-        localfiles = self._get_put_file_sources(sources)
-        remotefiles, remotedir = self._get_put_file_destinations(
-                    localfiles, destination, path_separator)
-        self._create_missing_remote_path(remotedir)
-        for src, dst in zip(localfiles, remotefiles):
-            self._put_file(src, dst, mode, newline)
-        return localfiles, remotefiles
-
-    def _put_file(self, source, dest, mode, newline_char):
-        remotefile = self._create_remote_file(dest, mode)
-        with open(source, 'rb') as localfile:
-            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)
-
-    def _parse_path_elements(self, dest, path_separator):
-        def _isabs(path):
-            if dest.startswith(path_separator):
-                return True
-            if path_separator == '\\' and path[1:3] == ':\\':
-                return True
-            return False
-        if not _isabs(dest):
-            dest = path_separator.join([self._homedir, dest])
-        return dest.rsplit(path_separator, 1)
-
-    def _get_put_file_sources(self, source):
-        sources = [f for f in glob.glob(source.replace('/', os.sep))
-                   if os.path.isfile(f)]
-        if not sources:
-            msg = "There are no source files matching '%s'" % source
-            raise SSHClientException(msg)
-        return sources
-
-    def _get_put_file_destinations(self, sources, dest, path_separator):
-        dest = dest.split(':')[-1].replace('\\', '/')
-        if dest == '.':
-            dest = self._homedir + '/'
-        if len(sources) > 1 and dest[-1] != '/':
-            raise ValueError('It is not possible to copy multiple source '
-                             'files to one destination file.')
-        dirpath, filename = self._parse_path_elements(dest, path_separator)
-        if filename:
-            files = [path_separator.join([dirpath, filename])]
-        else:
-            files = [path_separator.join([dirpath, os.path.split(path)[1]])
-                     for path in sources]
-        return files, dirpath
+if sys.platform.startswith('java'):
+    from javaclient import JavaSSHClient as SSHClient
+else:
+    from pythonclient import PythonSSHClient as SSHClient
=======================================
--- /trunk/src/SSHLibrary/javaclient.py Mon Aug 27 05:07:10 2012
+++ /trunk/src/SSHLibrary/javaclient.py Wed Aug 29 05:46:34 2012
@@ -22,8 +22,8 @@
     raise ImportError('Importing Trilead SSH classes failed. '
'Make sure you have the Trilead jar file in CLASSPATH.')

-from .client import AbstractSSHClient, AbstractSFTPClient
-from .core import SSHClientException, Command
+from .abstractclient import (AbstractSSHClient, AbstractSFTPClient,
+        AbstractCommand, SSHClientException)


 class JavaSSHClient(AbstractSSHClient):
@@ -154,7 +154,7 @@
         localfile.close()


-class RemoteCommand(Command):
+class RemoteCommand(AbstractCommand):

     def _execute(self):
         self._session.execCommand(self._command)
=======================================
--- /trunk/src/SSHLibrary/library.py    Wed Aug 29 05:46:22 2012
+++ /trunk/src/SSHLibrary/library.py    Wed Aug 29 05:46:34 2012
@@ -1,6 +1,22 @@
-from .client import SSHClient, AbstractSSHClient
+#  Copyright 2008-2012 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.
+
+from .abstractclient import SSHClientException
+from .client import SSHClient
+from config import (Configuration, StringEntry, TimeEntry, LogLevelEntry,
+        NewlineEntry)
 from .connectioncache import ConnectionCache
-from .core import DefaultConfig, SSHClientException
 from .deprecated import DeprecatedSSHLibraryKeywords
 from .version import VERSION

@@ -206,7 +222,7 @@
Note that this keyword only works with Python, e.g. when executing the
         tests with `pybot`.
         """
-        if AbstractSSHClient.enable_logging(logfile):
+        if SSHClient.enable_logging(logfile):
self._log('SSH log is written to <a href="%s">file</a>.' % logfile,
                       'HTML')

@@ -536,3 +552,14 @@
level.upper() in ['TRACE', 'DEBUG', 'INFO', 'WARN', 'HTML']:
             return level.upper()
         raise AssertionError("Invalid log level '%s'" % level)
+
+
+class DefaultConfig(Configuration):
+
+    def __init__(self, timeout, newline, prompt, log_level):
+        Configuration.__init__(self,
+                timeout=TimeEntry(timeout or 3),
+                newline=NewlineEntry(newline or 'LF'),
+                prompt=StringEntry(prompt),
+                log_level=LogLevelEntry(log_level or 'INFO'))
+
=======================================
--- /trunk/src/SSHLibrary/pythonclient.py       Wed Aug 29 05:46:22 2012
+++ /trunk/src/SSHLibrary/pythonclient.py       Wed Aug 29 05:46:34 2012
@@ -22,8 +22,8 @@
             'Ensure that paramiko and pycrypto modules are installed.'
             )

-from .client import AbstractSSHClient, AbstractSFTPClient
-from .core import Command, SSHClientException
+from .abstractclient import (AbstractSSHClient, AbstractSFTPClient,
+        AbstractCommand, SSHClientException)


 # There doesn't seem to be a simpler way to increase banner timeout
@@ -132,7 +132,7 @@
                         stat.S_IFMT(fileinfo.st_mode) == 0]


-class RemoteCommand(Command):
+class RemoteCommand(AbstractCommand):

     def _execute(self):
         self._session.exec_command(self._command)

Reply via email to