diff -Nru duplicity-0.6.22/debian/changelog duplicity-0.6.22/debian/changelog --- duplicity-0.6.22/debian/changelog 2013-11-18 23:04:43.000000000 +0100 +++ duplicity-0.6.22/debian/changelog 2014-01-24 14:37:39.000000000 +0100 @@ -1,3 +1,17 @@ +duplicity (0.6.22-1ubuntu4) trusty; urgency=low + + * debian/patches/06-lp1266763-add-concurrency-locking + - Implement locking mechanism to avoid concurrent execution under the same + cache directory. This functionality adds a dependency to python-lockfile + Fixes LP: #1266763 + + * debian/patches/05-lp1266753-exception-if-no-s3 + - Add exception handling in the case where no S3 connection is + available instead of silently deleting the local cache. + Fixes LP: #1266753 + + -- Louis Bouchard Fri, 24 Jan 2014 14:02:09 +0100 + duplicity (0.6.22-1ubuntu3) trusty; urgency=low * debian/patches/04-dont-skip-first-chunk-on-restart.patch: diff -Nru duplicity-0.6.22/debian/control duplicity-0.6.22/debian/control --- duplicity-0.6.22/debian/control 2013-10-23 15:34:58.000000000 +0200 +++ duplicity-0.6.22/debian/control 2014-02-19 14:46:08.000000000 +0100 @@ -3,7 +3,7 @@ Priority: optional Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Alexander Zangerl -Build-Depends: debhelper (>= 8.0.0), librsync-dev (>=0.9.6), python-dev (>= 2.6.6-3), rdiff, gnupg, python-mock +Build-Depends: debhelper (>= 8.0.0), librsync-dev (>=0.9.6), python-dev (>= 2.6.6-3), rdiff, gnupg, python-mock, python-lockfile Standards-Version: 3.9.4 XS-Testsuite: autopkgtest X-Python-Version: >= 2.5 @@ -11,8 +11,9 @@ Package: duplicity Architecture: any Homepage: http://duplicity.nongnu.org/ -Depends: ${shlibs:Depends}, ${python:Depends}, ${misc:Depends} +Depends: ${shlibs:Depends}, ${python:Depends}, ${misc:Depends}, python-lockfile Suggests: rsync, python-paramiko, python-urllib3, python-oauthlib, python-boto, ncftp, python-pexpect (>=2.3-1), python-cloudfiles, lftp, python-gdata, tahoe-lafs +Breaks: deja-dup (<< 29.5 ) Description: encrypted bandwidth-efficient backup Duplicity backs directories by producing encrypted tar-format volumes and uploading them to a remote or local file server. Because duplicity diff -Nru duplicity-0.6.22/debian/patches/05-lp1266753-exception-if-no-s3 duplicity-0.6.22/debian/patches/05-lp1266753-exception-if-no-s3 --- duplicity-0.6.22/debian/patches/05-lp1266753-exception-if-no-s3 1970-01-01 01:00:00.000000000 +0100 +++ duplicity-0.6.22/debian/patches/05-lp1266753-exception-if-no-s3 2014-01-24 14:01:29.000000000 +0100 @@ -0,0 +1,29 @@ +Description: Avoid silent deletion of local cache + Fix for LP: #1266753 - Avoid silent deletion of local cache if +S3 connection is not available +Author: Kurt Huwig +Bug-Ubuntu: http://bugs.launchpad.net/bugs/1266753 +Reviewed-by: Louis Bouchard +--- +--- a/duplicity/backends/_boto_multi.py ++++ b/duplicity/backends/_boto_multi.py +@@ -296,7 +296,7 @@ + + def list(self): + if not self.bucket: +- return [] ++ raise BackendException("No connection to backend") + + for n in range(1, globals.num_retries+1): + if n > 1: +--- a/duplicity/backends/_boto_single.py ++++ b/duplicity/backends/_boto_single.py +@@ -266,7 +266,7 @@ + + def list(self): + if not self.bucket: +- return [] ++ raise BackendException("No connection to backend") + + for n in range(1, globals.num_retries+1): + if n > 1: diff -Nru duplicity-0.6.22/debian/patches/06-lp1266763-add-concurrency-locking duplicity-0.6.22/debian/patches/06-lp1266763-add-concurrency-locking --- duplicity-0.6.22/debian/patches/06-lp1266763-add-concurrency-locking 1970-01-01 01:00:00.000000000 +0100 +++ duplicity-0.6.22/debian/patches/06-lp1266763-add-concurrency-locking 2014-01-24 14:01:17.000000000 +0100 @@ -0,0 +1,151 @@ +Description: Add the locking mechanism to prevent concurrent execution + Also add --allow-concurrency option to enable concurrency if required +Author: Louis Bouchard +Bug-Ubuntu: http://bugs.launchpad.net/bugs/1266763 +--- +--- a/bin/duplicity ++++ b/bin/duplicity +@@ -43,6 +43,8 @@ + import gettext + gettext.install('duplicity', codeset='utf8') + ++from lockfile import FileLock ++ + from duplicity import log + log.setup() + +@@ -1318,6 +1320,25 @@ + # determine what action we're performing and process command line + action = commandline.ProcessCommandLine(sys.argv[1:]) + ++ globals.lockfile = FileLock(os.path.join(globals.archive_dir.name, "lockfile")) ++ if globals.lockfile.is_locked(): ++ log.FatalError("Another instance is already running with this archive directory\n" ++ "If you are sure that this is the only instance running you may delete\n" ++ "the following lockfile and run the command again :\n" ++ "\t%s" % os.path.join(globals.archive_dir.name, "lockfile.lock" ) ++ , log.ErrorCode.user_error) ++ log.shutdown() ++ sys.exit(2) ++ ++ globals.lockfile.acquire(timeout = 0) ++ ++ try: ++ do_backup(action) ++ ++ finally: ++ util.release_lockfile() ++ ++def do_backup(action): + # The following is for starting remote debugging in Eclipse with Pydev. + # Adjust the path to your location and version of Eclipse and Pydev. + if globals.pydevd: +@@ -1467,7 +1488,6 @@ + finally: + tempdir.default().cleanup() + +- + if __name__ == "__main__": + try: + with_tempdir(main) +@@ -1479,16 +1499,19 @@ + # goes here, if needed. + except SystemExit, e: + # No traceback, just get out ++ util.release_lockfile() + sys.exit(e) + + except KeyboardInterrupt, e: + # No traceback, just get out + log.Info(_("INT intercepted...exiting.")) ++ util.release_lockfile() + sys.exit(4) + + except gpg.GPGError, e: + # For gpg errors, don't show an ugly stack trace by + # default. But do with sufficient verbosity. ++ util.release_lockfile() + log.Info(_("GPG error detail: %s") + % (''.join(traceback.format_exception(*sys.exc_info())))) + log.FatalError("%s: %s" % (e.__class__.__name__, e.args[0]), +@@ -1496,6 +1519,7 @@ + e.__class__.__name__) + + except duplicity.errors.UserError, e: ++ util.release_lockfile() + # For user errors, don't show an ugly stack trace by + # default. But do with sufficient verbosity. + log.Info(_("User error detail: %s") +@@ -1505,6 +1529,7 @@ + e.__class__.__name__) + + except duplicity.errors.BackendException, e: ++ util.release_lockfile() + # For backend errors, don't show an ugly stack trace by + # default. But do with sufficient verbosity. + log.Info(_("Backend error detail: %s") +@@ -1514,6 +1539,7 @@ + e.__class__.__name__) + + except Exception, e: ++ util.release_lockfile() + if "Forced assertion for testing" in str(e): + log.FatalError("%s: %s" % (e.__class__.__name__, str(e)), + log.ErrorCode.exception, +--- a/duplicity/collections.py ++++ b/duplicity/collections.py +@@ -24,9 +24,11 @@ + import types + import gettext + ++ + from duplicity import log + from duplicity import file_naming + from duplicity import path ++from duplicity import util + from duplicity import dup_time + from duplicity import globals + from duplicity import manifest +@@ -157,6 +159,7 @@ + except Exception: + log.Debug("BackupSet.delete: missing %s" % lfn) + pass ++ util.release_lockfile() + + def __str__(self): + """ +--- a/duplicity/globals.py ++++ b/duplicity/globals.py +@@ -93,6 +93,9 @@ + # windows machines. + time_separator = ":" + ++# Global lockfile used to manage concurrency ++lockfile = None ++ + # If this is true, only warn and don't raise fatal error when backup + # source directory doesn't match previous backup source directory. + allow_source_mismatch = None +--- a/duplicity/util.py ++++ b/duplicity/util.py +@@ -28,6 +28,8 @@ + import string + import traceback + ++from lockfile import FileLock, UnlockError ++ + from duplicity import tarfile + + import duplicity.globals as globals +@@ -119,3 +121,11 @@ + pass + else: + raise ++ ++def release_lockfile(): ++ if globals.lockfile and globals.lockfile.is_locked(): ++ log.Debug(_("Releasing lockfile %s") % globals.lockfile ) ++ try: ++ globals.lockfile.release() ++ except UnlockError: ++ pass diff -Nru duplicity-0.6.22/debian/patches/series duplicity-0.6.22/debian/patches/series --- duplicity-0.6.22/debian/patches/series 2013-11-18 22:51:40.000000000 +0100 +++ duplicity-0.6.22/debian/patches/series 2014-01-24 13:57:44.000000000 +0100 @@ -3,3 +3,5 @@ 02-unicode 03-ignoremissing 04-dont-skip-first-chunk-on-restart.patch +05-lp1266753-exception-if-no-s3 +06-lp1266763-add-concurrency-locking