[Checkins] SVN: zc.buildoutsftp/branches/jim-dev/ checkpoint

jim cvs-admin at zope.org
Thu Jun 28 15:48:01 UTC 2012


Log message for revision 127143:
  checkpoint

Changed:
  U   zc.buildoutsftp/branches/jim-dev/buildout.cfg
  U   zc.buildoutsftp/branches/jim-dev/setup.py
  U   zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/__init__.py
  D   zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/buildoutsftp.py
  A   zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/main.test
  A   zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/tests.py
  D   zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/urllib2sftp.py

-=-
Modified: zc.buildoutsftp/branches/jim-dev/buildout.cfg
===================================================================
--- zc.buildoutsftp/branches/jim-dev/buildout.cfg	2012-06-28 15:45:59 UTC (rev 127142)
+++ zc.buildoutsftp/branches/jim-dev/buildout.cfg	2012-06-28 15:47:58 UTC (rev 127143)
@@ -2,9 +2,13 @@
 develop = .
 parts = py
 
+[test]
+recipe = zc.recipe.testrunner
+eggs = zc.buildoutsftp [test]
+
 [py]
 recipe = zc.recipe.egg
-eggs = zc.buildoutsftp
+eggs = ${test:eggs}
 interpreter = py
 
 

Modified: zc.buildoutsftp/branches/jim-dev/setup.py
===================================================================
--- zc.buildoutsftp/branches/jim-dev/setup.py	2012-06-28 15:45:59 UTC (rev 127142)
+++ zc.buildoutsftp/branches/jim-dev/setup.py	2012-06-28 15:47:58 UTC (rev 127143)
@@ -17,6 +17,7 @@
     package_dir = {'':'src'},
     namespace_packages = ['zc'],
     install_requires = ['paramiko', 'setuptools'],
+    extras_require = dict(test=['zope.testing', 'mock']),
     zip_safe=False,
     entry_points = {
         'zc.buildout.extension': ['default = %s.buildoutsftp:install' % name],

Modified: zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/__init__.py
===================================================================
--- zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/__init__.py	2012-06-28 15:45:59 UTC (rev 127142)
+++ zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/__init__.py	2012-06-28 15:47:58 UTC (rev 127143)
@@ -1 +1,259 @@
+##############################################################################
 #
+# Copyright (c) 2006, 2012 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import atexit
+import cStringIO
+import getpass
+import logging
+import logging
+import mimetypes
+import os
+import paramiko
+import re
+import stat
+import sys
+import urllib
+import urllib2
+
+logger = logging.getLogger(__name__)
+
+def install(buildout=None):
+    urllib2.install_opener(urllib2.build_opener(SFTPHandler))
+    logging.getLogger('paramiko').setLevel(logger.getEffectiveLevel()+10)
+
+def unload(buildout=None):
+    # no uninstall_opener. Screw it. :)
+    cleanup()
+
+parse_url_host = re.compile(
+    '(?:' '([^@:]+)(?::([^@]*))?@' ')?'
+    '([^:]*)(?::(\d+))?$').match
+
+_configs = None
+def _get_config(host):
+    global _configs
+    if _configs is None:
+        _configs = []
+        for path in ('/etc/ssh/ssh_config', '/etc/ssh/ssh_config',
+                     os.path.expanduser('~/.ssh/config')):
+            if os.path.exists(path):
+                config = paramiko.SSHConfig()
+                with open(path) as f:
+                    config.parse(f)
+                _configs.append(config)
+
+    r = {}
+    for config in _configs:
+        r.update(config.lookup(host))
+
+    return r
+
+if sys.platform == 'win32':
+    import _winreg
+    parse_reg_key_name = re.compile('(rsa|dss)2?@22:(\S+)$').match
+    def _get_host_keys(config):
+        regkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
+                                 r'Software\SimonTatham\PuTTY\SshHostKeys',
+                                 )
+        keys = paramiko.HostKeys()
+        i = 0
+        while 1:
+            try:
+                name, value, type_ = _winreg.EnumValue(regkey, i)
+                i += 1
+                value = [long(v, 16) for v in value.split(',')]
+                ktype, host = parse_reg_key_name(name).groups()
+                if ktype == 'rsa':
+                    key = paramiko.RSAKey(vals=value)
+                if ktype == 'dss':
+                    key = paramiko.DSSKey(vals=value)
+                keys.add(host, 'ssh-'+ktype, key)
+            except WindowsError:
+                break
+
+        return keys
+
+else:
+    def _get_host_keys(config):
+        user_host_keys = os.path.expanduser('~/.ssh/known_hosts')
+        if os.path.exists(user_host_keys):
+            host_keys = paramiko.HostKeys(user_host_keys)
+        else:
+            host_keys = {}
+        global_host_keys = config.get('GlobalKnownHostsFile')
+        if not global_host_keys:
+            for path in ('/etc/ssh/GlobalKnownHostsFile',
+                         '/etc/ssh_known_hosts'):
+                if os.path.exists(path):
+                    global_host_keys = path
+                    break
+        if global_host_keys:
+            host_keys.update(paramiko.HostKeys(user_host_keys))
+        return host_keys
+
+class Result:
+
+    def __init__(self, fp, url, info, trans):
+        self._fp = fp
+        self.url = url
+        self.headers = info
+        self.__trans = trans
+
+    def geturl(self):
+        return self.url
+
+    def info(self):
+        return self.headers
+
+    def __getattr__(self, name):
+        return getattr(self._fp, name)
+
+def _open_key(key_path):
+    key = None
+    if os.path.exists(key_path):
+        try:
+            key = paramiko.RSAKey.from_private_key_file(key_path)
+        except paramiko.SSHException:
+            try:
+                key = paramiko.DSSKey.from_private_key_file(key_path)
+            except paramiko.SSHException:
+                logger.error('Invalid key file: %s', key_path)
+    return key
+
+_connection_pool = {}
+
+def cleanup():
+    for k in list(_connection_pool):
+        trans = _connection_pool.pop(k)
+        if trans is not False:
+            trans.close()
+
+atexit.register(cleanup)
+
+class SFTPHandler(urllib2.BaseHandler):
+
+    def sftp_open(self, req):
+        host = req.get_host()
+        if not host:
+            raise IOError, ('sftp error', 'no host given')
+
+        parsed = parse_url_host(host)
+        if not parsed:
+            raise IOError, ('sftp error', 'invalid host', host)
+
+        user, pw, host, port = parsed.groups()
+
+        host = urllib.unquote(host or '')
+
+        config = _get_config(host)
+
+        host_keys = _get_host_keys(config).get(host)
+        if host_keys is None:
+            raise paramiko.AuthenticationException("No stored host key", host)
+
+        if user:
+            user = urllib.unquote(user)
+        else:
+            user = config.get('user', getpass.getuser())
+
+        if port:
+            port = int(port)
+        else:
+            port = 22
+
+        if pw:
+            pw = urllib.unquote(pw)
+
+
+        if pw is not None:
+            pool_key = (host, port, user, pw)
+            trans = _connection_pool.get(pool_key)
+            if trans is None:
+                trans = paramiko.Transport((host, port))
+                try:
+                    trans.connect(username=user, password=pw)
+                except paramiko.AuthenticationException:
+                    trans.close()
+                    raise
+        else:
+            keys = list(paramiko.Agent().get_keys())
+            IdentityFile = config.get('IdentityFile')
+            if IdentityFile:
+                key = _open_key(IdentityFile)
+                if key is None:
+                    logger.error('IdentityFile, %s, does not exist',
+                                 IdentityFile)
+                else:
+                    keys.insert(0, key)
+            else:
+                for path in (
+                    '~/.ssh/identity', '~/.ssh/id_rsa', '~/.ssh/id_dsa'):
+                    key = _open_key(os.path.expanduser(path))
+                    if key is not None:
+                        keys.insert(0, key)
+
+            for key in keys:
+                pool_key = (host, port, str(key))
+                trans = _connection_pool.get(pool_key)
+                if trans is not None:
+                    if trans is False:
+                        # Failed previously, so don't try again
+                        continue
+                    break
+                trans = paramiko.Transport((host, port))
+                try:
+                    trans.connect(username=user, pkey=key)
+                    break
+                except paramiko.AuthenticationException:
+                    trans.close()
+                    _connection_pool[pool_key] = False
+            else:
+                raise paramiko.AuthenticationException(
+                    "Authentication failed.")
+
+        if pool_key not in _connection_pool:
+            # Check host key
+            remote_server_key = trans.get_remote_server_key()
+            host_key = host_keys.get(remote_server_key.get_name())
+            if host_key != remote_server_key:
+                raise paramiko.AuthenticationException(
+                    "Remote server authentication failed.", host)
+            _connection_pool[pool_key] = trans
+
+        sftp = paramiko.SFTPClient.from_transport(trans)
+
+        path = req.get_selector()
+        url = req.get_full_url()
+        logger.debug('sftp get: %s', url)
+        mode = sftp.stat(path).st_mode
+        if stat.S_ISDIR(mode):
+            if logger.getEffectiveLevel() < logging.DEBUG:
+                logger.log(1, "Dir %s:\n  %s\n",
+                           path, '\n  '.join(sftp.listdir(path)))
+
+            return Result(
+                cStringIO.StringIO('\n'.join([
+                    ('<a href="%s/%s">%s</a><br />'
+                     % (url, x, x)
+                     )
+                    for x in sftp.listdir(path)
+                    ])),
+                url, {'content-type': 'text/html'}, trans)
+        else:
+            mtype = mimetypes.guess_type(url)[0]
+            if mtype is None:
+                mtype = 'application/octet-stream'
+            return Result(sftp.open(path), url, {'content-type': mtype},
+                          trans)
+

Deleted: zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/buildoutsftp.py
===================================================================
--- zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/buildoutsftp.py	2012-06-28 15:45:59 UTC (rev 127142)
+++ zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/buildoutsftp.py	2012-06-28 15:47:58 UTC (rev 127143)
@@ -1,28 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-
-import logging
-import urllib2
-import zc.buildoutsftp.urllib2sftp
-
-def install(buildout=None):
-    urllib2.install_opener(
-        urllib2.build_opener(zc.buildoutsftp.urllib2sftp.SFTPHandler)
-        )
-    logging.getLogger('paramiko').setLevel(
-        logging.getLogger().getEffectiveLevel()+10)
-
-def unload(buildout=None):
-    # no uninstall_opener. Screw it. :)
-    zc.buildoutsftp.urllib2sftp.cleanup()

Added: zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/main.test
===================================================================
--- zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/main.test	                        (rev 0)
+++ zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/main.test	2012-06-28 15:47:58 UTC (rev 127143)
@@ -0,0 +1,49 @@
+Mochiavellian tests
+===================
+
+We're not going to try to test actuall sftp interaction.  Too hard.
+Instead, we'll mock the environmet and back up the mock-based tests
+with integration tests.
+
+The buildoutsftp extension installs an sftp handler in urllib2.
+
+    >>> import zc.buildoutsftp, urllib2
+    >>> zc.buildoutsftp.install(None)
+    >>> urllib2.build_opener.assert_called_with(zc.buildoutsftp.SFTPHandler)
+    >>> urllib2.install_opener.assert_called_with(
+    ...     urllib2.build_opener.return_value)
+
+A buildout object is passed to install, but install ignores it.
+
+    >>> handler = zc.buildoutsftp.SFTPHandler()
+    >>> request = urllib2.Request('sftp://example.com')
+
+Let's start with essentially no ssh support in the user's environment:
+
+    >>> handler.sftp_open(request)
+    Traceback (most recent call last):
+    ...
+    AuthenticationException: ('No stored host key', 'example.com')
+
+There's a early check for the presense of host keys that failed.
+We'll create an empty host key file:
+
+    >>> import os, paramiko
+    >>> host_key = paramiko.RSAKey.generate(1024)
+    >>> host_keys = paramiko.HostKeys()
+    >>> host_keys.add('example.com', 'ssh-rsa', host_key)
+    >>> os.mkdir('.ssh', 0700)
+    >>> host_keys.save(os.path.join('.ssh', 'known_hosts'))
+
+    >>> handler.sftp_open(request)
+    Traceback (most recent call last):
+    ...
+    AuthenticationException: Authentication failed.
+
+Authentication failed because the user has no keys.
+
+Let's give them one:
+
+    >>> ukey = creds[(('example.com', 22), 'testuser')]['user_key']
+    >>> ukey.write_private_key_file(os.path.join('.ssh', 'id_rsa'))
+

Added: zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/tests.py
===================================================================
--- zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/tests.py	                        (rev 0)
+++ zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/tests.py	2012-06-28 15:47:58 UTC (rev 127143)
@@ -0,0 +1,130 @@
+##############################################################################
+#
+# Copyright (c) Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+from zope.testing import setupstack
+import doctest
+import mock
+import os
+import paramiko
+import unittest
+
+def side_effect(mock, f=None):
+    if f is None:
+        return lambda f: side_effect(mock, f)
+    mock.side_effect = f
+
+def hack_path(path):
+    if path.startswith('/etc/'):
+        return path[1:]
+    return path
+
+def setup(test):
+    globs = test.globs
+    setupstack.setUpDirectory(test)
+    setupstack.context_manager(test, mock.patch('urllib2.install_opener'))
+    setupstack.context_manager(test, mock.patch('urllib2.build_opener'))
+    setupstack.context_manager(
+        test, mock.patch.dict(os.environ, values=dict(HOME=os.getcwd())))
+
+    original_exists = os.path.exists
+    @side_effect(setupstack.context_manager(test, mock.patch('os.path.exists')))
+    def exists(path):
+        return original_exists(hack_path(path))
+
+    original_open = open
+    setupstack.context_manager(
+        test, mock.patch.dict(__builtins__, values=dict(open=mock.MagicMock())))
+    @side_effect(__builtins__['open'])
+    def _open(path, *args, **kw):
+        return original_open(hack_path(path), *args, **kw)
+
+    setupstack.context_manager(test, mock.patch('getpass.getuser')
+                               ).return_value = 'testuser'
+
+    globs['agent_keys'] = agent_keys = []
+    @side_effect(
+        setupstack.context_manager(
+            test, mock.patch('paramiko.Agent')).return_value.get_keys)
+    def get_keys():
+        return agent_keys
+
+    globs['creds'] = creds = {
+        # {(addr, user} -> dict(host_key, user_key}
+        (('example.com', 22), 'testuser'): dict(
+            host_key = paramiko.RSAKey.generate(1024),
+            user_key = paramiko.RSAKey.generate(1024),
+            ),
+        }
+
+    class Transport:
+
+        def __init__(self, addr):
+            self.addr = addr
+
+        def connect(self, username, pkey):
+            if pkey != creds.get((self.addr, username))['user_key']:
+                raise paramiko.AuthenticationException()
+            self.username = username
+
+        def close(self):
+            pass
+
+        def get_remote_server_key(self):
+            return creds.get((self.addr, self.username))['user_key']
+
+    @side_effect(
+        setupstack.context_manager(
+            test, mock.patch('paramiko.Transport')))
+    def transport(addr):
+        return Transport(addr)
+
+    globs['server_files'] = server_files = {} # addr -> path
+    class SFTPClient:
+
+        def __init__(self, transport):
+            self.addr = transport.addr
+
+        def _path(self, path):
+            assert path.startswith(os.path.sep)
+            base = '%s:%s' % self.addr
+            path = path[1:]
+            if path:
+                return os.path.join(base, path)
+            else:
+                return base
+
+        def stat(path):
+            return os.stat(self._path(path))
+
+        def listdir(self):
+            return os.listdir(self._path(path))
+
+        def open(self, path):
+            return original_open(self._path(path))
+
+    @side_effect(
+        setupstack.context_manager(
+            test, mock.patch('paramiko.SFTPClient.from_transport')))
+    def from_transport(trans):
+        return SFTPClient(addr)
+
+    os.makedirs(os.path.join('example.com:22', 'data', 'moredata'))
+    with open(os.path.join('example.com:22', 'data', 'index.html'), 'w') as f:
+        f.write('Hi world!\n')
+
+def test_suite():
+    return unittest.TestSuite((
+        doctest.DocFileSuite(
+            'main.test', setUp=setup, tearDown=setupstack.tearDown),
+        ))
+

Deleted: zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/urllib2sftp.py
===================================================================
--- zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/urllib2sftp.py	2012-06-28 15:45:59 UTC (rev 127142)
+++ zc.buildoutsftp/branches/jim-dev/src/zc/buildoutsftp/urllib2sftp.py	2012-06-28 15:47:58 UTC (rev 127143)
@@ -1,190 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2005 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""SFTP Handler for urllib2
-
-$Id$
-"""
-
-import atexit, cStringIO, getpass, logging, mimetypes, os, re, stat, sys
-import urllib, urllib2
-import paramiko
-
-logger = logging.getLogger(__name__)
-
-parse_url_host = re.compile(
-    '(?:' '([^@:]+)(?::([^@]*))?@' ')?'
-    '([^:]*)(?::(\d+))?$').match
-
-if sys.platform == 'win32':
-    import _winreg
-    parse_reg_key_name = re.compile('(rsa|dss)2?@22:(\S+)$').match
-    def _get_hosts_keys():
-        regkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
-                                 r'Software\SimonTatham\PuTTY\SshHostKeys',
-                                 )
-        keys = paramiko.HostKeys()
-        i = 0
-        while 1:
-            try:
-                name, value, type_ = _winreg.EnumValue(regkey, i)
-                i += 1
-                value = [long(v, 16) for v in value.split(',')]
-                ktype, host = parse_reg_key_name(name).groups()
-                if ktype == 'rsa':
-                    key = paramiko.RSAKey(vals=value)
-                if ktype == 'dss':
-                    key = paramiko.DSSKey(vals=value)
-                keys.add(host, 'ssh-'+ktype, key)
-            except WindowsError:
-                break
-
-        return keys
-
-else:
-
-    def _get_hosts_keys():
-        return paramiko.HostKeys(os.path.expanduser('~/.ssh/known_hosts'))
-
-
-class Result:
-
-    def __init__(self, fp, url, info, trans):
-        self._fp = fp
-        self.url = url
-        self.headers = info
-        self.__trans = trans
-
-    def geturl(self):
-        return self.url
-
-    def info(self):
-        return self.headers
-
-    def __getattr__(self, name):
-        return getattr(self._fp, name)
-
-_connection_pool = {}
-def cleanup():
-    for k in list(_connection_pool):
-        trans = _connection_pool.pop(k)
-        if trans is not False:
-            trans.close()
-
-atexit.register(cleanup)
-
-class SFTPHandler(urllib2.BaseHandler):
-
-    def sftp_open(self, req):
-        host = req.get_host()
-        if not host:
-            raise IOError, ('sftp error', 'no host given')
-
-        parsed = parse_url_host(host)
-        if not parsed:
-            raise IOError, ('sftp error', 'invalid host', host)
-
-        user, pw, host, port = parsed.groups()
-
-        host = urllib.unquote(host or '')
-
-        if user:
-            user = urllib.unquote(user)
-        else:
-            user = getpass.getuser()
-            config_path = os.path.expanduser('~/.ssh/config')
-            if os.path.exists(config_path):
-                config = paramiko.SSHConfig()
-                config.parse(open(config_path))
-                user = config.lookup(host).get('user', user)
-
-        if port:
-            port = int(port)
-        else:
-            port = 22
-
-        if pw:
-            pw = urllib.unquote(pw)
-
-
-        host_keys = _get_hosts_keys().get(host)
-        if host_keys is None:
-            raise paramiko.AuthenticationException(
-                "No stored host key", host)
-
-        if pw is not None:
-            pool_key = (host, port, user, pw)
-            trans = _connection_pool.get(pool_key)
-            if trans is None:
-                trans = paramiko.Transport((host, port))
-                try:
-                    trans.connect(username=user, password=pw)
-                except paramiko.AuthenticationException:
-                    trans.close()
-                    raise
-        else:
-            for key in paramiko.Agent().get_keys():
-                pool_key = (host, port, str(key))
-                trans = _connection_pool.get(pool_key)
-                if trans is not None:
-                    if trans is False:
-                        # Failed previously, so don't try again
-                        continue
-                    break
-                trans = paramiko.Transport((host, port))
-                try:
-                    trans.connect(username=user, pkey=key)
-                    break
-                except paramiko.AuthenticationException:
-                    trans.close()
-                    _connection_pool[pool_key] = False
-            else:
-                raise paramiko.AuthenticationException(
-                    "Authentication failed.")
-
-
-        if pool_key not in _connection_pool:
-            # Check host key
-            remote_server_key = trans.get_remote_server_key()
-            host_key = host_keys.get(remote_server_key.get_name())
-            if host_key != remote_server_key:
-                raise paramiko.AuthenticationException(
-                    "Remote server authentication failed.", host)
-            _connection_pool[pool_key] = trans
-
-        sftp = paramiko.SFTPClient.from_transport(trans)
-
-        path = req.get_selector()
-        url = req.get_full_url()
-        logger.debug('sftp get: %s', url)
-        mode = sftp.stat(path).st_mode
-        if stat.S_ISDIR(mode):
-            if logger.getEffectiveLevel() < logging.DEBUG:
-                logger.log(1, "Dir %s:\n  %s\n",
-                           path, '\n  '.join(sftp.listdir(path)))
-
-            return Result(
-                cStringIO.StringIO('\n'.join([
-                    ('<a href="%s/%s">%s</a><br />'
-                     % (url, x, x)
-                     )
-                    for x in sftp.listdir(path)
-                    ])),
-                url, {'content-type': 'text/html'}, trans)
-        else:
-            mtype = mimetypes.guess_type(url)[0]
-            if mtype is None:
-                mtype = 'application/octet-stream'
-            return Result(sftp.open(path), url, {'content-type': mtype},
-                          trans)
-



More information about the checkins mailing list