summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrej Kacian <ticho@gentoo.org>2006-10-19 17:17:40 +0000
committerAndrej Kacian <ticho@gentoo.org>2006-10-19 17:17:40 +0000
commitb2f5d65ce911a1f4b05dfaf6cfb0056308b53dfd (patch)
treea37e161a66b7289d3e5911d9eb6c9fdf3ca7bc61 /app-backup/duplicity
parentAdd latest beta, package.masked as almost every package breaks with it. (diff)
downloadgentoo-2-b2f5d65ce911a1f4b05dfaf6cfb0056308b53dfd.tar.gz
gentoo-2-b2f5d65ce911a1f4b05dfaf6cfb0056308b53dfd.tar.bz2
gentoo-2-b2f5d65ce911a1f4b05dfaf6cfb0056308b53dfd.zip
Apply patch to handle FTP timeouts better. Bug #147054, reported by Bernd Wurst <bugzilla-gentoo at bwurst.org>. Fix behavior for scp:// URLs when /bin/sh is in fact bash. Bug #151938, reported by Steve Haeck <gentoo_steve at shic.co.uk>.
(Portage version: 2.1.2_pre2-r8)
Diffstat (limited to 'app-backup/duplicity')
-rw-r--r--app-backup/duplicity/ChangeLog11
-rw-r--r--app-backup/duplicity/duplicity-0.4.2-r1.ebuild49
-rw-r--r--app-backup/duplicity/files/0.4.2-ftp-retry.patch278
-rw-r--r--app-backup/duplicity/files/digest-duplicity-0.4.2-r13
4 files changed, 340 insertions, 1 deletions
diff --git a/app-backup/duplicity/ChangeLog b/app-backup/duplicity/ChangeLog
index 56c8dedef62f..811bffcb20dd 100644
--- a/app-backup/duplicity/ChangeLog
+++ b/app-backup/duplicity/ChangeLog
@@ -1,6 +1,15 @@
# ChangeLog for app-backup/duplicity
# Copyright 2002-2006 Gentoo Foundation; Distributed under the GPL v2
-# $Header: /var/cvsroot/gentoo-x86/app-backup/duplicity/ChangeLog,v 1.8 2006/04/30 16:06:59 dertobi123 Exp $
+# $Header: /var/cvsroot/gentoo-x86/app-backup/duplicity/ChangeLog,v 1.9 2006/10/19 17:17:40 ticho Exp $
+
+*duplicity-0.4.2-r1 (19 Oct 2006)
+
+ 19 Oct 2006; <ticho@gentoo.org> +files/0.4.2-ftp-retry.patch,
+ +duplicity-0.4.2-r1.ebuild:
+ Apply patch to handle FTP timeouts better. Bug #147054, reported by Bernd
+ Wurst <bugzilla-gentoo at bwurst.org>. Fix behavior for scp:// URLs when
+ /bin/sh is in fact bash. Bug #151938, reported by Steve Haeck <gentoo_steve
+ at shic.co.uk>.
30 Apr 2006; Tobias Scherbaum <dertobi123@gentoo.org>
duplicity-0.4.2.ebuild:
diff --git a/app-backup/duplicity/duplicity-0.4.2-r1.ebuild b/app-backup/duplicity/duplicity-0.4.2-r1.ebuild
new file mode 100644
index 000000000000..bcf307af1560
--- /dev/null
+++ b/app-backup/duplicity/duplicity-0.4.2-r1.ebuild
@@ -0,0 +1,49 @@
+# Copyright 1999-2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/app-backup/duplicity/duplicity-0.4.2-r1.ebuild,v 1.1 2006/10/19 17:17:40 ticho Exp $
+
+inherit distutils
+
+IUSE=""
+DESCRIPTION="duplicity is a secure backup system using gnupg to encrypt data"
+HOMEPAGE="http://www.nongnu.org/duplicity/"
+SRC_URI="http://savannah.nongnu.org/download/${PN}/${P}.tar.gz"
+
+LICENSE="GPL-2"
+SLOT="0"
+KEYWORDS="~ppc ~x86"
+
+DEPEND="virtual/libc
+ >=dev-lang/python-2.3
+ >=net-libs/librsync-0.9.6"
+RDEPEND="${DEPEND}
+ app-crypt/gnupg"
+
+src_unpack() {
+ unpack ${A}
+ cd ${S}
+
+ # Fix crash on FTP timeout, bug #147054.
+ epatch "${FILESDIR}"/${PV}-ftp-retry.patch
+
+ # Fix behavior for scp:// URL when /bin/sh is bash, bug #151938.
+ sed -i -e "s:echo -e:printf:" src/backends.py
+}
+
+src_compile() {
+ distutils_src_compile
+}
+
+src_install() {
+ python setup.py install --prefix=${D}/usr
+}
+
+pkg_postinst() {
+ python_version
+ python_mod_optimize /usr/lib/python${PYVER}/site-packages/duplicity
+}
+
+pkg_postrm() {
+ python_version
+ python_mod_cleanup
+}
diff --git a/app-backup/duplicity/files/0.4.2-ftp-retry.patch b/app-backup/duplicity/files/0.4.2-ftp-retry.patch
new file mode 100644
index 000000000000..c0a1fbe321a4
--- /dev/null
+++ b/app-backup/duplicity/files/0.4.2-ftp-retry.patch
@@ -0,0 +1,278 @@
+--- src/backends.py 2006-02-03 04:44:31.000000000 +0100
++++ src/backends.py.new 2006-10-19 18:41:24.000000000 +0200
+@@ -18,8 +18,12 @@
+
+ """Provides functions and classes for getting/sending files to destination"""
+
+-import os, types, ftplib, tempfile
++import os, types, ftplib, tempfile, time, sys
+ import log, path, dup_temp, file_naming
++import socket
++
++# TODO: move into globals?
++socket.setdefaulttimeout(10)
+
+ class BackendException(Exception): pass
+ class ParsingException(Exception): pass
+@@ -110,8 +114,6 @@
+ and delete methods.
+
+ """
+- def init(self, parsed_url): pass
+-
+ def put(self, source_path, remote_filename = None):
+ """Transfer source_path (Path object) to remote_filename (string)
+
+@@ -126,7 +128,7 @@
+ """Retrieve remote_filename and place in local_path"""
+ local_path.setdata()
+ pass
+-
++
+ def list(self):
+ """Return list of filenames (strings) present in backend"""
+ pass
+@@ -285,7 +287,7 @@
+ local_path.setdata()
+ if not local_path.exists():
+ raise BackendException("File %s not found" % local_path.name)
+-
++
+ def list(self):
+ """List files available for scp
+
+@@ -318,21 +320,72 @@
+
+ class ftpBackend(Backend):
+ """Connect to remote store using File Transfer Protocol"""
++ RETRY_SLEEP = 10 # time in seconds before reconnecting on errors (gets multiplied with the try counter)
++ RETRIES = 15 # number of retries
++
+ def __init__(self, parsed_url):
+ """Create a new ftp backend object, log in to host"""
++ self.parsed_url = parsed_url
++ self.connect()
++
++ def connect(self):
++ """Connect to self.parsed_url"""
+ self.ftp = ftplib.FTP()
+- if parsed_url.port is None: self.error_wrap('connect', parsed_url.host)
+- else: self.error_wrap('connect', parsed_url.host, parsed_url.port)
++ self.is_connected = False
++ if self.parsed_url.port is None:
++ self.error_wrap('connect', self.parsed_url.host)
++ else: self.error_wrap('connect', self.parsed_url.host,
++ self.parsed_url.port)
++ self.is_connected = True
+
+- if parsed_url.user is not None:
+- self.error_wrap('login', parsed_url.user, self.get_password())
++ if self.parsed_url.user is not None:
++ self.error_wrap('login', self.parsed_url.user, self.get_password())
+ else: self.error_wrap('login')
+- self.ftp.cwd(parsed_url.path)
++ self.ftp.cwd(self.parsed_url.path)
+
+ def error_wrap(self, command, *args):
+ """Run self.ftp.command(*args), but raise BackendException on error"""
+- try: return ftplib.FTP.__dict__[command](self.ftp, *args)
+- except ftplib.all_errors, e: raise BackendException(e)
++
++ # Log FTP command:
++ if command is 'login':
++ if log.verbosity > 8:
++ # Log full args at level 9:
++ log.Log("FTP: %s %s" % (command,args), 9)
++ else:
++ # replace password with stars:
++ log_args = list(args)
++ log_args[1] = '*' * len(log_args[1])
++ log.Log("FTP: %s %s" % (command,log_args), 5)
++ else:
++ log.Log("FTP: %s %s" % (command,args), 5)
++
++ # Execute:
++ tries = 0
++ while( True ):
++ tries = tries+1
++ try:
++ return ftplib.FTP.__dict__[command](self.ftp, *args)
++ except ftplib.all_errors, e:
++ if "450" in str(e) and command == 'nlst':
++ # 450 on list isn't an error, but indicates an empty dir
++ return []
++
++ if tries > self.RETRIES:
++ # Give up:
++ log.FatalError("Catched exception %s%s (%d exceptions in total), giving up.." % (sys.exc_info()[0],sys.exc_info()[1],tries,))
++ raise BackendException(e)
++
++ # Sleep and retry (after trying to reconnect, if possible):
++ sleep_time = self.RETRY_SLEEP * tries;
++ log.Warn("Catched exception %s%s (#%d), sleeping %ds before retry.." % (sys.exc_info()[0],sys.exc_info()[1],tries,sleep_time,))
++ time.sleep(sleep_time)
++ try:
++ if self.is_connected:
++ self.connect()
++ return ftplib.FTP.__dict__[command](self.ftp, *args)
++ except ftplib.all_errors, e:
++ continue
++ else: break
+
+ def get_password(self):
+ """Get ftp password using environment if possible"""
+@@ -364,7 +417,8 @@
+ # Some ftp servers raise error 450 if the directory is empty
+ try: return self.error_wrap('nlst')
+ except BackendException, e:
+- if "450" in str(e): return []
++ if "450" in str(e) or "500" in str(e) or "550" in str(e):
++ return []
+ raise
+
+ def delete(self, filename_list):
+@@ -375,7 +429,10 @@
+
+ def close(self):
+ """Shut down connection"""
+- self.error_wrap('quit')
++ try: self.error_wrap('quit')
++ except BackendException, e:
++ if "104" in str(e): return
++ raise
+
+
+ class rsyncBackend(Backend):
+@@ -405,7 +462,7 @@
+ local_path.setdata()
+ if not local_path.exists():
+ raise BackendException("File %s not found" % local_path.name)
+-
++
+ def list(self):
+ """List files"""
+ def split (str):
+@@ -447,11 +504,121 @@
+ for file in to_delete:
+ os.unlink (file)
+ os.rmdir (dir)
+-
++
++
++class BitBucketBackend(Backend):
++ """Backend for accessing Amazon S3 using the bitbucket.py module.
++
++ This backend supports access to Amazon S3 (http://aws.amazon.com/s3)
++ using a mix of environment variables and URL's. The access key and
++ secret key are taken from the environment variables S3KEY and S3SECRET
++ and the bucket name from the url. For example (in BASH):
++
++ $ export S3KEY='44CF9590006BF252F707'
++ $ export S3SECRET='OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV'
++ $ duplicity /home/me s3+http://bucket_name
++
++ Note: / is disallowed in bucket names in case prefix support is implemented
++ in future.
++
++ TODO:
++ - support bucket prefixes with url's like s3+http://bucket_name/prefix
++ - bitbucket and amazon s3 are currently not very robust. We provide a
++ simplistic way of trying to re-connect and re-try an operation when
++ it fails. This is just a band-aid and should be removed if bitbucket
++ becomes more robust.
++ - Logging of actions.
++ - Better error messages for failures.
++ """
++
++ def __init__(self, parsed_url):
++ import bitbucket
++ self.module = bitbucket
++ self.bucket_name = parsed_url.suffix
++ if '/' in self.bucket_name:
++ raise NotImplementedError("/ disallowed in bucket names and "
++ "bucket prefixes not supported.")
++ self.access_key = os.environ["S3KEY"]
++ self.secret_key = os.environ["S3SECRET"]
++ self._connect()
++
++ def _connect(self):
++ self.connection = self.module.connect(access_key=self.access_key,
++ secret_key=self.secret_key)
++ self.bucket = self.connection.get_bucket(self.bucket_name)
++ # populate the bitbucket cache we do it here to be sure that
++ # even on re-connect we have a list of all keys on the server
++ self.bucket.fetch_all_keys()
++
++ def _logException(self, message=None):
++ # Simply dump the exception onto stderr since formatting it
++ # ourselves looks dangerous.
++ if message is not None:
++ sys.stderr.write(message)
++ sys.excepthook(*sys.exc_info())
++
++ def put(self, source_path, remote_filename = None):
++ """Transfer source_path (Path object) to remote_filename (string)
++
++ If remote_filename is None, get the filename from the last
++ path component of pathname.
++
++ """
++ if not remote_filename:
++ remote_filename = source_path.get_filename()
++ bits = self.module.Bits(filename=source_path.name)
++ try:
++ self.bucket[remote_filename] = bits
++ except:
++ self._logException("Error sending file %s, attempting to "
++ "re-connect.\n Got this Traceback:\n"
++ % remote_filename)
++ self._connect()
++ self.bucket[remote_filename] = bits
++
++ def get(self, remote_filename, local_path):
++ """Retrieve remote_filename and place in local_path"""
++ local_path.setdata()
++ try:
++ bits = self.bucket[remote_filename]
++ bits.to_file(local_path.name)
++ except:
++ self._logException("Error getting file %s, attempting to "
++ "re-connect.\n Got this Traceback:\n"
++ % remote_filename)
++ self._connect()
++ bits = self.bucket[remote_filename]
++ bits.to_file(local_path.name)
++ local_path.setdata()
++
++ def list(self):
++ """Return list of filenames (strings) present in backend"""
++ try:
++ keys = self.bucket.keys()
++ except:
++ self._logException("Error getting bucket keys, attempting to "
++ "re-connect.\n Got this Traceback:\n")
++ self._connect()
++ keys = self.bucket.keys()
++ return keys
++
++ def delete(self, filename_list):
++ """Delete each filename in filename_list, in order if possible"""
++ for file in filename_list:
++ try:
++ del self.bucket[file]
++ except:
++ self._logException("Error deleting file %s, attempting to "
++ "re-connect.\n Got this Traceback:\n"
++ % file)
++ self._connect()
++ del self.bucket[file]
++
+ # Dictionary relating protocol strings to backend_object classes.
+ protocol_class_dict = {"scp": scpBackend,
+ "ssh": scpBackend,
+ "file": LocalBackend,
+ "ftp": ftpBackend,
+- "rsync": rsyncBackend}
++ "rsync": rsyncBackend,
++ "s3+http": BitBucketBackend}
+
diff --git a/app-backup/duplicity/files/digest-duplicity-0.4.2-r1 b/app-backup/duplicity/files/digest-duplicity-0.4.2-r1
new file mode 100644
index 000000000000..36319b479175
--- /dev/null
+++ b/app-backup/duplicity/files/digest-duplicity-0.4.2-r1
@@ -0,0 +1,3 @@
+MD5 a9fd4094f23bb36c82cc1dc2816a5b7d duplicity-0.4.2.tar.gz 103183
+RMD160 c6c86f397e43b7d5f63965d69f3328daa601d00b duplicity-0.4.2.tar.gz 103183
+SHA256 5fdf8aeb32bb4c09e3c9d5c4150245a71d757d31d9bb341524de75e06421e176 duplicity-0.4.2.tar.gz 103183