Merge lp:~yajo/duplicity/duplicity into lp:~duplicity-team/duplicity/0.8-series

Proposed by Yajo
Status: Superseded
Proposed branch: lp:~yajo/duplicity/duplicity
Merge into: lp:~duplicity-team/duplicity/0.8-series
Diff against target: 55815 lines (+29724/-2223) (has conflicts)
171 files modified
CHANGELOG (+289/-53)
Changelog.GNU (+281/-164)
README (+5/-0)
README-REPO (+53/-0)
README-TESTING (+0/-138)
bin/duplicity (+151/-21)
bin/duplicity.1 (+23/-144)
docs/duplicity.asyncscheduler.rst (+0/-7)
docs/duplicity.backend.rst (+0/-7)
docs/duplicity.backends.azurebackend.rst (+0/-7)
docs/duplicity.backends.b2backend.rst (+0/-7)
docs/duplicity.backends.botobackend.rst (+0/-7)
docs/duplicity.backends.cfbackend.rst (+0/-7)
docs/duplicity.backends.dpbxbackend.rst (+0/-7)
docs/duplicity.backends.gdocsbackend.rst (+0/-7)
docs/duplicity.backends.giobackend.rst (+0/-7)
docs/duplicity.backends.hsibackend.rst (+0/-7)
docs/duplicity.backends.hubicbackend.rst (+0/-7)
docs/duplicity.backends.imapbackend.rst (+0/-7)
docs/duplicity.backends.lftpbackend.rst (+0/-7)
docs/duplicity.backends.localbackend.rst (+0/-7)
docs/duplicity.backends.mediafirebackend.rst (+0/-7)
docs/duplicity.backends.megabackend.rst (+0/-7)
docs/duplicity.backends.multibackend.rst (+0/-7)
docs/duplicity.backends.ncftpbackend.rst (+0/-7)
docs/duplicity.backends.onedrivebackend.rst (+0/-7)
docs/duplicity.backends.par2backend.rst (+0/-7)
docs/duplicity.backends.pydrivebackend.rst (+0/-7)
docs/duplicity.backends.rsyncbackend.rst (+0/-7)
docs/duplicity.backends.swiftbackend.rst (+0/-7)
docs/duplicity.backends.sxbackend.rst (+0/-7)
docs/duplicity.backends.tahoebackend.rst (+0/-7)
docs/duplicity.backends.webdavbackend.rst (+0/-7)
docs/duplicity.collections.rst (+0/-7)
docs/duplicity.commandline.rst (+0/-7)
docs/duplicity.diffdir.rst (+0/-7)
docs/duplicity.errors.rst (+0/-7)
docs/duplicity.filechunkio.rst (+0/-7)
docs/duplicity.globals.rst (+0/-7)
docs/duplicity.globmatch.rst (+0/-7)
docs/duplicity.gpg.rst (+0/-7)
docs/duplicity.gpginterface.rst (+0/-7)
docs/duplicity.lazy.rst (+0/-7)
docs/duplicity.librsync.rst (+0/-7)
docs/duplicity.log.rst (+0/-7)
docs/duplicity.manifest.rst (+0/-7)
docs/duplicity.patchdir.rst (+0/-7)
docs/duplicity.path.rst (+0/-7)
docs/duplicity.progress.rst (+0/-7)
docs/duplicity.robust.rst (+0/-7)
docs/duplicity.selection.rst (+0/-7)
docs/duplicity.statistics.rst (+0/-7)
docs/duplicity.tarfile.rst (+0/-7)
docs/duplicity.tempdir.rst (+0/-7)
docs/duplicity.util.rst (+0/-7)
docs/testing.overrides.gettext.rst (+0/-7)
docs/testing.overrides.rst (+0/-17)
docs/testing.unit.rst (+0/-34)
duplicity/_librsyncmodule.c (+1/-1)
duplicity/backend.py (+30/-0)
duplicity/backends/_cf_pyrax.py (+22/-0)
duplicity/backends/acdclibackend.py.OTHER (+151/-0)
duplicity/backends/azurebackend.py (+27/-5)
duplicity/backends/b2backend.py (+103/-0)
duplicity/backends/dpbxbackend.py (+49/-0)
duplicity/backends/gdocsbackend.py (+6/-0)
duplicity/backends/giobackend.py (+16/-0)
duplicity/backends/hsibackend.py (+5/-0)
duplicity/backends/hubicbackend.py (+4/-0)
duplicity/backends/lftpbackend.py (+29/-0)
duplicity/backends/localbackend.py (+6/-0)
duplicity/backends/megabackend.py (+147/-0)
duplicity/backends/multibackend.py (+14/-14)
duplicity/backends/ncftpbackend.py (+5/-0)
duplicity/backends/onedrivebackend.py (+4/-0)
duplicity/backends/par2backend.py (+4/-0)
duplicity/backends/pydrivebackend.py (+13/-0)
duplicity/backends/rsyncbackend.py (+5/-0)
duplicity/backends/ssh_paramiko_backend.py (+5/-0)
duplicity/backends/ssh_pexpect_backend.py (+6/-0)
duplicity/backends/swiftbackend.py (+7/-3)
duplicity/backends/sxbackend.py (+4/-0)
duplicity/backends/tahoebackend.py (+6/-0)
duplicity/backends/webdavbackend.py (+27/-0)
duplicity/collections.py (+103/-27)
duplicity/commandline.py (+107/-8)
duplicity/compilec.py (+4/-0)
duplicity/diffdir.py (+10/-6)
duplicity/dup_threading.py (+7/-0)
duplicity/file_naming.py (+0/-8)
duplicity/globals.py (+21/-3)
duplicity/globmatch.py (+19/-3)
duplicity/gpg.py (+31/-0)
duplicity/gpginterface.py (+0/-1)
duplicity/lazy.py (+37/-11)
duplicity/log.py (+3/-0)
duplicity/manifest.py (+18/-4)
duplicity/patchdir.py (+15/-6)
duplicity/progress.py (+8/-0)
duplicity/robust.py (+4/-3)
duplicity/selection.py (+72/-3)
duplicity/statistics.py (+14/-8)
duplicity/tarfile.py (+1/-1)
duplicity/util.py (+20/-0)
po/bg.po (+664/-20)
po/bs.po (+747/-18)
po/ca.po (+638/-14)
po/ca@valencia.po (+638/-14)
po/cs.po (+778/-15)
po/de.po (+842/-18)
po/duplicity.pot (+872/-11)
po/el.po (+638/-14)
po/en_AU.po (+841/-27)
po/en_GB.po (+844/-27)
po/eo.po (+638/-14)
po/es.po (+813/-19)
po/fi.po (+638/-14)
po/fr.po (+789/-23)
po/gl.po (+727/-23)
po/he.po (+642/-14)
po/hu.po (+737/-22)
po/id.po (+745/-18)
po/io.po (+637/-14)
po/it.po (+760/-20)
po/ja.po (+629/-17)
po/km.po (+638/-14)
po/ms.po (+774/-24)
po/nb.po (+690/-20)
po/nl.po (+638/-14)
po/oc.po (+653/-14)
po/pl.po (+720/-24)
po/pt.po (+666/-16)
po/pt_BR.po (+759/-24)
po/ru.po (+756/-30)
po/sl.po (+776/-20)
po/sq.po (+638/-14)
po/sr.po (+640/-14)
po/sv.po (+805/-41)
po/tr.po (+664/-14)
po/ug.po (+646/-14)
po/uk.po (+764/-18)
po/zh_CN.po (+712/-12)
requirements.txt (+13/-0)
setup.py (+10/-12)
testing/__init__.py (+8/-1)
testing/functional/test_selection.py (+8/-1)
testing/gnupg/gpg-agent.conf (+0/-3)
testing/gnupg/gpg.conf (+0/-9)
testing/infrastructure/.env (+0/-28)
testing/infrastructure/build-duplicity_test.sh (+0/-21)
testing/infrastructure/check_docker_container.sh (+0/-64)
testing/infrastructure/docker-compose.yml (+0/-75)
testing/infrastructure/duplicity_test/Dockerfile (+0/-81)
testing/infrastructure/ftp_server/Dockerfile (+0/-32)
testing/infrastructure/ftp_server/pureftpd.passwd (+0/-1)
testing/infrastructure/id_rsa (+0/-27)
testing/infrastructure/id_rsa.pub (+0/-1)
testing/infrastructure/setup.sh (+0/-27)
testing/infrastructure/ssh_server/Dockerfile (+0/-65)
testing/infrastructure/teardown.sh (+0/-26)
testing/test_code.py (+27/-0)
testing/unit/test_collections.py (+43/-5)
testing/unit/test_diffdir.py (+39/-8)
testing/unit/test_dup_time.py (+8/-0)
testing/unit/test_globmatch.py (+229/-0)
testing/unit/test_gpg.py (+2/-2)
testing/unit/test_gpginterface.py (+24/-0)
testing/unit/test_lazy.py (+11/-0)
testing/unit/test_manifest.py (+23/-1)
testing/unit/test_selection.py (+55/-0)
tox.ini (+36/-1)
Text conflict in CHANGELOG
Text conflict in Changelog.GNU
Text conflict in README
Text conflict in bin/duplicity
Text conflict in bin/duplicity.1
Conflict: can't delete docs because it is not empty.  Not deleting.
Conflict because docs is not versioned, but has versioned children.  Versioned directory.
Contents conflict in docs/Makefile
Contents conflict in docs/conf.py
Contents conflict in docs/duplicity.backends.pyrax_identity.hubic.rst
Contents conflict in docs/duplicity.backends.pyrax_identity.rst
Contents conflict in docs/duplicity.backends.rst
Contents conflict in docs/duplicity.backends.ssh_paramiko_backend.rst
Contents conflict in docs/duplicity.backends.ssh_pexpect_backend.rst
Contents conflict in docs/duplicity.cached_ops.rst
Contents conflict in docs/duplicity.dup_temp.rst
Contents conflict in docs/duplicity.dup_threading.rst
Contents conflict in docs/duplicity.dup_time.rst
Contents conflict in docs/duplicity.file_naming.rst
Contents conflict in docs/duplicity.rst
Contents conflict in docs/index.rst
Contents conflict in docs/make.bat
Contents conflict in docs/testing.functional.rst
Contents conflict in docs/testing.functional.test_badupload.rst
Contents conflict in docs/testing.functional.test_cleanup.rst
Contents conflict in docs/testing.functional.test_final.rst
Contents conflict in docs/testing.functional.test_log.rst
Contents conflict in docs/testing.functional.test_rdiffdir.rst
Contents conflict in docs/testing.functional.test_restart.rst
Contents conflict in docs/testing.functional.test_selection.rst
Contents conflict in docs/testing.functional.test_verify.rst
Contents conflict in docs/testing.rst
Contents conflict in docs/testing.test_code.rst
Contents conflict in docs/testing.unit.test_backend.rst
Contents conflict in docs/testing.unit.test_backend_instance.rst
Contents conflict in docs/testing.unit.test_collections.rst
Contents conflict in docs/testing.unit.test_diffdir.rst
Contents conflict in docs/testing.unit.test_dup_temp.rst
Contents conflict in docs/testing.unit.test_dup_time.rst
Contents conflict in docs/testing.unit.test_file_naming.rst
Contents conflict in docs/testing.unit.test_globmatch.rst
Contents conflict in docs/testing.unit.test_gpg.rst
Contents conflict in docs/testing.unit.test_gpginterface.rst
Contents conflict in docs/testing.unit.test_lazy.rst
Contents conflict in docs/testing.unit.test_manifest.rst
Contents conflict in docs/testing.unit.test_patchdir.rst
Contents conflict in docs/testing.unit.test_path.rst
Contents conflict in docs/testing.unit.test_selection.rst
Contents conflict in docs/testing.unit.test_statistics.rst
Contents conflict in docs/testing.unit.test_tarfile.rst
Contents conflict in docs/testing.unit.test_tempdir.rst
Text conflict in duplicity/backend.py
Text conflict in duplicity/backends/_cf_pyrax.py
Contents conflict in duplicity/backends/acdclibackend.py
Contents conflict in duplicity/backends/adbackend.py
Text conflict in duplicity/backends/azurebackend.py
Text conflict in duplicity/backends/b2backend.py
Text conflict in duplicity/backends/dpbxbackend.py
Text conflict in duplicity/backends/gdocsbackend.py
Text conflict in duplicity/backends/giobackend.py
Text conflict in duplicity/backends/hsibackend.py
Text conflict in duplicity/backends/hubicbackend.py
Contents conflict in duplicity/backends/jottacloudbackend.py
Text conflict in duplicity/backends/lftpbackend.py
Text conflict in duplicity/backends/localbackend.py
Text conflict in duplicity/backends/megabackend.py
Text conflict in duplicity/backends/multibackend.py
Text conflict in duplicity/backends/ncftpbackend.py
Text conflict in duplicity/backends/onedrivebackend.py
Text conflict in duplicity/backends/par2backend.py
Contents conflict in duplicity/backends/pcabackend.py
Text conflict in duplicity/backends/pydrivebackend.py
Text conflict in duplicity/backends/rsyncbackend.py
Text conflict in duplicity/backends/ssh_paramiko_backend.py
Text conflict in duplicity/backends/ssh_pexpect_backend.py
Text conflict in duplicity/backends/swiftbackend.py
Text conflict in duplicity/backends/sxbackend.py
Text conflict in duplicity/backends/tahoebackend.py
Text conflict in duplicity/backends/webdavbackend.py
Text conflict in duplicity/collections.py
Text conflict in duplicity/commandline.py
Text conflict in duplicity/compilec.py
Text conflict in duplicity/diffdir.py
Text conflict in duplicity/dup_threading.py
Text conflict in duplicity/globals.py
Text conflict in duplicity/globmatch.py
Text conflict in duplicity/gpg.py
Text conflict in duplicity/lazy.py
Text conflict in duplicity/log.py
Text conflict in duplicity/manifest.py
Text conflict in duplicity/patchdir.py
Text conflict in duplicity/progress.py
Text conflict in duplicity/selection.py
Text conflict in duplicity/statistics.py
Text conflict in duplicity/util.py
Text conflict in po/bg.po
Text conflict in po/bs.po
Text conflict in po/ca.po
Text conflict in po/ca@valencia.po
Text conflict in po/cs.po
Text conflict in po/de.po
Text conflict in po/duplicity.pot
Text conflict in po/el.po
Text conflict in po/en_AU.po
Text conflict in po/en_GB.po
Text conflict in po/eo.po
Text conflict in po/es.po
Text conflict in po/fi.po
Text conflict in po/fr.po
Text conflict in po/gl.po
Text conflict in po/he.po
Text conflict in po/hu.po
Text conflict in po/id.po
Text conflict in po/io.po
Text conflict in po/it.po
Text conflict in po/ja.po
Text conflict in po/km.po
Text conflict in po/ms.po
Text conflict in po/nb.po
Text conflict in po/nl.po
Text conflict in po/oc.po
Text conflict in po/pl.po
Text conflict in po/pt.po
Text conflict in po/pt_BR.po
Text conflict in po/ru.po
Text conflict in po/sl.po
Text conflict in po/sq.po
Text conflict in po/sr.po
Text conflict in po/sv.po
Text conflict in po/tr.po
Text conflict in po/ug.po
Text conflict in po/uk.po
Text conflict in po/zh_CN.po
Conflict adding file requirements.txt.  Moved existing file to requirements.txt.moved.
Text conflict in setup.py
Text conflict in testing/__init__.py
Contents conflict in testing/functional/test_replicate.py
Text conflict in testing/functional/test_selection.py
Text conflict in testing/test_code.py
Conflict adding file testing/testfiles.tar.gz.  Moved existing file to testing/testfiles.tar.gz.moved.
Text conflict in testing/unit/test_collections.py
Text conflict in testing/unit/test_diffdir.py
Text conflict in testing/unit/test_dup_time.py
Text conflict in testing/unit/test_globmatch.py
Text conflict in testing/unit/test_gpginterface.py
Text conflict in testing/unit/test_lazy.py
Text conflict in testing/unit/test_manifest.py
Text conflict in testing/unit/test_selection.py
Text conflict in tox.ini
To merge this branch: bzr merge lp:~yajo/duplicity/duplicity
Reviewer Review Type Date Requested Status
duplicity-team Pending
Review via email: mp+366357@code.launchpad.net

Description of the change

Support partial metadata sync.

Fixes bug #1823858 by letting the user to choose partial syncing. Only the metadata for the target chain will be downloaded. If older (or newer) chains are encrypted with a different passphrase, the user will be able to restore to a given time by supplying only the passphrase for the chain selected by the `--restore-time` option when using this new option.

A side effect is that using this flag reduces dramatically the sync time when moving files from one to another location, in cases where big amounts of chains are found.

To post a comment you must log in.
lp:~yajo/duplicity/duplicity updated
1373. By Yajo

Support partial metadata sync.

Fixes bug #1823858 by letting the user to choose partial syncing. Only the metadata for the target chain will be downloaded. If older (or newer) chains are encrypted with a different passphrase, the user will be able to restore to a given time by supplying only the passphrase for the chain selected by the `--restore-time` option when using this new option.

A side effect is that using this flag reduces dramatically the sync time when moving files from one to another location, in cases where big amounts of chains are found.

Unmerged revisions

1373. By Yajo

Support partial metadata sync.

Fixes bug #1823858 by letting the user to choose partial syncing. Only the metadata for the target chain will be downloaded. If older (or newer) chains are encrypted with a different passphrase, the user will be able to restore to a given time by supplying only the passphrase for the chain selected by the `--restore-time` option when using this new option.

A side effect is that using this flag reduces dramatically the sync time when moving files from one to another location, in cases where big amounts of chains are found.

1372. By Kenneth Loafman

* Merged in lp:~mterry/duplicity/pydrive-root-0.7
  - Just a tiny fix to clean up the temporary file we create to find the root ID.
    It's a little surprising for the user if they wind up with this file called
    "i_am_in_root" that they don't know where it came from. Almost sounds like
    they were hacked.

1371. By Kenneth Loafman

Bug #1813214 was marked fixed in 0.7.13. There were still a couple of copy.com references remaining in the docs and web. Got those nuked, finally.

1370. By Kenneth Loafman

Fix some punctuation.

1369. By Kenneth Loafman

Whoops, missed 'global paramiko' in __init__.

1368. By Kenneth Loafman

* Fixed bug #1798206 and bug #1798504
  * Made paramiko a global with import during __init__ so it would
    not be loaded unless needed.

1367. By Kenneth Loafman

* Prep for 0.7.18.2

1366. By Kenneth Loafman

* Fixed bug #1788558 again
  - If we get None for size skip check.

1365. By Kenneth Loafman

* Fixed bug #1788558 again
  - If we get None for size skip check.

1364. By Kenneth Loafman <email address hidden>>

* Catch up on red tape.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CHANGELOG'
2--- CHANGELOG 2019-03-16 23:23:40 +0000
3+++ CHANGELOG 2019-04-22 12:43:18 +0000
4@@ -1,3 +1,4 @@
5+<<<<<<< TREE
6 New in v0.8.00 (2019/??/??)
7 ---------------------------
8 * Merged in lp:~aaron-whitehouse/duplicity/remove-python26
9@@ -128,46 +129,183 @@
10 - change util.uexc() back to bare uexc()
11 * Fixed bug #1668750 - Don't mask backend errors
12 - added exception prints to module import errors
13+=======
14+New in v0.7.19 (2019/??/??)
15+-----------------------------
16+* Fixed bug #1798206 and bug #1798504
17+ - Made paramiko a global with import during __init__ so it would
18+ not be loaded unless needed.
19+* Merged in lp:~mterry/duplicity/pydrive-root-0.7
20+ - Just a tiny fix to clean up the temporary file we create to find the root ID.
21+ It's a little surprising for the user if they wind up with this file called
22+ "i_am_in_root" that they don't know where it came from. Almost sounds like
23+ they were hacked.
24+
25+
26+New in v0.7.18.2 (2018/10/17)
27+-----------------------------
28+* Fixed bug #1788558 again
29+ - If we get None for size skip check.
30+
31+
32+New in v0.7.18.1 (2018/08/27)
33+-----------------------------
34+* Fixed bug #1788558
35+ - Treat None as zero when printing log.
36+* Revert fix for bug #1788599.
37+ - Was causing problems with directory names
38+
39+
40+New in v0.7.18 (2018/08/21)
41+---------------------------
42+* Fixed bug #1756550 Online html man page is showing a 0 byte file
43+* Partial fix of bug #1734144 with patch from Joris van Eijden
44+ - Note: this is really just a partial fix for now, since it only covers
45+ the case where the local size does not yet match the remote size. A
46+ case where -1 is the returned length is not fixed.
47+ - Number of retries is now same as globals.num_retries.
48+ - Added standoff delay of 0.5 sec per attempt.
49+* Fixed bug #1764432 with patch from Robke Geenen
50+ - Just join the parts together.
51+* Fixed bug #1717935 with suggestion from strainu
52+ - Use urllib.quote_plus() to properly quote pathnames passed via URL
53+* Fixed bug #1780617 Test fail when GnuPG >= 2.2.8
54+ - Relevant change in GnuPG 2.2.8: https://dev.gnupg.org/T3981
55+ - Added '--ignore-mdc-error' to all gpg calls made.
56+* Fixed bug #1785520 with patch from Chris Hunt
57+ - Fix for B2 version 1.3.4 just released
58+* Fix a 2to3 error in ssh_paramiko_backend.py
59+
60+
61+New in v0.7.17 (2018/02/26)
62+---------------------------
63+* Removed changes made in bug #1044715 Provide a file history feature
64+ - Changes required too much memory to carry in the manifest
65+ - The option --file-changed in collection-status is now invalid
66+ - This will close bugs: #1730451, #896728, #1526557, #1550176
67+ - Starting a full backup will be needed to fully utilize this fix
68+* Fix update of Launchpad Translations. Translations were not being picked
69+ up on a daily basis and we got several months behind.
70+
71+
72+New in v0.7.16 (2018/01/12)
73+---------------------------
74+* Fixed bug #1733057 AttributeError: 'GPGError' object has no attribute 'decode'
75+ - Replaced call to util.ufn() with call to util.uexc(). Stupid typo!
76+* More fixes for Unicode handling
77+ - Default to 'utf-8' if sys.getfilesystemencoding() returns 'ascii' or None
78+ - Fixed bug #1386373 with suggestion from Eugene Morozov
79+* Patched in lp:~crosser/duplicity/fix-oauth-flow
80+ - Fixed bug #1638236 "BackendException with oauth2client 4.0.0"
81+* Patched in lp:~crosser/duplicity/dpbx-fix-file-listing
82+ - Fixed bug #1639664 "Dropbox support needs to be updated for Dropbox SDK v7.1"
83+* Patched in lp:~crosser/duplicity/fix-small-file-upload
84+ - Fixed small file upload changes made in Dropbox SDK v7.1
85+* Fix pylint error in webdavbackend.py
86+
87+
88+New in v0.7.15 (2017/11/13)
89+---------------------------
90+* Fixed bug introduced in new megabackend.py where process_commandline()
91+ takes a string not a list. Now it takes both.
92+* Updated web page for new megabackend requirements.
93+* Patched in lp:~mterry/duplicity/more-decode-issues
94+ - Here's some fixes for another couple UnicodeDecodeErrors.
95+ - The duplicity/dup_time.py fixes when a user passes a utf8 date string (or a string with bogus
96+ utf8 characters, but they have to really try to do that). This is bug 1334436.
97+ - The bin/duplicity change from str(e) to util.uexc(e) fixes bug 1324188.
98+ - The rest of the changes (util.exception_traceback and bin/duplicity changes to use it) are to
99+ make the printing of exceptions prettier. Without this, if you see a French exception, you see
100+ "accept\xe9es" instead of "acceptées".
101+ - You can test all of these changes in one simple line:
102+ $ LANGUAGE=fr duplicity remove-older-than $'accept\xffées'
103+* Fix backend.py to allow string, list, and tuple types to support megabackend.py.
104+* Fixed bug #1715650 with patch from Mattheww S
105+ - Fix to make duplicity attempt a get first, then create, a container
106+ in order to support container ACLs.
107+* Fixed bug #1714663 "Volume signed by XXXXXXXXXXXXXXXX, not XXXXXXXX"
108+ - Normalized comparison length to min length of compared keys before comparison
109+ - Avoids comparing mix of short, long, or fingerprint size keys.
110+* Merged in lp:~mterry/duplicity/rename-dep
111+ - Make rename command a dependency for LP build
112+* Fixed bug #1654756 with new b2backend.py module from Vincent Rouille
113+ - Faster (big files are uploaded in chunks)
114+ - Added upload progress reporting support
115+* Fixed bug #1448094 with patch from Wolfgang Rohdewald
116+ - Don't log incremental deletes for chains that have no incrementals
117+* Fixed bug #1724144 "--gpg-options unused with some commands"
118+ - Add --gpg-options to get version run command
119+* Fixed bug #1720159 - Cannot allocate memory with large manifest file since 0.7.03
120+ - filelist is not read if --file-changed option in collection-status not present
121+ - This will keep memory usage lower in non collection-status operations
122+* Fixed bug #1723890 with patch from Killian Lackhove
123+ - Fixes error handling in pydrivebackend.py
124+* Fixed bug #1730902 GPG Error Handling
125+ - use util.ufn() not str() to handle encoding
126+
127+
128+New in v0.7.14 (2017/08/31)
129+---------------------------
130+* Merged in lp:~dawgfoto/duplicity/skip_sync_collection_status
131+ - collection-status should not sync metadata
132+ - up-to-date local metadata is not needed as collection-status is
133+ generated from remote file list
134+ - syncing metadata might require to download several GBs
135+* Fixed slowness in 'collection-status' by basing the status on the
136+ remote system only. The local cache is treated as empty.
137+* Fixed encrypted remote manifest handling to merely put out a non-fatal
138+ error message and continue if the private key is not available.
139+* Patched in lp:~mterry/duplicity/giobackend-display-name
140+ - giobackend: handle a wider variety of gio backends by making less assumptions;
141+ in particular, this fixes the google-drive: backend
142+* Fixed bug #1709047 with suggestion from Gary Hasson
143+ - fixed so default was to use original filename
144+* Fixed PEP8 errors in bin/duplicity
145+* Merged in lp:~mterry/duplicity/gio_child_for_display_name_0.7
146+ - gio: be slightly more correct and get child GFiles based on display name
147+* Fixed bug #1711905 with suggestion from Schneider
148+ - log.Warn was invoked with log.warn in webdavbackend.py
149+* Merged in lp:~mterry/duplicity/gpg-tag-versions
150+ - Support gpg versions numbers that have tags on them.
151+ - This can happen if you build gpg from git trunk (e.g. 2.1.15-beta20). Or if you run
152+ against the freedesktop flatpak runtime (e.g. 2.1.14-unknown).
153+* Fixed bug #1394386 with new module megabackend.py from Tomas Vondra
154+ - uses megatools from https://megatools.megous.com/ instead of mega.py library
155+ which has been deprecated
156+ - fixed copyright and PEP8 issues
157+ - replaced subprocess.call() with self.subprocess_popen() to standardize
158+* Fixed bug #1713640 with patch from Aleksandar Ivanisevic
159+ - replace 2.7 syntax with 2.6 equivalent
160+* Fixed bug #1538333 Assertion error in manifest.py: assert filecount == ...
161+ - Made sure to never pass .part files as true manifest files
162+ - Changed assert to log.Error to warn about truncated/corrupt filelist
163+ - Added unit test to make sure detection works
164+ - Note: while this condition is serious, it will not affect the basic backup and restore
165+ functions. Interactive options like --list-files-changed and --file-changed will not
166+ work correctly for this backup set, so it is advised to run a full backup as soon as
167+ possible after this error occurs.
168+* Fixed bug #1638033 Remove leading slash on --file-to-restore
169+ - code already used rstrip('/') so change to just strip('/')
170+
171+
172+New in v0.7.13.1 (2017/06/18)
173+-----------------------------
174+* Fixed problem in dist/makedist when building on Mac where AppleDouble
175+ files were being created in the tarball. See:
176+ https://superuser.com/questions/61185/why-do-i-get-files-like-foo-in-my-tarball-on-os-x
177+
178+
179+New in v0.7.13 (2017/06/12)
180+---------------------------
181+>>>>>>> MERGE-SOURCE
182 * Fixed bug #1680682 with patch supplied from Dave Allan
183 - Only specify --pinentry-mode=loopback when --use-agent is not specified
184 * Fixed man page that had 'cancel' instead of 'loopback' for pinentry mode
185 * Fixed bug #1684312 with suggestion from Wade Rossman
186 - Use shutil.copyfile instead of os.system('cp ...')
187 - Should reduce overhead of os.system() memory usage.
188-* Merged in lp:~dernils/duplicity/testing
189- - Fixed minor stuff in requirements.txt.
190- - Added a Dockerfile for testing.
191- - Minor changes to README files.
192- - Added README-TESTING with some information on testing.
193-* Merged in lp:~dernils/duplicity/documentation
194- - Minor changes to README-REPO, README-TESTING
195- - Also redo the changes to requirements.txt and Dockerfile
196-* Merged in lp:~dawgfoto/duplicity/replicate
197- - Add replicate command to replicate a backup (or backup
198- sets older than a given time) to another backend, leveraging
199- duplicity's backend and compression/encryption infrastructure.
200-* Fixed some incoming PyLint and PEP-8 errors.
201-* Merged in lp:~marix/duplicity/add-azure-arguments
202- - Using the Azure backend to store large amounts of data we found that
203- performance is sub-optimal. The changes on this branch add command line
204- parameters to fine-tune some parameters of the Azure storage library,
205- allowing to push write performance towards Azure above 1 Gb/s for large
206- back-ups. If a user does not provide the parameters the defaults of the
207- Azure storage library will continue to be used.
208-* Replace incoming non-ASCII chars in commandline.py
209-* bzr does not honor perms so fix the perms at the start of the testing and
210- avoid annoying error regarding testing/gnupg having too lenient perms
211-* Merged in lp:~dernils/duplicity/DockerfileConvenience
212- - Added a few tools to the Dockerfile that make life easier
213 * Fixed bug #1320832 with suggestion from Oskar Wycislak
214 - Use chunks instead of reading it all in swiftbackend
215-* Merged in lp:~dernils/duplicity/DockerfileConvenience
216- - Add a few files that are the beginning of further infrastructure based
217- on docker. It contains a Dockerfile for a simple ftp server (used for
218- backend testing) and a setup script that can be used to set up the
219- complete test environment.
220-* Moved Dockerfile for duplicitytest into testinfrastructure/duplicity_test
221-* Moved some things around in testing/infrastructure to clean up
222 * Fixed bug #1689632 with patch from Howard Kaye
223 - On MacOS, the tempfile.TemporaryFile call erroneously raises an
224 IOError exception saying that too many files are open. This causes
225@@ -176,17 +314,6 @@
226 - swap from lockfile to fasteners module
227 - use an fcntl() style lock for process lock of duplicity cache
228 - lockfile will now clear if duplicity is killed or crashes
229-* Merged in lp:~aaron-whitehouse/duplicity/tox_pylint_fixes
230- - Changes needed to run-tests without pylint E0401(import-error) errors
231-* Merged in lp:~xlucas/duplicity/swift-storage-policies
232- - This brings support for Swift storage policies: when using a Swift
233- backend, you can specify the policy containers should be operating on.
234- - This is similar to AWS Cloud Storage classes (ia, rrs, glacier and so on).
235-* Merged in lp:~dernils/duplicity/Dockerfile
236- - Added another backend to the docker test infrastructure, updated the setup
237- for testing and updated the documentation.
238-* Merged in lp:~dernils/duplicity/Dockerfile
239- - Now have subnet name and IP of the subnet for testing as a variable.
240 * May have finally fixed bug #1556553, "Too many open files...".
241 - Applied patch from Howard Kaye, question #631423. The fix is to dup
242 the file descriptor, and then close the file in the deallocator
243@@ -203,19 +330,13 @@
244 * Fix bug #1672540 with patch from Benoit Nadeau
245 - Rename would fail to move par files when moving across filesystems.
246 - Patch uses shutil.move() to do the rename instead.
247-* Merged in lp:~dernils/duplicity/docker-compose
248- - Test Infrastructure now utilizing docker-compose
249-* Merged in lp:~aaron-whitehouse/duplicity/08-fix-man-verify
250- - Fix description of --verify and --compare-data in the man page. Now
251- clarifies that verify compares the restored files to hashes stored at
252- backup date, while --compare-data compares restored files to files
253- in target_path.
254 * Fixed bug #1265765 with patches from Matthias Larisch and Edgar Soldin
255 - SSH Paramiko backend now uses BufferedFile implementation to enable
256 collecting the entire list of files on the backend.
257 * Copy.com is gone so remove copycombackend.py.
258 * Merged in lp:~xlucas/duplicity/swift-multibackend-bug
259 - Fix a bug when swift backend is used in a multibackend configuration.
260+<<<<<<< TREE
261 * Fixed problem in dist/makedist when building on Mac where AppleDouble
262 files were being created in the tarball. See:
263 https://superuser.com/questions/61185/why-do-i-get-files-like-foo-in-my-tarball-on-os-x
264@@ -416,6 +537,116 @@
265 * Removed last mention of copy.com from man page with help from edso.
266 * Fix bug #1811114 with revised onedrivebackend.py from David Martin
267 - Adapt to new Microsoft Graph API
268+=======
269+* Merged in lp:~duplicity-team/duplicity/po-updates
270+
271+
272+New in v0.7.12 (2017/03/21)
273+---------------------------
274+* Fixed bug #1623342 with patch supplied by Daniel Jakots
275+ - Failing test on OpenBSD because tar/gtar not found
276+* Fixed bug #1654220 with patch supplied by Kenneth Newwood
277+ - Duplicity fails on MacOS because GPG version parsing fails
278+* Fixed bug #1655268 "--gpg-binary option not working"
279+ - If gpg binary is specified rebuild gpg profile using new binary location
280+* Fixed bug #1658283 "Duplicity 0.7.11 broken with GnuPG 2.0"
281+ - Made gpg version check more robust than just major version
282+ - Now use --pinentry-mode=loopback on gpg 2.1 and greater
283+ - Removed check for non-Linux systems, a false problem
284+* Merged in lp:~matthew-t-bentley/duplicity/duplicity
285+ - Sets a user agent. Backblaze asked for this in case there are errors that originate
286+ from the Duplicity B2 backend
287+ - Only retrieves a new upload URL when the current one expires, to bring it in line
288+ with their best practices for integrations: https://www.backblaze.com/b2/docs/integration_checklist.html
289+* Add detail about import exceptions in onedrivebackend.py
290+* Fixed bug #1657916 with patch supplied by Daniel Harvey
291+ - B2 provider cannot handle two backups in the same bucket
292+* Fixed bug #1603704 with patch supplied by Maciej Bliziński
293+ - Crash with UnicodeEncodeError
294+* Some fixes to gpg.py to handle gpg1 & gpg2 & gpg2.1 commandline issues
295+ - --gpg-agent is optional on gpg1, but on gpg2 it is used automatically
296+ - --pinentry-mode is not a valid opt until gpg2.1, so condition on that
297+* Fixed bug #1367675 - IMAP Backend does not work with Yahoo server
298+ - added the split() as needed in 'nums=list[0].strip().split(" ")'
299+ - the other fixes mentioned in the bug report comments were already done
300+* Fixed bug #1671852 - Code regression caused by revision 1108
301+ - change util.uexc() back to bare uexc()
302+* Fixed bug #1668750 - Don't mask backend errors
303+ - added exception prints to module import errors
304+
305+
306+New in v0.7.11 (2016/12/31)
307+---------------------------
308+* Fixed bugs #815510 and #1615480
309+ - Changed default --volsize to 200MB
310+* Merged in lp:~mstoll-de/duplicity/duplicity
311+ - Backblaze announced a new domain for the b2 api
312+* Merged in lp:~aaron-whitehouse/duplicity/bug_1620085_exclude-if-present-locked-folder
313+ - Fixes Bug #1620085: --exclude-if-present gives OSError looking for tag in locked folders
314+* Fixed bug #1623342 with patch from Daniel Jakots
315+ - failing test on OpenBSD because tar/gtar not found
316+* Merged in lp:~mwilck/duplicity/duplicity
317+ - GPG: enable truly non-interactive operation with gpg2
318+ - This patch fixes the IMO unexpected behavior that, when using GnuPG2, a pass phrase dialog always pops up for
319+ saving backups. This is particularly annoying when trying to do unattended / fully automatic backups.
320+* Fixed bug #1621194 with code from Tornhoof
321+ - Do backup to google drive working without a service account
322+* Fixed bug #1642098 - does not create PAR2 archives when '--par2-options' is used
323+ - Missing space between par2-options plus default options
324+* Fix bug using 40-char sign keys, from Richard McGraw on mail list
325+ - Remove truncation of argument and adjust comments
326+* Merged in lp:~dernils/duplicity/robust-dropbox-backend
327+ - Added new command line option --backend-retry-delay
328+ that allows to determine the time that duplicity sleeps
329+ before retrying after an error has occured.
330+ - Added some robustness to dpbxbackend.py that ensures re-authentication
331+ happens in case that a socket is changed (e.g. due to a forced reconnect
332+ of a dynamic internet connection).
333+* Merged in lp:~ed.so/duplicity/manpage.fixes
334+ - Fix html output via rman on the website
335+* Merged in lp:~horgh/duplicity/copy-symlink-targets-721599
336+ - Add --copy-links to copy symlink contents, not just the link itself.
337+* Merged in lp:~aaron-whitehouse/duplicity/Bug_1624725_files_within_folder_slash
338+ - Fixed Bug #1624725, so that an include glob ending in "/" now includes folder contents (for globs with
339+ and without special characters). This preserves the behaviour that an expression ending in "/" only
340+ matches a folder, but now the contents of any matching folder is included.
341+* Fix problem with gpg2 in yakety and zesty
342+* Fix Bug #1642813 with patch from Ravi
343+ - If stat() returns None, don't attempt to set perms.
344+* Merged in lp:~breunigs/duplicity/amazondrive3
345+ - As reported on the mailinglist, if a space is entered while duplicity asks for the URL, it fails.
346+ Since all important spaces are URL encoded anyway, this should be fine even if there are spaces in
347+ the URL at all. I also patched it in the onedrive backend, because it must have similar issues.
348+* Prep for 0.7.11
349+
350+
351+New in v0.7.10 (2016/08/20)
352+---------------------------
353+* Merged in lp:~mwilck/duplicity/0.7-series
354+ - Speedup of path_matches_glob() by about 8x. See
355+ https://code.launchpad.net/~mwilck/duplicity/0.7-series/+merge/301332
356+ for more details.
357+* Remove -w from setsid in functional tests.
358+* Fixed conflict in merge from Martin Wilck and applied
359+ - https://code.launchpad.net/~mwilck/duplicity/0.7-series/+merge/301492
360+ - merge fixes setsid usage in functional testing.
361+* Fixed bug #1612472 with patch from David Cuthbert
362+ - Restore from S3 fails with --with-prefix-archive if prefix includes '/'
363+* Merged in lp:~arashad.ahamad/duplicity/duplicity_latest
364+ - Changes for connecting to IBM Bluemix ObjectStorage. See man page.
365+* Merged in lp:~fenisilius/duplicity/acd_init_mkdir
366+ - Allow duplicity to create remote folder
367+
368+
369+New in v0.7.09 (2016/07/24)
370+---------------------------
371+* Fixed bug #1600692 with patch from Wolfgang Rohdewald
372+ - Allow symlink to have optional trailing slash during verify.
373+* Merged in lp:~aaron-whitehouse/duplicity/07-fix_deja_dup_error_on_locked_files
374+ - Revert log.Error to log.Warn, as it was prior to the merge in rev 1224,
375+ as this was affecting other applications (e.g. deja dup; Bug #1605939).
376+* Merged in lp:~duplicity-team/duplicity/po-updates
377+>>>>>>> MERGE-SOURCE
378
379
380 New in v0.7.08 (2016/07/02)
381@@ -456,6 +687,7 @@
382 - Set line length error length to 120 (matching tox.ini) for PEP8 and
383 fixed E501(line too long) errors.
384 * Merged in lp:~duplicity-team/duplicity/po-updates
385+<<<<<<< TREE
386 * Merged in lp:~aaron-whitehouse/duplicity/08-unicode
387 - Many strings have been changed to unicode for better handling of international
388 characters and to make the transition to Python 3 significantly easier, primarily
389@@ -475,6 +707,10 @@
390 they were hacked.
391 * Fixed bug #1817375 with hint from mgorse
392 - Added 'global pexpect' at end of imports
393+=======
394+* Fix bug using 40-char sign keys, from Richard McGraw on mail list
395+ - Remove truncation of argument and adjust comments
396+>>>>>>> MERGE-SOURCE
397
398
399 New in v0.7.07.1 (2016/04/19)
400@@ -492,6 +728,9 @@
401 * Fixed bug #1570293 duplicity is very slow due to excessive fsync
402 - removed flush() after write.
403 - revert to previous version
404+* Merged in lp:~aaron-whitehouse/duplicity/07-fix_deja_dup_error_on_locked_files
405+ - Revert log.Error to log.Warn, as it was prior to the merge in rev 1224,
406+ as this was affecting other applications (e.g. deja dup; Bug #1605939).
407
408
409 New in v0.7.07 (2016/04/10)
410@@ -744,9 +983,6 @@
411 * Merged in lp:~ed.so/duplicity/gpg.binary
412 - new parameter --gpg-binary allows user to point to a different gpg binary,
413 not necessarily in path
414-* Merged in lp:~ed.so/duplicity/gpg.binary
415- - new parameter --gpg-binary allows user to point to a different gpg binary,
416- not necessarily in path
417 * Merged in lp:~aaron-whitehouse/duplicity/fix_POTFILES.in_and_run-tests
418 - Fixed two filename references in po/POTFILES.in, a mistake which crept in in
419 rev 1093 and caused testing/run-tests to fail with "IndexError: list index
420
421=== modified file 'Changelog.GNU'
422--- Changelog.GNU 2019-03-16 23:23:40 +0000
423+++ Changelog.GNU 2019-04-22 12:43:18 +0000
424@@ -1,3 +1,4 @@
425+<<<<<<< TREE
426 2019-03-16 Kenneth Loafman <kenneth@loafman.com>
427
428 * Merged in lp:~mgorse/duplicity/0.8-series
429@@ -347,43 +348,271 @@
430 - giobackend: handle a wider variety of gio backends by making less assumptions;
431 in particular, this fixes the google-drive: backend
432
433+=======
434+2019-02-25 Kenneth Loafman <kenneth@loafman.com>
435+
436+ * Merged in lp:~mterry/duplicity/pydrive-root-0.7
437+ - Just a tiny fix to clean up the temporary file we create to find the root ID.
438+ It's a little surprising for the user if they wind up with this file called
439+ "i_am_in_root" that they don't know where it came from. Almost sounds like
440+ they were hacked.
441+
442+2018-10-17 Kenneth Loafman <kenneth@loafman.com>
443+
444+ * Fixed bug #1798206 and bug #1798504
445+ - Made paramiko a global with import during __init__ so it would
446+ not be loaded unless needed.
447+
448+2018-10-17 Kenneth Loafman <kenneth@loafman.com>
449+
450+ * Prep for 0.7.18.2
451+
452+2018-08-27 Kenneth Loafman <kenneth@loafman.com>
453+
454+ * Fixed bug #1788558 again
455+ - If we get None for size skip check.
456+
457+2018-08-27 Kenneth Loafman <kenneth@loafman.com>
458+
459+ * Prep for 0.7.18.1
460+
461+2018-08-26 Kenneth Loafman <kenneth@loafman.com>
462+
463+ * Fixed bug #1788558
464+ - Treat None as zero when printing log.
465+ * Revert fix for bug #1788599.
466+ - Was causing problems with directory names
467+
468+2018-08-21 Kenneth Loafman <kenneth@loafman.com>
469+
470+ * Fix a 2to3 error in ssh_paramiko_backend.py
471+ * Merged in lp:~duplicity-team/duplicity/po-updates
472+ * Prep for 0.7.18
473+
474+2018-08-11 Kenneth Loafman <kenneth@loafman.com>
475+
476+ * Fixed bug #1785520 with patch from Chris Hunt
477+ - Fix for B2 version 1.3.4 just released
478+
479+2018-07-08 Kenneth Loafman <kenneth@loafman.com>
480+
481+ * Fixed bug #1780617 Test fail when GnuPG >= 2.2.8
482+ - Relevant change in GnuPG 2.2.8: https://dev.gnupg.org/T3981
483+ - Added '--ignore-mdc-error' to all gpg calls made.
484+
485+2018-05-07 Kenneth Loafman <kenneth@loafman.com>
486+
487+ * Fixed bug #1717935 with suggestion from strainu
488+ - Use urllib.quote_plus() to properly quote pathnames passed via URL
489+
490+2018-05-01 Kenneth Loafman <kenneth@loafman.com>
491+
492+ * More fixes for bug #1734144
493+ - Number of retries is now same as globals.num_retries.
494+ - Added standoff delay of 0.5 sec per attempt.
495+ * Fixed bug #1764432 with patch from Robke Geenen
496+ - Just join the parts together.
497+
498+2018-04-04 Kenneth Loafman <kenneth@loafman.com>
499+
500+ * Partial fix of bug #1734144 with patch from Joris van Eijden
501+ - Note: this is really just a partial fix for now, since it only covers
502+ the case where the local size does not yet match the remote size. A
503+ case where -1 is the returned length is not fixed.
504+
505+2018-03-17 Kenneth Loafman <kenneth@loafman.com>
506+
507+ * Fixed bug #1756550 Online html man page is showing a 0 byte file
508+
509+2018-02-26 Kenneth Loafman <kenneth@loafman.com>
510+
511+ * Fix update of Launchpad Translations. Translations were not being picked
512+ up on a daily basis and we got several months behind.
513+ * Prep for 0.7.17
514+
515+2018-02-01 Kenneth Loafman <kenneth@loafman.com>
516+
517+ * Removed changes made in bug #1044715 Provide a file history feature
518+ - Changes required too much memory to carry in the manifest
519+ - The option --file-changed in collection-status is now invalid
520+ - This will close bugs: #1730451, #896728, #1526557, #1550176
521+ - Starting a full backup will be needed to fully utilize this fix
522+
523+2018-01-12 Kenneth Loafman <kenneth@loafman.com>
524+
525+ * Fix pylint error in webdavbackend.py
526+ * Prep for 0.7.16
527+
528+2017-11-28 Kenneth Loafman <kenneth@loafman.com>
529+
530+ * Patched in lp:~crosser/duplicity/fix-small-file-upload
531+ - Fixed small file upload changes made in Dropbox SDK v7.1
532+
533+2017-11-25 Kenneth Loafman <kenneth@loafman.com>
534+
535+ * Patched in lp:~crosser/duplicity/fix-oauth-flow
536+ - Fixed bug #1638236 "BackendException with oauth2client 4.0.0"
537+ * Patched in lp:~crosser/duplicity/dpbx-fix-file-listing
538+ - Fixed bug #1639664 "Dropbox support needs to be updated for Dropbox SDK v7.1"
539+
540+2017-11-23 Kenneth Loafman <kenneth@loafman.com>
541+
542+ * More fixes for Unicode handling
543+ - Default to 'utf-8' if sys.getfilesystemencoding() returns 'ascii' or None
544+ - Fixed bug #1386373 with suggestion from Eugene Morozov
545+
546+2017-11-18 Kenneth Loafman <kenneth@loafman.com>
547+
548+ * Fixed bug #1733057 AttributeError: 'GPGError' object has no attribute 'decode'
549+ - Replaced call to util.ufn() with call to util.uexc(). Stupid typo!
550+
551+2017-11-09 Kenneth Loafman <kenneth@loafman.com>
552+
553+ * Prep for 0.7.15
554+
555+2017-11-09 Kenneth Loafman <kenneth@loafman.com>
556+
557+ * Fixed bug #1730902 GPG Error Handling
558+ - use util.ufn() not str() to handle encoding
559+
560+2017-11-01 Kenneth Loafman <kenneth@loafman.com>
561+
562+ * Fixed bug #1723890 with patch from Killian Lackhove
563+ - Fixes error handling in pydrivebackend.py
564+
565+2017-10-31 Kenneth Loafman <kenneth@loafman.com>
566+
567+ * Fixed bug #1720159 - Cannot allocate memory with large manifest file since 0.7.03
568+ - filelist is not read if --file-changed option in collection-status not present
569+ - This will keep memory usage lower in non collection-status operations
570+
571+2017-10-26 Kenneth Loafman <kenneth@loafman.com>
572+
573+ * Fixed bug #1448094 with patch from Tomáš Zvala
574+ - Don't log incremental deletes for chains that have no incrementals
575+ * Fixed bug #1724144 "--gpg-options unused with some commands"
576+ - Add --gpg-options to get version run command
577+
578+2017-10-16 Kenneth Loafman <kenneth@loafman.com>
579+
580+ * Fixed bug #1654756 with new b2backend.py module from Vincent Rouille
581+ - Faster (big files are uploaded in chunks)
582+ - Added upload progress reporting support
583+
584+2017-10-12 Kenneth Loafman <kenneth@loafman.com>
585+
586+ * Merged in lp:~mterry/duplicity/rename-dep
587+ - Make rename command a dependency for LP build
588+
589+2017-09-22 Kenneth Loafman <kenneth@loafman.com>
590+
591+ * Fixed bug #1714663 "Volume signed by XXXXXXXXXXXXXXXX, not XXXXXXXX"
592+ - Normalized comparison length to min length of compared keys before comparison
593+ - Avoids comparing mix of short, long, or fingerprint size keys.
594+
595+2017-09-13 Kenneth Loafman <kenneth@loafman.com>
596+
597+ * Fixed bug #1715650 with patch from Mattheww S
598+ - Fix to make duplicity attempt a get first, then create, a container
599+ in order to support container ACLs.
600+
601+2017-09-07 Kenneth Loafman <kenneth@loafman.com>
602+
603+ * Merged in lp:~mterry/duplicity/more-decode-issues
604+ - Here's some fixes for another couple UnicodeDecodeErrors.
605+ - The duplicity/dup_time.py fixes when a user passes a utf8 date string (or a string with bogus
606+ utf8 characters, but they have to really try to do that). This is bug 1334436.
607+ - The bin/duplicity change from str(e) to util.uexc(e) fixes bug 1324188.
608+ - The rest of the changes (util.exception_traceback and bin/duplicity changes to use it) are to
609+ make the printing of exceptions prettier. Without this, if you see a French exception, you see
610+ "accept\xe9es" instead of "acceptées".
611+ - You can test all of these changes in one simple line:
612+ $ LANGUAGE=fr duplicity remove-older-than $'accept\xffées'
613+ * Fix backend.py to allow string, list, and tuple types to support megabackend.py.
614+
615+2017-09-06 Kenneth Loafman <kenneth@loafman.com>
616+
617+ * Fixed bug introduced in new megabackend.py where process_commandline()
618+ takes a string not a list. Now it takes both.
619+ * Updated web page for new megabackend requirements.
620+
621+2017-08-31 Kenneth Loafman <kenneth@loafman.com>
622+
623+ * Fixed bug #1538333 Assertion error in manifest.py: assert filecount == ...
624+ - Made sure to never pass .part files as true manifest files
625+ - Changed assert to log.Error to warn about truncated/corrupt filelist
626+ - Added unit test to make sure detection works
627+ - Note: while this condition is serious, it will not affect the basic backup and restore
628+ functions. Interactive options like --list-files-changed and --file-changed will not
629+ work correctly for this backup set, so it is advised to run a full backup as soon as
630+ possible after this error occurs.
631+ * Fixed bug #1638033 Remove leading slash on --file-to-restore
632+ - code already used rstrip('/') so change to just strip('/')
633+ * Prep for 0.7.14
634+
635+2017-08-29 Kenneth Loafman <kenneth@loafman.com>
636+
637+ * Fixed bug #1394386 with new module megabackend.py from Tomas Vondra
638+ - uses megatools from https://megatools.megous.com/ instead of mega.py library
639+ which has been deprecated
640+ - fixed copyright and PEP8 issues
641+ - replaced subprocess.call() with self.subprocess_popen() to standardize
642+ * Fixed bug #1713640 with patch from Aleksandar Ivanisevic
643+ - replace 2.7 syntax with 2.6 equivalent
644+
645+2017-08-28 Kenneth Loafman <kenneth@loafman.com>
646+
647+ * Fixed bug #1711905 with suggestion from Schneider
648+ - log.Warn was invoked with log.warn in webdavbackend.py
649+ * Merged in lp:~mterry/duplicity/gpg-tag-versions
650+ - Support gpg versions numbers that have tags on them.
651+ - This can happen if you build gpg from git trunk (e.g. 2.1.15-beta20). Or if you run
652+ against the freedesktop flatpak runtime (e.g. 2.1.14-unknown).
653+
654+2017-08-15 Kenneth Loafman <kenneth@loafman.com>
655+
656+ * Fixed bug #1709047 with suggestion from Gary Hasson
657+ - fixed so default was to use original filename
658+ * Fixed PEP8 errors in bin/duplicity
659+ * Merged in lp:~mterry/duplicity/gio_child_for_display_name_0.7
660+ - gio: be slightly more correct and get child GFiles based on display name
661+
662+2017-08-06 Kenneth Loafman <kenneth@loafman.com>
663+
664+ * Patched in lp:~mterry/duplicity/giobackend-display-name
665+ - giobackend: handle a wider variety of gio backends by making less assumptions;
666+ in particular, this fixes the google-drive: backend
667+
668+>>>>>>> MERGE-SOURCE
669 2017-07-20 Kenneth Loafman <kenneth@loafman.com>
670
671 * Fixed encrypted remote manifest handling to merely put out a non-fatal
672 error message and continue if the private key is not available.
673
674-2017-07-19 Kenneth Loafman <kenneth@loafman.com>
675+2017-07-18 Kenneth Loafman <kenneth@loafman.com>
676
677 * Fixed slowness in 'collection-status' by basing the status on the
678 remote system only. The local cache is treated as empty.
679
680 2017-07-11 Kenneth Loafman <kenneth@loafman.com>
681
682- * Patched in lp:~dawgfoto/duplicity/skip_sync_collection_status
683+ * Merged in lp:~dawgfoto/duplicity/skip_sync_collection_status
684 - collection-status should not sync metadata
685 - up-to-date local metadata is not needed as collection-status is
686 generated from remote file list
687 - syncing metadata might require to download several GBs
688
689-2017-06-30 Kenneth Loafman <kenneth@loafman.com>
690-
691- * Merged in lp:~xlucas/duplicity/multibackend-prefix-affinity
692- - Support prefix affinity in multibackend.
693- * Merged in lp:~xlucas/duplicity/pca-backend
694- - Add support for OVH Public Cloud Archive backend.
695- * Fixed PEP8 and 2to3 issues.
696-
697-2017-06-23 Kenneth Loafman <kenneth@loafman.com>
698-
699- * Merged in lp:~dawgfoto/duplicity/replicate
700- - Add integration test for newly added replicate command.
701- - Also see https://code.launchpad.net/~dawgfoto/duplicity/replicate/+merge/322836.
702-
703-2017-06-19 Kenneth Loafman <kenneth@loafman.com>
704+2017-06-18 Kenneth Loafman <kenneth@loafman.com>
705
706 * Fixed problem in dist/makedist when building on Mac where AppleDouble
707 files were being created in the tarball. See:
708 https://superuser.com/questions/61185/why-do-i-get-files-like-foo-in-my-tarball-on-os-x
709+ * Prep for 0.17.13.1
710+
711+2017-06-10 Kenneth Loafman <kenneth@loafman.com>
712+
713+ * Merged in lp:~duplicity-team/duplicity/po-updates
714+ * Prep for 0.7.13
715
716 2017-06-10 Kenneth Loafman <kenneth@loafman.com>
717
718@@ -394,19 +623,6 @@
719 * Merged in lp:~xlucas/duplicity/swift-multibackend-bug
720 - Fix a bug when swift backend is used in a multibackend configuration.
721
722-2017-06-04 Kenneth Loafman <kenneth@loafman.com>
723-
724- * Merged in lp:~aaron-whitehouse/duplicity/08-fix-man-verify
725- - Fix description of --verify and --compare-data in the man page. Now
726- clarifies that verify compares the restored files to hashes stored at
727- backup date, while --compare-data compares restored files to files
728- in target_path.
729-
730-2017-06-03 Kenneth Loafman <kenneth@loafman.com>
731-
732- * Merged in lp:~dernils/duplicity/docker-compose
733- - Test Infrastructure now utilizing docker-compose
734-
735 2017-06-02 Kenneth Loafman <kenneth@loafman.com>
736
737 * Fix bug #1672540 with patch from Benoit Nadeau
738@@ -432,26 +648,6 @@
739 - Caveat: long incremental chains will still eat up a large number of file
740 descriptors. It's a very risky practice, so I'm not inclined to fix it.
741
742-2017-05-15 Kenneth Loafman <kenneth@loafman.com>
743-
744- * Merged in lp:~dernils/duplicity/Dockerfile
745- - Now have subnet name and IP of the subnet for testing as a variable.
746-
747-2017-05-14 Kenneth Loafman <kenneth@loafman.com>
748-
749- * Merged in lp:~xlucas/duplicity/swift-storage-policies
750- - This brings support for Swift storage policies: when using a Swift
751- backend, you can specify the policy containers should be operating on.
752- - This is similar to AWS Cloud Storage classes (ia, rrs, glacier and so on).
753- * Merged in lp:~dernils/duplicity/Dockerfile
754- - Added another backend to the docker test infrastructure, updated the setup
755- for testing and updated the documentation.
756-
757-2017-05-12 Kenneth Loafman <kenneth@loafman.com>
758-
759- * Merged in lp:~aaron-whitehouse/duplicity/tox_pylint_fixes
760- - Changes needed to run-tests without pylint E0401(import-error) errors
761-
762 2017-05-11 Kenneth Loafman <kenneth@loafman.com>
763
764 * Fixed bug #1320641 and others regarding lockfile
765@@ -466,53 +662,12 @@
766 IOError exception saying that too many files are open. This causes
767 restores to fail randomly, after thousands of files have been restored.
768
769-2017-05-06 Kenneth Loafman <kenneth@loafman.com>
770-
771- * Merged in lp:~dernils/duplicity/DockerfileConvenience
772- - Add a few files that are the beginning of further infrastructure based
773- on docker. It contains a Dockerfile for a simple ftp server (used for
774- backend testing) and a setup script that can be used to set up the
775- complete test environment.
776- * Moved Dockerfile for duplicitytest into testinfrastructure/duplicity_test
777- * Moved some things around in testing/infrastructure to clean up
778-
779-2017-05-05 Kenneth Loafman <kenneth@loafman.com>
780-
781- * Merged in lp:~dernils/duplicity/DockerfileConvenience
782- - Added a few tools to the Dockerfile that make life easier
783+2017-05-07 Kenneth Loafman <kenneth@loafman.com>
784+
785 * Fixed bug #1320832 with suggestion from Oskar Wycislak
786 - Use chunks instead of reading it all in swiftbackend
787
788-2017-05-04 Kenneth Loafman <kenneth@loafman.com>
789-
790- * Merged in lp:~dawgfoto/duplicity/replicate
791- - Add replicate command to replicate a backup (or backup
792- sets older than a given time) to another backend, leveraging
793- duplicity's backend and compression/encryption infrastructure.
794- * Fixed some incoming PyLint and PEP-8 errors.
795- * Merged in lp:~marix/duplicity/add-azure-arguments
796- - Using the Azure backend to store large amounts of data we found that
797- performance is sub-optimal. The changes on this branch add command line
798- parameters to fine-tune some parameters of the Azure storage library,
799- allowing to push write performance towards Azure above 1 Gb/s for large
800- back-ups. If a user does not provide the parameters the defaults of the
801- Azure storage library will continue to be used.
802- * Replace incoming non-ASCII chars in commandline.py
803- * bzr does not honor perms so fix the perms at the start of the testing and
804- avoid annoying error regarding testing/gnupg having too lenient perms
805-
806-2017-04-23 Kenneth Loafman <kenneth@loafman.com>
807-
808- * Merged in lp:~dernils/duplicity/testing
809- - Fixed minor stuff in requirements.txt.
810- - Added a Dockerfile for testing.
811- - Minor changes to README files.
812- - Added README-TESTING with some information on testing.
813- * Merged in lp:~dernils/duplicity/documentation
814- - Minor changes to README-REPO, README-TESTING
815- - Also redo the changes to requirements.txt and Dockerfile
816-
817-2017-04-22 Kenneth Loafman <kenneth@loafman.com>
818+2017-04-20 Kenneth Loafman <kenneth@loafman.com>
819
820 * Fixed bug #1680682 with patch supplied from Dave Allan
821 - Only specify --pinentry-mode=loopback when --use-agent is not specified
822@@ -521,6 +676,10 @@
823 - Use shutil.copyfile instead of os.system('cp ...')
824 - Should reduce overhead of os.system() memory usage.
825
826+2017-03-21 Kenneth Loafman <kenneth@loafman.com>
827+
828+ * Prep for 0.7.12
829+
830 2017-03-13 Kenneth Loafman <kenneth@loafman.com>
831
832 * Fixed bug #1668750 - Don't mask backend errors
833@@ -531,55 +690,22 @@
834 * Fixed bug #1671852 - Code regression caused by revision 1108
835 - change util.uexc() back to bare uexc()
836
837-2017-03-05 Kenneth Loafman <kenneth@loafman.com>
838-
839- * Merged in p:~aaron-whitehouse/duplicity/pep8_E402_fixes
840- - Fixed PEP8 errors: E402 module level import not at top of file
841-
842-2017-03-02 Kenneth Loafman <kenneth@loafman.com>
843-
844- * Merged in lp:~benoit.bertholon/duplicity/duplicity
845- - Use the globals.archive_dir variable to store only a string
846- in the case of a path, uses globals.archive_dir_path
847-
848 2017-02-21 Kenneth Loafman <kenneth@loafman.com>
849
850- * Merged in lp:~marix/duplicity/azure-storage-0.30.0-plus
851- - This makes the Azure backend compatible with version 0.30.0 and up of the
852- underlying azure-storage package.
853- * Merged in lp:~marix/duplicity/azure-storage-sas
854- - This branch adds support for Shared Access Signature to the Azure backend
855- which allows to run Duplicity with a minimal set of permissions.
856- * Merged in lp:~aaron-whitehouse/duplicity/pep8_test_fixes
857- - Fix PEP-8 testing by moving to using pycodestyle library.
858- - Temporarily add ignores to allow these tests to pass.
859- - Fix E305 PEP8 errors: expected 2 blank lines after class or function definition, found 1.
860- * Merged in lp:~benoit.bertholon/duplicity/duplicity
861- - Fixes bug #1666194 - ProcessCommandLine function called twice fail and arglist argument not used
862- * Fixed variable name change in last merge which broke a bunch of tests
863- - Changed archive_dir_root back to archive_dir
864 * Fixed bug #1367675 - IMAP Backend does not work with Yahoo server
865 - added the split() as needed in 'nums=list[0].strip().split(" ")'
866 - the other fixes mentioned in the bug report comments were already done
867
868-2017-02-12 Kenneth Loafman <kenneth@loafman.com>
869-
870- * Merged in lp:~aaron-whitehouse/duplicity/08-python-futurize-stage-1
871- - Made many of the safer changes for improved Python 3 support (python-future's futurize -stage1)
872- without functional change to the code (and leaving the isinstance(s, types.StringType) tests unchanged).
873- - Created Python 2/3 compatible tests for int and long.
874- - Update setup.py to show only Python 2.7 support.
875-
876 2017-02-11 Kenneth Loafman <kenneth@loafman.com>
877
878 * Fixed bug #1603704 with patch supplied by Maciej Bliziński
879 - Crash with UnicodeEncodeError
880+ * Some fixes to gpg.py to handle gpg1 & gpg2 & gpg2.1 commandline issues
881+ - --gpg-agent is optional on gpg1, but on gpg2 it is used automatically
882+ - --pinentry-mode is not a valid opt until gpg2.1, so condition on that
883
884 2017-02-08 Kenneth Loafman <kenneth@loafman.com>
885
886- * Merged in lp:~aaron-whitehouse/duplicity/08-refactor-unit-test-globmatch
887- - Rename path_matches_glob_fn to select_fn_from_glob, as this more accurately reflects the return value.
888- - Significantly refactored unit/test_globmatch.py to make this cleaner and clearer.
889 * Fixed bug #1657916 with patch supplied by Daniel Harvey
890 - B2 provider cannot handle two backups in the same bucket
891
892@@ -587,13 +713,6 @@
893
894 * Add detail about import exceptions in onedrivebackend.py
895
896-2017-01-30 Kenneth Loafman <kenneth@loafman.com>
897-
898- * Merged in lp:~aaron-whitehouse/duplicity/08-merge-glob-parsers
899- - Use a single code path for glob strings whether or not these contain special
900- characters/wildcards (glob_get_normal_sf) and remove glob_get_filename_sf and glob_get_tuple_sf.
901- - Remove run-tests-ve as this was identical to run-tests.
902-
903 2017-01-24 Kenneth Loafman <kenneth@loafman.com>
904
905 * Merged in lp:~matthew-t-bentley/duplicity/duplicity
906@@ -602,6 +721,13 @@
907 - Only retrieves a new upload URL when the current one expires, to bring it in line
908 with their best practices for integrations: https://www.backblaze.com/b2/docs/integration_checklist.html
909
910+2017-01-21 Kenneth Loafman <kenneth@loafman.com>
911+
912+ * Fixed bug #1658283 "Duplicity 0.7.11 broken with GnuPG 2.0"
913+ - Made gpg version check more robust than just major version
914+ - Now use --pinentry-mode=loopback on gpg 2.1 and greater
915+ - Removed check for non-Linux systems, a false problem
916+
917 2017-01-19 Kenneth Loafman <kenneth@loafman.com>
918
919 * Fixed bug #1655268 "--gpg-binary option not working"
920@@ -613,13 +739,10 @@
921 - Failing test on OpenBSD because tar/gtar not found
922 * Fixed bug #1654220 with patch supplied by Kenneth Newwood
923 - Duplicity fails on MacOS because GPG version parsing fails
924- * Merged in lp:~aaron-whitehouse/duplicity/0-8-merge_selection_tests
925- - Merge in TestExcludeIfPresent from 0.7-series, which tests the behaviour of
926- duplicity's --exclude-if-present option.
927- - Move and rename TestTrailingSlash2 test (was duplicate name) as in 0.7-series.
928- - Fix PEP error on adbackend.py.
929- - Add jottalib as a tox dep to fix pylint error.
930- - Remove unnecessary skipUnless Linux as per 0.7-series.
931+
932+2016-12-31 Kenneth Loafman <kenneth@loafman.com>
933+
934+ * Prep for 0.7.11
935
936 2016-12-29 Kenneth Loafman <kenneth@loafman.com>
937
938@@ -630,9 +753,8 @@
939 Since all important spaces are URL encoded anyway, this should be fine even if there are spaces in
940 the URL at all. I also patched it in the onedrive backend, because it must have similar issues.
941
942-2016-12-25 Kenneth Loafman <kenneth@loafman.com>
943+2016-12-24 Kenneth Loafman <kenneth@loafman.com>
944
945- * Fix some issues with testing on MacOS
946 * Fix problem with gpg2 in yakety and zesty
947
948 2016-12-11 Kenneth Loafman <kenneth@loafman.com>
949@@ -666,21 +788,10 @@
950 * Fixed bug #1642098 - does not create PAR2 archives when '--par2-options' is used
951 - Missing space between par2-options plus default options
952
953-2016-11-07 Kenneth Loafman <kenneth@loafman.com>
954-
955- * Merged in lp:~breunigs/duplicity/amazondrive2
956- - Fixed variable renaming issue
957-
958 2016-11-01 Kenneth Loafman <kenneth@loafman.com>
959
960 * Fixed bug #1621194 with code from Tornhoof
961 - Do backup to google drive working without a service account
962- * Merged in lp:~havard/duplicity/jottacloudbackend
963- - Adds support for a new backend, jottacloud.com, using the scheme `jottacloud:/<folder>`.
964- - Reverse-engineered library, `jottalib`: http://github.com/havardgulldahl/jottalib
965- - Here's how you set up jottalib https://github.com/havardgulldahl/jottalib/wiki
966- * Merged in lp:~breunigs/duplicity/amazondrive
967- - Provide a native backend for AmazonDrive
968
969 2016-10-22 Kenneth Loafman <kenneth@loafman.com>
970
971@@ -694,6 +805,11 @@
972 * Fixed bug #1623342 with patch from Daniel Jakots
973 - failing test on OpenBSD because tar/gtar not found
974
975+2016-09-06 Kenneth Loafman <kenneth@loafman.com>
976+
977+ * Merged in lp:~aaron-whitehouse/duplicity/bug_1620085_exclude-if-present-locked-folder
978+ - Fixes Bug #1620085: --exclude-if-present gives OSError looking for tag in locked folders
979+
980 2016-08-22 Kenneth Loafman <kenneth@loafman.com>
981
982 * Fixed bugs #815510 and #1615480
983@@ -701,6 +817,10 @@
984 * Merged in lp:~mstoll-de/duplicity/duplicity
985 - Backblaze announced a new domain for the b2 api
986
987+2016-08-20 Kenneth Loafman <kenneth@loafman.com>
988+
989+ * Prep for 0.7.10
990+
991 2016-08-18 Kenneth Loafman <kenneth@loafman.com>
992
993 * Merged in lp:~fenisilius/duplicity/acd_init_mkdir
994@@ -721,27 +841,24 @@
995
996 2016-07-28 Kenneth Loafman <kenneth@loafman.com>
997
998- * Merged in lp:~mwilck/duplicity/duplicity
999+ * Merged in lp:~mwilck/duplicity/0.7-series
1000 - Speedup of path_matches_glob() by about 8x. See
1001- https://code.launchpad.net/~mwilck/duplicity/duplicity/+merge/301268
1002+ https://code.launchpad.net/~mwilck/duplicity/0.7-series/+merge/301332
1003 for more details.
1004+ * Remove -w from setsid in functional tests.
1005
1006 2016-07-24 Kenneth Loafman <kenneth@loafman.com>
1007
1008 * Merged in lp:~aaron-whitehouse/duplicity/07-fix_deja_dup_error_on_locked_files
1009 - Revert log.Error to log.Warn, as it was prior to the merge in rev 1224,
1010 as this was affecting other applications (e.g. deja dup; Bug #1605939).
1011+ * Prep for 0.7.09
1012
1013 2016-07-20 Kenneth Loafman <kenneth@loafman.com>
1014
1015 * Fixed bug #1600692 with patch from Wolfgang Rohdewald
1016 - Allow symlink to have optional trailing slash during verify.
1017
1018-2016-07-03 Kenneth Loafman <kenneth@loafman.com>
1019-
1020- * Merged in lp:~aaron-whitehouse/duplicity/remove-python26
1021- - Remove Python 2.6 support references and tests.
1022-
1023 2016-07-02 Kenneth Loafman <kenneth@loafman.com>
1024
1025 * Merged in lp:~aaron-whitehouse/duplicity/PEP8_W503_fixes
1026
1027=== modified file 'README'
1028--- README 2018-10-07 11:54:04 +0000
1029+++ README 2019-04-22 12:43:18 +0000
1030@@ -19,7 +19,11 @@
1031
1032 REQUIREMENTS:
1033
1034+<<<<<<< TREE
1035 * Python v2.7
1036+=======
1037+ * Python v2.6 or later
1038+>>>>>>> MERGE-SOURCE
1039 * librsync v0.9.6 or later
1040 * GnuPG for encryption
1041 * fasteners 0.14.1 or later for concurrency locking
1042@@ -34,6 +38,7 @@
1043
1044 * Python development files, normally found in module 'python-dev'.
1045 * librsync development files, normally found in module 'librsync-dev'.
1046+ * internationalization tools, normally found in module 'intltool'.
1047
1048
1049 A NOTE ON GnuPGInterface.py AND MULTIPLE GPG PROCESSES:
1050
1051=== modified file 'README-REPO'
1052--- README-REPO 2017-07-11 14:55:38 +0000
1053+++ README-REPO 2019-04-22 12:43:18 +0000
1054@@ -26,3 +26,56 @@
1055 or
1056
1057 PYTHONPATH=$DUP_ROOT bin/rdiffdir
1058+
1059+-----------------------
1060+Running the unit tests:
1061+-----------------------
1062+
1063+To run all tests:
1064+cd testing; ./run-tests
1065+
1066+You can run specific tests using:
1067+tox -- -s [folder].[folder].[file].[class].[test]
1068+For example:
1069+tox -- -s testing.unit.test_selection
1070+or:
1071+tox -- -s testing.unit.test_selection.MatchingTest.test_tuple_include
1072+
1073+Note: some tests require rdiff and pylint to be installed on the system for
1074+them to pass.
1075+
1076+Please run all tests on your branch (run-tests) before proposing a merge, to
1077+ensure that all tests pass. The decorator @unittest.expectedFailure can be used
1078+to commit a known-failing test case without breaking the test suite, for
1079+example to exhibit the behaviour in a bug report before it has been fixed:
1080+
1081+if sys.version_info < (2, 7):
1082+ import unittest2 as unittest
1083+else:
1084+ import unittest
1085+
1086+
1087+class TestClass(unittest.TestCase):
1088+ """Test class to show expectedFailure"""
1089+
1090+ @unittest.expectedFailure
1091+ def test_expected_failure(self):
1092+ """Test behaviour of expectedFailure"""
1093+ self.assertEqual(1, 2)
1094+
1095+-----------------------------------------
1096+Testing against multiple Python versions:
1097+-----------------------------------------
1098+
1099+Duplicity currently supports Python versions v2.6 or later. Duplicity uses tox
1100+to make it easy to test your code against multiple Python versions. Running
1101+tests using the commands above will automatically test code against both
1102+Python v2.6 and v2.7, if you have both installed on your system. It will also
1103+test against the versions of dependencies used by the Launchpad build system.
1104+You can test against a single environment, e.g.
1105+tox -e py26
1106+for example if you are working on fixing a bug, but please do a full run-tests
1107+before submitting a merge request.
1108+
1109+For instructions on installing Python v2.6 on newer versions of Ubuntu, see
1110+https://launchpad.net/~fkrull/+archive/ubuntu/deadsnakes
1111
1112=== removed file 'README-TESTING'
1113--- README-TESTING 2017-05-14 07:17:59 +0000
1114+++ README-TESTING 1970-01-01 00:00:00 +0000
1115@@ -1,138 +0,0 @@
1116-# Testing duplicty
1117-
1118-## Introduction
1119-Duplicitys test concept bases on unit test.
1120-All tests are contained in the /testing folder of the main repository.
1121-
1122-As to see in the following sketch, there are several levels of testing duplicity and each can be used directly.
1123-
1124- ┌─────────────────────┐
1125- │ docker image │
1126- ├─────────────────────┴────┐
1127- │ │
1128- │ ┌──────────────────┐ │
1129- │ │ tox │ │
1130- │ └──────────────────┘ │
1131- │ │ │
1132- │ ▼ │
1133- │ ┌──────────────────┐ │
1134- │ │ unittests │ │
1135- │ └──────────────────┘ │
1136- │ │ │
1137- │ ▼ │
1138- │ ┌──────────────────┐ │
1139- │ │ duplicity │ │
1140- │ └──────────────────┘ │
1141- │ │
1142- └──────────────────────────┘
1143-1. Testing directly using __setup.py__
1144-Assuming that your machine has all the required dependencies installed, you can start all the unit tests by simply typing
1145-
1146-‘setup.py test‘
1147-
1148-2. Using __tox__
1149-Tox is a generic virtualenv management and test command line tool that is used for checking your package installs correctly with different Python versions and interpreters. It
1150-runs the tests in each of the environments that are configured in the tox.ini file (see root folder of the repository)
1151-
1152-Duplicity uses tox to make it easy to test your code against multiple
1153-environments. Running tests using the commands above will automatically test
1154-code against different supported environments, including the versions of
1155-dependencies used by the Launchpad build system.
1156-
1157-A tox run can be started simply by typing
1158-
1159-‘tox‘
1160-
1161-from the main duplicity folder.
1162-
1163-You can run specific tests using:
1164-‘tox -- -s [folder].[folder].[file].[class].[test]‘
1165-For example:
1166-‘tox -- -s testing.unit.test_selection‘
1167-or:
1168-‘tox -- -s testing.unit.test_selection.MatchingTest.test_tuple_include‘
1169-
1170-You can test against a single environment, e.g.
1171-‘tox -e py27‘
1172-for example if you are working on fixing a bug, but please do a full run-tests
1173-before submitting a merge request.
1174-
1175-Note: some tests require rdiff and pylint to be installed on the system for
1176-them to pass.
1177-
1178-Please run all tests on your branch (run-tests) before proposing a merge, to
1179-ensure that all tests pass. The decorator @unittest.expectedFailure can be used
1180-to commit a known-failing test case without breaking the test suite, for
1181-example to exhibit the behaviour in a bug report before it has been fixed.
1182-
1183-3. Via a __docker__ image
1184-Testing on a developer's machine can be tricky. Testing duplicity requires a set of dependencies being installed and reacts sensitiviely to changes of the local python configuration. In order to make sure that such interactions do not pose any influence on executing the tests, docker is the technology of choice.
1185-Along with the tests, a docker image has been created (cf. Dockerfile in root folder of repo) that ensure the following things:
1186-- It bases on a clean Ubunut 16.04
1187-- It installs all the required packages that are needed for testing
1188-- It then branches the repository of duplicty to the folder /duplicty/testing within the docker image
1189-- And installs all the required python packages (as defined in the requirements.txt)
1190-Therewith, the docker image provides a clean and reproducible environment for executing the tests of duplicty.
1191-In order to get hands on the docker image you simply:
1192-1) Install Docker on your machine (https://docs.docker.com/engine/installation/)
1193-2) Start the image docker run -it dernils/duplicitytest /bin/bash (if you did not use the image before, it will be downloaded automatically)
1194-3) At the prompt of the docker image type:
1195-‘cd /testing‘
1196-‘tox‘
1197-to start a run of the test cases.
1198-
1199-## Dependencies for testing
1200-If you should prefer to execute the tests locally without using docker, the Dockerfile that is checked into the root folder of the repository contains useful information. It contains a section marked "The following packages are needed for testing duplicity". Within this section all dependencies that need to be installed on a machine to execute the test cases are identified.
1201-
1202-## Working with test coverage
1203-Python makes it easy to determine, how well the tests cover the source code.
1204-
1205-You first run the tests __under observation__ of the coverage script:
1206-‘coverage run setup.py test‘
1207-After that, a report can be generated by the use of the command:
1208-‘coverage html --omit="testing/*,/usr/*"‘
1209-
1210-The report will be generated and stored in the folder htmlcov.
1211-
1212-## The wider picture - supporting containers for testing
1213-Testing duplicity invokes backends. The backends are the places where the backup data is actually stored (e.g. an ftp server). In order to have the highest degree of control over the testing process, backends that can be set up locally are also operated in separated docker containers. The whole test infrastructure is shown in the following picture.
1214-
1215-┌─────────────────────┐ ┌──────────────────────────────────────────┐
1216-│docker image │ │docker image │
1217-│dernils/duplicitytest│ │dernils/duplicity_testinfrastructure_ssh │
1218-├─────────────────────┴────┐ ├──────────────────────────────────────────┴──┐
1219-│ │ │ │
1220-│ ┌──────────────────┐ │ │ ┌──────────────────┐ │
1221-│ │ tox │ │ ┌──┼──▶│ sshd │ │
1222-│ └──────────────────┘ │ │ │ └──────────────────┘ │
1223-│ │ │ │ │ │
1224-│ ▼ │ │ └─────────────────────────────────────────────┘
1225-│ ┌──────────────────┐ │ │ ┌──────────────────────────────────────────┐
1226-│ │ unittests │ │ │ │docker image │
1227-│ └──────────────────┘ │ │ │dernils/duplicity_testinfrastructure_ftp │
1228-│ │ │ │ ├──────────────────────────────────────────┴──┐
1229-│ ▼ │ │ │ │
1230-│ ┌──────────────────┐ │ │ │ ┌──────────────────┐ │
1231-│ │ duplicity │◀───┼─┴──┼──▶│ pure-ftpd │ │
1232-│ └──────────────────┘ │ │ └──────────────────┘ │
1233-│ │ │ │ │
1234-└────────────┼─────────────┘ └─────────────────────────────────────────────┘
1235- │
1236- │
1237- │
1238- └────────────┐
1239- │
1240- Internet .─────────┼─────────.
1241- _.────' │ `─────.
1242- _.─' │ `──.
1243- ,' ▼ `.
1244- ; ┌──────────────────┐ :
1245- : │ Dropbox │ ;
1246- ╲ └──────────────────┘ ╱
1247- `. ,'
1248- `──. _.─'
1249- `─────. _.────'
1250- `─────────────────'
1251-
1252-The docker images that contain the test infrastructure are defined in the folder /testing/infrastructure. There is a build script to compile the Dockerfile into actual images (build-duplicitiy-test.sh). However, as all images are also published on the docker hub, it is not necessary to build the images before starting testing. Testing can directly be started by using the script setup.sh. If the required docker images are not yet existing, locally, they will be downloaded by Docker.
1253-
1254
1255=== modified file 'bin/duplicity'
1256--- bin/duplicity 2019-02-26 21:48:04 +0000
1257+++ bin/duplicity 2019-04-22 12:43:18 +0000
1258@@ -27,6 +27,7 @@
1259 # Please send mail to me or the mailing list if you find bugs or have
1260 # any suggestions.
1261
1262+<<<<<<< TREE
1263 from builtins import filter
1264 from builtins import next
1265 from builtins import map
1266@@ -34,21 +35,33 @@
1267 from builtins import object
1268 import duplicity.errors
1269 import copy
1270+=======
1271+>>>>>>> MERGE-SOURCE
1272 import gzip
1273 import os
1274+import sys
1275+import time
1276+import types
1277+import traceback
1278 import platform
1279+import statvfs
1280+import resource
1281 import re
1282+<<<<<<< TREE
1283 import resource
1284 from os import statvfs
1285 import sys
1286+=======
1287+>>>>>>> MERGE-SOURCE
1288 import threading
1289-import time
1290-import traceback
1291-import types
1292+from datetime import datetime
1293 import fasteners
1294
1295-from datetime import datetime
1296-from duplicity import asyncscheduler
1297+from duplicity import log
1298+log.setup()
1299+
1300+import duplicity.errors
1301+
1302 from duplicity import collections
1303 from duplicity import commandline
1304 from duplicity import diffdir
1305@@ -57,17 +70,23 @@
1306 from duplicity import file_naming
1307 from duplicity import globals
1308 from duplicity import gpg
1309-from duplicity import log
1310 from duplicity import manifest
1311 from duplicity import patchdir
1312 from duplicity import path
1313-from duplicity import progress
1314 from duplicity import robust
1315 from duplicity import tempdir
1316+from duplicity import asyncscheduler
1317 from duplicity import util
1318-
1319+from duplicity import progress
1320+
1321+
1322+<<<<<<< TREE
1323 if u'--pydevd' in sys.argv or os.getenv(u'PYDEVD', None):
1324 import pydevd # pylint: disable=import-error
1325+=======
1326+if '--pydevd' in sys.argv or os.getenv('PYDEVD', None):
1327+ import pydevd # @UnresolvedImport
1328+>>>>>>> MERGE-SOURCE
1329 pydevd.settrace()
1330 # In a dev environment the path is screwed so fix it.
1331 base = sys.path.pop(0)
1332@@ -75,8 +94,6 @@
1333 base = os.path.sep.join(base)
1334 sys.path.insert(0, base)
1335
1336-log.setup()
1337-
1338 # If exit_val is not None, exit with given value at end.
1339 exit_val = None
1340
1341@@ -317,10 +334,31 @@
1342 return start_index, start_block, end_index, end_block
1343
1344 def validate_block(orig_size, dest_filename):
1345+<<<<<<< TREE
1346 info = backend.query_info([dest_filename])[dest_filename]
1347 size = info[u'size']
1348 if size is None:
1349 return # error querying file
1350+=======
1351+ """
1352+ Compare the remote size to the local one to ensure the transfer went
1353+ through.
1354+ Try to get the remote size 3 times because some systems take a little
1355+ time before they report the size accurately.
1356+ """
1357+ for attempt in range(0, globals.num_retries):
1358+ info = backend.query_info([dest_filename])[dest_filename]
1359+ size = info['size']
1360+ if size == orig_size:
1361+ break
1362+ if size is None:
1363+ return
1364+ log.Notice(_("Remote filesize %d for %s does not match local size %d, retrying.") %
1365+ (0 if size is None else size,
1366+ util.escape(dest_filename),
1367+ orig_size))
1368+ time.sleep(1 + (attempt * 0.5))
1369+>>>>>>> MERGE-SOURCE
1370 if size != orig_size:
1371 code_extra = u"%s %d %d" % (util.escape(dest_filename), orig_size, size)
1372 log.FatalError(_(u"File %s was corrupted during upload.") % util.fsdecode(dest_filename),
1373@@ -465,7 +503,6 @@
1374
1375 # Upload the collection summary.
1376 # bytes_written += write_manifest(mf, backup_type, backend)
1377- mf.set_files_changed_info(diffdir.stats.get_delta_entries_file())
1378
1379 return bytes_written
1380
1381@@ -474,7 +511,7 @@
1382 u"""
1383 Return a fileobj opened for writing, save results as manifest
1384
1385- Save manifest in globals.archive_dir_path gzipped.
1386+ Save manifest in globals.archive_dir gzipped.
1387 Save them on the backend encrypted as needed.
1388
1389 @type man_type: string
1390@@ -494,7 +531,7 @@
1391 manifest=True,
1392 encrypted=globals.encryption)
1393
1394- fh = dup_temp.get_fileobj_duppath(globals.archive_dir_path,
1395+ fh = dup_temp.get_fileobj_duppath(globals.archive_dir,
1396 part_man_filename,
1397 perm_man_filename,
1398 remote_man_filename)
1399@@ -524,7 +561,7 @@
1400 remote_sig_filename = file_naming.get(sig_type, encrypted=globals.encryption,
1401 gzipped=globals.compression)
1402
1403- fh = dup_temp.get_fileobj_duppath(globals.archive_dir_path,
1404+ fh = dup_temp.get_fileobj_duppath(globals.archive_dir,
1405 part_sig_filename,
1406 perm_sig_filename,
1407 remote_sig_filename,
1408@@ -533,8 +570,13 @@
1409
1410
1411 def full_backup(col_stats):
1412+<<<<<<< TREE
1413 u"""
1414 Do full backup of directory to backend, using archive_dir_path
1415+=======
1416+ """
1417+ Do full backup of directory to backend, using archive_dir
1418+>>>>>>> MERGE-SOURCE
1419
1420 @type col_stats: CollectionStatus object
1421 @param col_stats: collection status
1422@@ -622,8 +664,13 @@
1423
1424
1425 def incremental_backup(sig_chain):
1426+<<<<<<< TREE
1427 u"""
1428 Do incremental backup of directory to backend, using archive_dir_path
1429+=======
1430+ """
1431+ Do incremental backup of directory to backend, using archive_dir
1432+>>>>>>> MERGE-SOURCE
1433
1434 @rtype: void
1435 @return: void
1436@@ -836,6 +883,7 @@
1437 def check_signature():
1438 u"""Thunk run when closing volume file"""
1439 actual_sig = fileobj.fileobj.get_signature()
1440+<<<<<<< TREE
1441 actual_sig = u"None" if actual_sig is None else actual_sig
1442 sign_key = globals.gpg_profile.sign_key
1443 sign_key = u"None" if sign_key is None else sign_key
1444@@ -843,6 +891,15 @@
1445 if actual_sig[ofs:] != sign_key[ofs:]:
1446 log.FatalError(_(u"Volume was signed by key %s, not %s") %
1447 (actual_sig[ofs:], sign_key[ofs:]),
1448+=======
1449+ actual_sig = "None" if actual_sig is None else actual_sig
1450+ sign_key = globals.gpg_profile.sign_key
1451+ sign_key = "None" if sign_key is None else sign_key
1452+ ofs = -min(len(actual_sig), len(sign_key))
1453+ if actual_sig[ofs:] != sign_key[ofs:]:
1454+ log.FatalError(_("Volume was signed by key %s, not %s") %
1455+ (actual_sig[ofs:], sign_key[ofs:]),
1456+>>>>>>> MERGE-SOURCE
1457 log.ErrorCode.unsigned_volume)
1458
1459 fileobj.addhook(check_signature)
1460@@ -907,7 +964,7 @@
1461 col_stats.backend.delete(ext_remote)
1462 for fn in ext_local:
1463 try:
1464- globals.archive_dir_path.append(fn).delete()
1465+ globals.archive_dir.append(fn).delete()
1466 except Exception:
1467 pass
1468 else:
1469@@ -1011,6 +1068,7 @@
1470 _(u"Rerun command with --force option to actually delete."))
1471
1472
1473+<<<<<<< TREE
1474 def replicate():
1475 u"""
1476 Replicate backup files from one remote to another, possibly encrypting or adding parity.
1477@@ -1129,6 +1187,10 @@
1478
1479 def sync_archive():
1480 u"""
1481+=======
1482+def sync_archive(col_stats):
1483+ """
1484+>>>>>>> MERGE-SOURCE
1485 Synchronize local archive manifest file and sig chains to remote archives.
1486 Copy missing files from remote to local as needed to make sure the local
1487 archive is synchronized to remote storage.
1488@@ -1138,6 +1200,27 @@
1489 """
1490 suffixes = [b".g", b".gpg", b".z", b".gz", b".part"]
1491
1492+ def is_needed(filename):
1493+ """Indicates if the metadata file should be synced.
1494+
1495+ In full sync mode, or if there's a collection misbehavior, all files
1496+ are needed.
1497+
1498+ Otherwise, only the metadata for the target chain needs sync.
1499+ """
1500+ if globals.metadata_sync_mode == "full":
1501+ return True
1502+ assert globals.metadata_sync_mode == "partial"
1503+ parsed = file_naming.parse(filename)
1504+ try:
1505+ target_chain = col_stats.get_backup_chain_at_time(
1506+ globals.restore_time or dup_time.curtime)
1507+ except collections.CollectionsError:
1508+ # With zero or multiple chains at this time, do a full sync
1509+ return True
1510+ return parsed.end_time >= target_chain.start_time and \
1511+ parsed.start_time <= target_chain.end_time
1512+
1513 def get_metafiles(filelist):
1514 u"""
1515 Return metafiles of interest from the file list.
1516@@ -1199,7 +1282,7 @@
1517 return (pr, loc_name, fn)
1518
1519 def remove_local(fn):
1520- del_name = globals.archive_dir_path.append(fn).name
1521+ del_name = globals.archive_dir.append(fn).name
1522
1523 log.Notice(_(u"Deleting local %s (not authoritative at backend).") %
1524 util.fsdecode(del_name))
1525@@ -1266,14 +1349,14 @@
1526 else:
1527 gpg.GzipWriteFile(src_iter, tdp.name, size=sys.maxsize)
1528 tdp.setdata()
1529- tdp.move(globals.archive_dir_path.append(loc_name))
1530+ tdp.move(globals.archive_dir.append(loc_name))
1531
1532 # get remote metafile list
1533 remlist = globals.backend.list()
1534 remote_metafiles, ignored, rem_needpass = get_metafiles(remlist)
1535
1536 # get local metafile list
1537- loclist = globals.archive_dir_path.listdir()
1538+ loclist = globals.archive_dir.listdir()
1539 local_metafiles, local_partials, loc_needpass = get_metafiles(loclist)
1540
1541 # we have the list of metafiles on both sides. remote is always
1542@@ -1284,13 +1367,14 @@
1543
1544 local_missing = []
1545 local_spurious = []
1546+ import pudb; pudb.set_trace()
1547
1548 for key in remote_keys:
1549 # If we lost our cache, re-get the remote file. But don't do it if we
1550 # already have a local partial. The local partial will already be
1551 # complete in this case (seems we got interrupted before we could move
1552 # it to its final location).
1553- if key not in local_keys and key not in local_partials:
1554+ if key not in local_keys and key not in local_partials and is_needed(key):
1555 local_missing.append(remote_metafiles[key])
1556
1557 for key in local_keys:
1558@@ -1496,7 +1580,11 @@
1559 # determine what action we're performing and process command line
1560 action = commandline.ProcessCommandLine(sys.argv[1:])
1561
1562+<<<<<<< TREE
1563 globals.lockpath = os.path.join(globals.archive_dir_path.name, b"lockfile")
1564+=======
1565+ globals.lockpath = os.path.join(globals.archive_dir.name, "lockfile")
1566+>>>>>>> MERGE-SOURCE
1567 globals.lockfile = fasteners.process_lock.InterProcessLock(globals.lockpath)
1568 log.Debug(_(u"Acquiring lockfile %s") % globals.lockpath)
1569 if not globals.lockfile.acquire(blocking=False):
1570@@ -1526,15 +1614,22 @@
1571 # check for disk space and available file handles
1572 check_resources(action)
1573
1574+<<<<<<< TREE
1575 # check archive synch with remote, fix if needed
1576 if action not in [u"collection-status", u"replicate"]:
1577 sync_archive()
1578
1579+=======
1580+>>>>>>> MERGE-SOURCE
1581 # get current collection status
1582 col_stats = collections.CollectionsStatus(globals.backend,
1583- globals.archive_dir_path,
1584+ globals.archive_dir,
1585 action).set_values()
1586
1587+ # check archive synch with remote, fix if needed
1588+ if action not in ["collection-status"]:
1589+ sync_archive(col_stats)
1590+
1591 while True:
1592 # if we have to clean up the last partial, then col_stats are invalidated
1593 # and we have to start the process all over again until clean.
1594@@ -1563,7 +1658,7 @@
1595 log.Notice(_(u"Cleaning up previous partial %s backup set, restarting." % action))
1596 last_backup.delete()
1597 col_stats = collections.CollectionsStatus(globals.backend,
1598- globals.archive_dir_path,
1599+ globals.archive_dir,
1600 action).set_values()
1601 continue
1602 break
1603@@ -1592,21 +1687,32 @@
1604 verify(col_stats)
1605 elif action == u"list-current":
1606 list_current(col_stats)
1607+<<<<<<< TREE
1608 elif action == u"collection-status":
1609 if not globals.file_changed:
1610 log.PrintCollectionStatus(col_stats, True)
1611 else:
1612 log.PrintCollectionFileChangedStatus(col_stats, globals.file_changed, True)
1613 elif action == u"cleanup":
1614+=======
1615+ elif action == "collection-status":
1616+ log.PrintCollectionStatus(col_stats, True)
1617+ elif action == "cleanup":
1618+>>>>>>> MERGE-SOURCE
1619 cleanup(col_stats)
1620 elif action == u"remove-old":
1621 remove_old(col_stats)
1622 elif action == u"remove-all-but-n-full" or action == u"remove-all-inc-of-but-n-full":
1623 remove_all_but_n_full(col_stats)
1624+<<<<<<< TREE
1625 elif action == u"sync":
1626 sync_archive()
1627 elif action == u"replicate":
1628 replicate()
1629+=======
1630+ elif action == "sync":
1631+ sync_archive(col_stats)
1632+>>>>>>> MERGE-SOURCE
1633 else:
1634 assert action == u"inc" or action == u"full", action
1635 # the passphrase for full and inc is used by --sign-key
1636@@ -1665,8 +1771,13 @@
1637 finally:
1638 tempdir.default().cleanup()
1639
1640+<<<<<<< TREE
1641
1642 if __name__ == u"__main__":
1643+=======
1644+
1645+if __name__ == "__main__":
1646+>>>>>>> MERGE-SOURCE
1647 try:
1648
1649 # import cProfile
1650@@ -1703,8 +1814,13 @@
1651 # For gpg errors, don't show an ugly stack trace by
1652 # default. But do with sufficient verbosity.
1653 util.release_lockfile()
1654+<<<<<<< TREE
1655 log.Info(_(u"GPG error detail: %s")
1656 % util.exception_traceback())
1657+=======
1658+ log.Info(_("GPG error detail: %s")
1659+ % util.exception_traceback())
1660+>>>>>>> MERGE-SOURCE
1661 log.FatalError(u"%s: %s" % (e.__class__.__name__, e.args[0]),
1662 log.ErrorCode.gpg_failed,
1663 e.__class__.__name__)
1664@@ -1713,8 +1829,13 @@
1665 util.release_lockfile()
1666 # For user errors, don't show an ugly stack trace by
1667 # default. But do with sufficient verbosity.
1668+<<<<<<< TREE
1669 log.Info(_(u"User error detail: %s")
1670 % util.exception_traceback())
1671+=======
1672+ log.Info(_("User error detail: %s")
1673+ % util.exception_traceback())
1674+>>>>>>> MERGE-SOURCE
1675 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),
1676 log.ErrorCode.user_error,
1677 e.__class__.__name__)
1678@@ -1723,15 +1844,24 @@
1679 util.release_lockfile()
1680 # For backend errors, don't show an ugly stack trace by
1681 # default. But do with sufficient verbosity.
1682+<<<<<<< TREE
1683 log.Info(_(u"Backend error detail: %s")
1684 % util.exception_traceback())
1685+=======
1686+ log.Info(_("Backend error detail: %s")
1687+ % util.exception_traceback())
1688+>>>>>>> MERGE-SOURCE
1689 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),
1690 log.ErrorCode.user_error,
1691 e.__class__.__name__)
1692
1693 except Exception as e:
1694 util.release_lockfile()
1695+<<<<<<< TREE
1696 if u"Forced assertion for testing" in util.uexc(e):
1697+=======
1698+ if "Forced assertion for testing" in util.uexc(e):
1699+>>>>>>> MERGE-SOURCE
1700 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),
1701 log.ErrorCode.exception,
1702 e.__class__.__name__)
1703
1704=== modified file 'bin/duplicity.1'
1705--- bin/duplicity.1 2019-03-16 19:29:24 +0000
1706+++ bin/duplicity.1 2019-04-22 12:43:18 +0000
1707@@ -21,7 +21,7 @@
1708 source_url target_directory
1709
1710 .B duplicity collection-status
1711-.I [options] [--file-changed <relpath>]
1712+.I [options]
1713 target_url
1714
1715 .B duplicity list-current-files
1716@@ -48,10 +48,6 @@
1717 .I [options] [--force] [--extra-clean]
1718 target_url
1719
1720-.B duplicity replicate
1721-.I [options] [--time time]
1722-source_url target_url
1723-
1724 .SH DESCRIPTION
1725 Duplicity incrementally backs up files and folders into
1726 tar-format volumes encrypted with GnuPG and places them to a
1727@@ -168,28 +164,23 @@
1728
1729 .TP
1730 .BI "verify " "[--compare-data] [--time <time>] [--file-to-restore <rel_path>] <url> <local_path>"
1731-Verify tests the integrity of the backup archives at the remote location by downloading each file
1732-and checking both that it can restore the archive and that the restored file matches the signature
1733-of that file stored in the backup, i.e. compares the archived file with its hash value from archival
1734-time. Verify does not actually restore and will not overwrite any local files. Duplicity
1735-will exit with a non-zero error level if any files do not match the signature stored in the archive
1736-for that file. On verbosity level 4 or higher, it will log a message for each file that differs
1737-from the stored signature. Files must be downloaded to the local machine in order to compare them.
1738-Verify does not compare the backed-up version of the file to the current local copy of the files
1739-unless the --compare-data option is used (see below).
1740+Restore backup contents temporarily file by file and compare against the local path's contents.
1741+duplicity will exit with a non-zero error level if any files are different.
1742+On verbosity level info (4) or higher, a message for each file that has
1743+changed will be logged.
1744 .br
1745 The
1746 .I --file-to-restore
1747 option restricts verify to that file or folder.
1748 The
1749 .I --time
1750-option allows to select a backup to verify.
1751+option allows to select a backup to verify against.
1752 The
1753 .I --compare-data
1754 option enables data comparison (see below).
1755
1756 .TP
1757-.BI "collection-status " "[--file-changed <relpath>]" "<url>"
1758+.BI "collection-status " "<url>"
1759 Summarize the status of the backup repository by printing the chains
1760 and sets found, and the number of volumes in each.
1761
1762@@ -252,19 +243,6 @@
1763 .I --force
1764 will be needed to delete the files instead of just listing them.
1765
1766-.TP
1767-.BI "replicate " "[--time time] <source_url> <target_url>"
1768-Replicate backup sets from source to target backend. Files will be
1769-(re)-encrypted and (re)-compressed depending on normal backend
1770-options. Signatures and volumes will not get recomputed, thus options like
1771-.BI --volsize
1772-or
1773-.BI --max-blocksize
1774-have no effect.
1775-When
1776-.I --time time
1777-is given, only backup sets older than time will be replicated.
1778-
1779 .SH OPTIONS
1780
1781 .TP
1782@@ -349,14 +327,8 @@
1783
1784 .TP
1785 .BI --compare-data
1786-Enable data comparison of regular files on action verify. This conducts a
1787-verify as described above to verify the integrity of the backup archives,
1788-but additionally compares restored files to those in target_directory.
1789-Duplicity will not replace any files in target_directory. Duplicity will
1790-exit with a non-zero error level if the files do not correctly verify or
1791-if any files from the archive differ from those in target_directory. On
1792-verbosity level 4 or higher, it will log a message for each file that
1793-differs from its equivalent in target_directory.
1794+Enable data comparison of regular files on action verify.
1795+This is disabled by default for performance reasons.
1796
1797 .TP
1798 .BI --copy-links
1799@@ -465,15 +437,6 @@
1800 argument for more information.
1801
1802 .TP
1803-.BI "--file-changed " path
1804-This option may be given in collection-status mode, causing only
1805-.I path
1806-status to be collect instead of the entire contents of the backup archive.
1807-.I path
1808-should be given relative to the root of the directory backed up.
1809-
1810-
1811-.TP
1812 .BI "--file-prefix, --file-prefix-manifest, --file-prefix-archive, --file-prefix-signature
1813 Adds a prefix to all files, manifest files, archive files, and/or signature files.
1814
1815@@ -816,6 +779,7 @@
1816 when uploading to S3 to ensure you kill connections to slow S3 endpoints.
1817
1818 .TP
1819+<<<<<<< TREE
1820 .BI "--azure-blob-tier"
1821 Standard storage tier used for backup files (Hot|Cool|Archive).
1822
1823@@ -839,6 +803,8 @@
1824 blob size exceeds 64MB. The default values is 2.
1825
1826 .TP
1827+=======
1828+>>>>>>> MERGE-SOURCE
1829 .BI "--scp-command " command
1830 .B (only ssh pexpect backend with --use-scp enabled)
1831 The
1832@@ -948,11 +914,12 @@
1833 .BR "A NOTE ON SSL CERTIFICATE VERIFICATION" .
1834
1835 .TP
1836-.BI --swift-storage-policy
1837-Use this storage policy when operating on Swift containers.
1838-.br
1839-See also
1840-.BR "A NOTE ON SWIFT (OPENSTACK OBJECT STORAGE) ACCESS" .
1841+.BI "--metadata-sync-mode " mode
1842+This option defaults to 'full', but you can set it to 'partial'
1843+to avoid syncing metadata for backup chains that you are not going to use.
1844+This saves time when restoring for the first time, and lets you restore an
1845+old backup that was encrypted with a different passphrase by supplying only
1846+the target passphrase.
1847
1848 .TP
1849 .BI "--tempdir " directory
1850@@ -1093,15 +1060,6 @@
1851 Formats of each of the URL schemes follow:
1852
1853 .PP
1854-.B "Amazon Drive Backend"
1855-.PP
1856-.RS
1857-ad://some_dir
1858-.PP
1859-See also
1860-.B "A NOTE ON AMAZON DRIVE"
1861-.RE
1862-.PP
1863 .BR "Azure"
1864 .PP
1865 .RS
1866@@ -1266,15 +1224,6 @@
1867 .B "A NOTE ON SWIFT (OPENSTACK OBJECT STORAGE) ACCESS"
1868 .RE
1869 .PP
1870-.BR "Public Cloud Archive" " (OVH)"
1871-.PP
1872-.RS
1873-pca://container_name[/prefix]
1874-.PP
1875-See also
1876-.B "A NOTE ON PCA ACCESS"
1877-.RE
1878-.PP
1879 .B "Tahoe-LAFS"
1880 .PP
1881 .RS
1882@@ -1584,25 +1533,6 @@
1883 which aren't followed by 'foo'. However, it wouldn't match /home even
1884 if /home/ben/1234567 existed.
1885
1886-.SH A NOTE ON AMAZON DRIVE
1887-.IP 1.
1888-The API Keys used for Amazon Drive have not been granted production limits.
1889-Amazon do not say what the development limits are and are not replying to
1890-to requests to whitelist duplicity. A related tool, acd_cli, was demoted to
1891-development limits, but continues to work fine except for cases of excessive
1892-usage. If you experience throttling and similar issues with Amazon Drive using
1893-this backend, please report them to the mailing list.
1894-.IR
1895-.IP 2.
1896-If you previously used the
1897-.BI acd+acdcli
1898-backend, it is strongly recommended to update to the
1899-.BI ad
1900-backend instead, since it interfaces directly with Amazon Drive. You will need
1901-to setup the OAuth once again, but can otherwise keep your backups and config.
1902-.IR
1903-.RE
1904-
1905 .SH A NOTE ON AZURE ACCESS
1906 The Azure backend requires the Microsoft Azure Storage SDK for Python to be
1907 installed on the system.
1908@@ -1610,13 +1540,9 @@
1909 .B REQUIREMENTS
1910 above.
1911
1912-It uses environment variables for authentification:
1913+It uses two environment variables for authentification:
1914 .BR AZURE_ACCOUNT_NAME " (required),"
1915-.BR AZURE_ACCOUNT_KEY " (optional),
1916-.BR AZURE_SHARED_ACCESS_SIGNATURE " (optional)."
1917-One of
1918-.BR AZURE_ACCOUNT_KEY " or"
1919-.BR AZURE_SHARED_ACCESS_SIGNATURE " is required."
1920+.BR AZURE_ACCOUNT_KEY " (required)"
1921
1922 A container name must be a valid DNS name, conforming to the following naming
1923 rules:
1924@@ -1753,13 +1679,8 @@
1925
1926 .SH A NOTE ON FILENAME PREFIXES
1927
1928-Filename prefixes can be used in
1929-.B "multi backend "
1930-with
1931-.B "mirror "
1932-mode to define affinity rules. They can also be used in conjunction with
1933-S3 lifecycle rules to transition archive files to Glacier, while keeping
1934-metadata (signature and manifest files) on S3.
1935+Filename prefixes can be used in conjunction with S3 lifecycle rules to transition
1936+archive files to Glacier, while keeping metadata (signature and manifest files) on S3.
1937
1938 Duplicity does not require access to archive files except when restoring from backup.
1939
1940@@ -1876,8 +1797,7 @@
1941 "name" : "FOO",
1942 "value" : "bar"
1943 }
1944- ],
1945- "prefixes": ["prefix1_", "prefix2_"]
1946+ ]
1947 },
1948 {
1949 "url": "file:///path/to/dir"
1950@@ -2093,40 +2013,6 @@
1951 .B SWIFT_AUTHVERSION
1952 is unspecified, it will default to version 1.
1953
1954-.SH A NOTE ON PCA ACCESS
1955-PCA is a long-term data archival solution by OVH. It runs a slightly modified
1956-version of Openstack Swift introducing latency in the data retrieval process.
1957-It is a good pick for a
1958-.BR "multi backend "
1959-configuration where receiving volumes while an other backend is used to store
1960-manifests and signatures.
1961-
1962-.br
1963-The backend requires python-switclient to be installed on the system.
1964-python-keystoneclient is also needed to interact with OpenStack's Keystone
1965-Identity service.
1966-See
1967-.B REQUIREMENTS
1968-above.
1969-
1970-It uses following environment variables for authentification:
1971-.BR PCA_USERNAME " (required),"
1972-.BR PCA_PASSWORD " (required),"
1973-.BR PCA_AUTHURL " (required),"
1974-.BR PCA_USERID " (optional),"
1975-.BR PCA_TENANTID " (optional, but either the tenant name or tenant id must be supplied)"
1976-.BR PCA_REGIONNAME " (optional),"
1977-.BR PCA_TENANTNAME " (optional, but either the tenant name or tenant id must be supplied)"
1978-
1979-If the user was previously authenticated, the following environment
1980-variables can be used instead:
1981-.BR PCA_PREAUTHURL " (required),"
1982-.BR PCA_PREAUTHTOKEN " (required)"
1983-
1984-If
1985-.B PCA_AUTHVERSION
1986-is unspecified, it will default to version 2.
1987-
1988 .SH A NOTE ON MEDIAFIRE BACKEND
1989 This backend requires
1990 .B mediafire
1991@@ -2237,13 +2123,6 @@
1992
1993 Some backends also require additional components (probably available as packages for your specific platform):
1994 .TP
1995-.BR "Amazon Drive backend"
1996-.B python-requests
1997-- http://python-requests.org
1998-.br
1999-.B python-requests-oauthlib
2000-- https://github.com/requests/requests-oauthlib
2001-.TP
2002 .BR "azure backend" " (Azure Blob Storage Service)"
2003 .B Microsoft Azure Storage SDK for Python
2004 - https://pypi.python.org/pypi/azure-storage/
2005
2006=== modified file 'debian/control'
2007=== renamed file 'docs/Makefile' => 'docs/Makefile.THIS'
2008=== removed directory 'docs/_static'
2009=== removed directory 'docs/_templates'
2010=== renamed file 'docs/conf.py' => 'docs/conf.py.THIS'
2011=== removed file 'docs/duplicity.asyncscheduler.rst'
2012--- docs/duplicity.asyncscheduler.rst 2018-07-24 16:17:12 +0000
2013+++ docs/duplicity.asyncscheduler.rst 1970-01-01 00:00:00 +0000
2014@@ -1,7 +0,0 @@
2015-duplicity.asyncscheduler module
2016-===============================
2017-
2018-.. automodule:: duplicity.asyncscheduler
2019- :members:
2020- :undoc-members:
2021- :show-inheritance:
2022
2023=== removed file 'docs/duplicity.backend.rst'
2024--- docs/duplicity.backend.rst 2018-07-24 16:17:12 +0000
2025+++ docs/duplicity.backend.rst 1970-01-01 00:00:00 +0000
2026@@ -1,7 +0,0 @@
2027-duplicity.backend module
2028-========================
2029-
2030-.. automodule:: duplicity.backend
2031- :members:
2032- :undoc-members:
2033- :show-inheritance:
2034
2035=== removed file 'docs/duplicity.backends.azurebackend.rst'
2036--- docs/duplicity.backends.azurebackend.rst 2018-07-24 16:17:12 +0000
2037+++ docs/duplicity.backends.azurebackend.rst 1970-01-01 00:00:00 +0000
2038@@ -1,7 +0,0 @@
2039-duplicity.backends.azurebackend module
2040-======================================
2041-
2042-.. automodule:: duplicity.backends.azurebackend
2043- :members:
2044- :undoc-members:
2045- :show-inheritance:
2046
2047=== removed file 'docs/duplicity.backends.b2backend.rst'
2048--- docs/duplicity.backends.b2backend.rst 2018-07-24 16:17:12 +0000
2049+++ docs/duplicity.backends.b2backend.rst 1970-01-01 00:00:00 +0000
2050@@ -1,7 +0,0 @@
2051-duplicity.backends.b2backend module
2052-===================================
2053-
2054-.. automodule:: duplicity.backends.b2backend
2055- :members:
2056- :undoc-members:
2057- :show-inheritance:
2058
2059=== removed file 'docs/duplicity.backends.botobackend.rst'
2060--- docs/duplicity.backends.botobackend.rst 2018-07-24 16:17:12 +0000
2061+++ docs/duplicity.backends.botobackend.rst 1970-01-01 00:00:00 +0000
2062@@ -1,7 +0,0 @@
2063-duplicity.backends.botobackend module
2064-=====================================
2065-
2066-.. automodule:: duplicity.backends.botobackend
2067- :members:
2068- :undoc-members:
2069- :show-inheritance:
2070
2071=== removed file 'docs/duplicity.backends.cfbackend.rst'
2072--- docs/duplicity.backends.cfbackend.rst 2018-07-24 16:17:12 +0000
2073+++ docs/duplicity.backends.cfbackend.rst 1970-01-01 00:00:00 +0000
2074@@ -1,7 +0,0 @@
2075-duplicity.backends.cfbackend module
2076-===================================
2077-
2078-.. automodule:: duplicity.backends.cfbackend
2079- :members:
2080- :undoc-members:
2081- :show-inheritance:
2082
2083=== removed file 'docs/duplicity.backends.dpbxbackend.rst'
2084--- docs/duplicity.backends.dpbxbackend.rst 2018-07-24 16:17:12 +0000
2085+++ docs/duplicity.backends.dpbxbackend.rst 1970-01-01 00:00:00 +0000
2086@@ -1,7 +0,0 @@
2087-duplicity.backends.dpbxbackend module
2088-=====================================
2089-
2090-.. automodule:: duplicity.backends.dpbxbackend
2091- :members:
2092- :undoc-members:
2093- :show-inheritance:
2094
2095=== removed file 'docs/duplicity.backends.gdocsbackend.rst'
2096--- docs/duplicity.backends.gdocsbackend.rst 2018-07-24 16:17:12 +0000
2097+++ docs/duplicity.backends.gdocsbackend.rst 1970-01-01 00:00:00 +0000
2098@@ -1,7 +0,0 @@
2099-duplicity.backends.gdocsbackend module
2100-======================================
2101-
2102-.. automodule:: duplicity.backends.gdocsbackend
2103- :members:
2104- :undoc-members:
2105- :show-inheritance:
2106
2107=== removed file 'docs/duplicity.backends.giobackend.rst'
2108--- docs/duplicity.backends.giobackend.rst 2018-07-24 16:17:12 +0000
2109+++ docs/duplicity.backends.giobackend.rst 1970-01-01 00:00:00 +0000
2110@@ -1,7 +0,0 @@
2111-duplicity.backends.giobackend module
2112-====================================
2113-
2114-.. automodule:: duplicity.backends.giobackend
2115- :members:
2116- :undoc-members:
2117- :show-inheritance:
2118
2119=== removed file 'docs/duplicity.backends.hsibackend.rst'
2120--- docs/duplicity.backends.hsibackend.rst 2018-07-24 16:17:12 +0000
2121+++ docs/duplicity.backends.hsibackend.rst 1970-01-01 00:00:00 +0000
2122@@ -1,7 +0,0 @@
2123-duplicity.backends.hsibackend module
2124-====================================
2125-
2126-.. automodule:: duplicity.backends.hsibackend
2127- :members:
2128- :undoc-members:
2129- :show-inheritance:
2130
2131=== removed file 'docs/duplicity.backends.hubicbackend.rst'
2132--- docs/duplicity.backends.hubicbackend.rst 2018-07-24 16:17:12 +0000
2133+++ docs/duplicity.backends.hubicbackend.rst 1970-01-01 00:00:00 +0000
2134@@ -1,7 +0,0 @@
2135-duplicity.backends.hubicbackend module
2136-======================================
2137-
2138-.. automodule:: duplicity.backends.hubicbackend
2139- :members:
2140- :undoc-members:
2141- :show-inheritance:
2142
2143=== removed file 'docs/duplicity.backends.imapbackend.rst'
2144--- docs/duplicity.backends.imapbackend.rst 2018-07-24 16:17:12 +0000
2145+++ docs/duplicity.backends.imapbackend.rst 1970-01-01 00:00:00 +0000
2146@@ -1,7 +0,0 @@
2147-duplicity.backends.imapbackend module
2148-=====================================
2149-
2150-.. automodule:: duplicity.backends.imapbackend
2151- :members:
2152- :undoc-members:
2153- :show-inheritance:
2154
2155=== removed file 'docs/duplicity.backends.lftpbackend.rst'
2156--- docs/duplicity.backends.lftpbackend.rst 2018-07-24 16:17:12 +0000
2157+++ docs/duplicity.backends.lftpbackend.rst 1970-01-01 00:00:00 +0000
2158@@ -1,7 +0,0 @@
2159-duplicity.backends.lftpbackend module
2160-=====================================
2161-
2162-.. automodule:: duplicity.backends.lftpbackend
2163- :members:
2164- :undoc-members:
2165- :show-inheritance:
2166
2167=== removed file 'docs/duplicity.backends.localbackend.rst'
2168--- docs/duplicity.backends.localbackend.rst 2018-07-24 16:17:12 +0000
2169+++ docs/duplicity.backends.localbackend.rst 1970-01-01 00:00:00 +0000
2170@@ -1,7 +0,0 @@
2171-duplicity.backends.localbackend module
2172-======================================
2173-
2174-.. automodule:: duplicity.backends.localbackend
2175- :members:
2176- :undoc-members:
2177- :show-inheritance:
2178
2179=== removed file 'docs/duplicity.backends.mediafirebackend.rst'
2180--- docs/duplicity.backends.mediafirebackend.rst 2018-07-24 16:17:12 +0000
2181+++ docs/duplicity.backends.mediafirebackend.rst 1970-01-01 00:00:00 +0000
2182@@ -1,7 +0,0 @@
2183-duplicity.backends.mediafirebackend module
2184-==========================================
2185-
2186-.. automodule:: duplicity.backends.mediafirebackend
2187- :members:
2188- :undoc-members:
2189- :show-inheritance:
2190
2191=== removed file 'docs/duplicity.backends.megabackend.rst'
2192--- docs/duplicity.backends.megabackend.rst 2018-07-24 16:17:12 +0000
2193+++ docs/duplicity.backends.megabackend.rst 1970-01-01 00:00:00 +0000
2194@@ -1,7 +0,0 @@
2195-duplicity.backends.megabackend module
2196-=====================================
2197-
2198-.. automodule:: duplicity.backends.megabackend
2199- :members:
2200- :undoc-members:
2201- :show-inheritance:
2202
2203=== removed file 'docs/duplicity.backends.multibackend.rst'
2204--- docs/duplicity.backends.multibackend.rst 2018-07-24 16:17:12 +0000
2205+++ docs/duplicity.backends.multibackend.rst 1970-01-01 00:00:00 +0000
2206@@ -1,7 +0,0 @@
2207-duplicity.backends.multibackend module
2208-======================================
2209-
2210-.. automodule:: duplicity.backends.multibackend
2211- :members:
2212- :undoc-members:
2213- :show-inheritance:
2214
2215=== removed file 'docs/duplicity.backends.ncftpbackend.rst'
2216--- docs/duplicity.backends.ncftpbackend.rst 2018-07-24 16:17:12 +0000
2217+++ docs/duplicity.backends.ncftpbackend.rst 1970-01-01 00:00:00 +0000
2218@@ -1,7 +0,0 @@
2219-duplicity.backends.ncftpbackend module
2220-======================================
2221-
2222-.. automodule:: duplicity.backends.ncftpbackend
2223- :members:
2224- :undoc-members:
2225- :show-inheritance:
2226
2227=== removed file 'docs/duplicity.backends.onedrivebackend.rst'
2228--- docs/duplicity.backends.onedrivebackend.rst 2018-07-24 16:17:12 +0000
2229+++ docs/duplicity.backends.onedrivebackend.rst 1970-01-01 00:00:00 +0000
2230@@ -1,7 +0,0 @@
2231-duplicity.backends.onedrivebackend module
2232-=========================================
2233-
2234-.. automodule:: duplicity.backends.onedrivebackend
2235- :members:
2236- :undoc-members:
2237- :show-inheritance:
2238
2239=== removed file 'docs/duplicity.backends.par2backend.rst'
2240--- docs/duplicity.backends.par2backend.rst 2018-07-24 16:17:12 +0000
2241+++ docs/duplicity.backends.par2backend.rst 1970-01-01 00:00:00 +0000
2242@@ -1,7 +0,0 @@
2243-duplicity.backends.par2backend module
2244-=====================================
2245-
2246-.. automodule:: duplicity.backends.par2backend
2247- :members:
2248- :undoc-members:
2249- :show-inheritance:
2250
2251=== removed file 'docs/duplicity.backends.pydrivebackend.rst'
2252--- docs/duplicity.backends.pydrivebackend.rst 2018-07-24 16:17:12 +0000
2253+++ docs/duplicity.backends.pydrivebackend.rst 1970-01-01 00:00:00 +0000
2254@@ -1,7 +0,0 @@
2255-duplicity.backends.pydrivebackend module
2256-========================================
2257-
2258-.. automodule:: duplicity.backends.pydrivebackend
2259- :members:
2260- :undoc-members:
2261- :show-inheritance:
2262
2263=== renamed file 'docs/duplicity.backends.pyrax_identity.hubic.rst' => 'docs/duplicity.backends.pyrax_identity.hubic.rst.THIS'
2264=== renamed file 'docs/duplicity.backends.pyrax_identity.rst' => 'docs/duplicity.backends.pyrax_identity.rst.THIS'
2265=== renamed file 'docs/duplicity.backends.rst' => 'docs/duplicity.backends.rst.THIS'
2266=== removed file 'docs/duplicity.backends.rsyncbackend.rst'
2267--- docs/duplicity.backends.rsyncbackend.rst 2018-07-24 16:17:12 +0000
2268+++ docs/duplicity.backends.rsyncbackend.rst 1970-01-01 00:00:00 +0000
2269@@ -1,7 +0,0 @@
2270-duplicity.backends.rsyncbackend module
2271-======================================
2272-
2273-.. automodule:: duplicity.backends.rsyncbackend
2274- :members:
2275- :undoc-members:
2276- :show-inheritance:
2277
2278=== renamed file 'docs/duplicity.backends.ssh_paramiko_backend.rst' => 'docs/duplicity.backends.ssh_paramiko_backend.rst.THIS'
2279=== renamed file 'docs/duplicity.backends.ssh_pexpect_backend.rst' => 'docs/duplicity.backends.ssh_pexpect_backend.rst.THIS'
2280=== removed file 'docs/duplicity.backends.swiftbackend.rst'
2281--- docs/duplicity.backends.swiftbackend.rst 2018-07-24 16:17:12 +0000
2282+++ docs/duplicity.backends.swiftbackend.rst 1970-01-01 00:00:00 +0000
2283@@ -1,7 +0,0 @@
2284-duplicity.backends.swiftbackend module
2285-======================================
2286-
2287-.. automodule:: duplicity.backends.swiftbackend
2288- :members:
2289- :undoc-members:
2290- :show-inheritance:
2291
2292=== removed file 'docs/duplicity.backends.sxbackend.rst'
2293--- docs/duplicity.backends.sxbackend.rst 2018-07-24 16:17:12 +0000
2294+++ docs/duplicity.backends.sxbackend.rst 1970-01-01 00:00:00 +0000
2295@@ -1,7 +0,0 @@
2296-duplicity.backends.sxbackend module
2297-===================================
2298-
2299-.. automodule:: duplicity.backends.sxbackend
2300- :members:
2301- :undoc-members:
2302- :show-inheritance:
2303
2304=== removed file 'docs/duplicity.backends.tahoebackend.rst'
2305--- docs/duplicity.backends.tahoebackend.rst 2018-07-24 16:17:12 +0000
2306+++ docs/duplicity.backends.tahoebackend.rst 1970-01-01 00:00:00 +0000
2307@@ -1,7 +0,0 @@
2308-duplicity.backends.tahoebackend module
2309-======================================
2310-
2311-.. automodule:: duplicity.backends.tahoebackend
2312- :members:
2313- :undoc-members:
2314- :show-inheritance:
2315
2316=== removed file 'docs/duplicity.backends.webdavbackend.rst'
2317--- docs/duplicity.backends.webdavbackend.rst 2018-07-24 16:17:12 +0000
2318+++ docs/duplicity.backends.webdavbackend.rst 1970-01-01 00:00:00 +0000
2319@@ -1,7 +0,0 @@
2320-duplicity.backends.webdavbackend module
2321-=======================================
2322-
2323-.. automodule:: duplicity.backends.webdavbackend
2324- :members:
2325- :undoc-members:
2326- :show-inheritance:
2327
2328=== renamed file 'docs/duplicity.cached_ops.rst' => 'docs/duplicity.cached_ops.rst.THIS'
2329=== removed file 'docs/duplicity.collections.rst'
2330--- docs/duplicity.collections.rst 2018-07-24 16:17:12 +0000
2331+++ docs/duplicity.collections.rst 1970-01-01 00:00:00 +0000
2332@@ -1,7 +0,0 @@
2333-duplicity.collections module
2334-============================
2335-
2336-.. automodule:: duplicity.collections
2337- :members:
2338- :undoc-members:
2339- :show-inheritance:
2340
2341=== removed file 'docs/duplicity.commandline.rst'
2342--- docs/duplicity.commandline.rst 2018-07-24 16:17:12 +0000
2343+++ docs/duplicity.commandline.rst 1970-01-01 00:00:00 +0000
2344@@ -1,7 +0,0 @@
2345-duplicity.commandline module
2346-============================
2347-
2348-.. automodule:: duplicity.commandline
2349- :members:
2350- :undoc-members:
2351- :show-inheritance:
2352
2353=== removed file 'docs/duplicity.diffdir.rst'
2354--- docs/duplicity.diffdir.rst 2018-07-24 16:17:12 +0000
2355+++ docs/duplicity.diffdir.rst 1970-01-01 00:00:00 +0000
2356@@ -1,7 +0,0 @@
2357-duplicity.diffdir module
2358-========================
2359-
2360-.. automodule:: duplicity.diffdir
2361- :members:
2362- :undoc-members:
2363- :show-inheritance:
2364
2365=== renamed file 'docs/duplicity.dup_temp.rst' => 'docs/duplicity.dup_temp.rst.THIS'
2366=== renamed file 'docs/duplicity.dup_threading.rst' => 'docs/duplicity.dup_threading.rst.THIS'
2367=== renamed file 'docs/duplicity.dup_time.rst' => 'docs/duplicity.dup_time.rst.THIS'
2368=== removed file 'docs/duplicity.errors.rst'
2369--- docs/duplicity.errors.rst 2018-07-24 16:17:12 +0000
2370+++ docs/duplicity.errors.rst 1970-01-01 00:00:00 +0000
2371@@ -1,7 +0,0 @@
2372-duplicity.errors module
2373-=======================
2374-
2375-.. automodule:: duplicity.errors
2376- :members:
2377- :undoc-members:
2378- :show-inheritance:
2379
2380=== renamed file 'docs/duplicity.file_naming.rst' => 'docs/duplicity.file_naming.rst.THIS'
2381=== removed file 'docs/duplicity.filechunkio.rst'
2382--- docs/duplicity.filechunkio.rst 2018-07-24 16:17:12 +0000
2383+++ docs/duplicity.filechunkio.rst 1970-01-01 00:00:00 +0000
2384@@ -1,7 +0,0 @@
2385-duplicity.filechunkio module
2386-============================
2387-
2388-.. automodule:: duplicity.filechunkio
2389- :members:
2390- :undoc-members:
2391- :show-inheritance:
2392
2393=== removed file 'docs/duplicity.globals.rst'
2394--- docs/duplicity.globals.rst 2018-07-24 16:17:12 +0000
2395+++ docs/duplicity.globals.rst 1970-01-01 00:00:00 +0000
2396@@ -1,7 +0,0 @@
2397-duplicity.globals module
2398-========================
2399-
2400-.. automodule:: duplicity.globals
2401- :members:
2402- :undoc-members:
2403- :show-inheritance:
2404
2405=== removed file 'docs/duplicity.globmatch.rst'
2406--- docs/duplicity.globmatch.rst 2018-07-24 16:17:12 +0000
2407+++ docs/duplicity.globmatch.rst 1970-01-01 00:00:00 +0000
2408@@ -1,7 +0,0 @@
2409-duplicity.globmatch module
2410-==========================
2411-
2412-.. automodule:: duplicity.globmatch
2413- :members:
2414- :undoc-members:
2415- :show-inheritance:
2416
2417=== removed file 'docs/duplicity.gpg.rst'
2418--- docs/duplicity.gpg.rst 2018-07-24 16:17:12 +0000
2419+++ docs/duplicity.gpg.rst 1970-01-01 00:00:00 +0000
2420@@ -1,7 +0,0 @@
2421-duplicity.gpg module
2422-====================
2423-
2424-.. automodule:: duplicity.gpg
2425- :members:
2426- :undoc-members:
2427- :show-inheritance:
2428
2429=== removed file 'docs/duplicity.gpginterface.rst'
2430--- docs/duplicity.gpginterface.rst 2018-07-24 16:17:12 +0000
2431+++ docs/duplicity.gpginterface.rst 1970-01-01 00:00:00 +0000
2432@@ -1,7 +0,0 @@
2433-duplicity.gpginterface module
2434-=============================
2435-
2436-.. automodule:: duplicity.gpginterface
2437- :members:
2438- :undoc-members:
2439- :show-inheritance:
2440
2441=== removed file 'docs/duplicity.lazy.rst'
2442--- docs/duplicity.lazy.rst 2018-07-24 16:17:12 +0000
2443+++ docs/duplicity.lazy.rst 1970-01-01 00:00:00 +0000
2444@@ -1,7 +0,0 @@
2445-duplicity.lazy module
2446-=====================
2447-
2448-.. automodule:: duplicity.lazy
2449- :members:
2450- :undoc-members:
2451- :show-inheritance:
2452
2453=== removed file 'docs/duplicity.librsync.rst'
2454--- docs/duplicity.librsync.rst 2018-07-24 16:17:12 +0000
2455+++ docs/duplicity.librsync.rst 1970-01-01 00:00:00 +0000
2456@@ -1,7 +0,0 @@
2457-duplicity.librsync module
2458-=========================
2459-
2460-.. automodule:: duplicity.librsync
2461- :members:
2462- :undoc-members:
2463- :show-inheritance:
2464
2465=== removed file 'docs/duplicity.log.rst'
2466--- docs/duplicity.log.rst 2018-07-24 16:17:12 +0000
2467+++ docs/duplicity.log.rst 1970-01-01 00:00:00 +0000
2468@@ -1,7 +0,0 @@
2469-duplicity.log module
2470-====================
2471-
2472-.. automodule:: duplicity.log
2473- :members:
2474- :undoc-members:
2475- :show-inheritance:
2476
2477=== removed file 'docs/duplicity.manifest.rst'
2478--- docs/duplicity.manifest.rst 2018-07-24 16:17:12 +0000
2479+++ docs/duplicity.manifest.rst 1970-01-01 00:00:00 +0000
2480@@ -1,7 +0,0 @@
2481-duplicity.manifest module
2482-=========================
2483-
2484-.. automodule:: duplicity.manifest
2485- :members:
2486- :undoc-members:
2487- :show-inheritance:
2488
2489=== removed file 'docs/duplicity.patchdir.rst'
2490--- docs/duplicity.patchdir.rst 2018-07-24 16:17:12 +0000
2491+++ docs/duplicity.patchdir.rst 1970-01-01 00:00:00 +0000
2492@@ -1,7 +0,0 @@
2493-duplicity.patchdir module
2494-=========================
2495-
2496-.. automodule:: duplicity.patchdir
2497- :members:
2498- :undoc-members:
2499- :show-inheritance:
2500
2501=== removed file 'docs/duplicity.path.rst'
2502--- docs/duplicity.path.rst 2018-07-24 16:17:12 +0000
2503+++ docs/duplicity.path.rst 1970-01-01 00:00:00 +0000
2504@@ -1,7 +0,0 @@
2505-duplicity.path module
2506-=====================
2507-
2508-.. automodule:: duplicity.path
2509- :members:
2510- :undoc-members:
2511- :show-inheritance:
2512
2513=== removed file 'docs/duplicity.progress.rst'
2514--- docs/duplicity.progress.rst 2018-07-24 16:17:12 +0000
2515+++ docs/duplicity.progress.rst 1970-01-01 00:00:00 +0000
2516@@ -1,7 +0,0 @@
2517-duplicity.progress module
2518-=========================
2519-
2520-.. automodule:: duplicity.progress
2521- :members:
2522- :undoc-members:
2523- :show-inheritance:
2524
2525=== removed file 'docs/duplicity.robust.rst'
2526--- docs/duplicity.robust.rst 2018-07-24 16:17:12 +0000
2527+++ docs/duplicity.robust.rst 1970-01-01 00:00:00 +0000
2528@@ -1,7 +0,0 @@
2529-duplicity.robust module
2530-=======================
2531-
2532-.. automodule:: duplicity.robust
2533- :members:
2534- :undoc-members:
2535- :show-inheritance:
2536
2537=== renamed file 'docs/duplicity.rst' => 'docs/duplicity.rst.THIS'
2538=== removed file 'docs/duplicity.selection.rst'
2539--- docs/duplicity.selection.rst 2018-07-24 16:17:12 +0000
2540+++ docs/duplicity.selection.rst 1970-01-01 00:00:00 +0000
2541@@ -1,7 +0,0 @@
2542-duplicity.selection module
2543-==========================
2544-
2545-.. automodule:: duplicity.selection
2546- :members:
2547- :undoc-members:
2548- :show-inheritance:
2549
2550=== removed file 'docs/duplicity.statistics.rst'
2551--- docs/duplicity.statistics.rst 2018-07-24 16:17:12 +0000
2552+++ docs/duplicity.statistics.rst 1970-01-01 00:00:00 +0000
2553@@ -1,7 +0,0 @@
2554-duplicity.statistics module
2555-===========================
2556-
2557-.. automodule:: duplicity.statistics
2558- :members:
2559- :undoc-members:
2560- :show-inheritance:
2561
2562=== removed file 'docs/duplicity.tarfile.rst'
2563--- docs/duplicity.tarfile.rst 2018-07-24 16:17:12 +0000
2564+++ docs/duplicity.tarfile.rst 1970-01-01 00:00:00 +0000
2565@@ -1,7 +0,0 @@
2566-duplicity.tarfile module
2567-========================
2568-
2569-.. automodule:: duplicity.tarfile
2570- :members:
2571- :undoc-members:
2572- :show-inheritance:
2573
2574=== removed file 'docs/duplicity.tempdir.rst'
2575--- docs/duplicity.tempdir.rst 2018-07-24 16:17:12 +0000
2576+++ docs/duplicity.tempdir.rst 1970-01-01 00:00:00 +0000
2577@@ -1,7 +0,0 @@
2578-duplicity.tempdir module
2579-========================
2580-
2581-.. automodule:: duplicity.tempdir
2582- :members:
2583- :undoc-members:
2584- :show-inheritance:
2585
2586=== removed file 'docs/duplicity.util.rst'
2587--- docs/duplicity.util.rst 2018-07-24 16:17:12 +0000
2588+++ docs/duplicity.util.rst 1970-01-01 00:00:00 +0000
2589@@ -1,7 +0,0 @@
2590-duplicity.util module
2591-=====================
2592-
2593-.. automodule:: duplicity.util
2594- :members:
2595- :undoc-members:
2596- :show-inheritance:
2597
2598=== renamed file 'docs/index.rst' => 'docs/index.rst.THIS'
2599=== renamed file 'docs/make.bat' => 'docs/make.bat.THIS'
2600=== renamed file 'docs/testing.functional.rst' => 'docs/testing.functional.rst.THIS'
2601=== renamed file 'docs/testing.functional.test_badupload.rst' => 'docs/testing.functional.test_badupload.rst.THIS'
2602=== renamed file 'docs/testing.functional.test_cleanup.rst' => 'docs/testing.functional.test_cleanup.rst.THIS'
2603=== renamed file 'docs/testing.functional.test_final.rst' => 'docs/testing.functional.test_final.rst.THIS'
2604=== renamed file 'docs/testing.functional.test_log.rst' => 'docs/testing.functional.test_log.rst.THIS'
2605=== renamed file 'docs/testing.functional.test_rdiffdir.rst' => 'docs/testing.functional.test_rdiffdir.rst.THIS'
2606=== renamed file 'docs/testing.functional.test_restart.rst' => 'docs/testing.functional.test_restart.rst.THIS'
2607=== renamed file 'docs/testing.functional.test_selection.rst' => 'docs/testing.functional.test_selection.rst.THIS'
2608=== renamed file 'docs/testing.functional.test_verify.rst' => 'docs/testing.functional.test_verify.rst.THIS'
2609=== removed file 'docs/testing.overrides.gettext.rst'
2610--- docs/testing.overrides.gettext.rst 2018-07-24 16:17:12 +0000
2611+++ docs/testing.overrides.gettext.rst 1970-01-01 00:00:00 +0000
2612@@ -1,7 +0,0 @@
2613-testing.overrides.gettext module
2614-================================
2615-
2616-.. automodule:: testing.overrides.gettext
2617- :members:
2618- :undoc-members:
2619- :show-inheritance:
2620
2621=== removed file 'docs/testing.overrides.rst'
2622--- docs/testing.overrides.rst 2018-07-24 16:17:12 +0000
2623+++ docs/testing.overrides.rst 1970-01-01 00:00:00 +0000
2624@@ -1,17 +0,0 @@
2625-testing.overrides package
2626-=========================
2627-
2628-Submodules
2629-----------
2630-
2631-.. toctree::
2632-
2633- testing.overrides.gettext
2634-
2635-Module contents
2636----------------
2637-
2638-.. automodule:: testing.overrides
2639- :members:
2640- :undoc-members:
2641- :show-inheritance:
2642
2643=== renamed file 'docs/testing.rst' => 'docs/testing.rst.THIS'
2644=== renamed file 'docs/testing.test_code.rst' => 'docs/testing.test_code.rst.THIS'
2645=== removed file 'docs/testing.unit.rst'
2646--- docs/testing.unit.rst 2018-07-24 16:17:12 +0000
2647+++ docs/testing.unit.rst 1970-01-01 00:00:00 +0000
2648@@ -1,34 +0,0 @@
2649-testing.unit package
2650-====================
2651-
2652-Submodules
2653-----------
2654-
2655-.. toctree::
2656-
2657- testing.unit.test_backend
2658- testing.unit.test_backend_instance
2659- testing.unit.test_collections
2660- testing.unit.test_diffdir
2661- testing.unit.test_dup_temp
2662- testing.unit.test_dup_time
2663- testing.unit.test_file_naming
2664- testing.unit.test_globmatch
2665- testing.unit.test_gpg
2666- testing.unit.test_gpginterface
2667- testing.unit.test_lazy
2668- testing.unit.test_manifest
2669- testing.unit.test_patchdir
2670- testing.unit.test_path
2671- testing.unit.test_selection
2672- testing.unit.test_statistics
2673- testing.unit.test_tarfile
2674- testing.unit.test_tempdir
2675-
2676-Module contents
2677----------------
2678-
2679-.. automodule:: testing.unit
2680- :members:
2681- :undoc-members:
2682- :show-inheritance:
2683
2684=== renamed file 'docs/testing.unit.test_backend.rst' => 'docs/testing.unit.test_backend.rst.THIS'
2685=== renamed file 'docs/testing.unit.test_backend_instance.rst' => 'docs/testing.unit.test_backend_instance.rst.THIS'
2686=== renamed file 'docs/testing.unit.test_collections.rst' => 'docs/testing.unit.test_collections.rst.THIS'
2687=== renamed file 'docs/testing.unit.test_diffdir.rst' => 'docs/testing.unit.test_diffdir.rst.THIS'
2688=== renamed file 'docs/testing.unit.test_dup_temp.rst' => 'docs/testing.unit.test_dup_temp.rst.THIS'
2689=== renamed file 'docs/testing.unit.test_dup_time.rst' => 'docs/testing.unit.test_dup_time.rst.THIS'
2690=== renamed file 'docs/testing.unit.test_file_naming.rst' => 'docs/testing.unit.test_file_naming.rst.THIS'
2691=== renamed file 'docs/testing.unit.test_globmatch.rst' => 'docs/testing.unit.test_globmatch.rst.THIS'
2692=== renamed file 'docs/testing.unit.test_gpg.rst' => 'docs/testing.unit.test_gpg.rst.THIS'
2693=== renamed file 'docs/testing.unit.test_gpginterface.rst' => 'docs/testing.unit.test_gpginterface.rst.THIS'
2694=== renamed file 'docs/testing.unit.test_lazy.rst' => 'docs/testing.unit.test_lazy.rst.THIS'
2695=== renamed file 'docs/testing.unit.test_manifest.rst' => 'docs/testing.unit.test_manifest.rst.THIS'
2696=== renamed file 'docs/testing.unit.test_patchdir.rst' => 'docs/testing.unit.test_patchdir.rst.THIS'
2697=== renamed file 'docs/testing.unit.test_path.rst' => 'docs/testing.unit.test_path.rst.THIS'
2698=== renamed file 'docs/testing.unit.test_selection.rst' => 'docs/testing.unit.test_selection.rst.THIS'
2699=== renamed file 'docs/testing.unit.test_statistics.rst' => 'docs/testing.unit.test_statistics.rst.THIS'
2700=== renamed file 'docs/testing.unit.test_tarfile.rst' => 'docs/testing.unit.test_tarfile.rst.THIS'
2701=== renamed file 'docs/testing.unit.test_tempdir.rst' => 'docs/testing.unit.test_tempdir.rst.THIS'
2702=== modified file 'duplicity/_librsyncmodule.c'
2703--- duplicity/_librsyncmodule.c 2018-12-05 03:48:47 +0000
2704+++ duplicity/_librsyncmodule.c 2019-04-22 12:43:18 +0000
2705@@ -330,7 +330,7 @@
2706 fd = dup(fd);
2707 if (fd == -1) {
2708 char buf[256];
2709- (void)strerror_r(errno, buf, sizeof(buf));
2710+ strerror_r(errno, buf, sizeof(buf));
2711 PyErr_SetString(PyExc_TypeError, buf);
2712 return NULL;
2713 }
2714
2715=== modified file 'duplicity/backend.py'
2716--- duplicity/backend.py 2018-11-29 19:00:15 +0000
2717+++ duplicity/backend.py 2019-04-22 12:43:18 +0000
2718@@ -455,8 +455,13 @@
2719 else:
2720 return commandline
2721
2722+<<<<<<< TREE
2723 def __subprocess_popen(self, args):
2724 u"""
2725+=======
2726+ def __subprocess_popen(self, args):
2727+ """
2728+>>>>>>> MERGE-SOURCE
2729 For internal use.
2730 Execute the given command line, interpreted as a shell command.
2731 Returns int Exitcode, string StdOut, string StdErr
2732@@ -480,6 +485,7 @@
2733
2734 Raise a BackendException on failure.
2735 """
2736+<<<<<<< TREE
2737 import shlex
2738
2739 if isinstance(commandline, (list, tuple)):
2740@@ -493,6 +499,21 @@
2741 log.Info(_(u"Reading results of '%s'") % logstr)
2742
2743 result, stdout, stderr = self.__subprocess_popen(args)
2744+=======
2745+ import shlex
2746+
2747+ if isinstance(commandline, (types.ListType, types.TupleType)):
2748+ logstr = ' '.join(commandline)
2749+ args = commandline
2750+ else:
2751+ logstr = commandline
2752+ args = shlex.split(commandline)
2753+
2754+ logstr = self.munge_password(logstr)
2755+ log.Info(_("Reading results of '%s'") % logstr)
2756+
2757+ result, stdout, stderr = self.__subprocess_popen(args)
2758+>>>>>>> MERGE-SOURCE
2759 if result != 0:
2760 try:
2761 ignores = self.popen_breaks[args[0]]
2762@@ -500,8 +521,13 @@
2763 u""" ignore a predefined set of error codes """
2764 return 0, u'', u''
2765 except (KeyError, ValueError):
2766+<<<<<<< TREE
2767 raise BackendException(u"Error running '%s': returned %d, with output:\n%s" %
2768 (logstr, result, stdout.decode() + u'\n' + stderr.decode()))
2769+=======
2770+ raise BackendException("Error running '%s': returned %d, with output:\n%s" %
2771+ (logstr, result, stdout + '\n' + stderr))
2772+>>>>>>> MERGE-SOURCE
2773 return result, stdout, stderr
2774
2775
2776@@ -573,7 +599,11 @@
2777 # There shouldn't be any encoding errors for files we care
2778 # about, since duplicity filenames are ascii. But user files
2779 # may be in the same directory. So just replace characters.
2780+<<<<<<< TREE
2781 return util.fsencode(filename)
2782+=======
2783+ return filename.encode(globals.fsencoding, 'replace')
2784+>>>>>>> MERGE-SOURCE
2785 else:
2786 return filename
2787
2788
2789=== modified file 'duplicity/backends/_cf_pyrax.py'
2790--- duplicity/backends/_cf_pyrax.py 2018-11-29 19:00:15 +0000
2791+++ duplicity/backends/_cf_pyrax.py 2019-04-22 12:43:18 +0000
2792@@ -71,6 +71,7 @@
2793
2794 self.client_exc = pyrax.exceptions.ClientException
2795 self.nso_exc = pyrax.exceptions.NoSuchObject
2796+<<<<<<< TREE
2797
2798 # query rackspace for the specified container name
2799 try:
2800@@ -90,6 +91,27 @@
2801 u"You may be using a read-only user that can view but not create containers.\n" +
2802 u"Please check your credentials and permissions.",
2803 log.ErrorCode.backend_permission_denied)
2804+=======
2805+
2806+ # query rackspace for the specified container name
2807+ try:
2808+ self.container = pyrax.cloudfiles.get_container(container)
2809+ except pyrax.exceptions.Forbidden as e:
2810+ log.FatalError("%s : %s \n" % (e.__class__.__name__, util.uexc(e)) +
2811+ "Container may exist, but access was denied.\n" +
2812+ "If this container exists, please check its X-Container-Read/Write headers.\n" +
2813+ "Otherwise, please check your credentials and permissions.",
2814+ log.ErrorCode.backend_permission_denied)
2815+ except pyrax.exceptions.NoSuchContainer as e:
2816+ try:
2817+ self.container = pyrax.cloudfiles.create_container(container)
2818+ except pyrax.exceptions.Forbidden as e:
2819+ log.FatalError("%s : %s \n" % (e.__class__.__name__, util.uexc(e)) +
2820+ "Container does not exist, but creation was denied.\n" +
2821+ "You may be using a read-only user that can view but not create containers.\n" +
2822+ "Please check your credentials and permissions.",
2823+ log.ErrorCode.backend_permission_denied)
2824+>>>>>>> MERGE-SOURCE
2825
2826 def _error_code(self, operation, e):
2827 if isinstance(e, self.nso_exc):
2828
2829=== added file 'duplicity/backends/acdclibackend.py.OTHER'
2830--- duplicity/backends/acdclibackend.py.OTHER 1970-01-01 00:00:00 +0000
2831+++ duplicity/backends/acdclibackend.py.OTHER 2019-04-22 12:43:18 +0000
2832@@ -0,0 +1,151 @@
2833+# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
2834+#
2835+# Copyright 2015 Stefan Breunig <stefan-duplicity@breunig.xyz>
2836+# Copyright 2015 Malay Shah <malays@gmail.com>
2837+# Based on the backend ncftpbackend.py
2838+#
2839+# This file is part of duplicity.
2840+#
2841+# Duplicity is free software; you can redistribute it and/or modify it
2842+# under the terms of the GNU General Public License as published by the
2843+# Free Software Foundation; either version 2 of the License, or (at your
2844+# option) any later version.
2845+#
2846+# Duplicity is distributed in the hope that it will be useful, but
2847+# WITHOUT ANY WARRANTY; without even the implied warranty of
2848+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2849+# General Public License for more details.
2850+#
2851+# You should have received a copy of the GNU General Public License
2852+# along with duplicity; if not, write to the Free Software Foundation,
2853+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2854+
2855+import os.path
2856+import urllib
2857+import string
2858+import json
2859+
2860+import duplicity.backend
2861+from duplicity import globals
2862+from duplicity import log
2863+from duplicity.errors import * # @UnusedWildImport
2864+from duplicity import tempdir
2865+
2866+
2867+class ACDBackend(duplicity.backend.Backend):
2868+ acd_cmd = 'acd_cli'
2869+ """Connect to remote store using acd_cli"""
2870+ def __init__(self, parsed_url):
2871+ duplicity.backend.Backend.__init__(self, parsed_url)
2872+
2873+ # we expect an error return, so go low-level and ignore it
2874+ try:
2875+ p = os.popen(self.acd_cmd + " version")
2876+ fout = p.read()
2877+ ret = p.close()
2878+ except Exception:
2879+ pass
2880+ # the expected error is 0
2881+ if ret is not None:
2882+ log.FatalError(self.acd_cmd + " not found: Please install acd_cli",
2883+ log.ErrorCode.backend_not_found)
2884+
2885+ self.parsed_url = parsed_url
2886+ self.url_string = duplicity.backend.strip_auth_from_url(self.parsed_url)
2887+
2888+ # Use an explicit directory name.
2889+ if self.url_string[-1] != '/':
2890+ self.url_string += '/'
2891+
2892+ self.subprocess_popen(self.acd_cmd + " sync")
2893+
2894+ # Initialize remote directory
2895+ remote_path = urllib.unquote(self.parsed_url.path.replace('///', '/')).rstrip()
2896+ commandline = self.acd_cmd + " ls '%s'" % (remote_path)
2897+ try:
2898+ self.subprocess_popen(commandline)
2899+ except BackendException as e:
2900+ if e.code == 50: # Remote directory not there, create a new one
2901+ commandline = self.acd_cmd + " mkdir '%s'" % remote_path
2902+ self.subprocess_popen(commandline)
2903+
2904+ def _put(self, source_path, remote_filename=None):
2905+ """Transfer source_path to remote_filename"""
2906+ if not remote_filename:
2907+ remote_filename = source_path.get_filename()
2908+
2909+ # WORKAROUND for acd_cli: cannot specify remote filename
2910+ # Link tmp file to the desired remote filename locally and upload
2911+ remote_path = urllib.unquote(self.parsed_url.path.replace('///', '/'))
2912+ local_real_duplicity_file = os.path.join(os.path.dirname(source_path.name), remote_filename.rstrip())
2913+
2914+ deleteFile = False
2915+ if(source_path.name != local_real_duplicity_file):
2916+ try:
2917+ os.symlink(source_path.name, local_real_duplicity_file)
2918+ deleteFile = True
2919+ except IOError as e:
2920+ log.FatalError("Unable to copy " + source_path.name + " to " + local_real_duplicity_file)
2921+
2922+ commandline = self.acd_cmd + " upload --force --overwrite '%s' '%s'" % \
2923+ (local_real_duplicity_file, remote_path)
2924+
2925+ try:
2926+ l = self.subprocess_popen(commandline)
2927+ finally:
2928+ if (deleteFile):
2929+ try:
2930+ os.remove(local_real_duplicity_file)
2931+ except OSError as e:
2932+ log.FatalError("Unable to remove file %s" % e)
2933+
2934+ def _get(self, remote_filename, local_path):
2935+ """Get remote filename, saving it to local_path"""
2936+ remote_path = os.path.join(urllib.unquote(self.parsed_url.path.replace('///', '/')), remote_filename).rstrip()
2937+ local_dir = os.path.dirname(local_path.name)
2938+ local_filename = os.path.basename(local_path.name)
2939+ commandline = self.acd_cmd + " download '%s' '%s'" % \
2940+ (remote_path, local_dir)
2941+ l = self.subprocess_popen(commandline)
2942+
2943+ # Keep the remote filename and move the file over
2944+ try:
2945+ os.rename(os.path.join(local_dir, remote_filename), local_path.name)
2946+ except IOError as e:
2947+ log.FatalError("Unable to move file %s" % e)
2948+
2949+ local_path.setdata()
2950+ if not local_path.exists():
2951+ raise BackendException("File %s not found" % local_path.name)
2952+
2953+ def _query(self, remote_filename):
2954+ remote_path = os.path.join(urllib.unquote(self.parsed_url.path.replace('///', '/')), remote_filename).rstrip()
2955+ commandline = self.acd_cmd + " metadata '%s'" % remote_path
2956+ node = self.subprocess_popen(commandline)
2957+ if (node[0] == 0 and node[1]):
2958+ try:
2959+ size = json.loads(node[1])['contentProperties']['size']
2960+ return {'size': size}
2961+ except ValueError as e:
2962+ raise BackendException('Malformed JSON: expected "contentProperties->size" member in %s' % node[1])
2963+ return {'size': -1}
2964+
2965+ def _list(self):
2966+ """List files in directory"""
2967+ def dir_split(str):
2968+ if (str):
2969+ return str.split()[2]
2970+ else:
2971+ return None
2972+ commandline = self.acd_cmd + " ls '%s'" % self.parsed_url.path.replace('///', '/')
2973+ l = self.subprocess_popen(commandline)
2974+ return [x for x in map(dir_split, l[1].split('\n')) if x]
2975+
2976+ def _delete(self, remote_filename):
2977+ """Delete remote_filename"""
2978+ remote_file_path = os.path.join(urllib.unquote(self.parsed_url.path.replace('///', '/')),
2979+ remote_filename).rstrip()
2980+ commandline = self.acd_cmd + " rm '%s'" % (remote_file_path)
2981+ self.subprocess_popen(commandline)
2982+
2983+duplicity.backend.register_backend("acd+acdcli", ACDBackend)
2984
2985=== renamed file 'duplicity/backends/adbackend.py' => 'duplicity/backends/adbackend.py.THIS'
2986=== modified file 'duplicity/backends/azurebackend.py'
2987--- duplicity/backends/azurebackend.py 2019-03-10 22:58:32 +0000
2988+++ duplicity/backends/azurebackend.py 2019-04-22 12:43:18 +0000
2989@@ -23,7 +23,6 @@
2990 import os
2991
2992 import duplicity.backend
2993-from duplicity import globals
2994 from duplicity import log
2995 from duplicity.errors import BackendException
2996
2997@@ -46,11 +45,15 @@
2998 self.AzureConflictError = azure.WindowsAzureConflictError
2999 else:
3000 # v1.0.0 and above
3001+<<<<<<< TREE
3002 import azure.storage.blob
3003 if hasattr(azure.storage.blob, u'BlobService'):
3004 from azure.storage.blob import BlobService
3005 else:
3006 from azure.storage.blob.blockblobservice import BlockBlobService as BlobService
3007+=======
3008+ from azure.storage.blob import BlobService
3009+>>>>>>> MERGE-SOURCE
3010 self.AzureMissingResourceError = azure.common.AzureMissingResourceHttpError
3011 self.AzureConflictError = azure.common.AzureConflictHttpError
3012 except ImportError as e:
3013@@ -58,7 +61,15 @@
3014 Azure backend requires Microsoft Azure Storage SDK for Python (https://pypi.python.org/pypi/azure-storage/).
3015 Exception: %s""" % str(e))
3016
3017+ if 'AZURE_ACCOUNT_NAME' not in os.environ:
3018+ raise BackendException('AZURE_ACCOUNT_NAME environment variable not set.')
3019+ if 'AZURE_ACCOUNT_KEY' not in os.environ:
3020+ raise BackendException('AZURE_ACCOUNT_KEY environment variable not set.')
3021+ self.blob_service = BlobService(account_name=os.environ['AZURE_ACCOUNT_NAME'],
3022+ account_key=os.environ['AZURE_ACCOUNT_KEY'])
3023+
3024 # TODO: validate container name
3025+<<<<<<< TREE
3026 self.container = parsed_url.path.lstrip(u'/')
3027
3028 if u'AZURE_ACCOUNT_NAME' not in os.environ:
3029@@ -104,6 +115,9 @@
3030 self.blob_service._BLOB_MAX_CHUNK_DATA_SIZE = globals.azure_max_block_size
3031
3032 def _create_container(self):
3033+=======
3034+ self.container = parsed_url.path.lstrip('/')
3035+>>>>>>> MERGE-SOURCE
3036 try:
3037 self.blob_service.create_container(self.container, fail_on_exist=True)
3038 except self.AzureConflictError:
3039@@ -115,15 +129,15 @@
3040 log.ErrorCode.connection_failed)
3041
3042 def _put(self, source_path, remote_filename):
3043+<<<<<<< TREE
3044 kwargs = {}
3045 if globals.azure_max_connections:
3046 kwargs[u'max_connections'] = globals.azure_max_connections
3047
3048+=======
3049+>>>>>>> MERGE-SOURCE
3050 # https://azure.microsoft.com/en-us/documentation/articles/storage-python-how-to-use-blob-storage/#upload-a-blob-into-a-container
3051- try:
3052- self.blob_service.create_blob_from_path(self.container, remote_filename, source_path.name, **kwargs)
3053- except AttributeError: # Old versions use a different method name
3054- self.blob_service.put_block_blob_from_path(self.container, remote_filename, source_path.name, **kwargs)
3055+ self.blob_service.put_block_blob_from_path(self.container, remote_filename, source_path.name)
3056
3057 self._set_tier(remote_filename)
3058
3059@@ -156,16 +170,24 @@
3060
3061 def _query(self, filename):
3062 prop = self.blob_service.get_blob_properties(self.container, filename)
3063+<<<<<<< TREE
3064 try:
3065 info = {u'size': int(prop.properties.content_length)}
3066 except AttributeError:
3067 # old versions directly returned the properties
3068 info = {u'size': int(prop[u'content-length'])}
3069 return info
3070+=======
3071+ return {'size': int(prop['content-length'])}
3072+>>>>>>> MERGE-SOURCE
3073
3074 def _error_code(self, operation, e):
3075 if isinstance(e, self.AzureMissingResourceError):
3076 return log.ErrorCode.backend_not_found
3077
3078+<<<<<<< TREE
3079
3080 duplicity.backend.register_backend(u'azure', AzureBackend)
3081+=======
3082+duplicity.backend.register_backend('azure', AzureBackend)
3083+>>>>>>> MERGE-SOURCE
3084
3085=== modified file 'duplicity/backends/b2backend.py'
3086--- duplicity/backends/b2backend.py 2019-03-10 22:58:32 +0000
3087+++ duplicity/backends/b2backend.py 2019-04-22 12:43:18 +0000
3088@@ -27,11 +27,15 @@
3089 from builtins import object
3090 import os
3091 import hashlib
3092+<<<<<<< TREE
3093 from urllib.parse import quote_plus # pylint: disable=import-error
3094+=======
3095+>>>>>>> MERGE-SOURCE
3096
3097 import duplicity.backend
3098 from duplicity.errors import BackendException, FatalBackendException
3099 from duplicity import log
3100+<<<<<<< TREE
3101 from duplicity import progress
3102
3103
3104@@ -50,6 +54,29 @@
3105
3106 def __exit__(self, exc_type, exc_val, exc_tb):
3107 pass
3108+=======
3109+from duplicity import progress
3110+
3111+
3112+def progress_listener_factory():
3113+ u"""
3114+ Returns progress instance suitable for passing to b2.api.B2Api
3115+ methods.
3116+ """
3117+ class B2ProgressListener(b2.progress.AbstractProgressListener):
3118+ def __init__(self):
3119+ super(B2ProgressListener, self).__init__()
3120+
3121+ def set_total_bytes(self, total_byte_count):
3122+ self.total_byte_count = total_byte_count
3123+
3124+ def bytes_completed(self, byte_count):
3125+ progress.report_transfer(byte_count, self.total_byte_count)
3126+
3127+ def close(self):
3128+ super(B2ProgressListener, self).close()
3129+ return B2ProgressListener()
3130+>>>>>>> MERGE-SOURCE
3131
3132
3133 class B2Backend(duplicity.backend.Backend):
3134@@ -63,6 +90,7 @@
3135 """
3136 duplicity.backend.Backend.__init__(self, parsed_url)
3137
3138+<<<<<<< TREE
3139 # Import B2 API
3140 try:
3141 global b2
3142@@ -78,6 +106,24 @@
3143 self.parsed_url.hostname = u'B2'
3144
3145 account_id = parsed_url.username
3146+=======
3147+ # Import B2 API
3148+ try:
3149+ global b2
3150+ import b2
3151+ import b2.api
3152+ import b2.account_info
3153+ import b2.download_dest
3154+ import b2.file_version
3155+ import b2.progress
3156+ except ImportError:
3157+ raise BackendException('B2 backend requires B2 Python APIs (pip install b2)')
3158+
3159+ self.service = b2.api.B2Api(b2.account_info.InMemoryAccountInfo())
3160+ self.parsed_url.hostname = 'B2'
3161+
3162+ account_id = parsed_url.username
3163+>>>>>>> MERGE-SOURCE
3164 account_key = self.get_password()
3165
3166 self.url_parts = [
3167@@ -87,13 +133,23 @@
3168 self.username = self.url_parts.pop(0)
3169 bucket_name = self.url_parts.pop(0)
3170 else:
3171+<<<<<<< TREE
3172 raise BackendException(u"B2 requires a bucket name")
3173 self.path = u"".join([url_part + u"/" for url_part in self.url_parts])
3174 self.service.authorize_account(u'production', account_id, account_key)
3175
3176 log.Log(u"B2 Backend (path= %s, bucket= %s, minimum_part_size= %s)" %
3177 (self.path, bucket_name, self.service.account_info.get_minimum_part_size()), log.INFO)
3178+=======
3179+ raise BackendException("B2 requires a bucket name")
3180+ self.path = "".join([url_part + "/" for url_part in self.url_parts])
3181+ self.service.authorize_account('production', account_id, account_key)
3182+
3183+ log.Log("B2 Backend (path= %s, bucket= %s, minimum_part_size= %s)" %
3184+ (self.path, bucket_name, self.service.account_info.get_minimum_part_size()), log.INFO)
3185+>>>>>>> MERGE-SOURCE
3186 try:
3187+<<<<<<< TREE
3188 self.bucket = self.service.get_bucket_by_name(bucket_name)
3189 log.Log(u"Bucket found", log.INFO)
3190 except b2.exception.NonExistentBucket:
3191@@ -102,23 +158,46 @@
3192 self.bucket = self.service.create_bucket(bucket_name, u'allPrivate')
3193 except:
3194 raise FatalBackendException(u"Bucket cannot be created")
3195+=======
3196+ self.bucket = self.service.get_bucket_by_name(bucket_name)
3197+ log.Log("Bucket found", log.INFO)
3198+ except b2.exception.NonExistentBucket:
3199+ try:
3200+ log.Log("Bucket not found, creating one", log.INFO)
3201+ self.bucket = self.service.create_bucket(bucket_name, 'allPrivate')
3202+ except:
3203+ raise FatalBackendException("Bucket cannot be created")
3204+>>>>>>> MERGE-SOURCE
3205
3206 def _get(self, remote_filename, local_path):
3207 u"""
3208 Download remote_filename to local_path
3209 """
3210+<<<<<<< TREE
3211 log.Log(u"Get: %s -> %s" % (self.path + remote_filename, local_path.name), log.INFO)
3212 self.bucket.download_file_by_name(quote_plus(self.path + remote_filename),
3213 b2.download_dest.DownloadDestLocalFile(local_path.name))
3214+=======
3215+ log.Log("Get: %s -> %s" % (self.path + remote_filename, local_path.name), log.INFO)
3216+ self.bucket.download_file_by_name(self.path + remote_filename,
3217+ b2.download_dest.DownloadDestLocalFile(local_path.name))
3218+>>>>>>> MERGE-SOURCE
3219
3220 def _put(self, source_path, remote_filename):
3221 u"""
3222 Copy source_path to remote_filename
3223 """
3224+<<<<<<< TREE
3225 log.Log(u"Put: %s -> %s" % (source_path.name, self.path + remote_filename), log.INFO)
3226 self.bucket.upload_local_file(source_path.name, quote_plus(self.path + remote_filename),
3227 content_type=u'application/pgp-encrypted',
3228 progress_listener=B2ProgressListener())
3229+=======
3230+ log.Log("Put: %s -> %s" % (source_path.name, self.path + remote_filename), log.INFO)
3231+ self.bucket.upload_local_file(source_path.name, self.path + remote_filename,
3232+ content_type='application/pgp-encrypted',
3233+ progress_listener=progress_listener_factory())
3234+>>>>>>> MERGE-SOURCE
3235
3236 def _list(self):
3237 u"""
3238@@ -131,14 +210,21 @@
3239 u"""
3240 Delete filename from remote server
3241 """
3242+<<<<<<< TREE
3243 log.Log(u"Delete: %s" % self.path + filename, log.INFO)
3244 file_version_info = self.file_info(quote_plus(self.path + filename))
3245 self.bucket.delete_file_version(file_version_info.id_, file_version_info.file_name)
3246+=======
3247+ log.Log("Delete: %s" % self.path + filename, log.INFO)
3248+ file_version_info = self.file_info(self.path + filename)
3249+ self.bucket.delete_file_version(file_version_info.id_, file_version_info.file_name)
3250+>>>>>>> MERGE-SOURCE
3251
3252 def _query(self, filename):
3253 u"""
3254 Get size info of filename
3255 """
3256+<<<<<<< TREE
3257 log.Log(u"Query: %s" % self.path + filename, log.INFO)
3258 file_version_info = self.file_info(quote_plus(self.path + filename))
3259 return {u'size': file_version_info.size
3260@@ -154,3 +240,20 @@
3261
3262
3263 duplicity.backend.register_backend(u"b2", B2Backend)
3264+=======
3265+ log.Log("Query: %s" % self.path + filename, log.INFO)
3266+ file_version_info = self.file_info(self.path + filename)
3267+ return {'size': file_version_info.size
3268+ if file_version_info is not None and file_version_info.size is not None else -1}
3269+
3270+ def file_info(self, filename):
3271+ response = self.bucket.list_file_names(filename, 1)
3272+ for entry in response['files']:
3273+ file_version_info = b2.file_version.FileVersionInfoFactory.from_api_response(entry)
3274+ if file_version_info.file_name == filename:
3275+ return file_version_info
3276+ raise BackendException('File not found')
3277+
3278+
3279+duplicity.backend.register_backend("b2", B2Backend)
3280+>>>>>>> MERGE-SOURCE
3281
3282=== modified file 'duplicity/backends/dpbxbackend.py'
3283--- duplicity/backends/dpbxbackend.py 2018-11-29 19:00:15 +0000
3284+++ duplicity/backends/dpbxbackend.py 2019-04-22 12:43:18 +0000
3285@@ -45,7 +45,21 @@
3286 from duplicity import log, globals
3287 from duplicity import progress
3288 from duplicity.errors import BackendException
3289+<<<<<<< TREE
3290 from duplicity.globals import num_retries
3291+=======
3292+import os
3293+import sys
3294+import traceback
3295+import urllib
3296+import re
3297+
3298+from dropbox import Dropbox
3299+from dropbox.exceptions import AuthError, BadInputError, ApiError
3300+from dropbox.files import UploadSessionCursor, CommitInfo, WriteMode, \
3301+ GetMetadataError, DeleteError, UploadSessionLookupError, ListFolderError
3302+from dropbox.oauth import DropboxOAuth2FlowNoRedirect
3303+>>>>>>> MERGE-SOURCE
3304 from requests.exceptions import ConnectionError
3305 import duplicity.backend
3306
3307@@ -164,12 +178,23 @@
3308 print(u'-' * 72)
3309 auth_code = input(u"Enter the authorization code here: ").strip()
3310 try:
3311+<<<<<<< TREE
3312 log.Debug(u'dpbx,auth_flow.finish(%s)' % auth_code)
3313 authresult = auth_flow.finish(auth_code)
3314+=======
3315+ log.Debug('dpbx,auth_flow.finish(%s)' % auth_code)
3316+ authresult = auth_flow.finish(auth_code)
3317+>>>>>>> MERGE-SOURCE
3318 except Exception as e:
3319+<<<<<<< TREE
3320 raise BackendException(u'dpbx: Unable to obtain access token: %s' % e)
3321 log.Info(u"dpbx: Authentication successfull")
3322 self.save_access_token(authresult.access_token)
3323+=======
3324+ raise BackendException('dpbx: Unable to obtain access token: %s' % e)
3325+ log.Info("dpbx: Authentication successfull")
3326+ self.save_access_token(authresult.access_token)
3327+>>>>>>> MERGE-SOURCE
3328
3329 def login(self):
3330 if self.load_access_token() is None:
3331@@ -403,10 +428,17 @@
3332 # Do a long listing to avoid connection reset
3333 if not self.user_authenticated():
3334 self.login()
3335+<<<<<<< TREE
3336 remote_dir = u'/' + urllib.parse.unquote(self.parsed_url.path.lstrip(u'/')).rstrip()
3337
3338 log.Debug(u'dpbx.files_list_folder(%s)' % remote_dir)
3339+=======
3340+ remote_dir = '/' + urllib.unquote(self.parsed_url.path.lstrip('/')).rstrip()
3341+
3342+ log.Debug('dpbx.files_list_folder(%s)' % remote_dir)
3343+>>>>>>> MERGE-SOURCE
3344 res = []
3345+<<<<<<< TREE
3346 try:
3347 resp = self.api_client.files_list_folder(remote_dir)
3348 log.Debug(u'dpbx.list(%s): %s' % (remote_dir, resp))
3349@@ -422,6 +454,23 @@
3350 log.Debug(u'dpbx.list(%s): ignore missing folder (%s)' % (remote_dir, e))
3351 else:
3352 raise
3353+=======
3354+ try:
3355+ resp = self.api_client.files_list_folder(remote_dir)
3356+ log.Debug('dpbx.list(%s): %s' % (remote_dir, resp))
3357+
3358+ while True:
3359+ res.extend([entry.name for entry in resp.entries])
3360+ if not resp.has_more:
3361+ break
3362+ resp = self.api_client.files_list_folder_continue(resp.cursor)
3363+ except ApiError as e:
3364+ if (isinstance(e.error, ListFolderError) and e.error.is_path() and
3365+ e.error.get_path().is_not_found()):
3366+ log.Debug('dpbx.list(%s): ignore missing folder (%s)' % (remote_dir, e))
3367+ else:
3368+ raise
3369+>>>>>>> MERGE-SOURCE
3370
3371 # Warn users of old version dpbx about automatically renamed files
3372 self.check_renamed_files(res)
3373
3374=== modified file 'duplicity/backends/gdocsbackend.py'
3375--- duplicity/backends/gdocsbackend.py 2018-11-29 19:00:15 +0000
3376+++ duplicity/backends/gdocsbackend.py 2019-04-22 12:43:18 +0000
3377@@ -193,7 +193,13 @@
3378 # Done!
3379 return result
3380
3381+<<<<<<< TREE
3382
3383 u""" gdata is an alternate way to access gdocs, currently 05/2015 lacking OAuth support """
3384 duplicity.backend.register_backend(u'gdata+gdocs', GDocsBackend)
3385 duplicity.backend.uses_netloc.extend([u'gdata+gdocs'])
3386+=======
3387+""" gdata is an alternate way to access gdocs, currently 05/2015 lacking OAuth support """
3388+duplicity.backend.register_backend('gdata+gdocs', GDocsBackend)
3389+duplicity.backend.uses_netloc.extend(['gdata+gdocs'])
3390+>>>>>>> MERGE-SOURCE
3391
3392=== modified file 'duplicity/backends/giobackend.py'
3393--- duplicity/backends/giobackend.py 2018-07-23 14:55:39 +0000
3394+++ duplicity/backends/giobackend.py 2019-04-22 12:43:18 +0000
3395@@ -143,8 +143,13 @@
3396 self.__copy_file(source_file, target_file)
3397
3398 def _get(self, filename, local_path):
3399+<<<<<<< TREE
3400 from gi.repository import Gio # @UnresolvedImport # pylint: disable=import-error
3401 source_file = self.remote_file.get_child_for_display_name(filename)
3402+=======
3403+ from gi.repository import Gio # @UnresolvedImport
3404+ source_file = self.remote_file.get_child_for_display_name(filename)
3405+>>>>>>> MERGE-SOURCE
3406 target_file = Gio.File.new_for_path(local_path.name)
3407 self.__copy_file(source_file, target_file)
3408
3409@@ -169,11 +174,22 @@
3410 target_file.delete(None)
3411
3412 def _query(self, filename):
3413+<<<<<<< TREE
3414 from gi.repository import Gio # @UnresolvedImport # pylint: disable=import-error
3415 target_file = self.remote_file.get_child_for_display_name(filename)
3416+=======
3417+ from gi.repository import Gio # @UnresolvedImport
3418+ target_file = self.remote_file.get_child_for_display_name(filename)
3419+>>>>>>> MERGE-SOURCE
3420 info = target_file.query_info(Gio.FILE_ATTRIBUTE_STANDARD_SIZE,
3421 Gio.FileQueryInfoFlags.NONE, None)
3422+<<<<<<< TREE
3423 return {u'size': info.get_size()}
3424
3425
3426 duplicity.backend.register_backend_prefix(u'gio', GIOBackend)
3427+=======
3428+ return {'size': info.get_size()}
3429+
3430+duplicity.backend.register_backend_prefix('gio', GIOBackend)
3431+>>>>>>> MERGE-SOURCE
3432
3433=== modified file 'duplicity/backends/hsibackend.py'
3434--- duplicity/backends/hsibackend.py 2018-11-29 19:00:15 +0000
3435+++ duplicity/backends/hsibackend.py 2019-04-22 12:43:18 +0000
3436@@ -65,6 +65,11 @@
3437 commandline = u'%s "rm %s%s"' % (hsi_command, self.remote_prefix, filename)
3438 self.subprocess_popen(commandline)
3439
3440+<<<<<<< TREE
3441
3442 duplicity.backend.register_backend(u"hsi", HSIBackend)
3443 duplicity.backend.uses_netloc.extend([u'hsi'])
3444+=======
3445+duplicity.backend.register_backend("hsi", HSIBackend)
3446+duplicity.backend.uses_netloc.extend(['hsi'])
3447+>>>>>>> MERGE-SOURCE
3448
3449=== modified file 'duplicity/backends/hubicbackend.py'
3450--- duplicity/backends/hubicbackend.py 2018-11-29 19:00:15 +0000
3451+++ duplicity/backends/hubicbackend.py 2019-04-22 12:43:18 +0000
3452@@ -64,5 +64,9 @@
3453 self.nso_exc = pyrax.exceptions.NoSuchObject
3454 self.container = pyrax.cloudfiles.create_container(container)
3455
3456+<<<<<<< TREE
3457
3458 duplicity.backend.register_backend(u"cf+hubic", HubicBackend)
3459+=======
3460+duplicity.backend.register_backend("cf+hubic", HubicBackend)
3461+>>>>>>> MERGE-SOURCE
3462
3463=== renamed file 'duplicity/backends/jottacloudbackend.py' => 'duplicity/backends/jottacloudbackend.py.THIS'
3464=== modified file 'duplicity/backends/lftpbackend.py'
3465--- duplicity/backends/lftpbackend.py 2019-02-21 21:42:26 +0000
3466+++ duplicity/backends/lftpbackend.py 2019-04-22 12:43:18 +0000
3467@@ -205,6 +205,7 @@
3468 )
3469 log.Debug(u"CMD: %s" % commandline)
3470 _, l, e = self.subprocess_popen(commandline)
3471+<<<<<<< TREE
3472 log.Debug(u"STDERR:\n"
3473 u"%s" % (e))
3474 log.Debug(u"STDOUT:\n"
3475@@ -232,4 +233,32 @@
3476 u'lftp+sftp',
3477 u'lftp+webdav', u'lftp+webdavs',
3478 u'lftp+http', u'lftp+https']
3479+=======
3480+ log.Debug("STDERR:\n"
3481+ "%s" % (e))
3482+ log.Debug("STDOUT:\n"
3483+ "%s" % (l))
3484+
3485+duplicity.backend.register_backend("ftp", LFTPBackend)
3486+duplicity.backend.register_backend("ftps", LFTPBackend)
3487+duplicity.backend.register_backend("fish", LFTPBackend)
3488+duplicity.backend.register_backend("ftpes", LFTPBackend)
3489+
3490+duplicity.backend.register_backend("lftp+ftp", LFTPBackend)
3491+duplicity.backend.register_backend("lftp+ftps", LFTPBackend)
3492+duplicity.backend.register_backend("lftp+fish", LFTPBackend)
3493+duplicity.backend.register_backend("lftp+ftpes", LFTPBackend)
3494+duplicity.backend.register_backend("lftp+sftp", LFTPBackend)
3495+duplicity.backend.register_backend("lftp+webdav", LFTPBackend)
3496+duplicity.backend.register_backend("lftp+webdavs", LFTPBackend)
3497+duplicity.backend.register_backend("lftp+http", LFTPBackend)
3498+duplicity.backend.register_backend("lftp+https", LFTPBackend)
3499+
3500+duplicity.backend.uses_netloc.extend(['ftp', 'ftps', 'fish', 'ftpes',
3501+ 'lftp+ftp', 'lftp+ftps',
3502+ 'lftp+fish', 'lftp+ftpes',
3503+ 'lftp+sftp',
3504+ 'lftp+webdav', 'lftp+webdavs',
3505+ 'lftp+http', 'lftp+https']
3506+>>>>>>> MERGE-SOURCE
3507 )
3508
3509=== modified file 'duplicity/backends/localbackend.py'
3510--- duplicity/backends/localbackend.py 2018-07-23 14:55:39 +0000
3511+++ duplicity/backends/localbackend.py 2019-04-22 12:43:18 +0000
3512@@ -71,7 +71,13 @@
3513 target_file = self.remote_pathdir.append(filename)
3514 target_file.setdata()
3515 size = target_file.getsize() if target_file.exists() else -1
3516+<<<<<<< TREE
3517 return {u'size': size}
3518
3519
3520 duplicity.backend.register_backend(u"file", LocalBackend)
3521+=======
3522+ return {'size': size}
3523+
3524+duplicity.backend.register_backend("file", LocalBackend)
3525+>>>>>>> MERGE-SOURCE
3526
3527=== modified file 'duplicity/backends/megabackend.py'
3528--- duplicity/backends/megabackend.py 2018-11-29 19:00:15 +0000
3529+++ duplicity/backends/megabackend.py 2019-04-22 12:43:18 +0000
3530@@ -34,6 +34,7 @@
3531 def __init__(self, parsed_url):
3532 duplicity.backend.Backend.__init__(self, parsed_url)
3533
3534+<<<<<<< TREE
3535 # ensure all the necessary megatools binaries exist
3536 self._check_binary_exists(u'megals')
3537 self._check_binary_exists(u'megamkdir')
3538@@ -61,7 +62,37 @@
3539 def _check_binary_exists(self, cmd):
3540 u'checks that a specified command exists in the current path'
3541
3542+=======
3543+ # ensure all the necessary megatools binaries exist
3544+ self._check_binary_exists('megals')
3545+ self._check_binary_exists('megamkdir')
3546+ self._check_binary_exists('megaget')
3547+ self._check_binary_exists('megaput')
3548+ self._check_binary_exists('megarm')
3549+
3550+ # store some basic info
3551+ self._hostname = parsed_url.hostname
3552+
3553+ if parsed_url.password is None:
3554+ self._megarc = os.getenv('HOME') + '/.megarc'
3555+ else:
3556+ self._megarc = False
3557+ self._username = parsed_url.username
3558+ self._password = self.get_password()
3559+
3560+ # remote folder (Can we assume /Root prefix?)
3561+ self._root = '/Root'
3562+ self._folder = self._root + '/' + parsed_url.path[1:]
3563+
3564+ # make sure the remote folder exists (the whole path)
3565+ self._makedir_recursive(parsed_url.path[1:].split('/'))
3566+
3567+ def _check_binary_exists(self, cmd):
3568+ 'checks that a specified command exists in the current path'
3569+
3570+>>>>>>> MERGE-SOURCE
3571 try:
3572+<<<<<<< TREE
3573 # ignore the output, we only need the return code
3574 subprocess.check_output([u'which', cmd])
3575 except Exception as e:
3576@@ -90,10 +121,45 @@
3577 self._make_dir(p)
3578 except:
3579 pass
3580+=======
3581+ # ignore the output, we only need the return code
3582+ subprocess.check_output(['which', cmd])
3583+ except Exception as e:
3584+ raise BackendException("command '%s' not found, make sure megatools are installed" % (cmd,))
3585+
3586+ def _makedir(self, path):
3587+ 'creates a remote directory'
3588+
3589+ if self._megarc:
3590+ cmd = ['megamkdir', '--config', self._megarc, path]
3591+ else:
3592+ cmd = ['megamkdir', '-u', self._username, '-p', self._password, path]
3593+
3594+ self.subprocess_popen(cmd)
3595+
3596+ def _makedir_recursive(self, path):
3597+ 'creates a remote directory (recursively the whole path), ingores errors'
3598+
3599+ print ("mkdir: %s" % ('/'.join(path),))
3600+
3601+ p = self._root
3602+
3603+ for folder in path:
3604+ p = p + '/' + folder
3605+ try:
3606+ self._make_dir(p)
3607+ except:
3608+ pass
3609+>>>>>>> MERGE-SOURCE
3610
3611 def _put(self, source_path, remote_filename):
3612+<<<<<<< TREE
3613 u'uploads file to Mega (deletes it first, to ensure it does not exist)'
3614
3615+=======
3616+ 'uploads file to Mega (deletes it first, to ensure it does not exist)'
3617+
3618+>>>>>>> MERGE-SOURCE
3619 try:
3620 self.delete(remote_filename)
3621 except Exception:
3622@@ -102,16 +168,29 @@
3623 self.upload(local_file=source_path.get_canonical(), remote_file=remote_filename)
3624
3625 def _get(self, remote_filename, local_path):
3626+<<<<<<< TREE
3627 u'downloads file from Mega'
3628
3629 self.download(remote_file=remote_filename, local_file=local_path.name)
3630+=======
3631+ 'downloads file from Mega'
3632+
3633+ self.download(remote_file=remote_filename, local_file=local_path.name)
3634+>>>>>>> MERGE-SOURCE
3635
3636 def _list(self):
3637+<<<<<<< TREE
3638 u'list files in the backup folder'
3639
3640 return self.folder_contents(files_only=True)
3641+=======
3642+ 'list files in the backup folder'
3643+
3644+ return self.folder_contents(files_only=True)
3645+>>>>>>> MERGE-SOURCE
3646
3647 def _delete(self, filename):
3648+<<<<<<< TREE
3649 u'deletes remote '
3650
3651 self.delete(remote_file=filename)
3652@@ -178,3 +257,71 @@
3653
3654 duplicity.backend.register_backend(u'mega', MegaBackend)
3655 duplicity.backend.uses_netloc.extend([u'mega'])
3656+=======
3657+ 'deletes remote '
3658+
3659+ self.delete(remote_file=filename)
3660+
3661+ def folder_contents(self, files_only=False):
3662+ 'lists contents of a folder, optionally ignoring subdirectories'
3663+
3664+ print ("megals: %s" % (self._folder,))
3665+
3666+ if self._megarc:
3667+ cmd = ['megals', '--config', self._megarc, self._folder]
3668+ else:
3669+ cmd = ['megals', '-u', self._username, '-p', self._password, self._folder]
3670+
3671+ files = subprocess.check_output(cmd)
3672+ files = files.strip().split('\n')
3673+
3674+ # remove the folder name, including the path separator
3675+ files = [f[len(self._folder) + 1:] for f in files]
3676+
3677+ # optionally ignore entries containing path separator (i.e. not files)
3678+ if files_only:
3679+ files = [f for f in files if '/' not in f]
3680+
3681+ return files
3682+
3683+ def download(self, remote_file, local_file):
3684+
3685+ print ("megaget: %s" % (remote_file,))
3686+
3687+ if self._megarc:
3688+ cmd = ['megaget', '--config', self._megarc, '--no-progress',
3689+ '--path', local_file, self._folder + '/' + remote_file]
3690+ else:
3691+ cmd = ['megaget', '-u', self._username, '-p', self._password, '--no-progress',
3692+ '--path', local_file, self._folder + '/' + remote_file]
3693+
3694+ self.subprocess_popen(cmd)
3695+
3696+ def upload(self, local_file, remote_file):
3697+
3698+ print ("megaput: %s" % (remote_file,))
3699+
3700+ if self._megarc:
3701+ cmd = ['megaput', '--config', self._megarc, '--no-progress',
3702+ '--path', self._folder + '/' + remote_file, local_file]
3703+ else:
3704+ cmd = ['megaput', '-u', self._username, '-p', self._password, '--no-progress',
3705+ '--path', self._folder + '/' + remote_file, local_file]
3706+
3707+ self.subprocess_popen(cmd)
3708+
3709+ def delete(self, remote_file):
3710+
3711+ print ("megarm: %s" % (remote_file,))
3712+
3713+ if self._megarc:
3714+ cmd = ['megarm', '--config', self._megarc, self._folder + '/' + remote_file]
3715+ else:
3716+ cmd = ['megarm', '-u', self._username, '-p', self._password, self._folder + '/' + remote_file]
3717+
3718+ self.subprocess_popen(cmd)
3719+
3720+
3721+duplicity.backend.register_backend('mega', MegaBackend)
3722+duplicity.backend.uses_netloc.extend(['mega'])
3723+>>>>>>> MERGE-SOURCE
3724
3725=== modified file 'duplicity/backends/multibackend.py'
3726--- duplicity/backends/multibackend.py 2018-11-29 19:00:15 +0000
3727+++ duplicity/backends/multibackend.py 2019-04-22 12:43:18 +0000
3728@@ -44,7 +44,6 @@
3729
3730 # the stores we are managing
3731 __stores = []
3732- __affinities = {}
3733
3734 # Set of known query paramaters
3735 __knownQueryParameters = frozenset([
3736@@ -188,6 +187,7 @@
3737
3738 store = duplicity.backend.get_backend(url)
3739 self.__stores.append(store)
3740+<<<<<<< TREE
3741
3742 # Prefix affinity
3743 if u'prefixes' in config:
3744@@ -201,11 +201,14 @@
3745 else:
3746 self.__affinities[prefix] = [store]
3747
3748+=======
3749+>>>>>>> MERGE-SOURCE
3750 # store_list = store.list()
3751 # log.Log(_("MultiBackend: at init, store %s has %s files")
3752 # % (url, len(store_list)),
3753 # log.INFO)
3754
3755+<<<<<<< TREE
3756 def _eligible_stores(self, filename):
3757 if self.__affinities:
3758 matching_prefixes = [k for k in list(self.__affinities.keys()) if filename.startswith(k)]
3759@@ -217,23 +220,21 @@
3760 # No affinity rule or no matching store for that prefix
3761 return self.__stores
3762
3763+=======
3764+>>>>>>> MERGE-SOURCE
3765 def _put(self, source_path, remote_filename):
3766 # Store an indication of whether any of these passed
3767 passed = False
3768-
3769- # Eligibile stores for this action
3770- stores = self._eligible_stores(remote_filename)
3771-
3772 # Mirror mode always starts at zero
3773 if self.__mode == u'mirror':
3774 self.__write_cursor = 0
3775
3776 first = self.__write_cursor
3777 while True:
3778- store = stores[self.__write_cursor]
3779+ store = self.__stores[self.__write_cursor]
3780 try:
3781 next = self.__write_cursor + 1
3782- if (next > len(stores) - 1):
3783+ if (next > len(self.__stores) - 1):
3784 next = 0
3785 log.Log(_(u"MultiBackend: _put: write to store #%s (%s)")
3786 % (self.__write_cursor, store.backend.parsed_url.url_string),
3787@@ -274,9 +275,7 @@
3788 # before finally giving up). So we need to get the list first
3789 # before we try to fetch
3790 # ENHANCEME: maintain a cached list for each store
3791- stores = self._eligible_stores(remote_filename)
3792-
3793- for s in stores:
3794+ for s in self.__stores:
3795 list = s.list()
3796 if remote_filename in list:
3797 s.get(remote_filename, local_path)
3798@@ -307,16 +306,13 @@
3799 def _delete(self, filename):
3800 # Store an indication on whether any passed
3801 passed = False
3802-
3803- stores = self._eligible_stores(filename)
3804-
3805 # since the backend operations will be retried, we can't
3806 # simply try to get from the store, if not found, move to the
3807 # next store (since each failure will be retried n times
3808 # before finally giving up). So we need to get the list first
3809 # before we try to delete
3810 # ENHANCEME: maintain a cached list for each store
3811- for s in stores:
3812+ for s in self.__stores:
3813 list = s.list()
3814 if filename in list:
3815 s._do_delete(filename)
3816@@ -333,5 +329,9 @@
3817 log.ERROR)
3818 # raise BackendException("failed to delete")
3819
3820+<<<<<<< TREE
3821
3822 duplicity.backend.register_backend(u'multi', MultiBackend)
3823+=======
3824+duplicity.backend.register_backend('multi', MultiBackend)
3825+>>>>>>> MERGE-SOURCE
3826
3827=== modified file 'duplicity/backends/ncftpbackend.py'
3828--- duplicity/backends/ncftpbackend.py 2019-02-26 22:21:52 +0000
3829+++ duplicity/backends/ncftpbackend.py 2019-04-22 12:43:18 +0000
3830@@ -126,6 +126,11 @@
3831 (self.flags, filename, self.url_string)
3832 self.subprocess_popen(commandline)
3833
3834+<<<<<<< TREE
3835
3836 duplicity.backend.register_backend(u"ncftp+ftp", NCFTPBackend)
3837 duplicity.backend.uses_netloc.extend([u'ncftp+ftp'])
3838+=======
3839+duplicity.backend.register_backend("ncftp+ftp", NCFTPBackend)
3840+duplicity.backend.uses_netloc.extend(['ncftp+ftp'])
3841+>>>>>>> MERGE-SOURCE
3842
3843=== modified file 'duplicity/backends/onedrivebackend.py'
3844--- duplicity/backends/onedrivebackend.py 2019-03-16 23:23:40 +0000
3845+++ duplicity/backends/onedrivebackend.py 2019-04-22 12:43:18 +0000
3846@@ -289,5 +289,9 @@
3847 def _retry_cleanup(self):
3848 self.initialize_oauth2_session()
3849
3850+<<<<<<< TREE
3851
3852 duplicity.backend.register_backend(u'onedrive', OneDriveBackend)
3853+=======
3854+duplicity.backend.register_backend('onedrive', OneDriveBackend)
3855+>>>>>>> MERGE-SOURCE
3856
3857=== modified file 'duplicity/backends/par2backend.py'
3858--- duplicity/backends/par2backend.py 2018-11-29 19:00:15 +0000
3859+++ duplicity/backends/par2backend.py 2019-04-22 12:43:18 +0000
3860@@ -218,5 +218,9 @@
3861 def close(self):
3862 self.wrapped_backend._close()
3863
3864+<<<<<<< TREE
3865
3866 backend.register_backend_prefix(u'par2', Par2Backend)
3867+=======
3868+backend.register_backend_prefix('par2', Par2Backend)
3869+>>>>>>> MERGE-SOURCE
3870
3871=== renamed file 'duplicity/backends/pcabackend.py' => 'duplicity/backends/pcabackend.py.THIS'
3872=== modified file 'duplicity/backends/pydrivebackend.py'
3873--- duplicity/backends/pydrivebackend.py 2019-02-24 15:09:46 +0000
3874+++ duplicity/backends/pydrivebackend.py 2019-04-22 12:43:18 +0000
3875@@ -93,8 +93,13 @@
3876 else:
3877 file_in_root = self.drive.CreateFile({u'title': u'i_am_in_root'})
3878 file_in_root.Upload()
3879+<<<<<<< TREE
3880 parent_folder_id = file_in_root[u'parents'][0][u'id']
3881 file_in_root.Delete()
3882+=======
3883+ parent_folder_id = file_in_root['parents'][0]['id']
3884+ file_in_root.Delete()
3885+>>>>>>> MERGE-SOURCE
3886
3887 # Fetch destination folder entry and create hierarchy if required.
3888 folder_names = string.split(parsed_url.path, u'/')
3889@@ -215,11 +220,19 @@
3890 return log.ErrorCode.backend_permission_denied
3891 return log.ErrorCode.backend_error
3892
3893+<<<<<<< TREE
3894
3895 duplicity.backend.register_backend(u'pydrive', PyDriveBackend)
3896 u""" pydrive is an alternate way to access gdocs """
3897 duplicity.backend.register_backend(u'pydrive+gdocs', PyDriveBackend)
3898 u""" register pydrive as the default way to access gdocs """
3899 duplicity.backend.register_backend(u'gdocs', PyDriveBackend)
3900+=======
3901+duplicity.backend.register_backend('pydrive', PyDriveBackend)
3902+""" pydrive is an alternate way to access gdocs """
3903+duplicity.backend.register_backend('pydrive+gdocs', PyDriveBackend)
3904+""" register pydrive as the default way to access gdocs """
3905+duplicity.backend.register_backend('gdocs', PyDriveBackend)
3906+>>>>>>> MERGE-SOURCE
3907
3908 duplicity.backend.uses_netloc.extend([u'pydrive', u'pydrive+gdocs', u'gdocs'])
3909
3910=== modified file 'duplicity/backends/rsyncbackend.py'
3911--- duplicity/backends/rsyncbackend.py 2019-02-27 16:16:50 +0000
3912+++ duplicity/backends/rsyncbackend.py 2019-04-22 12:43:18 +0000
3913@@ -157,6 +157,11 @@
3914 util.ignore_missing(os.unlink, file)
3915 os.rmdir(dir)
3916
3917+<<<<<<< TREE
3918
3919 duplicity.backend.register_backend(u"rsync", RsyncBackend)
3920 duplicity.backend.uses_netloc.extend([u'rsync'])
3921+=======
3922+duplicity.backend.register_backend("rsync", RsyncBackend)
3923+duplicity.backend.uses_netloc.extend(['rsync'])
3924+>>>>>>> MERGE-SOURCE
3925
3926=== modified file 'duplicity/backends/ssh_paramiko_backend.py'
3927--- duplicity/backends/ssh_paramiko_backend.py 2018-12-23 16:52:31 +0000
3928+++ duplicity/backends/ssh_paramiko_backend.py 2019-04-22 12:43:18 +0000
3929@@ -103,8 +103,13 @@
3930 """
3931 def missing_host_key(self, client, hostname, key):
3932 fp = hexlify(key.get_fingerprint())
3933+<<<<<<< TREE
3934 fingerprint = u':'.join(a + b for a, b in list(zip(fp[::2], fp[1::2])))
3935 question = u"""The authenticity of host '%s' can't be established.
3936+=======
3937+ fingerprint = ':'.join(a + b for a, b in list(zip(fp[::2], fp[1::2])))
3938+ question = """The authenticity of host '%s' can't be established.
3939+>>>>>>> MERGE-SOURCE
3940 %s key fingerprint is %s.
3941 Are you sure you want to continue connecting (yes/no)? """ % (hostname,
3942 key.get_name().upper(),
3943
3944=== modified file 'duplicity/backends/ssh_pexpect_backend.py'
3945--- duplicity/backends/ssh_pexpect_backend.py 2019-02-26 21:47:38 +0000
3946+++ duplicity/backends/ssh_pexpect_backend.py 2019-04-22 12:43:18 +0000
3947@@ -300,7 +300,13 @@
3948 commandline = (u"%s %s %s" % (self.sftp_command, globals.ssh_options, self.host_string))
3949 self.run_sftp_command(commandline, commands)
3950
3951+<<<<<<< TREE
3952
3953 duplicity.backend.register_backend(u"pexpect+sftp", SSHPExpectBackend)
3954 duplicity.backend.register_backend(u"pexpect+scp", SSHPExpectBackend)
3955 duplicity.backend.uses_netloc.extend([u'pexpect+sftp', u'pexpect+scp'])
3956+=======
3957+duplicity.backend.register_backend("pexpect+sftp", SSHPExpectBackend)
3958+duplicity.backend.register_backend("pexpect+scp", SSHPExpectBackend)
3959+duplicity.backend.uses_netloc.extend(['pexpect+sftp', 'pexpect+scp'])
3960+>>>>>>> MERGE-SOURCE
3961
3962=== modified file 'duplicity/backends/swiftbackend.py'
3963--- duplicity/backends/swiftbackend.py 2018-11-29 19:00:15 +0000
3964+++ duplicity/backends/swiftbackend.py 2019-04-22 12:43:18 +0000
3965@@ -22,7 +22,6 @@
3966 import os
3967
3968 import duplicity.backend
3969-from duplicity import globals
3970 from duplicity import log
3971 from duplicity import util
3972 from duplicity.errors import BackendException
3973@@ -112,9 +111,12 @@
3974 else:
3975 self.prefix = u''
3976
3977+<<<<<<< TREE
3978 policy = globals.swift_storage_policy
3979 policy_header = u'X-Storage-Policy'
3980
3981+=======
3982+>>>>>>> MERGE-SOURCE
3983 container_metadata = None
3984 try:
3985 self.conn = Connection(**conn_kwargs)
3986@@ -129,15 +131,17 @@
3987 if container_metadata is None:
3988 log.Info(u"Creating container %s" % self.container)
3989 try:
3990- headers = dict([[policy_header, policy]]) if policy else None
3991- self.conn.put_container(self.container, headers=headers)
3992+ self.conn.put_container(self.container)
3993 except Exception as e:
3994 log.FatalError(u"Container creation failed: %s %s"
3995 % (e.__class__.__name__, str(e)),
3996 log.ErrorCode.connection_failed)
3997+<<<<<<< TREE
3998 elif policy and container_metadata[policy_header.lower()] != policy:
3999 log.FatalError(u"Container '%s' exists but its storage policy is '%s' not '%s'."
4000 % (self.container, container_metadata[policy_header.lower()], policy))
4001+=======
4002+>>>>>>> MERGE-SOURCE
4003
4004 def _error_code(self, operation, e):
4005 if isinstance(e, self.resp_exc):
4006
4007=== modified file 'duplicity/backends/sxbackend.py'
4008--- duplicity/backends/sxbackend.py 2019-02-27 18:43:19 +0000
4009+++ duplicity/backends/sxbackend.py 2019-04-22 12:43:18 +0000
4010@@ -52,5 +52,9 @@
4011 commandline = u"sxrm {0}/{1}".format(self.url_string, filename)
4012 self.subprocess_popen(commandline)
4013
4014+<<<<<<< TREE
4015
4016 duplicity.backend.register_backend(u"sx", SXBackend)
4017+=======
4018+duplicity.backend.register_backend("sx", SXBackend)
4019+>>>>>>> MERGE-SOURCE
4020
4021=== modified file 'duplicity/backends/tahoebackend.py'
4022--- duplicity/backends/tahoebackend.py 2018-11-29 19:00:15 +0000
4023+++ duplicity/backends/tahoebackend.py 2019-04-22 12:43:18 +0000
4024@@ -73,7 +73,13 @@
4025 return output.split(b'\n') if output else []
4026
4027 def _delete(self, filename):
4028+<<<<<<< TREE
4029 self.run(u"tahoe", u"rm", self.get_remote_path(filename))
4030
4031
4032 duplicity.backend.register_backend(u"tahoe", TAHOEBackend)
4033+=======
4034+ self.run("tahoe", "rm", self.get_remote_path(filename))
4035+
4036+duplicity.backend.register_backend("tahoe", TAHOEBackend)
4037+>>>>>>> MERGE-SOURCE
4038
4039=== modified file 'duplicity/backends/webdavbackend.py'
4040--- duplicity/backends/webdavbackend.py 2019-03-10 22:58:32 +0000
4041+++ duplicity/backends/webdavbackend.py 2019-04-22 12:43:18 +0000
4042@@ -260,11 +260,19 @@
4043 try:
4044 return self.get_kerberos_authorization()
4045 except ImportError:
4046+<<<<<<< TREE
4047 log.Warn(_(u"python-kerberos needed to use kerberos \
4048+=======
4049+ log.Warn(_("python-kerberos needed to use kerberos \
4050+>>>>>>> MERGE-SOURCE
4051 authorization, falling back to basic auth."))
4052 return self.get_basic_authorization()
4053 except Exception as e:
4054+<<<<<<< TREE
4055 log.Warn(_(u"Kerberos authorization failed: %s.\
4056+=======
4057+ log.Warn(_("Kerberos authorization failed: %s.\
4058+>>>>>>> MERGE-SOURCE
4059 Falling back to basic auth.") % e)
4060 return self.get_basic_authorization()
4061 elif token.lower() == u'basic':
4062@@ -277,9 +285,15 @@
4063 return urllib2.parse_keqv_list(urllib2.parse_http_list(challenge_string))
4064
4065 def get_kerberos_authorization(self):
4066+<<<<<<< TREE
4067 import kerberos # pylint: disable=import-error
4068 _, ctx = kerberos.authGSSClientInit(u"HTTP@%s" % self.conn.host)
4069 kerberos.authGSSClientStep(ctx, u"")
4070+=======
4071+ import kerberos # pylint: disable=import-error
4072+ _, ctx = kerberos.authGSSClientInit("HTTP@%s" % self.conn.host)
4073+ kerberos.authGSSClientStep(ctx, "")
4074+>>>>>>> MERGE-SOURCE
4075 tgt = kerberos.authGSSClientResponse(ctx)
4076 return u'Negotiate %s' % tgt
4077
4078@@ -287,8 +301,13 @@
4079 u"""
4080 Returns the basic auth header
4081 """
4082+<<<<<<< TREE
4083 auth_string = u'%s:%s' % (self.username, self.password)
4084 return u'Basic %s' % base64.encodestring(auth_string).strip()
4085+=======
4086+ auth_string = '%s:%s' % (self.username, self.password)
4087+ return 'Basic %s' % "".join(base64.encodestring(auth_string).split())
4088+>>>>>>> MERGE-SOURCE
4089
4090 def get_digest_authorization(self, path):
4091 u"""
4092@@ -474,9 +493,17 @@
4093 if response:
4094 response.close()
4095
4096+<<<<<<< TREE
4097
4098 duplicity.backend.register_backend(u"http", WebDAVBackend)
4099 duplicity.backend.register_backend(u"https", WebDAVBackend)
4100 duplicity.backend.register_backend(u"webdav", WebDAVBackend)
4101 duplicity.backend.register_backend(u"webdavs", WebDAVBackend)
4102 duplicity.backend.uses_netloc.extend([u'http', u'https', u'webdav', u'webdavs'])
4103+=======
4104+duplicity.backend.register_backend("http", WebDAVBackend)
4105+duplicity.backend.register_backend("https", WebDAVBackend)
4106+duplicity.backend.register_backend("webdav", WebDAVBackend)
4107+duplicity.backend.register_backend("webdavs", WebDAVBackend)
4108+duplicity.backend.uses_netloc.extend(['http', 'https', 'webdav', 'webdavs'])
4109+>>>>>>> MERGE-SOURCE
4110
4111=== modified file 'duplicity/collections.py'
4112--- duplicity/collections.py 2019-03-10 22:58:32 +0000
4113+++ duplicity/collections.py 2019-04-22 12:43:18 +0000
4114@@ -31,8 +31,8 @@
4115 from future.builtins import filter, map
4116
4117 import types
4118-import gettext
4119-import sys
4120+from gettext import gettext as _
4121+
4122
4123 from duplicity import log
4124 from duplicity import file_naming
4125@@ -44,12 +44,15 @@
4126 from duplicity import util
4127 from duplicity.gpg import GPGError
4128
4129+<<<<<<< TREE
4130 # For type testing against both int and long types that works in python 2/3
4131 if sys.version_info < (3,):
4132 integer_types = (int, int)
4133 else:
4134 integer_types = (int,)
4135
4136+=======
4137+>>>>>>> MERGE-SOURCE
4138
4139 class CollectionsError(Exception):
4140 pass
4141@@ -73,7 +76,6 @@
4142 self.end_time = None # will be set if inc
4143 self.partial = False # true if a partial backup
4144 self.encrypted = False # true if an encrypted backup
4145- self.files_changed = []
4146 self.action = action
4147
4148 def is_complete(self):
4149@@ -138,10 +140,6 @@
4150 self.encrypted = bool(pr.encrypted)
4151 self.info_set = True
4152
4153- def set_files_changed(self):
4154- mf = self.get_manifest()
4155- self.files_changed = mf.get_files_changed()
4156-
4157 def set_manifest(self, remote_filename):
4158 u"""
4159 Add local and remote manifest filenames to backup set
4160@@ -150,8 +148,13 @@
4161 remote_filename)
4162 self.remote_manifest_name = remote_filename
4163
4164+<<<<<<< TREE
4165 if self.action not in [u"collection-status", u"replicate"]:
4166 local_filename_list = globals.archive_dir_path.listdir()
4167+=======
4168+ if self.action not in ["collection-status"]:
4169+ local_filename_list = globals.archive_dir.listdir()
4170+>>>>>>> MERGE-SOURCE
4171 else:
4172 local_filename_list = []
4173 for local_filename in local_filename_list:
4174@@ -161,9 +164,7 @@
4175 pr.start_time == self.start_time and
4176 pr.end_time == self.end_time):
4177 self.local_manifest_path = \
4178- globals.archive_dir_path.append(local_filename)
4179-
4180- self.set_files_changed()
4181+ globals.archive_dir.append(local_filename)
4182 break
4183
4184 def delete(self):
4185@@ -177,8 +178,13 @@
4186 except Exception:
4187 log.Debug(_(u"BackupSet.delete: missing %s") % [util.fsdecode(f) for f in rfn])
4188 pass
4189+<<<<<<< TREE
4190 if self.action not in [u"collection-status", u"replicate"]:
4191 local_filename_list = globals.archive_dir_path.listdir()
4192+=======
4193+ if self.action not in ["collection-status"]:
4194+ local_filename_list = globals.archive_dir.listdir()
4195+>>>>>>> MERGE-SOURCE
4196 else:
4197 local_filename_list = []
4198 for lfn in local_filename_list:
4199@@ -187,7 +193,7 @@
4200 pr.start_time == self.start_time and
4201 pr.end_time == self.end_time):
4202 try:
4203- globals.archive_dir_path.append(lfn).delete()
4204+ globals.archive_dir.append(lfn).delete()
4205 except Exception:
4206 log.Debug(_(u"BackupSet.delete: missing %s") % [util.fsdecode(f) for f in lfn])
4207 pass
4208@@ -242,8 +248,13 @@
4209 """
4210 assert self.local_manifest_path
4211 manifest_buffer = self.local_manifest_path.get_data()
4212+<<<<<<< TREE
4213 log.Info(_(u"Processing local manifest %s (%s)") % (
4214 self.local_manifest_path.name, len(manifest_buffer)))
4215+=======
4216+ log.Info(_("Processing local manifest %s (%s)") % (
4217+ self.local_manifest_path.name, len(manifest_buffer)))
4218+>>>>>>> MERGE-SOURCE
4219 return manifest.Manifest().from_string(manifest_buffer)
4220
4221 def get_remote_manifest(self):
4222@@ -254,11 +265,21 @@
4223 try:
4224 manifest_buffer = self.backend.get_data(self.remote_manifest_name)
4225 except GPGError as message:
4226+<<<<<<< TREE
4227 log.Error(_(u"Error processing remote manifest (%s): %s") %
4228 (util.fsdecode(self.remote_manifest_name), util.uexc(message)))
4229+=======
4230+ log.Error(_("Error processing remote manifest (%s): %s") %
4231+ (util.ufn(self.remote_manifest_name), util.uexc(message)))
4232+>>>>>>> MERGE-SOURCE
4233 return None
4234+<<<<<<< TREE
4235 log.Info(_(u"Processing remote manifest %s (%s)") % (
4236 util.fsdecode(self.remote_manifest_name), len(manifest_buffer)))
4237+=======
4238+ log.Info(_("Processing remote manifest %s (%s)") % (
4239+ util.ufn(self.remote_manifest_name), len(manifest_buffer)))
4240+>>>>>>> MERGE-SOURCE
4241 return manifest.Manifest().from_string(manifest_buffer)
4242
4243 def get_manifest(self):
4244@@ -298,9 +319,6 @@
4245 return self.end_time
4246 assert 0, u"Neither self.time nor self.end_time set"
4247
4248- def get_files_changed(self):
4249- return self.files_changed
4250-
4251 def __len__(self):
4252 u"""
4253 Return the number of volumes in the set
4254@@ -482,19 +500,19 @@
4255 Return new SignatureChain.
4256
4257 local should be true iff the signature chain resides in
4258- globals.archive_dir_path and false if the chain is in
4259+ globals.archive_dir and false if the chain is in
4260 globals.backend.
4261
4262- @param local: True if sig chain in globals.archive_dir_path
4263+ @param local: True if sig chain in globals.archive_dir
4264 @type local: Boolean
4265
4266 @param location: Where the sig chain is located
4267- @type location: globals.archive_dir_path or globals.backend
4268+ @type location: globals.archive_dir or globals.backend
4269 """
4270 if local:
4271- self.archive_dir_path, self.backend = location, None
4272+ self.archive_dir, self.backend = location, None
4273 else:
4274- self.archive_dir_path, self.backend = None, location
4275+ self.archive_dir, self.backend = None, location
4276 self.fullsig = None # filename of full signature
4277 self.inclist = [] # list of filenames of incremental signatures
4278 self.start_time, self.end_time = None, None
4279@@ -503,8 +521,13 @@
4280 u"""
4281 Local or Remote and List of files in the set
4282 """
4283+<<<<<<< TREE
4284 if self.archive_dir_path:
4285 place = _(u"local")
4286+=======
4287+ if self.archive_dir:
4288+ place = _("local")
4289+>>>>>>> MERGE-SOURCE
4290 else:
4291 place = _(u"remote")
4292 filelist = []
4293@@ -518,14 +541,24 @@
4294 Check to make sure times are in whole seconds
4295 """
4296 for time in time_list:
4297+<<<<<<< TREE
4298 if type(time) not in integer_types:
4299 assert 0, u"Time %s in %s wrong type" % (time, time_list)
4300+=======
4301+ if type(time) not in (types.LongType, types.IntType):
4302+ assert 0, "Time %s in %s wrong type" % (time, time_list)
4303+>>>>>>> MERGE-SOURCE
4304
4305 def islocal(self):
4306+<<<<<<< TREE
4307 u"""
4308 Return true if represents a signature chain in archive_dir_path
4309- """
4310- if self.archive_dir_path:
4311+=======
4312+ """
4313+ Return true if represents a signature chain in archive_dir
4314+>>>>>>> MERGE-SOURCE
4315+ """
4316+ if self.archive_dir:
4317 return True
4318 else:
4319 return False
4320@@ -562,11 +595,17 @@
4321 optionally at a certain time
4322 """
4323 assert self.fullsig
4324- if self.archive_dir_path: # local
4325+ if self.archive_dir: # local
4326 def filename_to_fileobj(filename):
4327+<<<<<<< TREE
4328 u"""Open filename in archive_dir_path, return filtered fileobj"""
4329 sig_dp = path.DupPath(self.archive_dir_path.name, (filename,))
4330 return sig_dp.filtered_open(u"rb")
4331+=======
4332+ """Open filename in archive_dir, return filtered fileobj"""
4333+ sig_dp = path.DupPath(self.archive_dir.name, (filename,))
4334+ return sig_dp.filtered_open("rb")
4335+>>>>>>> MERGE-SOURCE
4336 else:
4337 filename_to_fileobj = self.backend.get_fileobj_read
4338 return [filename_to_fileobj(f) for f in self.get_filenames(time)]
4339@@ -576,11 +615,11 @@
4340 Remove all files in signature set
4341 """
4342 # Try to delete in opposite order, so something useful even if aborted
4343- if self.archive_dir_path:
4344+ if self.archive_dir:
4345 for i in range(len(self.inclist) - 1, -1, -1):
4346- self.archive_dir_path.append(self.inclist[i]).delete()
4347+ self.archive_dir.append(self.inclist[i]).delete()
4348 if not keep_full:
4349- self.archive_dir_path.append(self.fullsig).delete()
4350+ self.archive_dir.append(self.fullsig).delete()
4351 else:
4352 assert self.backend
4353 inclist_copy = self.inclist[:]
4354@@ -610,12 +649,17 @@
4355 u"""
4356 Hold information about available chains and sets
4357 """
4358+<<<<<<< TREE
4359 def __init__(self, backend, archive_dir_path, action):
4360 u"""
4361+=======
4362+ def __init__(self, backend, archive_dir, action):
4363+ """
4364+>>>>>>> MERGE-SOURCE
4365 Make new object. Does not set values
4366 """
4367 self.backend = backend
4368- self.archive_dir_path = archive_dir_path
4369+ self.archive_dir = archive_dir
4370 self.action = action
4371
4372 # Will hold (signature chain, backup chain) pair of active
4373@@ -640,8 +684,13 @@
4374 u"""
4375 Return summary of the collection, suitable for printing to log
4376 """
4377+<<<<<<< TREE
4378 l = [u"backend %s" % (self.backend.__class__.__name__,),
4379 u"archive-dir %s" % (self.archive_dir_path,)]
4380+=======
4381+ l = ["backend %s" % (self.backend.__class__.__name__,),
4382+ "archive-dir %s" % (self.archive_dir,)]
4383+>>>>>>> MERGE-SOURCE
4384
4385 for i in range(len(self.other_backup_chains)):
4386 # A bit of a misnomer. Chain might have a sig.
4387@@ -665,7 +714,11 @@
4388 u"-----------------",
4389 _(u"Connecting with backend: %s") %
4390 (self.backend.__class__.__name__,),
4391+<<<<<<< TREE
4392 _(u"Archive dir: %s") % (self.archive_dir_path.uc_name if self.archive_dir_path else u'None',)]
4393+=======
4394+ _("Archive dir: %s") % (util.ufn(self.archive_dir.name),)]
4395+>>>>>>> MERGE-SOURCE
4396
4397 l.append(u"\n" +
4398 ngettext(u"Found %d secondary backup chain.",
4399@@ -703,8 +756,13 @@
4400 return u"\n".join(l)
4401
4402 def set_values(self, sig_chain_warning=1):
4403+<<<<<<< TREE
4404 u"""
4405 Set values from archive_dir_path and backend.
4406+=======
4407+ """
4408+ Set values from archive_dir and backend.
4409+>>>>>>> MERGE-SOURCE
4410
4411 Returns self for convenience. If sig_chain_warning is set to None,
4412 do not warn about unnecessary sig chains. This is because there may
4413@@ -720,8 +778,13 @@
4414 len(backend_filename_list))
4415
4416 # get local filename list
4417+<<<<<<< TREE
4418 if self.action not in [u"collection-status", u"replicate"]:
4419 local_filename_list = self.archive_dir_path.listdir()
4420+=======
4421+ if self.action not in ["collection-status"]:
4422+ local_filename_list = self.archive_dir.listdir()
4423+>>>>>>> MERGE-SOURCE
4424 else:
4425 local_filename_list = []
4426 log.Debug(ngettext(u"%d file exists in cache",
4427@@ -909,8 +972,13 @@
4428 return ([p[1] for p in time_set_pairs], incomplete_sets)
4429
4430 def get_signature_chains(self, local, filelist=None):
4431+<<<<<<< TREE
4432 u"""
4433 Find chains in archive_dir_path (if local is true) or backend
4434+=======
4435+ """
4436+ Find chains in archive_dir (if local is true) or backend
4437+>>>>>>> MERGE-SOURCE
4438
4439 Use filelist if given, otherwise regenerate. Return value is
4440 pair (list of chains, list of signature paths not in any
4441@@ -920,8 +988,13 @@
4442 if filelist is not None:
4443 return filelist
4444 elif local:
4445+<<<<<<< TREE
4446 if self.action not in [u"collection-status", u"replicate"]:
4447 return self.archive_dir_path.listdir()
4448+=======
4449+ if self.action not in ["collection-status"]:
4450+ return self.archive_dir.listdir()
4451+>>>>>>> MERGE-SOURCE
4452 else:
4453 return []
4454 else:
4455@@ -932,7 +1005,7 @@
4456 Return new empty signature chain
4457 """
4458 if local:
4459- return SignatureChain(True, self.archive_dir_path)
4460+ return SignatureChain(True, self.archive_dir)
4461 else:
4462 return SignatureChain(False, self.backend)
4463
4464@@ -1196,6 +1269,7 @@
4465 old_sets = [s for s in chain.get_all_sets() if s.get_time() < t]
4466 result_sets.extend(old_sets)
4467 return self.sort_sets(result_sets)
4468+<<<<<<< TREE
4469
4470 def get_file_changed_record(self, filepath):
4471 u"""
4472@@ -1246,3 +1320,5 @@
4473
4474 l.append(u"-------------------------")
4475 return u"\n".join(l)
4476+=======
4477+>>>>>>> MERGE-SOURCE
4478
4479=== modified file 'duplicity/commandline.py'
4480--- duplicity/commandline.py 2019-01-25 17:08:40 +0000
4481+++ duplicity/commandline.py 2019-04-22 12:43:18 +0000
4482@@ -19,8 +19,12 @@
4483 # along with duplicity; if not, write to the Free Software Foundation,
4484 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4485
4486+<<<<<<< TREE
4487 u"""Parse command line, check for consistency, and set globals"""
4488 from __future__ import print_function
4489+=======
4490+"""Parse command line, check for consistency, and set globals"""
4491+>>>>>>> MERGE-SOURCE
4492
4493 from builtins import filter
4494 from builtins import str
4495@@ -58,8 +62,8 @@
4496 collection_status = None # Will be set to true if collection-status command given
4497 cleanup = None # Set to true if cleanup command given
4498 verify = None # Set to true if verify command given
4499-replicate = None # Set to true if replicate command given
4500
4501+<<<<<<< TREE
4502 commands = [u"cleanup",
4503 u"collection-status",
4504 u"full",
4505@@ -71,6 +75,18 @@
4506 u"restore",
4507 u"verify",
4508 u"replicate"
4509+=======
4510+commands = ["cleanup",
4511+ "collection-status",
4512+ "full",
4513+ "incremental",
4514+ "list-current-files",
4515+ "remove-older-than",
4516+ "remove-all-but-n-full",
4517+ "remove-all-inc-of-but-n-full",
4518+ "restore",
4519+ "verify",
4520+>>>>>>> MERGE-SOURCE
4521 ]
4522
4523
4524@@ -203,8 +219,12 @@
4525 optparse.Option.take_action(
4526 self, action, dest, opt, value, values, parser)
4527
4528+<<<<<<< TREE
4529
4530 u"""
4531+=======
4532+"""
4533+>>>>>>> MERGE-SOURCE
4534 Fix:
4535 File "/usr/lib/pythonX.X/optparse.py", line XXXX, in print_help
4536 file.write(self.format_help().encode(encoding, "replace"))
4537@@ -245,7 +265,7 @@
4538 def parse_cmdline_options(arglist):
4539 u"""Parse argument list"""
4540 global select_opts, select_files, full_backup
4541- global list_current, collection_status, cleanup, remove_time, verify, replicate
4542+ global list_current, collection_status, cleanup, remove_time, verify
4543
4544 def set_log_fd(fd):
4545 if fd < 1:
4546@@ -270,7 +290,11 @@
4547 log.ErrorCode.cant_open_filelist)
4548
4549 def print_ver(o, s, v, p):
4550+<<<<<<< TREE
4551 print(u"duplicity %s" % (globals.version))
4552+=======
4553+ print "duplicity %s" % (globals.version)
4554+>>>>>>> MERGE-SOURCE
4555 sys.exit(0)
4556
4557 def add_rename(o, s, v, p):
4558@@ -391,9 +415,15 @@
4559 # whole root.
4560 # TRANSL: Used in usage help to represent a Unix-style path name. Example:
4561 # --archive-dir <path>
4562+<<<<<<< TREE
4563 parser.add_option(u"--file-to-restore", u"-r", action=u"callback", type=u"file",
4564 metavar=_(u"path"), dest=u"restore_dir",
4565 callback=lambda o, s, v, p: setattr(p.values, u"restore_dir", util.fsencode(v.strip(u'/'))))
4566+=======
4567+ parser.add_option("--file-to-restore", "-r", action="callback", type="file",
4568+ metavar=_("path"), dest="restore_dir",
4569+ callback=lambda o, s, v, p: setattr(p.values, "restore_dir", v.strip('/')))
4570+>>>>>>> MERGE-SOURCE
4571
4572 # Used to confirm certain destructive operations like deleting old files.
4573 parser.add_option(u"--force", action=u"store_true")
4574@@ -501,6 +531,11 @@
4575 callback=lambda o, s, v, p: (setattr(p.values, o.dest, True),
4576 old_fn_deprecation(s)))
4577
4578+ # Sync only required metadata
4579+ parser.add_option("--metadata-sync-mode",
4580+ default="full",
4581+ choices=("full", "partial"))
4582+
4583 # Level of Redundancy in % for Par2 files
4584 parser.add_option(u"--par2-redundancy", type=u"int", metavar=_(u"number"))
4585
4586@@ -577,6 +612,7 @@
4587 parser.add_option("--s3-kms-key-id", action=u"store", dest="s3_kms_key_id")
4588 parser.add_option("--s3-kms-grant", action=u"store", dest="s3_kms_grant")
4589
4590+<<<<<<< TREE
4591 # Option to specify a Swift container storage policy.
4592 parser.add_option(u"--swift-storage-policy", type=u"string", metavar=_(u"policy"))
4593
4594@@ -598,6 +634,8 @@
4595 # Standard storage tier used for storring backup files (Hot|Cool|Archive).
4596 parser.add_option(u"--azure-blob-tier", type=u"string", metavar=_(u"Hot|Cool|Archive"))
4597
4598+=======
4599+>>>>>>> MERGE-SOURCE
4600 # scp command to use (ssh pexpect backend)
4601 parser.add_option(u"--scp-command", metavar=_(u"command"))
4602
4603@@ -662,18 +700,21 @@
4604 parser.add_option(u"--volsize", type=u"int", action=u"callback", metavar=_(u"number"),
4605 callback=lambda o, s, v, p: setattr(p.values, u"volsize", v * 1024 * 1024))
4606
4607+<<<<<<< TREE
4608 # If set, collect only the file status, not the whole root.
4609 parser.add_option(u"--file-changed", action=u"callback", type=u"file",
4610 metavar=_(u"path"), dest=u"file_changed",
4611 callback=lambda o, s, v, p: setattr(p.values, u"file_changed", v.rstrip(u'/')))
4612
4613+=======
4614+>>>>>>> MERGE-SOURCE
4615 # delay time before next try after a failure of a backend operation
4616 # TRANSL: Used in usage help. Example:
4617 # --backend-retry-delay <seconds>
4618 parser.add_option(u"--backend-retry-delay", type=u"int", metavar=_(u"seconds"))
4619
4620 # parse the options
4621- (options, args) = parser.parse_args(arglist)
4622+ (options, args) = parser.parse_args()
4623
4624 # Copy all arguments and their values to the globals module. Don't copy
4625 # attributes that are 'hidden' (start with an underscore) or whose name is
4626@@ -743,9 +784,12 @@
4627 num_expect = 1
4628 elif cmd == u"verify":
4629 verify = True
4630+<<<<<<< TREE
4631 elif cmd == u"replicate":
4632 replicate = True
4633 num_expect = 2
4634+=======
4635+>>>>>>> MERGE-SOURCE
4636
4637 if len(args) != num_expect:
4638 command_line_error(u"Expected %d args, got %d" % (num_expect, len(args)))
4639@@ -764,12 +808,16 @@
4640 elif len(args) == 1:
4641 backend_url = args[0]
4642 elif len(args) == 2:
4643+<<<<<<< TREE
4644 if replicate:
4645 if not backend.is_backend_url(args[0]) or not backend.is_backend_url(args[1]):
4646 command_line_error(u"Two URLs expected for replicate.")
4647 src_backend_url, backend_url = args[0], args[1]
4648 else:
4649 lpath, backend_url = args_to_path_backend(args[0], args[1]) # @UnusedVariable
4650+=======
4651+ lpath, backend_url = args_to_path_backend(args[0], args[1]) # @UnusedVariable
4652+>>>>>>> MERGE-SOURCE
4653 else:
4654 command_line_error(u"Too many arguments")
4655
4656@@ -780,8 +828,13 @@
4657 set_archive_dir(expand_archive_dir(globals.archive_dir,
4658 globals.backup_name))
4659
4660+<<<<<<< TREE
4661 log.Info(_(u"Using archive dir: %s") % (globals.archive_dir_path.uc_name,))
4662 log.Info(_(u"Using backup name: %s") % (globals.backup_name,))
4663+=======
4664+ log.Info(_("Using archive dir: %s") % (util.ufn(globals.archive_dir.name),))
4665+ log.Info(_("Using backup name: %s") % (globals.backup_name,))
4666+>>>>>>> MERGE-SOURCE
4667
4668 return args
4669
4670@@ -944,7 +997,6 @@
4671 duplicity remove-older-than %(time)s [%(options)s] %(target_url)s
4672 duplicity remove-all-but-n-full %(count)s [%(options)s] %(target_url)s
4673 duplicity remove-all-inc-of-but-n-full %(count)s [%(options)s] %(target_url)s
4674- duplicity replicate %(source_url)s %(target_url)s
4675
4676 """ % dict
4677
4678@@ -964,7 +1016,6 @@
4679 scp://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
4680 ssh://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
4681 swift://%(container_name)s
4682- pca://%(container_name)s
4683 tahoe://%(alias)s/%(directory)s
4684 webdav://%(user)s[:%(password)s]@%(other_host)s/%(some_dir)s
4685 webdavs://%(user)s[:%(password)s]@%(other_host)s/%(some_dir)s
4686@@ -991,8 +1042,7 @@
4687 remove-older-than <%(time)s> <%(target_url)s>
4688 remove-all-but-n-full <%(count)s> <%(target_url)s>
4689 remove-all-inc-of-but-n-full <%(count)s> <%(target_url)s>
4690- verify <%(target_url)s> <%(source_dir)s>
4691- replicate <%(source_url)s> <%(target_url)s>""" % dict
4692+ verify <%(target_url)s> <%(source_dir)s>""" % dict
4693
4694 return msg
4695
4696@@ -1004,12 +1054,19 @@
4697 os.makedirs(dirstring)
4698 except Exception:
4699 pass
4700+<<<<<<< TREE
4701 archive_dir_path = path.Path(dirstring)
4702 if not archive_dir_path.isdir():
4703 log.FatalError(_(u"Specified archive directory '%s' does not exist, "
4704 u"or is not a directory") % (archive_dir_path.uc_name,),
4705+=======
4706+ archive_dir = path.Path(dirstring)
4707+ if not archive_dir.isdir():
4708+ log.FatalError(_("Specified archive directory '%s' does not exist, "
4709+ "or is not a directory") % (util.ufn(archive_dir.name),),
4710+>>>>>>> MERGE-SOURCE
4711 log.ErrorCode.bad_archive_dir)
4712- globals.archive_dir_path = archive_dir_path
4713+ globals.archive_dir = archive_dir
4714
4715
4716 def set_sign_key(sign_key):
4717@@ -1094,8 +1151,13 @@
4718
4719
4720 def check_consistency(action):
4721+<<<<<<< TREE
4722 u"""Final consistency check, see if something wrong with command line"""
4723 global full_backup, select_opts, list_current, collection_status, cleanup, replicate
4724+=======
4725+ """Final consistency check, see if something wrong with command line"""
4726+ global full_backup, select_opts, list_current
4727+>>>>>>> MERGE-SOURCE
4728
4729 def assert_only_one(arglist):
4730 u"""Raises error if two or more of the elements of arglist are true"""
4731@@ -1105,9 +1167,15 @@
4732 n += 1
4733 assert n <= 1, u"Invalid syntax, two conflicting modes specified"
4734
4735+<<<<<<< TREE
4736 if action in [u"list-current", u"collection-status",
4737 u"cleanup", u"remove-old", u"remove-all-but-n-full", u"remove-all-inc-of-but-n-full", u"replicate"]:
4738 assert_only_one([list_current, collection_status, cleanup, replicate,
4739+=======
4740+ if action in ["list-current", "collection-status",
4741+ "cleanup", "remove-old", "remove-all-but-n-full", "remove-all-inc-of-but-n-full"]:
4742+ assert_only_one([list_current, collection_status, cleanup,
4743+>>>>>>> MERGE-SOURCE
4744 globals.remove_time is not None])
4745 elif action == u"restore" or action == u"verify":
4746 if full_backup:
4747@@ -1153,8 +1221,14 @@
4748 sign_key=src.sign_key,
4749 recipients=src.recipients,
4750 hidden_recipients=src.hidden_recipients)
4751+<<<<<<< TREE
4752 log.Debug(_(u"GPG binary is %s, version %s") %
4753 ((globals.gpg_binary or u'gpg'), globals.gpg_profile.gpg_version))
4754+=======
4755+ log.Debug(_("GPG binary is %s, version %s") %
4756+ ((globals.gpg_binary or 'gpg'),
4757+ "%d.%d.%d" % globals.gpg_profile.gpg_version))
4758+>>>>>>> MERGE-SOURCE
4759
4760 # we can now try to import all the backends
4761 backend.import_backends()
4762@@ -1185,11 +1259,22 @@
4763 "file:///usr/local". See the man page for more information.""") % (args[0],),
4764 log.ErrorCode.bad_url)
4765 elif len(args) == 2:
4766+<<<<<<< TREE
4767 if replicate:
4768 globals.src_backend = backend.get_backend(args[0])
4769 globals.backend = backend.get_backend(args[1])
4770 action = u"replicate"
4771+=======
4772+ # Figure out whether backup or restore
4773+ backup, local_pathname = set_backend(args[0], args[1])
4774+ if backup:
4775+ if full_backup:
4776+ action = "full"
4777+ else:
4778+ action = "inc"
4779+>>>>>>> MERGE-SOURCE
4780 else:
4781+<<<<<<< TREE
4782 # Figure out whether backup or restore
4783 backup, local_pathname = set_backend(args[0], args[1])
4784 if backup:
4785@@ -1197,15 +1282,29 @@
4786 action = u"full"
4787 else:
4788 action = u"inc"
4789+=======
4790+ if verify:
4791+ action = "verify"
4792+>>>>>>> MERGE-SOURCE
4793 else:
4794+<<<<<<< TREE
4795 if verify:
4796 action = u"verify"
4797 else:
4798 action = u"restore"
4799+=======
4800+ action = "restore"
4801+>>>>>>> MERGE-SOURCE
4802
4803+<<<<<<< TREE
4804 process_local_dir(action, local_pathname)
4805 if action in [u'full', u'inc', u'verify']:
4806 set_selection()
4807+=======
4808+ process_local_dir(action, local_pathname)
4809+ if action in ['full', 'inc', 'verify']:
4810+ set_selection()
4811+>>>>>>> MERGE-SOURCE
4812 elif len(args) > 2:
4813 raise AssertionError(u"this code should not be reachable")
4814
4815
4816=== modified file 'duplicity/compilec.py'
4817--- duplicity/compilec.py 2018-12-04 20:50:28 +0000
4818+++ duplicity/compilec.py 2019-04-22 12:43:18 +0000
4819@@ -22,6 +22,7 @@
4820
4821 import sys
4822 import os
4823+<<<<<<< TREE
4824
4825 # Avoid conflict on python 2 with collections.py vs. built-in collections module
4826 sp = sys.path
4827@@ -29,6 +30,9 @@
4828 # https://github.com/PyCQA/pylint/issues/73
4829 from distutils.core import setup, Extension # pylint: disable=import-error,no-name-in-module
4830 sys.path = sp
4831+=======
4832+from distutils.core import setup, Extension
4833+>>>>>>> MERGE-SOURCE
4834
4835 assert len(sys.argv) == 1
4836 sys.argv.append("build")
4837
4838=== modified file 'duplicity/diffdir.py'
4839--- duplicity/diffdir.py 2018-11-29 19:00:15 +0000
4840+++ duplicity/diffdir.py 2019-04-22 12:43:18 +0000
4841@@ -92,7 +92,7 @@
4842 """
4843 global stats
4844 stats = statistics.StatsDeltaProcess()
4845- if isinstance(dirsig_fileobj_list, list):
4846+ if isinstance(dirsig_fileobj_list, types.ListType):
4847 sig_iter = combine_path_iters([sigtar2path_iter(x) for x
4848 in dirsig_fileobj_list])
4849 else:
4850@@ -227,7 +227,7 @@
4851 else:
4852 ti.name = b"deleted/" + b"/".join(sig_path.index)
4853 sigTarFile.addfile(ti)
4854- stats.add_deleted_file(sig_path)
4855+ stats.add_deleted_file()
4856 yield ROPath(sig_path.index)
4857 elif not sig_path or new_path != sig_path:
4858 # Must calculate new signature and create delta
4859@@ -294,7 +294,7 @@
4860 while 1:
4861 if not relem1:
4862 try:
4863- relem1 = next(riter1)
4864+ relem1 = riter1.next()
4865 except StopIteration:
4866 if relem2:
4867 yield (None, relem2)
4868@@ -304,7 +304,7 @@
4869 index1 = relem1.index
4870 if not relem2:
4871 try:
4872- relem2 = next(riter2)
4873+ relem2 = riter2.next()
4874 except StopIteration:
4875 if relem1:
4876 yield (relem1, None)
4877@@ -345,7 +345,7 @@
4878 Represent the next element as a triple, to help sorting
4879 """
4880 try:
4881- path = next(path_iter_list[iter_index])
4882+ path = path_iter_list[iter_index].next()
4883 except StopIteration:
4884 return None
4885 return (path.index, iter_index, path)
4886@@ -385,7 +385,7 @@
4887 """
4888 global stats
4889 stats = statistics.StatsDeltaProcess()
4890- if isinstance(sig_infp_list, list):
4891+ if isinstance(sig_infp_list, types.ListType):
4892 sig_path_iter = get_combined_path_iter(sig_infp_list)
4893 else:
4894 sig_path_iter = sigtar2path_iter(sig_infp_list)
4895@@ -541,7 +541,11 @@
4896 result = self.process_continued() # pylint: disable=assignment-from-no-return
4897 else:
4898 # Below a StopIteration exception will just be passed upwards
4899+<<<<<<< TREE
4900 result = self.process(next(self.input_iter)) # pylint: disable=assignment-from-no-return
4901+=======
4902+ result = self.process(self.input_iter.next())
4903+>>>>>>> MERGE-SOURCE
4904 block_number = self.process_next_vol_number
4905 self.offset += len(result.data)
4906 self.previous_index = result.index
4907
4908=== modified file 'duplicity/dup_threading.py'
4909--- duplicity/dup_threading.py 2018-11-29 19:00:15 +0000
4910+++ duplicity/dup_threading.py 2019-04-22 12:43:18 +0000
4911@@ -28,12 +28,15 @@
4912 at least python 2.5.)
4913 """
4914
4915+<<<<<<< TREE
4916 from future import standard_library
4917 standard_library.install_aliases()
4918 from builtins import object
4919 import sys
4920 from duplicity import errors
4921
4922+=======
4923+>>>>>>> MERGE-SOURCE
4924 _threading_supported = True
4925
4926 try:
4927@@ -48,6 +51,10 @@
4928 import dummy_threading as threading
4929 _threading_supported = False
4930
4931+import sys
4932+
4933+from duplicity import errors
4934+
4935
4936 def threading_supported():
4937 u"""
4938
4939=== modified file 'duplicity/dup_time.py'
4940=== modified file 'duplicity/file_naming.py'
4941--- duplicity/file_naming.py 2018-11-29 19:00:15 +0000
4942+++ duplicity/file_naming.py 2019-04-22 12:43:18 +0000
4943@@ -448,11 +448,3 @@
4944 self.encrypted = encrypted # true if gpg encrypted
4945
4946 self.partial = partial
4947-
4948- def __eq__(self, other):
4949- return self.type == other.type and \
4950- self.manifest == other.manifest and \
4951- self.time == other.time and \
4952- self.start_time == other.start_time and \
4953- self.end_time == other.end_time and \
4954- self.partial == other.partial
4955
4956=== modified file 'duplicity/globals.py'
4957--- duplicity/globals.py 2019-01-25 17:08:40 +0000
4958+++ duplicity/globals.py 2019-04-22 12:43:18 +0000
4959@@ -58,9 +58,14 @@
4960 # contains the signatures and manifests of the relevent backup
4961 # collection), and for checkpoint state between volumes.
4962 # NOTE: this gets expanded in duplicity.commandline
4963+<<<<<<< TREE
4964 os.environ[u"XDG_CACHE_HOME"] = os.getenv(u"XDG_CACHE_HOME", os.path.expanduser(u"~/.cache"))
4965 archive_dir = os.path.expandvars(u"$XDG_CACHE_HOME/duplicity")
4966 archive_dir_path = None
4967+=======
4968+os.environ["XDG_CACHE_HOME"] = os.getenv("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
4969+archive_dir = os.path.expandvars("$XDG_CACHE_HOME/duplicity")
4970+>>>>>>> MERGE-SOURCE
4971
4972 # config dir for future use
4973 os.environ[u"XDG_CONFIG_HOME"] = os.getenv(u"XDG_CONFIG_HOME", os.path.expanduser(u"~/.config"))
4974@@ -220,6 +225,7 @@
4975 # Use server side encryption in s3
4976 s3_use_sse = False
4977
4978+<<<<<<< TREE
4979 # Use server side kms encryption in s3
4980 s3_use_sse_kms = False
4981 s3_kms_key_id = None
4982@@ -240,6 +246,8 @@
4983 # Standard storage tier used for storring backup blobs (Hot|Cool|Archive).
4984 azure_blob_tier = None
4985
4986+=======
4987+>>>>>>> MERGE-SOURCE
4988 # Whether to use the full email address as the user name when
4989 # logging into an imap server. If false just the user name
4990 # part of the email address is used.
4991@@ -249,6 +257,9 @@
4992 # Can be changed with a command line argument.
4993 imap_mailbox = u"INBOX"
4994
4995+# Sync all metadata by default
4996+metadata_sync_mode = "full"
4997+
4998 # Whether the old filename format is in effect.
4999 old_filenames = False
5000
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches