← Back to team overview

duplicity-team team mailing list archive

[Merge] lp:~ed.so/duplicity/backend_fixes into lp:duplicity

 

edso has proposed merging lp:~ed.so/duplicity/backend_fixes into lp:duplicity.

Requested reviews:
  duplicity-team (duplicity-team)

For more details, see:
https://code.launchpad.net/~ed.so/duplicity/backend_fixes/+merge/105956

- fixed ssh/gio backend import warnings
 + ssh paramiko backend imports paramiko lazily now
 + gio backend is not imported automatically but on request when --gio option is used
- added a warning when --ssh-backend is used with an incorrect value
-- 
https://code.launchpad.net/~ed.so/duplicity/backend_fixes/+merge/105956
Your team duplicity-team is requested to review the proposed merge of lp:~ed.so/duplicity/backend_fixes into lp:duplicity.
=== modified file 'duplicity/backend.py'
--- duplicity/backend.py	2012-02-29 16:40:41 +0000
+++ duplicity/backend.py	2012-05-16 11:17:18 +0000
@@ -74,6 +74,8 @@
         if fn.endswith("backend.py"):
             fn = fn[:-3]
             imp = "duplicity.backends.%s" % (fn,)
+            # ignore gio as it is explicitly loaded in commandline.parse_cmdline_options()
+            if fn == "giobackend": continue
             try:
                 __import__(imp)
                 res = "Succeeded"
@@ -155,7 +157,10 @@
     elif not pu.scheme in _backends:
         raise UnsupportedBackendScheme(url_string)
     else:
-        return _backends[pu.scheme](pu)
+        try:
+            return _backends[pu.scheme](pu)
+        except ImportError:
+            raise BackendException(_("Could not initialize backend: %s") % str(sys.exc_info()[1]))
 
 
 _urlparser_initialized = False

=== modified file 'duplicity/backends/_ssh_paramiko.py'
--- duplicity/backends/_ssh_paramiko.py	2012-05-15 11:34:57 +0000
+++ duplicity/backends/_ssh_paramiko.py	2012-05-16 11:17:18 +0000
@@ -32,13 +32,6 @@
 import getpass
 from binascii import hexlify
 
-# debian squeeze's paramiko is a bit old, so we silence randompool depreciation warning
-# note also: passphrased private keys work with squeeze's paramiko only if done with DES, not AES
-import warnings
-warnings.simplefilter("ignore")
-import paramiko
-warnings.resetwarnings()
-
 import duplicity.backend
 from duplicity import globals
 from duplicity import log
@@ -73,6 +66,42 @@
         else:
             self.remote_dir = '.'
 
+        # lazily import paramiko when we need it
+        # debian squeeze's paramiko is a bit old, so we silence randompool depreciation warning
+        # note also: passphrased private keys work with squeeze's paramiko only if done with DES, not AES
+        import warnings
+        warnings.simplefilter("ignore")
+        import paramiko
+        warnings.resetwarnings()
+
+        class AgreedAddPolicy (paramiko.AutoAddPolicy):
+            """
+            Policy for showing a yes/no prompt and adding the hostname and new 
+            host key to the known host file accordingly.
+            
+            This class simply extends the AutoAddPolicy class with a yes/no prompt.
+            """
+            def missing_host_key(self, client, hostname, key):
+                fp = hexlify(key.get_fingerprint())
+                fingerprint = ':'.join(a+b for a,b in zip(fp[::2], fp[1::2]))
+                question = """The authenticity of host '%s' can't be established.
+%s key fingerprint is %s.
+Are you sure you want to continue connecting (yes/no)? """ % (hostname, key.get_name().upper(), fingerprint)
+                while True:
+                    sys.stdout.write(question)
+                    choice = raw_input().lower()
+                    if choice in ['yes','y']:
+                        super(AgreedAddPolicy, self).missing_host_key(client, hostname, key)
+                        return
+                    elif choice in ['no','n']:
+                        raise AuthenticityException( hostname )
+                    else:
+                        question = "Please type 'yes' or 'no': "
+        
+        class AuthenticityException (paramiko.SSHException):
+            def __init__(self, hostname):
+                paramiko.SSHException.__init__(self, 'Host key verification for server %s failed.' % hostname)
+
         self.client = paramiko.SSHClient()
         self.client.set_missing_host_key_policy(AgreedAddPolicy())
         # load known_hosts files
@@ -358,6 +387,8 @@
         return output
 
     def gethostconfig(self, file, host):
+        import paramiko
+        
         file = os.path.expanduser(file)
         if not os.path.isfile(file):
             return {}
@@ -370,35 +401,6 @@
         
         return sshconfig.lookup(host)
 
-class AgreedAddPolicy (paramiko.AutoAddPolicy):
-    """
-    Policy for showing a yes/no prompt and adding the hostname and new 
-    host key to the known host file accordingly.
-    
-    This class simply extends the AutoAddPolicy class with a yes/no prompt.
-    """
-    def missing_host_key(self, client, hostname, key):
-        fp = hexlify(key.get_fingerprint())
-        fingerprint = ':'.join(a+b for a,b in zip(fp[::2], fp[1::2]))
-        question = """The authenticity of host '%s' can't be established.
-%s key fingerprint is %s.
-Are you sure you want to continue connecting (yes/no)? """ % (hostname, key.get_name().upper(), fingerprint)
-        while True:
-            sys.stdout.write(question)
-            choice = raw_input().lower()
-            if choice in ['yes','y']:
-                super(AgreedAddPolicy, self).missing_host_key(client, hostname, key)
-                return
-            elif choice in ['no','n']:
-                raise AuthenticityException( hostname )
-            else:
-                question = "Please type 'yes' or 'no': "
-
-class AuthenticityException (paramiko.SSHException):
-    def __init__(self, hostname):
-        paramiko.SSHException.__init__(self, 'Host key verification for server %s failed.' % hostname)
-
-
 duplicity.backend.register_backend("sftp", SSHParamikoBackend)
 duplicity.backend.register_backend("scp", SSHParamikoBackend)
 duplicity.backend.register_backend("ssh", SSHParamikoBackend)

=== modified file 'duplicity/backends/sshbackend.py'
--- duplicity/backends/sshbackend.py	2012-05-15 13:08:14 +0000
+++ duplicity/backends/sshbackend.py	2012-05-16 11:17:18 +0000
@@ -22,12 +22,15 @@
 
 def warn_option(option, optionvar):
     if optionvar:
-        log.Warn("Warning: Option %s is supported by ssh pexpect backend only and will be ignored. " % option)
+        log.Warn(_("Warning: Option %s is supported by ssh pexpect backend only and will be ignored.") % option)
 
 if (globals.ssh_backend and
     globals.ssh_backend.lower().strip() == 'pexpect'):
     import _ssh_pexpect
 else:
+    # take user by the hand to prevent typo driven bug reports
+    if globals.ssh_backend.lower().strip() != 'paramiko':
+        log.Warn(_("Warning: Selected ssh backend '%s' is neither 'paramiko nor 'pexpect'. Will use default paramiko instead.") % globals.ssh_backend)
     warn_option("--scp-command", globals.scp_command)
     warn_option("--sftp-command", globals.sftp_command)
     import _ssh_paramiko

=== modified file 'duplicity/commandline.py'
--- duplicity/commandline.py	2012-03-13 20:53:35 +0000
+++ duplicity/commandline.py	2012-05-16 11:17:18 +0000
@@ -207,7 +207,7 @@
             import duplicity.backends.giobackend
             backend.force_backend(duplicity.backends.giobackend.GIOBackend)
         except ImportError:
-            log.FatalError(_("Unable to load gio module"), log.ErrorCode.gio_not_available)
+            log.FatalError(_("Unable to load gio backend: %s") % str(sys.exc_info()[1]), log.ErrorCode.gio_not_available)
 
     def set_log_fd(fd):
         if fd < 1:


Follow ups