Merge lp:~ed.so/duplicity/remove_copyCom into lp:~duplicity-team/duplicity/0.8-series

Proposed by edso
Status: Merged
Merge reported by: Kenneth Loafman
Merged at revision: not available
Proposed branch: lp:~ed.so/duplicity/remove_copyCom
Merge into: lp:~duplicity-team/duplicity/0.8-series
Diff against target: 55746 lines (+29684/-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 (+121/-20)
bin/duplicity.1 (+17/-150)
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 (+31/-1)
duplicity/backends/b2backend.py (+104/-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 (+102/-26)
duplicity/commandline.py (+102/-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 (+18/-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:~ed.so/duplicity/remove_copyCom
Reviewer Review Type Date Requested Status
Kenneth Loafman Needs Fixing
Review via email: mp+363907@code.launchpad.net

Commit message

remove a small copy.com remainder in man page

To post a comment you must log in.
Revision history for this message
Kenneth Loafman (kenneth-loafman) wrote :

Looks like you're trying to merge 0.7 into 0.8.

lp:duplicity is 0.8
lp:duplicity/0.7-series is 0.7

review: Needs Fixing
Revision history for this message
edso (ed.so) wrote :

On 11.03.2019 19:26, Kenneth Loafman wrote:
> Review: Needs Fixing
>
> Looks like you're trying to merge 0.7 into 0.8.
>
> lp:duplicity is 0.8
> lp:duplicity/0.7-series is 0.7
>

@Ken, maybe its easier you remove the paragraph in the man page by hand.
https://bazaar.launchpad.net/~ed.so/duplicity/remove_copyCom/revision/1373

had to setup bzr again just to push this minor change and obviously failed miserably.

..ede

Revision history for this message
Kenneth Loafman (kenneth-loafman) wrote :

Manually removed.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CHANGELOG'
2--- CHANGELOG 2019-02-25 16:30:59 +0000
3+++ CHANGELOG 2019-03-04 12:09:45 +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@@ -404,6 +525,116 @@
265 (Hot,Cool,Archive) used for uploaded files.
266 * Merged in lp:~vam9/duplicity/0.8-series-s3-kms-support
267 - Added s3 kms server side encryption support with kms-grants support.
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@@ -444,6 +675,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@@ -463,6 +695,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@@ -480,6 +716,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@@ -732,9 +971,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-02-25 16:30:59 +0000
423+++ Changelog.GNU 2019-03-04 12:09:45 +0000
424@@ -1,3 +1,4 @@
425+<<<<<<< TREE
426 2019-02-25 Kenneth Loafman <kenneth@loafman.com>
427
428 * Merged in lp:~mgorse/duplicity/0.8-series
429@@ -333,43 +334,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@@ -380,19 +609,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@@ -418,26 +634,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@@ -452,53 +648,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@@ -507,6 +662,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@@ -517,55 +676,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@@ -573,13 +699,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@@ -588,6 +707,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@@ -599,13 +725,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@@ -616,9 +739,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@@ -652,21 +774,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@@ -680,6 +791,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@@ -687,6 +803,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@@ -707,27 +827,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-03-04 12:09:45 +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-03-04 12:09:45 +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 2018-11-29 19:00:15 +0000
1257+++ bin/duplicity 2019-03-04 12:09:45 +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@@ -1127,6 +1185,8 @@
1478 globals.backend.close()
1479
1480
1481+=======
1482+>>>>>>> MERGE-SOURCE
1483 def sync_archive():
1484 u"""
1485 Synchronize local archive manifest file and sig chains to remote archives.
1486@@ -1199,7 +1259,7 @@
1487 return (pr, loc_name, fn)
1488
1489 def remove_local(fn):
1490- del_name = globals.archive_dir_path.append(fn).name
1491+ del_name = globals.archive_dir.append(fn).name
1492
1493 log.Notice(_(u"Deleting local %s (not authoritative at backend).") %
1494 util.fsdecode(del_name))
1495@@ -1266,14 +1326,14 @@
1496 else:
1497 gpg.GzipWriteFile(src_iter, tdp.name, size=sys.maxsize)
1498 tdp.setdata()
1499- tdp.move(globals.archive_dir_path.append(loc_name))
1500+ tdp.move(globals.archive_dir.append(loc_name))
1501
1502 # get remote metafile list
1503 remlist = globals.backend.list()
1504 remote_metafiles, ignored, rem_needpass = get_metafiles(remlist)
1505
1506 # get local metafile list
1507- loclist = globals.archive_dir_path.listdir()
1508+ loclist = globals.archive_dir.listdir()
1509 local_metafiles, local_partials, loc_needpass = get_metafiles(loclist)
1510
1511 # we have the list of metafiles on both sides. remote is always
1512@@ -1496,7 +1556,11 @@
1513 # determine what action we're performing and process command line
1514 action = commandline.ProcessCommandLine(sys.argv[1:])
1515
1516+<<<<<<< TREE
1517 globals.lockpath = os.path.join(globals.archive_dir_path.name, b"lockfile")
1518+=======
1519+ globals.lockpath = os.path.join(globals.archive_dir.name, "lockfile")
1520+>>>>>>> MERGE-SOURCE
1521 globals.lockfile = fasteners.process_lock.InterProcessLock(globals.lockpath)
1522 log.Debug(_(u"Acquiring lockfile %s") % globals.lockpath)
1523 if not globals.lockfile.acquire(blocking=False):
1524@@ -1527,12 +1591,16 @@
1525 check_resources(action)
1526
1527 # check archive synch with remote, fix if needed
1528+<<<<<<< TREE
1529 if action not in [u"collection-status", u"replicate"]:
1530+=======
1531+ if action not in ["collection-status"]:
1532+>>>>>>> MERGE-SOURCE
1533 sync_archive()
1534
1535 # get current collection status
1536 col_stats = collections.CollectionsStatus(globals.backend,
1537- globals.archive_dir_path,
1538+ globals.archive_dir,
1539 action).set_values()
1540
1541 while True:
1542@@ -1563,7 +1631,7 @@
1543 log.Notice(_(u"Cleaning up previous partial %s backup set, restarting." % action))
1544 last_backup.delete()
1545 col_stats = collections.CollectionsStatus(globals.backend,
1546- globals.archive_dir_path,
1547+ globals.archive_dir,
1548 action).set_values()
1549 continue
1550 break
1551@@ -1592,12 +1660,18 @@
1552 verify(col_stats)
1553 elif action == u"list-current":
1554 list_current(col_stats)
1555+<<<<<<< TREE
1556 elif action == u"collection-status":
1557 if not globals.file_changed:
1558 log.PrintCollectionStatus(col_stats, True)
1559 else:
1560 log.PrintCollectionFileChangedStatus(col_stats, globals.file_changed, True)
1561 elif action == u"cleanup":
1562+=======
1563+ elif action == "collection-status":
1564+ log.PrintCollectionStatus(col_stats, True)
1565+ elif action == "cleanup":
1566+>>>>>>> MERGE-SOURCE
1567 cleanup(col_stats)
1568 elif action == u"remove-old":
1569 remove_old(col_stats)
1570@@ -1605,8 +1679,11 @@
1571 remove_all_but_n_full(col_stats)
1572 elif action == u"sync":
1573 sync_archive()
1574+<<<<<<< TREE
1575 elif action == u"replicate":
1576 replicate()
1577+=======
1578+>>>>>>> MERGE-SOURCE
1579 else:
1580 assert action == u"inc" or action == u"full", action
1581 # the passphrase for full and inc is used by --sign-key
1582@@ -1665,8 +1742,13 @@
1583 finally:
1584 tempdir.default().cleanup()
1585
1586+<<<<<<< TREE
1587
1588 if __name__ == u"__main__":
1589+=======
1590+
1591+if __name__ == "__main__":
1592+>>>>>>> MERGE-SOURCE
1593 try:
1594
1595 # import cProfile
1596@@ -1703,8 +1785,13 @@
1597 # For gpg errors, don't show an ugly stack trace by
1598 # default. But do with sufficient verbosity.
1599 util.release_lockfile()
1600+<<<<<<< TREE
1601 log.Info(_(u"GPG error detail: %s")
1602 % util.exception_traceback())
1603+=======
1604+ log.Info(_("GPG error detail: %s")
1605+ % util.exception_traceback())
1606+>>>>>>> MERGE-SOURCE
1607 log.FatalError(u"%s: %s" % (e.__class__.__name__, e.args[0]),
1608 log.ErrorCode.gpg_failed,
1609 e.__class__.__name__)
1610@@ -1713,8 +1800,13 @@
1611 util.release_lockfile()
1612 # For user errors, don't show an ugly stack trace by
1613 # default. But do with sufficient verbosity.
1614+<<<<<<< TREE
1615 log.Info(_(u"User error detail: %s")
1616 % util.exception_traceback())
1617+=======
1618+ log.Info(_("User error detail: %s")
1619+ % util.exception_traceback())
1620+>>>>>>> MERGE-SOURCE
1621 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),
1622 log.ErrorCode.user_error,
1623 e.__class__.__name__)
1624@@ -1723,15 +1815,24 @@
1625 util.release_lockfile()
1626 # For backend errors, don't show an ugly stack trace by
1627 # default. But do with sufficient verbosity.
1628+<<<<<<< TREE
1629 log.Info(_(u"Backend error detail: %s")
1630 % util.exception_traceback())
1631+=======
1632+ log.Info(_("Backend error detail: %s")
1633+ % util.exception_traceback())
1634+>>>>>>> MERGE-SOURCE
1635 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),
1636 log.ErrorCode.user_error,
1637 e.__class__.__name__)
1638
1639 except Exception as e:
1640 util.release_lockfile()
1641+<<<<<<< TREE
1642 if u"Forced assertion for testing" in util.uexc(e):
1643+=======
1644+ if "Forced assertion for testing" in util.uexc(e):
1645+>>>>>>> MERGE-SOURCE
1646 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),
1647 log.ErrorCode.exception,
1648 e.__class__.__name__)
1649
1650=== modified file 'bin/duplicity.1'
1651--- bin/duplicity.1 2019-01-26 16:36:27 +0000
1652+++ bin/duplicity.1 2019-03-04 12:09:45 +0000
1653@@ -21,7 +21,7 @@
1654 source_url target_directory
1655
1656 .B duplicity collection-status
1657-.I [options] [--file-changed <relpath>]
1658+.I [options]
1659 target_url
1660
1661 .B duplicity list-current-files
1662@@ -48,10 +48,6 @@
1663 .I [options] [--force] [--extra-clean]
1664 target_url
1665
1666-.B duplicity replicate
1667-.I [options] [--time time]
1668-source_url target_url
1669-
1670 .SH DESCRIPTION
1671 Duplicity incrementally backs up files and folders into
1672 tar-format volumes encrypted with GnuPG and places them to a
1673@@ -168,28 +164,23 @@
1674
1675 .TP
1676 .BI "verify " "[--compare-data] [--time <time>] [--file-to-restore <rel_path>] <url> <local_path>"
1677-Verify tests the integrity of the backup archives at the remote location by downloading each file
1678-and checking both that it can restore the archive and that the restored file matches the signature
1679-of that file stored in the backup, i.e. compares the archived file with its hash value from archival
1680-time. Verify does not actually restore and will not overwrite any local files. Duplicity
1681-will exit with a non-zero error level if any files do not match the signature stored in the archive
1682-for that file. On verbosity level 4 or higher, it will log a message for each file that differs
1683-from the stored signature. Files must be downloaded to the local machine in order to compare them.
1684-Verify does not compare the backed-up version of the file to the current local copy of the files
1685-unless the --compare-data option is used (see below).
1686+Restore backup contents temporarily file by file and compare against the local path's contents.
1687+duplicity will exit with a non-zero error level if any files are different.
1688+On verbosity level info (4) or higher, a message for each file that has
1689+changed will be logged.
1690 .br
1691 The
1692 .I --file-to-restore
1693 option restricts verify to that file or folder.
1694 The
1695 .I --time
1696-option allows to select a backup to verify.
1697+option allows to select a backup to verify against.
1698 The
1699 .I --compare-data
1700 option enables data comparison (see below).
1701
1702 .TP
1703-.BI "collection-status " "[--file-changed <relpath>]" "<url>"
1704+.BI "collection-status " "<url>"
1705 Summarize the status of the backup repository by printing the chains
1706 and sets found, and the number of volumes in each.
1707
1708@@ -252,19 +243,6 @@
1709 .I --force
1710 will be needed to delete the files instead of just listing them.
1711
1712-.TP
1713-.BI "replicate " "[--time time] <source_url> <target_url>"
1714-Replicate backup sets from source to target backend. Files will be
1715-(re)-encrypted and (re)-compressed depending on normal backend
1716-options. Signatures and volumes will not get recomputed, thus options like
1717-.BI --volsize
1718-or
1719-.BI --max-blocksize
1720-have no effect.
1721-When
1722-.I --time time
1723-is given, only backup sets older than time will be replicated.
1724-
1725 .SH OPTIONS
1726
1727 .TP
1728@@ -349,14 +327,8 @@
1729
1730 .TP
1731 .BI --compare-data
1732-Enable data comparison of regular files on action verify. This conducts a
1733-verify as described above to verify the integrity of the backup archives,
1734-but additionally compares restored files to those in target_directory.
1735-Duplicity will not replace any files in target_directory. Duplicity will
1736-exit with a non-zero error level if the files do not correctly verify or
1737-if any files from the archive differ from those in target_directory. On
1738-verbosity level 4 or higher, it will log a message for each file that
1739-differs from its equivalent in target_directory.
1740+Enable data comparison of regular files on action verify.
1741+This is disabled by default for performance reasons.
1742
1743 .TP
1744 .BI --copy-links
1745@@ -465,15 +437,6 @@
1746 argument for more information.
1747
1748 .TP
1749-.BI "--file-changed " path
1750-This option may be given in collection-status mode, causing only
1751-.I path
1752-status to be collect instead of the entire contents of the backup archive.
1753-.I path
1754-should be given relative to the root of the directory backed up.
1755-
1756-
1757-.TP
1758 .BI "--file-prefix, --file-prefix-manifest, --file-prefix-archive, --file-prefix-signature
1759 Adds a prefix to all files, manifest files, archive files, and/or signature files.
1760
1761@@ -816,6 +779,7 @@
1762 when uploading to S3 to ensure you kill connections to slow S3 endpoints.
1763
1764 .TP
1765+<<<<<<< TREE
1766 .BI "--azure-blob-tier"
1767 Standard storage tier used for backup files (Hot|Cool|Archive).
1768
1769@@ -839,6 +803,8 @@
1770 blob size exceeds 64MB. The default values is 2.
1771
1772 .TP
1773+=======
1774+>>>>>>> MERGE-SOURCE
1775 .BI "--scp-command " command
1776 .B (only ssh pexpect backend with --use-scp enabled)
1777 The
1778@@ -948,13 +914,6 @@
1779 .BR "A NOTE ON SSL CERTIFICATE VERIFICATION" .
1780
1781 .TP
1782-.BI --swift-storage-policy
1783-Use this storage policy when operating on Swift containers.
1784-.br
1785-See also
1786-.BR "A NOTE ON SWIFT (OPENSTACK OBJECT STORAGE) ACCESS" .
1787-
1788-.TP
1789 .BI "--tempdir " directory
1790 Use this existing directory for duplicity temporary files instead of
1791 the system default, which is usually the /tmp directory. This option
1792@@ -1093,15 +1052,6 @@
1793 Formats of each of the URL schemes follow:
1794
1795 .PP
1796-.B "Amazon Drive Backend"
1797-.PP
1798-.RS
1799-ad://some_dir
1800-.PP
1801-See also
1802-.B "A NOTE ON AMAZON DRIVE"
1803-.RE
1804-.PP
1805 .BR "Azure"
1806 .PP
1807 .RS
1808@@ -1266,15 +1216,6 @@
1809 .B "A NOTE ON SWIFT (OPENSTACK OBJECT STORAGE) ACCESS"
1810 .RE
1811 .PP
1812-.BR "Public Cloud Archive" " (OVH)"
1813-.PP
1814-.RS
1815-pca://container_name[/prefix]
1816-.PP
1817-See also
1818-.B "A NOTE ON PCA ACCESS"
1819-.RE
1820-.PP
1821 .B "Tahoe-LAFS"
1822 .PP
1823 .RS
1824@@ -1584,25 +1525,6 @@
1825 which aren't followed by 'foo'. However, it wouldn't match /home even
1826 if /home/ben/1234567 existed.
1827
1828-.SH A NOTE ON AMAZON DRIVE
1829-.IP 1.
1830-The API Keys used for Amazon Drive have not been granted production limits.
1831-Amazon do not say what the development limits are and are not replying to
1832-to requests to whitelist duplicity. A related tool, acd_cli, was demoted to
1833-development limits, but continues to work fine except for cases of excessive
1834-usage. If you experience throttling and similar issues with Amazon Drive using
1835-this backend, please report them to the mailing list.
1836-.IR
1837-.IP 2.
1838-If you previously used the
1839-.BI acd+acdcli
1840-backend, it is strongly recommended to update to the
1841-.BI ad
1842-backend instead, since it interfaces directly with Amazon Drive. You will need
1843-to setup the OAuth once again, but can otherwise keep your backups and config.
1844-.IR
1845-.RE
1846-
1847 .SH A NOTE ON AZURE ACCESS
1848 The Azure backend requires the Microsoft Azure Storage SDK for Python to be
1849 installed on the system.
1850@@ -1610,13 +1532,9 @@
1851 .B REQUIREMENTS
1852 above.
1853
1854-It uses environment variables for authentification:
1855+It uses two environment variables for authentification:
1856 .BR AZURE_ACCOUNT_NAME " (required),"
1857-.BR AZURE_ACCOUNT_KEY " (optional),
1858-.BR AZURE_SHARED_ACCESS_SIGNATURE " (optional)."
1859-One of
1860-.BR AZURE_ACCOUNT_KEY " or"
1861-.BR AZURE_SHARED_ACCESS_SIGNATURE " is required."
1862+.BR AZURE_ACCOUNT_KEY " (required)"
1863
1864 A container name must be a valid DNS name, conforming to the following naming
1865 rules:
1866@@ -1753,13 +1671,8 @@
1867
1868 .SH A NOTE ON FILENAME PREFIXES
1869
1870-Filename prefixes can be used in
1871-.B "multi backend "
1872-with
1873-.B "mirror "
1874-mode to define affinity rules. They can also be used in conjunction with
1875-S3 lifecycle rules to transition archive files to Glacier, while keeping
1876-metadata (signature and manifest files) on S3.
1877+Filename prefixes can be used in conjunction with S3 lifecycle rules to transition
1878+archive files to Glacier, while keeping metadata (signature and manifest files) on S3.
1879
1880 Duplicity does not require access to archive files except when restoring from backup.
1881
1882@@ -1876,8 +1789,7 @@
1883 "name" : "FOO",
1884 "value" : "bar"
1885 }
1886- ],
1887- "prefixes": ["prefix1_", "prefix2_"]
1888+ ]
1889 },
1890 {
1891 "url": "file:///path/to/dir"
1892@@ -2093,40 +2005,6 @@
1893 .B SWIFT_AUTHVERSION
1894 is unspecified, it will default to version 1.
1895
1896-.SH A NOTE ON PCA ACCESS
1897-PCA is a long-term data archival solution by OVH. It runs a slightly modified
1898-version of Openstack Swift introducing latency in the data retrieval process.
1899-It is a good pick for a
1900-.BR "multi backend "
1901-configuration where receiving volumes while an other backend is used to store
1902-manifests and signatures.
1903-
1904-.br
1905-The backend requires python-switclient to be installed on the system.
1906-python-keystoneclient is also needed to interact with OpenStack's Keystone
1907-Identity service.
1908-See
1909-.B REQUIREMENTS
1910-above.
1911-
1912-It uses following environment variables for authentification:
1913-.BR PCA_USERNAME " (required),"
1914-.BR PCA_PASSWORD " (required),"
1915-.BR PCA_AUTHURL " (required),"
1916-.BR PCA_USERID " (optional),"
1917-.BR PCA_TENANTID " (optional, but either the tenant name or tenant id must be supplied)"
1918-.BR PCA_REGIONNAME " (optional),"
1919-.BR PCA_TENANTNAME " (optional, but either the tenant name or tenant id must be supplied)"
1920-
1921-If the user was previously authenticated, the following environment
1922-variables can be used instead:
1923-.BR PCA_PREAUTHURL " (required),"
1924-.BR PCA_PREAUTHTOKEN " (required)"
1925-
1926-If
1927-.B PCA_AUTHVERSION
1928-is unspecified, it will default to version 2.
1929-
1930 .SH A NOTE ON MEDIAFIRE BACKEND
1931 This backend requires
1932 .B mediafire
1933@@ -2237,13 +2115,6 @@
1934
1935 Some backends also require additional components (probably available as packages for your specific platform):
1936 .TP
1937-.BR "Amazon Drive backend"
1938-.B python-requests
1939-- http://python-requests.org
1940-.br
1941-.B python-requests-oauthlib
1942-- https://github.com/requests/requests-oauthlib
1943-.TP
1944 .BR "azure backend" " (Azure Blob Storage Service)"
1945 .B Microsoft Azure Storage SDK for Python
1946 - https://pypi.python.org/pypi/azure-storage/
1947@@ -2260,10 +2131,6 @@
1948 .B Dropbox Python SDK
1949 - https://www.dropbox.com/developers/reference/sdk
1950 .TP
1951-.BR "copy backend" " (Copy.com)"
1952-.B python-urllib3
1953-- https://github.com/shazow/urllib3
1954-.TP
1955 .BR "gdocs gdata backend" " (legacy Google Docs backend)"
1956 .B Google Data APIs Python Client Library
1957 - http://code.google.com/p/gdata-python-client/
1958
1959=== modified file 'debian/control'
1960=== renamed file 'docs/Makefile' => 'docs/Makefile.THIS'
1961=== removed directory 'docs/_static'
1962=== removed directory 'docs/_templates'
1963=== renamed file 'docs/conf.py' => 'docs/conf.py.THIS'
1964=== removed file 'docs/duplicity.asyncscheduler.rst'
1965--- docs/duplicity.asyncscheduler.rst 2018-07-24 16:17:12 +0000
1966+++ docs/duplicity.asyncscheduler.rst 1970-01-01 00:00:00 +0000
1967@@ -1,7 +0,0 @@
1968-duplicity.asyncscheduler module
1969-===============================
1970-
1971-.. automodule:: duplicity.asyncscheduler
1972- :members:
1973- :undoc-members:
1974- :show-inheritance:
1975
1976=== removed file 'docs/duplicity.backend.rst'
1977--- docs/duplicity.backend.rst 2018-07-24 16:17:12 +0000
1978+++ docs/duplicity.backend.rst 1970-01-01 00:00:00 +0000
1979@@ -1,7 +0,0 @@
1980-duplicity.backend module
1981-========================
1982-
1983-.. automodule:: duplicity.backend
1984- :members:
1985- :undoc-members:
1986- :show-inheritance:
1987
1988=== removed file 'docs/duplicity.backends.azurebackend.rst'
1989--- docs/duplicity.backends.azurebackend.rst 2018-07-24 16:17:12 +0000
1990+++ docs/duplicity.backends.azurebackend.rst 1970-01-01 00:00:00 +0000
1991@@ -1,7 +0,0 @@
1992-duplicity.backends.azurebackend module
1993-======================================
1994-
1995-.. automodule:: duplicity.backends.azurebackend
1996- :members:
1997- :undoc-members:
1998- :show-inheritance:
1999
2000=== removed file 'docs/duplicity.backends.b2backend.rst'
2001--- docs/duplicity.backends.b2backend.rst 2018-07-24 16:17:12 +0000
2002+++ docs/duplicity.backends.b2backend.rst 1970-01-01 00:00:00 +0000
2003@@ -1,7 +0,0 @@
2004-duplicity.backends.b2backend module
2005-===================================
2006-
2007-.. automodule:: duplicity.backends.b2backend
2008- :members:
2009- :undoc-members:
2010- :show-inheritance:
2011
2012=== removed file 'docs/duplicity.backends.botobackend.rst'
2013--- docs/duplicity.backends.botobackend.rst 2018-07-24 16:17:12 +0000
2014+++ docs/duplicity.backends.botobackend.rst 1970-01-01 00:00:00 +0000
2015@@ -1,7 +0,0 @@
2016-duplicity.backends.botobackend module
2017-=====================================
2018-
2019-.. automodule:: duplicity.backends.botobackend
2020- :members:
2021- :undoc-members:
2022- :show-inheritance:
2023
2024=== removed file 'docs/duplicity.backends.cfbackend.rst'
2025--- docs/duplicity.backends.cfbackend.rst 2018-07-24 16:17:12 +0000
2026+++ docs/duplicity.backends.cfbackend.rst 1970-01-01 00:00:00 +0000
2027@@ -1,7 +0,0 @@
2028-duplicity.backends.cfbackend module
2029-===================================
2030-
2031-.. automodule:: duplicity.backends.cfbackend
2032- :members:
2033- :undoc-members:
2034- :show-inheritance:
2035
2036=== removed file 'docs/duplicity.backends.dpbxbackend.rst'
2037--- docs/duplicity.backends.dpbxbackend.rst 2018-07-24 16:17:12 +0000
2038+++ docs/duplicity.backends.dpbxbackend.rst 1970-01-01 00:00:00 +0000
2039@@ -1,7 +0,0 @@
2040-duplicity.backends.dpbxbackend module
2041-=====================================
2042-
2043-.. automodule:: duplicity.backends.dpbxbackend
2044- :members:
2045- :undoc-members:
2046- :show-inheritance:
2047
2048=== removed file 'docs/duplicity.backends.gdocsbackend.rst'
2049--- docs/duplicity.backends.gdocsbackend.rst 2018-07-24 16:17:12 +0000
2050+++ docs/duplicity.backends.gdocsbackend.rst 1970-01-01 00:00:00 +0000
2051@@ -1,7 +0,0 @@
2052-duplicity.backends.gdocsbackend module
2053-======================================
2054-
2055-.. automodule:: duplicity.backends.gdocsbackend
2056- :members:
2057- :undoc-members:
2058- :show-inheritance:
2059
2060=== removed file 'docs/duplicity.backends.giobackend.rst'
2061--- docs/duplicity.backends.giobackend.rst 2018-07-24 16:17:12 +0000
2062+++ docs/duplicity.backends.giobackend.rst 1970-01-01 00:00:00 +0000
2063@@ -1,7 +0,0 @@
2064-duplicity.backends.giobackend module
2065-====================================
2066-
2067-.. automodule:: duplicity.backends.giobackend
2068- :members:
2069- :undoc-members:
2070- :show-inheritance:
2071
2072=== removed file 'docs/duplicity.backends.hsibackend.rst'
2073--- docs/duplicity.backends.hsibackend.rst 2018-07-24 16:17:12 +0000
2074+++ docs/duplicity.backends.hsibackend.rst 1970-01-01 00:00:00 +0000
2075@@ -1,7 +0,0 @@
2076-duplicity.backends.hsibackend module
2077-====================================
2078-
2079-.. automodule:: duplicity.backends.hsibackend
2080- :members:
2081- :undoc-members:
2082- :show-inheritance:
2083
2084=== removed file 'docs/duplicity.backends.hubicbackend.rst'
2085--- docs/duplicity.backends.hubicbackend.rst 2018-07-24 16:17:12 +0000
2086+++ docs/duplicity.backends.hubicbackend.rst 1970-01-01 00:00:00 +0000
2087@@ -1,7 +0,0 @@
2088-duplicity.backends.hubicbackend module
2089-======================================
2090-
2091-.. automodule:: duplicity.backends.hubicbackend
2092- :members:
2093- :undoc-members:
2094- :show-inheritance:
2095
2096=== removed file 'docs/duplicity.backends.imapbackend.rst'
2097--- docs/duplicity.backends.imapbackend.rst 2018-07-24 16:17:12 +0000
2098+++ docs/duplicity.backends.imapbackend.rst 1970-01-01 00:00:00 +0000
2099@@ -1,7 +0,0 @@
2100-duplicity.backends.imapbackend module
2101-=====================================
2102-
2103-.. automodule:: duplicity.backends.imapbackend
2104- :members:
2105- :undoc-members:
2106- :show-inheritance:
2107
2108=== removed file 'docs/duplicity.backends.lftpbackend.rst'
2109--- docs/duplicity.backends.lftpbackend.rst 2018-07-24 16:17:12 +0000
2110+++ docs/duplicity.backends.lftpbackend.rst 1970-01-01 00:00:00 +0000
2111@@ -1,7 +0,0 @@
2112-duplicity.backends.lftpbackend module
2113-=====================================
2114-
2115-.. automodule:: duplicity.backends.lftpbackend
2116- :members:
2117- :undoc-members:
2118- :show-inheritance:
2119
2120=== removed file 'docs/duplicity.backends.localbackend.rst'
2121--- docs/duplicity.backends.localbackend.rst 2018-07-24 16:17:12 +0000
2122+++ docs/duplicity.backends.localbackend.rst 1970-01-01 00:00:00 +0000
2123@@ -1,7 +0,0 @@
2124-duplicity.backends.localbackend module
2125-======================================
2126-
2127-.. automodule:: duplicity.backends.localbackend
2128- :members:
2129- :undoc-members:
2130- :show-inheritance:
2131
2132=== removed file 'docs/duplicity.backends.mediafirebackend.rst'
2133--- docs/duplicity.backends.mediafirebackend.rst 2018-07-24 16:17:12 +0000
2134+++ docs/duplicity.backends.mediafirebackend.rst 1970-01-01 00:00:00 +0000
2135@@ -1,7 +0,0 @@
2136-duplicity.backends.mediafirebackend module
2137-==========================================
2138-
2139-.. automodule:: duplicity.backends.mediafirebackend
2140- :members:
2141- :undoc-members:
2142- :show-inheritance:
2143
2144=== removed file 'docs/duplicity.backends.megabackend.rst'
2145--- docs/duplicity.backends.megabackend.rst 2018-07-24 16:17:12 +0000
2146+++ docs/duplicity.backends.megabackend.rst 1970-01-01 00:00:00 +0000
2147@@ -1,7 +0,0 @@
2148-duplicity.backends.megabackend module
2149-=====================================
2150-
2151-.. automodule:: duplicity.backends.megabackend
2152- :members:
2153- :undoc-members:
2154- :show-inheritance:
2155
2156=== removed file 'docs/duplicity.backends.multibackend.rst'
2157--- docs/duplicity.backends.multibackend.rst 2018-07-24 16:17:12 +0000
2158+++ docs/duplicity.backends.multibackend.rst 1970-01-01 00:00:00 +0000
2159@@ -1,7 +0,0 @@
2160-duplicity.backends.multibackend module
2161-======================================
2162-
2163-.. automodule:: duplicity.backends.multibackend
2164- :members:
2165- :undoc-members:
2166- :show-inheritance:
2167
2168=== removed file 'docs/duplicity.backends.ncftpbackend.rst'
2169--- docs/duplicity.backends.ncftpbackend.rst 2018-07-24 16:17:12 +0000
2170+++ docs/duplicity.backends.ncftpbackend.rst 1970-01-01 00:00:00 +0000
2171@@ -1,7 +0,0 @@
2172-duplicity.backends.ncftpbackend module
2173-======================================
2174-
2175-.. automodule:: duplicity.backends.ncftpbackend
2176- :members:
2177- :undoc-members:
2178- :show-inheritance:
2179
2180=== removed file 'docs/duplicity.backends.onedrivebackend.rst'
2181--- docs/duplicity.backends.onedrivebackend.rst 2018-07-24 16:17:12 +0000
2182+++ docs/duplicity.backends.onedrivebackend.rst 1970-01-01 00:00:00 +0000
2183@@ -1,7 +0,0 @@
2184-duplicity.backends.onedrivebackend module
2185-=========================================
2186-
2187-.. automodule:: duplicity.backends.onedrivebackend
2188- :members:
2189- :undoc-members:
2190- :show-inheritance:
2191
2192=== removed file 'docs/duplicity.backends.par2backend.rst'
2193--- docs/duplicity.backends.par2backend.rst 2018-07-24 16:17:12 +0000
2194+++ docs/duplicity.backends.par2backend.rst 1970-01-01 00:00:00 +0000
2195@@ -1,7 +0,0 @@
2196-duplicity.backends.par2backend module
2197-=====================================
2198-
2199-.. automodule:: duplicity.backends.par2backend
2200- :members:
2201- :undoc-members:
2202- :show-inheritance:
2203
2204=== removed file 'docs/duplicity.backends.pydrivebackend.rst'
2205--- docs/duplicity.backends.pydrivebackend.rst 2018-07-24 16:17:12 +0000
2206+++ docs/duplicity.backends.pydrivebackend.rst 1970-01-01 00:00:00 +0000
2207@@ -1,7 +0,0 @@
2208-duplicity.backends.pydrivebackend module
2209-========================================
2210-
2211-.. automodule:: duplicity.backends.pydrivebackend
2212- :members:
2213- :undoc-members:
2214- :show-inheritance:
2215
2216=== renamed file 'docs/duplicity.backends.pyrax_identity.hubic.rst' => 'docs/duplicity.backends.pyrax_identity.hubic.rst.THIS'
2217=== renamed file 'docs/duplicity.backends.pyrax_identity.rst' => 'docs/duplicity.backends.pyrax_identity.rst.THIS'
2218=== renamed file 'docs/duplicity.backends.rst' => 'docs/duplicity.backends.rst.THIS'
2219=== removed file 'docs/duplicity.backends.rsyncbackend.rst'
2220--- docs/duplicity.backends.rsyncbackend.rst 2018-07-24 16:17:12 +0000
2221+++ docs/duplicity.backends.rsyncbackend.rst 1970-01-01 00:00:00 +0000
2222@@ -1,7 +0,0 @@
2223-duplicity.backends.rsyncbackend module
2224-======================================
2225-
2226-.. automodule:: duplicity.backends.rsyncbackend
2227- :members:
2228- :undoc-members:
2229- :show-inheritance:
2230
2231=== renamed file 'docs/duplicity.backends.ssh_paramiko_backend.rst' => 'docs/duplicity.backends.ssh_paramiko_backend.rst.THIS'
2232=== renamed file 'docs/duplicity.backends.ssh_pexpect_backend.rst' => 'docs/duplicity.backends.ssh_pexpect_backend.rst.THIS'
2233=== removed file 'docs/duplicity.backends.swiftbackend.rst'
2234--- docs/duplicity.backends.swiftbackend.rst 2018-07-24 16:17:12 +0000
2235+++ docs/duplicity.backends.swiftbackend.rst 1970-01-01 00:00:00 +0000
2236@@ -1,7 +0,0 @@
2237-duplicity.backends.swiftbackend module
2238-======================================
2239-
2240-.. automodule:: duplicity.backends.swiftbackend
2241- :members:
2242- :undoc-members:
2243- :show-inheritance:
2244
2245=== removed file 'docs/duplicity.backends.sxbackend.rst'
2246--- docs/duplicity.backends.sxbackend.rst 2018-07-24 16:17:12 +0000
2247+++ docs/duplicity.backends.sxbackend.rst 1970-01-01 00:00:00 +0000
2248@@ -1,7 +0,0 @@
2249-duplicity.backends.sxbackend module
2250-===================================
2251-
2252-.. automodule:: duplicity.backends.sxbackend
2253- :members:
2254- :undoc-members:
2255- :show-inheritance:
2256
2257=== removed file 'docs/duplicity.backends.tahoebackend.rst'
2258--- docs/duplicity.backends.tahoebackend.rst 2018-07-24 16:17:12 +0000
2259+++ docs/duplicity.backends.tahoebackend.rst 1970-01-01 00:00:00 +0000
2260@@ -1,7 +0,0 @@
2261-duplicity.backends.tahoebackend module
2262-======================================
2263-
2264-.. automodule:: duplicity.backends.tahoebackend
2265- :members:
2266- :undoc-members:
2267- :show-inheritance:
2268
2269=== removed file 'docs/duplicity.backends.webdavbackend.rst'
2270--- docs/duplicity.backends.webdavbackend.rst 2018-07-24 16:17:12 +0000
2271+++ docs/duplicity.backends.webdavbackend.rst 1970-01-01 00:00:00 +0000
2272@@ -1,7 +0,0 @@
2273-duplicity.backends.webdavbackend module
2274-=======================================
2275-
2276-.. automodule:: duplicity.backends.webdavbackend
2277- :members:
2278- :undoc-members:
2279- :show-inheritance:
2280
2281=== renamed file 'docs/duplicity.cached_ops.rst' => 'docs/duplicity.cached_ops.rst.THIS'
2282=== removed file 'docs/duplicity.collections.rst'
2283--- docs/duplicity.collections.rst 2018-07-24 16:17:12 +0000
2284+++ docs/duplicity.collections.rst 1970-01-01 00:00:00 +0000
2285@@ -1,7 +0,0 @@
2286-duplicity.collections module
2287-============================
2288-
2289-.. automodule:: duplicity.collections
2290- :members:
2291- :undoc-members:
2292- :show-inheritance:
2293
2294=== removed file 'docs/duplicity.commandline.rst'
2295--- docs/duplicity.commandline.rst 2018-07-24 16:17:12 +0000
2296+++ docs/duplicity.commandline.rst 1970-01-01 00:00:00 +0000
2297@@ -1,7 +0,0 @@
2298-duplicity.commandline module
2299-============================
2300-
2301-.. automodule:: duplicity.commandline
2302- :members:
2303- :undoc-members:
2304- :show-inheritance:
2305
2306=== removed file 'docs/duplicity.diffdir.rst'
2307--- docs/duplicity.diffdir.rst 2018-07-24 16:17:12 +0000
2308+++ docs/duplicity.diffdir.rst 1970-01-01 00:00:00 +0000
2309@@ -1,7 +0,0 @@
2310-duplicity.diffdir module
2311-========================
2312-
2313-.. automodule:: duplicity.diffdir
2314- :members:
2315- :undoc-members:
2316- :show-inheritance:
2317
2318=== renamed file 'docs/duplicity.dup_temp.rst' => 'docs/duplicity.dup_temp.rst.THIS'
2319=== renamed file 'docs/duplicity.dup_threading.rst' => 'docs/duplicity.dup_threading.rst.THIS'
2320=== renamed file 'docs/duplicity.dup_time.rst' => 'docs/duplicity.dup_time.rst.THIS'
2321=== removed file 'docs/duplicity.errors.rst'
2322--- docs/duplicity.errors.rst 2018-07-24 16:17:12 +0000
2323+++ docs/duplicity.errors.rst 1970-01-01 00:00:00 +0000
2324@@ -1,7 +0,0 @@
2325-duplicity.errors module
2326-=======================
2327-
2328-.. automodule:: duplicity.errors
2329- :members:
2330- :undoc-members:
2331- :show-inheritance:
2332
2333=== renamed file 'docs/duplicity.file_naming.rst' => 'docs/duplicity.file_naming.rst.THIS'
2334=== removed file 'docs/duplicity.filechunkio.rst'
2335--- docs/duplicity.filechunkio.rst 2018-07-24 16:17:12 +0000
2336+++ docs/duplicity.filechunkio.rst 1970-01-01 00:00:00 +0000
2337@@ -1,7 +0,0 @@
2338-duplicity.filechunkio module
2339-============================
2340-
2341-.. automodule:: duplicity.filechunkio
2342- :members:
2343- :undoc-members:
2344- :show-inheritance:
2345
2346=== removed file 'docs/duplicity.globals.rst'
2347--- docs/duplicity.globals.rst 2018-07-24 16:17:12 +0000
2348+++ docs/duplicity.globals.rst 1970-01-01 00:00:00 +0000
2349@@ -1,7 +0,0 @@
2350-duplicity.globals module
2351-========================
2352-
2353-.. automodule:: duplicity.globals
2354- :members:
2355- :undoc-members:
2356- :show-inheritance:
2357
2358=== removed file 'docs/duplicity.globmatch.rst'
2359--- docs/duplicity.globmatch.rst 2018-07-24 16:17:12 +0000
2360+++ docs/duplicity.globmatch.rst 1970-01-01 00:00:00 +0000
2361@@ -1,7 +0,0 @@
2362-duplicity.globmatch module
2363-==========================
2364-
2365-.. automodule:: duplicity.globmatch
2366- :members:
2367- :undoc-members:
2368- :show-inheritance:
2369
2370=== removed file 'docs/duplicity.gpg.rst'
2371--- docs/duplicity.gpg.rst 2018-07-24 16:17:12 +0000
2372+++ docs/duplicity.gpg.rst 1970-01-01 00:00:00 +0000
2373@@ -1,7 +0,0 @@
2374-duplicity.gpg module
2375-====================
2376-
2377-.. automodule:: duplicity.gpg
2378- :members:
2379- :undoc-members:
2380- :show-inheritance:
2381
2382=== removed file 'docs/duplicity.gpginterface.rst'
2383--- docs/duplicity.gpginterface.rst 2018-07-24 16:17:12 +0000
2384+++ docs/duplicity.gpginterface.rst 1970-01-01 00:00:00 +0000
2385@@ -1,7 +0,0 @@
2386-duplicity.gpginterface module
2387-=============================
2388-
2389-.. automodule:: duplicity.gpginterface
2390- :members:
2391- :undoc-members:
2392- :show-inheritance:
2393
2394=== removed file 'docs/duplicity.lazy.rst'
2395--- docs/duplicity.lazy.rst 2018-07-24 16:17:12 +0000
2396+++ docs/duplicity.lazy.rst 1970-01-01 00:00:00 +0000
2397@@ -1,7 +0,0 @@
2398-duplicity.lazy module
2399-=====================
2400-
2401-.. automodule:: duplicity.lazy
2402- :members:
2403- :undoc-members:
2404- :show-inheritance:
2405
2406=== removed file 'docs/duplicity.librsync.rst'
2407--- docs/duplicity.librsync.rst 2018-07-24 16:17:12 +0000
2408+++ docs/duplicity.librsync.rst 1970-01-01 00:00:00 +0000
2409@@ -1,7 +0,0 @@
2410-duplicity.librsync module
2411-=========================
2412-
2413-.. automodule:: duplicity.librsync
2414- :members:
2415- :undoc-members:
2416- :show-inheritance:
2417
2418=== removed file 'docs/duplicity.log.rst'
2419--- docs/duplicity.log.rst 2018-07-24 16:17:12 +0000
2420+++ docs/duplicity.log.rst 1970-01-01 00:00:00 +0000
2421@@ -1,7 +0,0 @@
2422-duplicity.log module
2423-====================
2424-
2425-.. automodule:: duplicity.log
2426- :members:
2427- :undoc-members:
2428- :show-inheritance:
2429
2430=== removed file 'docs/duplicity.manifest.rst'
2431--- docs/duplicity.manifest.rst 2018-07-24 16:17:12 +0000
2432+++ docs/duplicity.manifest.rst 1970-01-01 00:00:00 +0000
2433@@ -1,7 +0,0 @@
2434-duplicity.manifest module
2435-=========================
2436-
2437-.. automodule:: duplicity.manifest
2438- :members:
2439- :undoc-members:
2440- :show-inheritance:
2441
2442=== removed file 'docs/duplicity.patchdir.rst'
2443--- docs/duplicity.patchdir.rst 2018-07-24 16:17:12 +0000
2444+++ docs/duplicity.patchdir.rst 1970-01-01 00:00:00 +0000
2445@@ -1,7 +0,0 @@
2446-duplicity.patchdir module
2447-=========================
2448-
2449-.. automodule:: duplicity.patchdir
2450- :members:
2451- :undoc-members:
2452- :show-inheritance:
2453
2454=== removed file 'docs/duplicity.path.rst'
2455--- docs/duplicity.path.rst 2018-07-24 16:17:12 +0000
2456+++ docs/duplicity.path.rst 1970-01-01 00:00:00 +0000
2457@@ -1,7 +0,0 @@
2458-duplicity.path module
2459-=====================
2460-
2461-.. automodule:: duplicity.path
2462- :members:
2463- :undoc-members:
2464- :show-inheritance:
2465
2466=== removed file 'docs/duplicity.progress.rst'
2467--- docs/duplicity.progress.rst 2018-07-24 16:17:12 +0000
2468+++ docs/duplicity.progress.rst 1970-01-01 00:00:00 +0000
2469@@ -1,7 +0,0 @@
2470-duplicity.progress module
2471-=========================
2472-
2473-.. automodule:: duplicity.progress
2474- :members:
2475- :undoc-members:
2476- :show-inheritance:
2477
2478=== removed file 'docs/duplicity.robust.rst'
2479--- docs/duplicity.robust.rst 2018-07-24 16:17:12 +0000
2480+++ docs/duplicity.robust.rst 1970-01-01 00:00:00 +0000
2481@@ -1,7 +0,0 @@
2482-duplicity.robust module
2483-=======================
2484-
2485-.. automodule:: duplicity.robust
2486- :members:
2487- :undoc-members:
2488- :show-inheritance:
2489
2490=== renamed file 'docs/duplicity.rst' => 'docs/duplicity.rst.THIS'
2491=== removed file 'docs/duplicity.selection.rst'
2492--- docs/duplicity.selection.rst 2018-07-24 16:17:12 +0000
2493+++ docs/duplicity.selection.rst 1970-01-01 00:00:00 +0000
2494@@ -1,7 +0,0 @@
2495-duplicity.selection module
2496-==========================
2497-
2498-.. automodule:: duplicity.selection
2499- :members:
2500- :undoc-members:
2501- :show-inheritance:
2502
2503=== removed file 'docs/duplicity.statistics.rst'
2504--- docs/duplicity.statistics.rst 2018-07-24 16:17:12 +0000
2505+++ docs/duplicity.statistics.rst 1970-01-01 00:00:00 +0000
2506@@ -1,7 +0,0 @@
2507-duplicity.statistics module
2508-===========================
2509-
2510-.. automodule:: duplicity.statistics
2511- :members:
2512- :undoc-members:
2513- :show-inheritance:
2514
2515=== removed file 'docs/duplicity.tarfile.rst'
2516--- docs/duplicity.tarfile.rst 2018-07-24 16:17:12 +0000
2517+++ docs/duplicity.tarfile.rst 1970-01-01 00:00:00 +0000
2518@@ -1,7 +0,0 @@
2519-duplicity.tarfile module
2520-========================
2521-
2522-.. automodule:: duplicity.tarfile
2523- :members:
2524- :undoc-members:
2525- :show-inheritance:
2526
2527=== removed file 'docs/duplicity.tempdir.rst'
2528--- docs/duplicity.tempdir.rst 2018-07-24 16:17:12 +0000
2529+++ docs/duplicity.tempdir.rst 1970-01-01 00:00:00 +0000
2530@@ -1,7 +0,0 @@
2531-duplicity.tempdir module
2532-========================
2533-
2534-.. automodule:: duplicity.tempdir
2535- :members:
2536- :undoc-members:
2537- :show-inheritance:
2538
2539=== removed file 'docs/duplicity.util.rst'
2540--- docs/duplicity.util.rst 2018-07-24 16:17:12 +0000
2541+++ docs/duplicity.util.rst 1970-01-01 00:00:00 +0000
2542@@ -1,7 +0,0 @@
2543-duplicity.util module
2544-=====================
2545-
2546-.. automodule:: duplicity.util
2547- :members:
2548- :undoc-members:
2549- :show-inheritance:
2550
2551=== renamed file 'docs/index.rst' => 'docs/index.rst.THIS'
2552=== renamed file 'docs/make.bat' => 'docs/make.bat.THIS'
2553=== renamed file 'docs/testing.functional.rst' => 'docs/testing.functional.rst.THIS'
2554=== renamed file 'docs/testing.functional.test_badupload.rst' => 'docs/testing.functional.test_badupload.rst.THIS'
2555=== renamed file 'docs/testing.functional.test_cleanup.rst' => 'docs/testing.functional.test_cleanup.rst.THIS'
2556=== renamed file 'docs/testing.functional.test_final.rst' => 'docs/testing.functional.test_final.rst.THIS'
2557=== renamed file 'docs/testing.functional.test_log.rst' => 'docs/testing.functional.test_log.rst.THIS'
2558=== renamed file 'docs/testing.functional.test_rdiffdir.rst' => 'docs/testing.functional.test_rdiffdir.rst.THIS'
2559=== renamed file 'docs/testing.functional.test_restart.rst' => 'docs/testing.functional.test_restart.rst.THIS'
2560=== renamed file 'docs/testing.functional.test_selection.rst' => 'docs/testing.functional.test_selection.rst.THIS'
2561=== renamed file 'docs/testing.functional.test_verify.rst' => 'docs/testing.functional.test_verify.rst.THIS'
2562=== removed file 'docs/testing.overrides.gettext.rst'
2563--- docs/testing.overrides.gettext.rst 2018-07-24 16:17:12 +0000
2564+++ docs/testing.overrides.gettext.rst 1970-01-01 00:00:00 +0000
2565@@ -1,7 +0,0 @@
2566-testing.overrides.gettext module
2567-================================
2568-
2569-.. automodule:: testing.overrides.gettext
2570- :members:
2571- :undoc-members:
2572- :show-inheritance:
2573
2574=== removed file 'docs/testing.overrides.rst'
2575--- docs/testing.overrides.rst 2018-07-24 16:17:12 +0000
2576+++ docs/testing.overrides.rst 1970-01-01 00:00:00 +0000
2577@@ -1,17 +0,0 @@
2578-testing.overrides package
2579-=========================
2580-
2581-Submodules
2582-----------
2583-
2584-.. toctree::
2585-
2586- testing.overrides.gettext
2587-
2588-Module contents
2589----------------
2590-
2591-.. automodule:: testing.overrides
2592- :members:
2593- :undoc-members:
2594- :show-inheritance:
2595
2596=== renamed file 'docs/testing.rst' => 'docs/testing.rst.THIS'
2597=== renamed file 'docs/testing.test_code.rst' => 'docs/testing.test_code.rst.THIS'
2598=== removed file 'docs/testing.unit.rst'
2599--- docs/testing.unit.rst 2018-07-24 16:17:12 +0000
2600+++ docs/testing.unit.rst 1970-01-01 00:00:00 +0000
2601@@ -1,34 +0,0 @@
2602-testing.unit package
2603-====================
2604-
2605-Submodules
2606-----------
2607-
2608-.. toctree::
2609-
2610- testing.unit.test_backend
2611- testing.unit.test_backend_instance
2612- testing.unit.test_collections
2613- testing.unit.test_diffdir
2614- testing.unit.test_dup_temp
2615- testing.unit.test_dup_time
2616- testing.unit.test_file_naming
2617- testing.unit.test_globmatch
2618- testing.unit.test_gpg
2619- testing.unit.test_gpginterface
2620- testing.unit.test_lazy
2621- testing.unit.test_manifest
2622- testing.unit.test_patchdir
2623- testing.unit.test_path
2624- testing.unit.test_selection
2625- testing.unit.test_statistics
2626- testing.unit.test_tarfile
2627- testing.unit.test_tempdir
2628-
2629-Module contents
2630----------------
2631-
2632-.. automodule:: testing.unit
2633- :members:
2634- :undoc-members:
2635- :show-inheritance:
2636
2637=== renamed file 'docs/testing.unit.test_backend.rst' => 'docs/testing.unit.test_backend.rst.THIS'
2638=== renamed file 'docs/testing.unit.test_backend_instance.rst' => 'docs/testing.unit.test_backend_instance.rst.THIS'
2639=== renamed file 'docs/testing.unit.test_collections.rst' => 'docs/testing.unit.test_collections.rst.THIS'
2640=== renamed file 'docs/testing.unit.test_diffdir.rst' => 'docs/testing.unit.test_diffdir.rst.THIS'
2641=== renamed file 'docs/testing.unit.test_dup_temp.rst' => 'docs/testing.unit.test_dup_temp.rst.THIS'
2642=== renamed file 'docs/testing.unit.test_dup_time.rst' => 'docs/testing.unit.test_dup_time.rst.THIS'
2643=== renamed file 'docs/testing.unit.test_file_naming.rst' => 'docs/testing.unit.test_file_naming.rst.THIS'
2644=== renamed file 'docs/testing.unit.test_globmatch.rst' => 'docs/testing.unit.test_globmatch.rst.THIS'
2645=== renamed file 'docs/testing.unit.test_gpg.rst' => 'docs/testing.unit.test_gpg.rst.THIS'
2646=== renamed file 'docs/testing.unit.test_gpginterface.rst' => 'docs/testing.unit.test_gpginterface.rst.THIS'
2647=== renamed file 'docs/testing.unit.test_lazy.rst' => 'docs/testing.unit.test_lazy.rst.THIS'
2648=== renamed file 'docs/testing.unit.test_manifest.rst' => 'docs/testing.unit.test_manifest.rst.THIS'
2649=== renamed file 'docs/testing.unit.test_patchdir.rst' => 'docs/testing.unit.test_patchdir.rst.THIS'
2650=== renamed file 'docs/testing.unit.test_path.rst' => 'docs/testing.unit.test_path.rst.THIS'
2651=== renamed file 'docs/testing.unit.test_selection.rst' => 'docs/testing.unit.test_selection.rst.THIS'
2652=== renamed file 'docs/testing.unit.test_statistics.rst' => 'docs/testing.unit.test_statistics.rst.THIS'
2653=== renamed file 'docs/testing.unit.test_tarfile.rst' => 'docs/testing.unit.test_tarfile.rst.THIS'
2654=== renamed file 'docs/testing.unit.test_tempdir.rst' => 'docs/testing.unit.test_tempdir.rst.THIS'
2655=== modified file 'duplicity/_librsyncmodule.c'
2656--- duplicity/_librsyncmodule.c 2018-12-05 03:48:47 +0000
2657+++ duplicity/_librsyncmodule.c 2019-03-04 12:09:45 +0000
2658@@ -330,7 +330,7 @@
2659 fd = dup(fd);
2660 if (fd == -1) {
2661 char buf[256];
2662- (void)strerror_r(errno, buf, sizeof(buf));
2663+ strerror_r(errno, buf, sizeof(buf));
2664 PyErr_SetString(PyExc_TypeError, buf);
2665 return NULL;
2666 }
2667
2668=== modified file 'duplicity/backend.py'
2669--- duplicity/backend.py 2018-11-29 19:00:15 +0000
2670+++ duplicity/backend.py 2019-03-04 12:09:45 +0000
2671@@ -455,8 +455,13 @@
2672 else:
2673 return commandline
2674
2675+<<<<<<< TREE
2676 def __subprocess_popen(self, args):
2677 u"""
2678+=======
2679+ def __subprocess_popen(self, args):
2680+ """
2681+>>>>>>> MERGE-SOURCE
2682 For internal use.
2683 Execute the given command line, interpreted as a shell command.
2684 Returns int Exitcode, string StdOut, string StdErr
2685@@ -480,6 +485,7 @@
2686
2687 Raise a BackendException on failure.
2688 """
2689+<<<<<<< TREE
2690 import shlex
2691
2692 if isinstance(commandline, (list, tuple)):
2693@@ -493,6 +499,21 @@
2694 log.Info(_(u"Reading results of '%s'") % logstr)
2695
2696 result, stdout, stderr = self.__subprocess_popen(args)
2697+=======
2698+ import shlex
2699+
2700+ if isinstance(commandline, (types.ListType, types.TupleType)):
2701+ logstr = ' '.join(commandline)
2702+ args = commandline
2703+ else:
2704+ logstr = commandline
2705+ args = shlex.split(commandline)
2706+
2707+ logstr = self.munge_password(logstr)
2708+ log.Info(_("Reading results of '%s'") % logstr)
2709+
2710+ result, stdout, stderr = self.__subprocess_popen(args)
2711+>>>>>>> MERGE-SOURCE
2712 if result != 0:
2713 try:
2714 ignores = self.popen_breaks[args[0]]
2715@@ -500,8 +521,13 @@
2716 u""" ignore a predefined set of error codes """
2717 return 0, u'', u''
2718 except (KeyError, ValueError):
2719+<<<<<<< TREE
2720 raise BackendException(u"Error running '%s': returned %d, with output:\n%s" %
2721 (logstr, result, stdout.decode() + u'\n' + stderr.decode()))
2722+=======
2723+ raise BackendException("Error running '%s': returned %d, with output:\n%s" %
2724+ (logstr, result, stdout + '\n' + stderr))
2725+>>>>>>> MERGE-SOURCE
2726 return result, stdout, stderr
2727
2728
2729@@ -573,7 +599,11 @@
2730 # There shouldn't be any encoding errors for files we care
2731 # about, since duplicity filenames are ascii. But user files
2732 # may be in the same directory. So just replace characters.
2733+<<<<<<< TREE
2734 return util.fsencode(filename)
2735+=======
2736+ return filename.encode(globals.fsencoding, 'replace')
2737+>>>>>>> MERGE-SOURCE
2738 else:
2739 return filename
2740
2741
2742=== modified file 'duplicity/backends/_cf_pyrax.py'
2743--- duplicity/backends/_cf_pyrax.py 2018-11-29 19:00:15 +0000
2744+++ duplicity/backends/_cf_pyrax.py 2019-03-04 12:09:45 +0000
2745@@ -71,6 +71,7 @@
2746
2747 self.client_exc = pyrax.exceptions.ClientException
2748 self.nso_exc = pyrax.exceptions.NoSuchObject
2749+<<<<<<< TREE
2750
2751 # query rackspace for the specified container name
2752 try:
2753@@ -90,6 +91,27 @@
2754 u"You may be using a read-only user that can view but not create containers.\n" +
2755 u"Please check your credentials and permissions.",
2756 log.ErrorCode.backend_permission_denied)
2757+=======
2758+
2759+ # query rackspace for the specified container name
2760+ try:
2761+ self.container = pyrax.cloudfiles.get_container(container)
2762+ except pyrax.exceptions.Forbidden as e:
2763+ log.FatalError("%s : %s \n" % (e.__class__.__name__, util.uexc(e)) +
2764+ "Container may exist, but access was denied.\n" +
2765+ "If this container exists, please check its X-Container-Read/Write headers.\n" +
2766+ "Otherwise, please check your credentials and permissions.",
2767+ log.ErrorCode.backend_permission_denied)
2768+ except pyrax.exceptions.NoSuchContainer as e:
2769+ try:
2770+ self.container = pyrax.cloudfiles.create_container(container)
2771+ except pyrax.exceptions.Forbidden as e:
2772+ log.FatalError("%s : %s \n" % (e.__class__.__name__, util.uexc(e)) +
2773+ "Container does not exist, but creation was denied.\n" +
2774+ "You may be using a read-only user that can view but not create containers.\n" +
2775+ "Please check your credentials and permissions.",
2776+ log.ErrorCode.backend_permission_denied)
2777+>>>>>>> MERGE-SOURCE
2778
2779 def _error_code(self, operation, e):
2780 if isinstance(e, self.nso_exc):
2781
2782=== added file 'duplicity/backends/acdclibackend.py.OTHER'
2783--- duplicity/backends/acdclibackend.py.OTHER 1970-01-01 00:00:00 +0000
2784+++ duplicity/backends/acdclibackend.py.OTHER 2019-03-04 12:09:45 +0000
2785@@ -0,0 +1,151 @@
2786+# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
2787+#
2788+# Copyright 2015 Stefan Breunig <stefan-duplicity@breunig.xyz>
2789+# Copyright 2015 Malay Shah <malays@gmail.com>
2790+# Based on the backend ncftpbackend.py
2791+#
2792+# This file is part of duplicity.
2793+#
2794+# Duplicity is free software; you can redistribute it and/or modify it
2795+# under the terms of the GNU General Public License as published by the
2796+# Free Software Foundation; either version 2 of the License, or (at your
2797+# option) any later version.
2798+#
2799+# Duplicity is distributed in the hope that it will be useful, but
2800+# WITHOUT ANY WARRANTY; without even the implied warranty of
2801+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2802+# General Public License for more details.
2803+#
2804+# You should have received a copy of the GNU General Public License
2805+# along with duplicity; if not, write to the Free Software Foundation,
2806+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2807+
2808+import os.path
2809+import urllib
2810+import string
2811+import json
2812+
2813+import duplicity.backend
2814+from duplicity import globals
2815+from duplicity import log
2816+from duplicity.errors import * # @UnusedWildImport
2817+from duplicity import tempdir
2818+
2819+
2820+class ACDBackend(duplicity.backend.Backend):
2821+ acd_cmd = 'acd_cli'
2822+ """Connect to remote store using acd_cli"""
2823+ def __init__(self, parsed_url):
2824+ duplicity.backend.Backend.__init__(self, parsed_url)
2825+
2826+ # we expect an error return, so go low-level and ignore it
2827+ try:
2828+ p = os.popen(self.acd_cmd + " version")
2829+ fout = p.read()
2830+ ret = p.close()
2831+ except Exception:
2832+ pass
2833+ # the expected error is 0
2834+ if ret is not None:
2835+ log.FatalError(self.acd_cmd + " not found: Please install acd_cli",
2836+ log.ErrorCode.backend_not_found)
2837+
2838+ self.parsed_url = parsed_url
2839+ self.url_string = duplicity.backend.strip_auth_from_url(self.parsed_url)
2840+
2841+ # Use an explicit directory name.
2842+ if self.url_string[-1] != '/':
2843+ self.url_string += '/'
2844+
2845+ self.subprocess_popen(self.acd_cmd + " sync")
2846+
2847+ # Initialize remote directory
2848+ remote_path = urllib.unquote(self.parsed_url.path.replace('///', '/')).rstrip()
2849+ commandline = self.acd_cmd + " ls '%s'" % (remote_path)
2850+ try:
2851+ self.subprocess_popen(commandline)
2852+ except BackendException as e:
2853+ if e.code == 50: # Remote directory not there, create a new one
2854+ commandline = self.acd_cmd + " mkdir '%s'" % remote_path
2855+ self.subprocess_popen(commandline)
2856+
2857+ def _put(self, source_path, remote_filename=None):
2858+ """Transfer source_path to remote_filename"""
2859+ if not remote_filename:
2860+ remote_filename = source_path.get_filename()
2861+
2862+ # WORKAROUND for acd_cli: cannot specify remote filename
2863+ # Link tmp file to the desired remote filename locally and upload
2864+ remote_path = urllib.unquote(self.parsed_url.path.replace('///', '/'))
2865+ local_real_duplicity_file = os.path.join(os.path.dirname(source_path.name), remote_filename.rstrip())
2866+
2867+ deleteFile = False
2868+ if(source_path.name != local_real_duplicity_file):
2869+ try:
2870+ os.symlink(source_path.name, local_real_duplicity_file)
2871+ deleteFile = True
2872+ except IOError as e:
2873+ log.FatalError("Unable to copy " + source_path.name + " to " + local_real_duplicity_file)
2874+
2875+ commandline = self.acd_cmd + " upload --force --overwrite '%s' '%s'" % \
2876+ (local_real_duplicity_file, remote_path)
2877+
2878+ try:
2879+ l = self.subprocess_popen(commandline)
2880+ finally:
2881+ if (deleteFile):
2882+ try:
2883+ os.remove(local_real_duplicity_file)
2884+ except OSError as e:
2885+ log.FatalError("Unable to remove file %s" % e)
2886+
2887+ def _get(self, remote_filename, local_path):
2888+ """Get remote filename, saving it to local_path"""
2889+ remote_path = os.path.join(urllib.unquote(self.parsed_url.path.replace('///', '/')), remote_filename).rstrip()
2890+ local_dir = os.path.dirname(local_path.name)
2891+ local_filename = os.path.basename(local_path.name)
2892+ commandline = self.acd_cmd + " download '%s' '%s'" % \
2893+ (remote_path, local_dir)
2894+ l = self.subprocess_popen(commandline)
2895+
2896+ # Keep the remote filename and move the file over
2897+ try:
2898+ os.rename(os.path.join(local_dir, remote_filename), local_path.name)
2899+ except IOError as e:
2900+ log.FatalError("Unable to move file %s" % e)
2901+
2902+ local_path.setdata()
2903+ if not local_path.exists():
2904+ raise BackendException("File %s not found" % local_path.name)
2905+
2906+ def _query(self, remote_filename):
2907+ remote_path = os.path.join(urllib.unquote(self.parsed_url.path.replace('///', '/')), remote_filename).rstrip()
2908+ commandline = self.acd_cmd + " metadata '%s'" % remote_path
2909+ node = self.subprocess_popen(commandline)
2910+ if (node[0] == 0 and node[1]):
2911+ try:
2912+ size = json.loads(node[1])['contentProperties']['size']
2913+ return {'size': size}
2914+ except ValueError as e:
2915+ raise BackendException('Malformed JSON: expected "contentProperties->size" member in %s' % node[1])
2916+ return {'size': -1}
2917+
2918+ def _list(self):
2919+ """List files in directory"""
2920+ def dir_split(str):
2921+ if (str):
2922+ return str.split()[2]
2923+ else:
2924+ return None
2925+ commandline = self.acd_cmd + " ls '%s'" % self.parsed_url.path.replace('///', '/')
2926+ l = self.subprocess_popen(commandline)
2927+ return [x for x in map(dir_split, l[1].split('\n')) if x]
2928+
2929+ def _delete(self, remote_filename):
2930+ """Delete remote_filename"""
2931+ remote_file_path = os.path.join(urllib.unquote(self.parsed_url.path.replace('///', '/')),
2932+ remote_filename).rstrip()
2933+ commandline = self.acd_cmd + " rm '%s'" % (remote_file_path)
2934+ self.subprocess_popen(commandline)
2935+
2936+duplicity.backend.register_backend("acd+acdcli", ACDBackend)
2937
2938=== renamed file 'duplicity/backends/adbackend.py' => 'duplicity/backends/adbackend.py.THIS'
2939=== modified file 'duplicity/backends/azurebackend.py'
2940--- duplicity/backends/azurebackend.py 2019-01-01 21:36:27 +0000
2941+++ duplicity/backends/azurebackend.py 2019-03-04 12:09:45 +0000
2942@@ -23,7 +23,6 @@
2943 import os
2944
2945 import duplicity.backend
2946-from duplicity import globals
2947 from duplicity import log
2948 from duplicity.errors import BackendException
2949
2950@@ -46,11 +45,15 @@
2951 self.AzureConflictError = azure.WindowsAzureConflictError
2952 else:
2953 # v1.0.0 and above
2954+<<<<<<< TREE
2955 import azure.storage.blob
2956 if hasattr(azure.storage.blob, u'BlobService'):
2957 from azure.storage.blob import BlobService
2958 else:
2959 from azure.storage.blob.blockblobservice import BlockBlobService as BlobService
2960+=======
2961+ from azure.storage.blob import BlobService
2962+>>>>>>> MERGE-SOURCE
2963 self.AzureMissingResourceError = azure.common.AzureMissingResourceHttpError
2964 self.AzureConflictError = azure.common.AzureConflictHttpError
2965 except ImportError as e:
2966@@ -58,7 +61,15 @@
2967 Azure backend requires Microsoft Azure Storage SDK for Python (https://pypi.python.org/pypi/azure-storage/).
2968 Exception: %s""" % str(e))
2969
2970+ if 'AZURE_ACCOUNT_NAME' not in os.environ:
2971+ raise BackendException('AZURE_ACCOUNT_NAME environment variable not set.')
2972+ if 'AZURE_ACCOUNT_KEY' not in os.environ:
2973+ raise BackendException('AZURE_ACCOUNT_KEY environment variable not set.')
2974+ self.blob_service = BlobService(account_name=os.environ['AZURE_ACCOUNT_NAME'],
2975+ account_key=os.environ['AZURE_ACCOUNT_KEY'])
2976+
2977 # TODO: validate container name
2978+<<<<<<< TREE
2979 self.container = parsed_url.path.lstrip(u'/')
2980
2981 if u'AZURE_ACCOUNT_NAME' not in os.environ:
2982@@ -104,6 +115,9 @@
2983 self.blob_service._BLOB_MAX_CHUNK_DATA_SIZE = globals.azure_max_block_size
2984
2985 def _create_container(self):
2986+=======
2987+ self.container = parsed_url.path.lstrip('/')
2988+>>>>>>> MERGE-SOURCE
2989 try:
2990 self.blob_service.create_container(self.container, fail_on_exist=True)
2991 except self.AzureConflictError:
2992@@ -115,11 +129,15 @@
2993 log.ErrorCode.connection_failed)
2994
2995 def _put(self, source_path, remote_filename):
2996+<<<<<<< TREE
2997 kwargs = {}
2998 if globals.azure_max_connections:
2999 kwargs[u'max_connections'] = globals.azure_max_connections
3000
3001+=======
3002+>>>>>>> MERGE-SOURCE
3003 # https://azure.microsoft.com/en-us/documentation/articles/storage-python-how-to-use-blob-storage/#upload-a-blob-into-a-container
3004+<<<<<<< TREE
3005 try:
3006 self.blob_service.create_blob_from_path(self.container, remote_filename, source_path.name, **kwargs)
3007 except AttributeError: # Old versions use a different method name
3008@@ -134,6 +152,10 @@
3009 except AttributeError: # might not be available in old API
3010 pass
3011
3012+=======
3013+ self.blob_service.put_block_blob_from_path(self.container, remote_filename, source_path.name)
3014+
3015+>>>>>>> MERGE-SOURCE
3016 def _get(self, remote_filename, local_path):
3017 # https://azure.microsoft.com/en-us/documentation/articles/storage-python-how-to-use-blob-storage/#download-blobs
3018 self.blob_service.get_blob_to_path(self.container, remote_filename, local_path.name)
3019@@ -156,16 +178,24 @@
3020
3021 def _query(self, filename):
3022 prop = self.blob_service.get_blob_properties(self.container, filename)
3023+<<<<<<< TREE
3024 try:
3025 info = {u'size': int(prop.properties.content_length)}
3026 except AttributeError:
3027 # old versions directly returned the properties
3028 info = {u'size': int(prop[u'content-length'])}
3029 return info
3030+=======
3031+ return {'size': int(prop['content-length'])}
3032+>>>>>>> MERGE-SOURCE
3033
3034 def _error_code(self, operation, e):
3035 if isinstance(e, self.AzureMissingResourceError):
3036 return log.ErrorCode.backend_not_found
3037
3038+<<<<<<< TREE
3039
3040 duplicity.backend.register_backend(u'azure', AzureBackend)
3041+=======
3042+duplicity.backend.register_backend('azure', AzureBackend)
3043+>>>>>>> MERGE-SOURCE
3044
3045=== modified file 'duplicity/backends/b2backend.py'
3046--- duplicity/backends/b2backend.py 2018-12-27 16:43:07 +0000
3047+++ duplicity/backends/b2backend.py 2019-03-04 12:09:45 +0000
3048@@ -27,11 +27,15 @@
3049 from builtins import object
3050 import os
3051 import hashlib
3052+<<<<<<< TREE
3053 from urllib.parse import quote_plus # pylint: disable=import-error
3054+=======
3055+>>>>>>> MERGE-SOURCE
3056
3057 import duplicity.backend
3058 from duplicity.errors import BackendException, FatalBackendException
3059 from duplicity import log
3060+<<<<<<< TREE
3061 from duplicity import progress
3062
3063
3064@@ -50,6 +54,30 @@
3065
3066 def __exit__(self, exc_type, exc_val, exc_tb):
3067 pass
3068+=======
3069+from duplicity import progress
3070+
3071+
3072+def progress_listener_factory():
3073+ u"""
3074+ Returns progress instance suitable for passing to b2.api.B2Api
3075+ methods.
3076+ """
3077+ class B2ProgressListener(b2.progress.AbstractProgressListener):
3078+ def __init__(self):
3079+ super(B2ProgressListener, self).__init__()
3080+
3081+ def set_total_bytes(self, total_byte_count):
3082+ self.total_byte_count = total_byte_count
3083+
3084+ def bytes_completed(self, byte_count):
3085+ progress.report_transfer(byte_count, self.total_byte_count)
3086+
3087+ def close(self):
3088+ super(B2ProgressListener, self).close()
3089+ return B2ProgressListener()
3090+
3091+>>>>>>> MERGE-SOURCE
3092
3093 class B2Backend(duplicity.backend.Backend):
3094 u"""
3095@@ -62,6 +90,7 @@
3096 """
3097 duplicity.backend.Backend.__init__(self, parsed_url)
3098
3099+<<<<<<< TREE
3100 # Import B2 API
3101 try:
3102 global b2
3103@@ -77,6 +106,24 @@
3104 self.parsed_url.hostname = u'B2'
3105
3106 account_id = parsed_url.username
3107+=======
3108+ # Import B2 API
3109+ try:
3110+ global b2
3111+ import b2
3112+ import b2.api
3113+ import b2.account_info
3114+ import b2.download_dest
3115+ import b2.file_version
3116+ import b2.progress
3117+ except ImportError:
3118+ raise BackendException('B2 backend requires B2 Python APIs (pip install b2)')
3119+
3120+ self.service = b2.api.B2Api(b2.account_info.InMemoryAccountInfo())
3121+ self.parsed_url.hostname = 'B2'
3122+
3123+ account_id = parsed_url.username
3124+>>>>>>> MERGE-SOURCE
3125 account_key = self.get_password()
3126
3127 self.url_parts = [
3128@@ -86,13 +133,23 @@
3129 self.username = self.url_parts.pop(0)
3130 bucket_name = self.url_parts.pop(0)
3131 else:
3132+<<<<<<< TREE
3133 raise BackendException(u"B2 requires a bucket name")
3134 self.path = u"".join([url_part + u"/" for url_part in self.url_parts])
3135 self.service.authorize_account(u'production', account_id, account_key)
3136
3137 log.Log(u"B2 Backend (path= %s, bucket= %s, minimum_part_size= %s)" %
3138 (self.path, bucket_name, self.service.account_info.get_minimum_part_size()), log.INFO)
3139+=======
3140+ raise BackendException("B2 requires a bucket name")
3141+ self.path = "".join([url_part + "/" for url_part in self.url_parts])
3142+ self.service.authorize_account('production', account_id, account_key)
3143+
3144+ log.Log("B2 Backend (path= %s, bucket= %s, minimum_part_size= %s)" %
3145+ (self.path, bucket_name, self.service.account_info.get_minimum_part_size()), log.INFO)
3146+>>>>>>> MERGE-SOURCE
3147 try:
3148+<<<<<<< TREE
3149 self.bucket = self.service.get_bucket_by_name(bucket_name)
3150 log.Log(u"Bucket found", log.INFO)
3151 except b2.exception.NonExistentBucket:
3152@@ -101,23 +158,46 @@
3153 self.bucket = self.service.create_bucket(bucket_name, u'allPrivate')
3154 except:
3155 raise FatalBackendException(u"Bucket cannot be created")
3156+=======
3157+ self.bucket = self.service.get_bucket_by_name(bucket_name)
3158+ log.Log("Bucket found", log.INFO)
3159+ except b2.exception.NonExistentBucket:
3160+ try:
3161+ log.Log("Bucket not found, creating one", log.INFO)
3162+ self.bucket = self.service.create_bucket(bucket_name, 'allPrivate')
3163+ except:
3164+ raise FatalBackendException("Bucket cannot be created")
3165+>>>>>>> MERGE-SOURCE
3166
3167 def _get(self, remote_filename, local_path):
3168 u"""
3169 Download remote_filename to local_path
3170 """
3171+<<<<<<< TREE
3172 log.Log(u"Get: %s -> %s" % (self.path + remote_filename, local_path.name), log.INFO)
3173 self.bucket.download_file_by_name(quote_plus(self.path + remote_filename),
3174 b2.download_dest.DownloadDestLocalFile(local_path.name))
3175+=======
3176+ log.Log("Get: %s -> %s" % (self.path + remote_filename, local_path.name), log.INFO)
3177+ self.bucket.download_file_by_name(self.path + remote_filename,
3178+ b2.download_dest.DownloadDestLocalFile(local_path.name))
3179+>>>>>>> MERGE-SOURCE
3180
3181 def _put(self, source_path, remote_filename):
3182 u"""
3183 Copy source_path to remote_filename
3184 """
3185+<<<<<<< TREE
3186 log.Log(u"Put: %s -> %s" % (source_path.name, self.path + remote_filename), log.INFO)
3187 self.bucket.upload_local_file(source_path.name, quote_plus(self.path + remote_filename),
3188 content_type=u'application/pgp-encrypted',
3189 progress_listener=B2ProgressListener())
3190+=======
3191+ log.Log("Put: %s -> %s" % (source_path.name, self.path + remote_filename), log.INFO)
3192+ self.bucket.upload_local_file(source_path.name, self.path + remote_filename,
3193+ content_type='application/pgp-encrypted',
3194+ progress_listener=progress_listener_factory())
3195+>>>>>>> MERGE-SOURCE
3196
3197 def _list(self):
3198 u"""
3199@@ -130,14 +210,21 @@
3200 u"""
3201 Delete filename from remote server
3202 """
3203+<<<<<<< TREE
3204 log.Log(u"Delete: %s" % self.path + filename, log.INFO)
3205 file_version_info = self.file_info(quote_plus(self.path + filename))
3206 self.bucket.delete_file_version(file_version_info.id_, file_version_info.file_name)
3207+=======
3208+ log.Log("Delete: %s" % self.path + filename, log.INFO)
3209+ file_version_info = self.file_info(self.path + filename)
3210+ self.bucket.delete_file_version(file_version_info.id_, file_version_info.file_name)
3211+>>>>>>> MERGE-SOURCE
3212
3213 def _query(self, filename):
3214 u"""
3215 Get size info of filename
3216 """
3217+<<<<<<< TREE
3218 log.Log(u"Query: %s" % self.path + filename, log.INFO)
3219 file_version_info = self.file_info(quote_plus(self.path + filename))
3220 return {u'size': file_version_info.size
3221@@ -153,3 +240,20 @@
3222
3223
3224 duplicity.backend.register_backend(u"b2", B2Backend)
3225+=======
3226+ log.Log("Query: %s" % self.path + filename, log.INFO)
3227+ file_version_info = self.file_info(self.path + filename)
3228+ return {'size': file_version_info.size
3229+ if file_version_info is not None and file_version_info.size is not None else -1}
3230+
3231+ def file_info(self, filename):
3232+ response = self.bucket.list_file_names(filename, 1)
3233+ for entry in response['files']:
3234+ file_version_info = b2.file_version.FileVersionInfoFactory.from_api_response(entry)
3235+ if file_version_info.file_name == filename:
3236+ return file_version_info
3237+ raise BackendException('File not found')
3238+
3239+
3240+duplicity.backend.register_backend("b2", B2Backend)
3241+>>>>>>> MERGE-SOURCE
3242
3243=== modified file 'duplicity/backends/dpbxbackend.py'
3244--- duplicity/backends/dpbxbackend.py 2018-11-29 19:00:15 +0000
3245+++ duplicity/backends/dpbxbackend.py 2019-03-04 12:09:45 +0000
3246@@ -45,7 +45,21 @@
3247 from duplicity import log, globals
3248 from duplicity import progress
3249 from duplicity.errors import BackendException
3250+<<<<<<< TREE
3251 from duplicity.globals import num_retries
3252+=======
3253+import os
3254+import sys
3255+import traceback
3256+import urllib
3257+import re
3258+
3259+from dropbox import Dropbox
3260+from dropbox.exceptions import AuthError, BadInputError, ApiError
3261+from dropbox.files import UploadSessionCursor, CommitInfo, WriteMode, \
3262+ GetMetadataError, DeleteError, UploadSessionLookupError, ListFolderError
3263+from dropbox.oauth import DropboxOAuth2FlowNoRedirect
3264+>>>>>>> MERGE-SOURCE
3265 from requests.exceptions import ConnectionError
3266 import duplicity.backend
3267
3268@@ -164,12 +178,23 @@
3269 print(u'-' * 72)
3270 auth_code = input(u"Enter the authorization code here: ").strip()
3271 try:
3272+<<<<<<< TREE
3273 log.Debug(u'dpbx,auth_flow.finish(%s)' % auth_code)
3274 authresult = auth_flow.finish(auth_code)
3275+=======
3276+ log.Debug('dpbx,auth_flow.finish(%s)' % auth_code)
3277+ authresult = auth_flow.finish(auth_code)
3278+>>>>>>> MERGE-SOURCE
3279 except Exception as e:
3280+<<<<<<< TREE
3281 raise BackendException(u'dpbx: Unable to obtain access token: %s' % e)
3282 log.Info(u"dpbx: Authentication successfull")
3283 self.save_access_token(authresult.access_token)
3284+=======
3285+ raise BackendException('dpbx: Unable to obtain access token: %s' % e)
3286+ log.Info("dpbx: Authentication successfull")
3287+ self.save_access_token(authresult.access_token)
3288+>>>>>>> MERGE-SOURCE
3289
3290 def login(self):
3291 if self.load_access_token() is None:
3292@@ -403,10 +428,17 @@
3293 # Do a long listing to avoid connection reset
3294 if not self.user_authenticated():
3295 self.login()
3296+<<<<<<< TREE
3297 remote_dir = u'/' + urllib.parse.unquote(self.parsed_url.path.lstrip(u'/')).rstrip()
3298
3299 log.Debug(u'dpbx.files_list_folder(%s)' % remote_dir)
3300+=======
3301+ remote_dir = '/' + urllib.unquote(self.parsed_url.path.lstrip('/')).rstrip()
3302+
3303+ log.Debug('dpbx.files_list_folder(%s)' % remote_dir)
3304+>>>>>>> MERGE-SOURCE
3305 res = []
3306+<<<<<<< TREE
3307 try:
3308 resp = self.api_client.files_list_folder(remote_dir)
3309 log.Debug(u'dpbx.list(%s): %s' % (remote_dir, resp))
3310@@ -422,6 +454,23 @@
3311 log.Debug(u'dpbx.list(%s): ignore missing folder (%s)' % (remote_dir, e))
3312 else:
3313 raise
3314+=======
3315+ try:
3316+ resp = self.api_client.files_list_folder(remote_dir)
3317+ log.Debug('dpbx.list(%s): %s' % (remote_dir, resp))
3318+
3319+ while True:
3320+ res.extend([entry.name for entry in resp.entries])
3321+ if not resp.has_more:
3322+ break
3323+ resp = self.api_client.files_list_folder_continue(resp.cursor)
3324+ except ApiError as e:
3325+ if (isinstance(e.error, ListFolderError) and e.error.is_path() and
3326+ e.error.get_path().is_not_found()):
3327+ log.Debug('dpbx.list(%s): ignore missing folder (%s)' % (remote_dir, e))
3328+ else:
3329+ raise
3330+>>>>>>> MERGE-SOURCE
3331
3332 # Warn users of old version dpbx about automatically renamed files
3333 self.check_renamed_files(res)
3334
3335=== modified file 'duplicity/backends/gdocsbackend.py'
3336--- duplicity/backends/gdocsbackend.py 2018-11-29 19:00:15 +0000
3337+++ duplicity/backends/gdocsbackend.py 2019-03-04 12:09:45 +0000
3338@@ -193,7 +193,13 @@
3339 # Done!
3340 return result
3341
3342+<<<<<<< TREE
3343
3344 u""" gdata is an alternate way to access gdocs, currently 05/2015 lacking OAuth support """
3345 duplicity.backend.register_backend(u'gdata+gdocs', GDocsBackend)
3346 duplicity.backend.uses_netloc.extend([u'gdata+gdocs'])
3347+=======
3348+""" gdata is an alternate way to access gdocs, currently 05/2015 lacking OAuth support """
3349+duplicity.backend.register_backend('gdata+gdocs', GDocsBackend)
3350+duplicity.backend.uses_netloc.extend(['gdata+gdocs'])
3351+>>>>>>> MERGE-SOURCE
3352
3353=== modified file 'duplicity/backends/giobackend.py'
3354--- duplicity/backends/giobackend.py 2018-07-23 14:55:39 +0000
3355+++ duplicity/backends/giobackend.py 2019-03-04 12:09:45 +0000
3356@@ -143,8 +143,13 @@
3357 self.__copy_file(source_file, target_file)
3358
3359 def _get(self, filename, local_path):
3360+<<<<<<< TREE
3361 from gi.repository import Gio # @UnresolvedImport # pylint: disable=import-error
3362 source_file = self.remote_file.get_child_for_display_name(filename)
3363+=======
3364+ from gi.repository import Gio # @UnresolvedImport
3365+ source_file = self.remote_file.get_child_for_display_name(filename)
3366+>>>>>>> MERGE-SOURCE
3367 target_file = Gio.File.new_for_path(local_path.name)
3368 self.__copy_file(source_file, target_file)
3369
3370@@ -169,11 +174,22 @@
3371 target_file.delete(None)
3372
3373 def _query(self, filename):
3374+<<<<<<< TREE
3375 from gi.repository import Gio # @UnresolvedImport # pylint: disable=import-error
3376 target_file = self.remote_file.get_child_for_display_name(filename)
3377+=======
3378+ from gi.repository import Gio # @UnresolvedImport
3379+ target_file = self.remote_file.get_child_for_display_name(filename)
3380+>>>>>>> MERGE-SOURCE
3381 info = target_file.query_info(Gio.FILE_ATTRIBUTE_STANDARD_SIZE,
3382 Gio.FileQueryInfoFlags.NONE, None)
3383+<<<<<<< TREE
3384 return {u'size': info.get_size()}
3385
3386
3387 duplicity.backend.register_backend_prefix(u'gio', GIOBackend)
3388+=======
3389+ return {'size': info.get_size()}
3390+
3391+duplicity.backend.register_backend_prefix('gio', GIOBackend)
3392+>>>>>>> MERGE-SOURCE
3393
3394=== modified file 'duplicity/backends/hsibackend.py'
3395--- duplicity/backends/hsibackend.py 2018-11-29 19:00:15 +0000
3396+++ duplicity/backends/hsibackend.py 2019-03-04 12:09:45 +0000
3397@@ -65,6 +65,11 @@
3398 commandline = u'%s "rm %s%s"' % (hsi_command, self.remote_prefix, filename)
3399 self.subprocess_popen(commandline)
3400
3401+<<<<<<< TREE
3402
3403 duplicity.backend.register_backend(u"hsi", HSIBackend)
3404 duplicity.backend.uses_netloc.extend([u'hsi'])
3405+=======
3406+duplicity.backend.register_backend("hsi", HSIBackend)
3407+duplicity.backend.uses_netloc.extend(['hsi'])
3408+>>>>>>> MERGE-SOURCE
3409
3410=== modified file 'duplicity/backends/hubicbackend.py'
3411--- duplicity/backends/hubicbackend.py 2018-11-29 19:00:15 +0000
3412+++ duplicity/backends/hubicbackend.py 2019-03-04 12:09:45 +0000
3413@@ -64,5 +64,9 @@
3414 self.nso_exc = pyrax.exceptions.NoSuchObject
3415 self.container = pyrax.cloudfiles.create_container(container)
3416
3417+<<<<<<< TREE
3418
3419 duplicity.backend.register_backend(u"cf+hubic", HubicBackend)
3420+=======
3421+duplicity.backend.register_backend("cf+hubic", HubicBackend)
3422+>>>>>>> MERGE-SOURCE
3423
3424=== renamed file 'duplicity/backends/jottacloudbackend.py' => 'duplicity/backends/jottacloudbackend.py.THIS'
3425=== modified file 'duplicity/backends/lftpbackend.py'
3426--- duplicity/backends/lftpbackend.py 2019-02-21 21:42:26 +0000
3427+++ duplicity/backends/lftpbackend.py 2019-03-04 12:09:45 +0000
3428@@ -205,6 +205,7 @@
3429 )
3430 log.Debug(u"CMD: %s" % commandline)
3431 _, l, e = self.subprocess_popen(commandline)
3432+<<<<<<< TREE
3433 log.Debug(u"STDERR:\n"
3434 u"%s" % (e))
3435 log.Debug(u"STDOUT:\n"
3436@@ -232,4 +233,32 @@
3437 u'lftp+sftp',
3438 u'lftp+webdav', u'lftp+webdavs',
3439 u'lftp+http', u'lftp+https']
3440+=======
3441+ log.Debug("STDERR:\n"
3442+ "%s" % (e))
3443+ log.Debug("STDOUT:\n"
3444+ "%s" % (l))
3445+
3446+duplicity.backend.register_backend("ftp", LFTPBackend)
3447+duplicity.backend.register_backend("ftps", LFTPBackend)
3448+duplicity.backend.register_backend("fish", LFTPBackend)
3449+duplicity.backend.register_backend("ftpes", LFTPBackend)
3450+
3451+duplicity.backend.register_backend("lftp+ftp", LFTPBackend)
3452+duplicity.backend.register_backend("lftp+ftps", LFTPBackend)
3453+duplicity.backend.register_backend("lftp+fish", LFTPBackend)
3454+duplicity.backend.register_backend("lftp+ftpes", LFTPBackend)
3455+duplicity.backend.register_backend("lftp+sftp", LFTPBackend)
3456+duplicity.backend.register_backend("lftp+webdav", LFTPBackend)
3457+duplicity.backend.register_backend("lftp+webdavs", LFTPBackend)
3458+duplicity.backend.register_backend("lftp+http", LFTPBackend)
3459+duplicity.backend.register_backend("lftp+https", LFTPBackend)
3460+
3461+duplicity.backend.uses_netloc.extend(['ftp', 'ftps', 'fish', 'ftpes',
3462+ 'lftp+ftp', 'lftp+ftps',
3463+ 'lftp+fish', 'lftp+ftpes',
3464+ 'lftp+sftp',
3465+ 'lftp+webdav', 'lftp+webdavs',
3466+ 'lftp+http', 'lftp+https']
3467+>>>>>>> MERGE-SOURCE
3468 )
3469
3470=== modified file 'duplicity/backends/localbackend.py'
3471--- duplicity/backends/localbackend.py 2018-07-23 14:55:39 +0000
3472+++ duplicity/backends/localbackend.py 2019-03-04 12:09:45 +0000
3473@@ -71,7 +71,13 @@
3474 target_file = self.remote_pathdir.append(filename)
3475 target_file.setdata()
3476 size = target_file.getsize() if target_file.exists() else -1
3477+<<<<<<< TREE
3478 return {u'size': size}
3479
3480
3481 duplicity.backend.register_backend(u"file", LocalBackend)
3482+=======
3483+ return {'size': size}
3484+
3485+duplicity.backend.register_backend("file", LocalBackend)
3486+>>>>>>> MERGE-SOURCE
3487
3488=== modified file 'duplicity/backends/megabackend.py'
3489--- duplicity/backends/megabackend.py 2018-11-29 19:00:15 +0000
3490+++ duplicity/backends/megabackend.py 2019-03-04 12:09:45 +0000
3491@@ -34,6 +34,7 @@
3492 def __init__(self, parsed_url):
3493 duplicity.backend.Backend.__init__(self, parsed_url)
3494
3495+<<<<<<< TREE
3496 # ensure all the necessary megatools binaries exist
3497 self._check_binary_exists(u'megals')
3498 self._check_binary_exists(u'megamkdir')
3499@@ -61,7 +62,37 @@
3500 def _check_binary_exists(self, cmd):
3501 u'checks that a specified command exists in the current path'
3502
3503+=======
3504+ # ensure all the necessary megatools binaries exist
3505+ self._check_binary_exists('megals')
3506+ self._check_binary_exists('megamkdir')
3507+ self._check_binary_exists('megaget')
3508+ self._check_binary_exists('megaput')
3509+ self._check_binary_exists('megarm')
3510+
3511+ # store some basic info
3512+ self._hostname = parsed_url.hostname
3513+
3514+ if parsed_url.password is None:
3515+ self._megarc = os.getenv('HOME') + '/.megarc'
3516+ else:
3517+ self._megarc = False
3518+ self._username = parsed_url.username
3519+ self._password = self.get_password()
3520+
3521+ # remote folder (Can we assume /Root prefix?)
3522+ self._root = '/Root'
3523+ self._folder = self._root + '/' + parsed_url.path[1:]
3524+
3525+ # make sure the remote folder exists (the whole path)
3526+ self._makedir_recursive(parsed_url.path[1:].split('/'))
3527+
3528+ def _check_binary_exists(self, cmd):
3529+ 'checks that a specified command exists in the current path'
3530+
3531+>>>>>>> MERGE-SOURCE
3532 try:
3533+<<<<<<< TREE
3534 # ignore the output, we only need the return code
3535 subprocess.check_output([u'which', cmd])
3536 except Exception as e:
3537@@ -90,10 +121,45 @@
3538 self._make_dir(p)
3539 except:
3540 pass
3541+=======
3542+ # ignore the output, we only need the return code
3543+ subprocess.check_output(['which', cmd])
3544+ except Exception as e:
3545+ raise BackendException("command '%s' not found, make sure megatools are installed" % (cmd,))
3546+
3547+ def _makedir(self, path):
3548+ 'creates a remote directory'
3549+
3550+ if self._megarc:
3551+ cmd = ['megamkdir', '--config', self._megarc, path]
3552+ else:
3553+ cmd = ['megamkdir', '-u', self._username, '-p', self._password, path]
3554+
3555+ self.subprocess_popen(cmd)
3556+
3557+ def _makedir_recursive(self, path):
3558+ 'creates a remote directory (recursively the whole path), ingores errors'
3559+
3560+ print ("mkdir: %s" % ('/'.join(path),))
3561+
3562+ p = self._root
3563+
3564+ for folder in path:
3565+ p = p + '/' + folder
3566+ try:
3567+ self._make_dir(p)
3568+ except:
3569+ pass
3570+>>>>>>> MERGE-SOURCE
3571
3572 def _put(self, source_path, remote_filename):
3573+<<<<<<< TREE
3574 u'uploads file to Mega (deletes it first, to ensure it does not exist)'
3575
3576+=======
3577+ 'uploads file to Mega (deletes it first, to ensure it does not exist)'
3578+
3579+>>>>>>> MERGE-SOURCE
3580 try:
3581 self.delete(remote_filename)
3582 except Exception:
3583@@ -102,16 +168,29 @@
3584 self.upload(local_file=source_path.get_canonical(), remote_file=remote_filename)
3585
3586 def _get(self, remote_filename, local_path):
3587+<<<<<<< TREE
3588 u'downloads file from Mega'
3589
3590 self.download(remote_file=remote_filename, local_file=local_path.name)
3591+=======
3592+ 'downloads file from Mega'
3593+
3594+ self.download(remote_file=remote_filename, local_file=local_path.name)
3595+>>>>>>> MERGE-SOURCE
3596
3597 def _list(self):
3598+<<<<<<< TREE
3599 u'list files in the backup folder'
3600
3601 return self.folder_contents(files_only=True)
3602+=======
3603+ 'list files in the backup folder'
3604+
3605+ return self.folder_contents(files_only=True)
3606+>>>>>>> MERGE-SOURCE
3607
3608 def _delete(self, filename):
3609+<<<<<<< TREE
3610 u'deletes remote '
3611
3612 self.delete(remote_file=filename)
3613@@ -178,3 +257,71 @@
3614
3615 duplicity.backend.register_backend(u'mega', MegaBackend)
3616 duplicity.backend.uses_netloc.extend([u'mega'])
3617+=======
3618+ 'deletes remote '
3619+
3620+ self.delete(remote_file=filename)
3621+
3622+ def folder_contents(self, files_only=False):
3623+ 'lists contents of a folder, optionally ignoring subdirectories'
3624+
3625+ print ("megals: %s" % (self._folder,))
3626+
3627+ if self._megarc:
3628+ cmd = ['megals', '--config', self._megarc, self._folder]
3629+ else:
3630+ cmd = ['megals', '-u', self._username, '-p', self._password, self._folder]
3631+
3632+ files = subprocess.check_output(cmd)
3633+ files = files.strip().split('\n')
3634+
3635+ # remove the folder name, including the path separator
3636+ files = [f[len(self._folder) + 1:] for f in files]
3637+
3638+ # optionally ignore entries containing path separator (i.e. not files)
3639+ if files_only:
3640+ files = [f for f in files if '/' not in f]
3641+
3642+ return files
3643+
3644+ def download(self, remote_file, local_file):
3645+
3646+ print ("megaget: %s" % (remote_file,))
3647+
3648+ if self._megarc:
3649+ cmd = ['megaget', '--config', self._megarc, '--no-progress',
3650+ '--path', local_file, self._folder + '/' + remote_file]
3651+ else:
3652+ cmd = ['megaget', '-u', self._username, '-p', self._password, '--no-progress',
3653+ '--path', local_file, self._folder + '/' + remote_file]
3654+
3655+ self.subprocess_popen(cmd)
3656+
3657+ def upload(self, local_file, remote_file):
3658+
3659+ print ("megaput: %s" % (remote_file,))
3660+
3661+ if self._megarc:
3662+ cmd = ['megaput', '--config', self._megarc, '--no-progress',
3663+ '--path', self._folder + '/' + remote_file, local_file]
3664+ else:
3665+ cmd = ['megaput', '-u', self._username, '-p', self._password, '--no-progress',
3666+ '--path', self._folder + '/' + remote_file, local_file]
3667+
3668+ self.subprocess_popen(cmd)
3669+
3670+ def delete(self, remote_file):
3671+
3672+ print ("megarm: %s" % (remote_file,))
3673+
3674+ if self._megarc:
3675+ cmd = ['megarm', '--config', self._megarc, self._folder + '/' + remote_file]
3676+ else:
3677+ cmd = ['megarm', '-u', self._username, '-p', self._password, self._folder + '/' + remote_file]
3678+
3679+ self.subprocess_popen(cmd)
3680+
3681+
3682+duplicity.backend.register_backend('mega', MegaBackend)
3683+duplicity.backend.uses_netloc.extend(['mega'])
3684+>>>>>>> MERGE-SOURCE
3685
3686=== modified file 'duplicity/backends/multibackend.py'
3687--- duplicity/backends/multibackend.py 2018-11-29 19:00:15 +0000
3688+++ duplicity/backends/multibackend.py 2019-03-04 12:09:45 +0000
3689@@ -44,7 +44,6 @@
3690
3691 # the stores we are managing
3692 __stores = []
3693- __affinities = {}
3694
3695 # Set of known query paramaters
3696 __knownQueryParameters = frozenset([
3697@@ -188,6 +187,7 @@
3698
3699 store = duplicity.backend.get_backend(url)
3700 self.__stores.append(store)
3701+<<<<<<< TREE
3702
3703 # Prefix affinity
3704 if u'prefixes' in config:
3705@@ -201,11 +201,14 @@
3706 else:
3707 self.__affinities[prefix] = [store]
3708
3709+=======
3710+>>>>>>> MERGE-SOURCE
3711 # store_list = store.list()
3712 # log.Log(_("MultiBackend: at init, store %s has %s files")
3713 # % (url, len(store_list)),
3714 # log.INFO)
3715
3716+<<<<<<< TREE
3717 def _eligible_stores(self, filename):
3718 if self.__affinities:
3719 matching_prefixes = [k for k in list(self.__affinities.keys()) if filename.startswith(k)]
3720@@ -217,23 +220,21 @@
3721 # No affinity rule or no matching store for that prefix
3722 return self.__stores
3723
3724+=======
3725+>>>>>>> MERGE-SOURCE
3726 def _put(self, source_path, remote_filename):
3727 # Store an indication of whether any of these passed
3728 passed = False
3729-
3730- # Eligibile stores for this action
3731- stores = self._eligible_stores(remote_filename)
3732-
3733 # Mirror mode always starts at zero
3734 if self.__mode == u'mirror':
3735 self.__write_cursor = 0
3736
3737 first = self.__write_cursor
3738 while True:
3739- store = stores[self.__write_cursor]
3740+ store = self.__stores[self.__write_cursor]
3741 try:
3742 next = self.__write_cursor + 1
3743- if (next > len(stores) - 1):
3744+ if (next > len(self.__stores) - 1):
3745 next = 0
3746 log.Log(_(u"MultiBackend: _put: write to store #%s (%s)")
3747 % (self.__write_cursor, store.backend.parsed_url.url_string),
3748@@ -274,9 +275,7 @@
3749 # before finally giving up). So we need to get the list first
3750 # before we try to fetch
3751 # ENHANCEME: maintain a cached list for each store
3752- stores = self._eligible_stores(remote_filename)
3753-
3754- for s in stores:
3755+ for s in self.__stores:
3756 list = s.list()
3757 if remote_filename in list:
3758 s.get(remote_filename, local_path)
3759@@ -307,16 +306,13 @@
3760 def _delete(self, filename):
3761 # Store an indication on whether any passed
3762 passed = False
3763-
3764- stores = self._eligible_stores(filename)
3765-
3766 # since the backend operations will be retried, we can't
3767 # simply try to get from the store, if not found, move to the
3768 # next store (since each failure will be retried n times
3769 # before finally giving up). So we need to get the list first
3770 # before we try to delete
3771 # ENHANCEME: maintain a cached list for each store
3772- for s in stores:
3773+ for s in self.__stores:
3774 list = s.list()
3775 if filename in list:
3776 s._do_delete(filename)
3777@@ -333,5 +329,9 @@
3778 log.ERROR)
3779 # raise BackendException("failed to delete")
3780
3781+<<<<<<< TREE
3782
3783 duplicity.backend.register_backend(u'multi', MultiBackend)
3784+=======
3785+duplicity.backend.register_backend('multi', MultiBackend)
3786+>>>>>>> MERGE-SOURCE
3787
3788=== modified file 'duplicity/backends/ncftpbackend.py'
3789--- duplicity/backends/ncftpbackend.py 2018-11-29 19:00:15 +0000
3790+++ duplicity/backends/ncftpbackend.py 2019-03-04 12:09:45 +0000
3791@@ -122,6 +122,11 @@
3792 (self.flags, filename, self.url_string)
3793 self.subprocess_popen(commandline)
3794
3795+<<<<<<< TREE
3796
3797 duplicity.backend.register_backend(u"ncftp+ftp", NCFTPBackend)
3798 duplicity.backend.uses_netloc.extend([u'ncftp+ftp'])
3799+=======
3800+duplicity.backend.register_backend("ncftp+ftp", NCFTPBackend)
3801+duplicity.backend.uses_netloc.extend(['ncftp+ftp'])
3802+>>>>>>> MERGE-SOURCE
3803
3804=== modified file 'duplicity/backends/onedrivebackend.py'
3805--- duplicity/backends/onedrivebackend.py 2018-11-29 19:00:15 +0000
3806+++ duplicity/backends/onedrivebackend.py 2019-03-04 12:09:45 +0000
3807@@ -348,5 +348,9 @@
3808 def _retry_cleanup(self):
3809 self.initialize_oauth2_session()
3810
3811+<<<<<<< TREE
3812
3813 duplicity.backend.register_backend(u'onedrive', OneDriveBackend)
3814+=======
3815+duplicity.backend.register_backend('onedrive', OneDriveBackend)
3816+>>>>>>> MERGE-SOURCE
3817
3818=== modified file 'duplicity/backends/par2backend.py'
3819--- duplicity/backends/par2backend.py 2018-11-29 19:00:15 +0000
3820+++ duplicity/backends/par2backend.py 2019-03-04 12:09:45 +0000
3821@@ -218,5 +218,9 @@
3822 def close(self):
3823 self.wrapped_backend._close()
3824
3825+<<<<<<< TREE
3826
3827 backend.register_backend_prefix(u'par2', Par2Backend)
3828+=======
3829+backend.register_backend_prefix('par2', Par2Backend)
3830+>>>>>>> MERGE-SOURCE
3831
3832=== renamed file 'duplicity/backends/pcabackend.py' => 'duplicity/backends/pcabackend.py.THIS'
3833=== modified file 'duplicity/backends/pydrivebackend.py'
3834--- duplicity/backends/pydrivebackend.py 2019-02-24 15:09:46 +0000
3835+++ duplicity/backends/pydrivebackend.py 2019-03-04 12:09:45 +0000
3836@@ -93,8 +93,13 @@
3837 else:
3838 file_in_root = self.drive.CreateFile({u'title': u'i_am_in_root'})
3839 file_in_root.Upload()
3840+<<<<<<< TREE
3841 parent_folder_id = file_in_root[u'parents'][0][u'id']
3842 file_in_root.Delete()
3843+=======
3844+ parent_folder_id = file_in_root['parents'][0]['id']
3845+ file_in_root.Delete()
3846+>>>>>>> MERGE-SOURCE
3847
3848 # Fetch destination folder entry and create hierarchy if required.
3849 folder_names = string.split(parsed_url.path, u'/')
3850@@ -215,11 +220,19 @@
3851 return log.ErrorCode.backend_permission_denied
3852 return log.ErrorCode.backend_error
3853
3854+<<<<<<< TREE
3855
3856 duplicity.backend.register_backend(u'pydrive', PyDriveBackend)
3857 u""" pydrive is an alternate way to access gdocs """
3858 duplicity.backend.register_backend(u'pydrive+gdocs', PyDriveBackend)
3859 u""" register pydrive as the default way to access gdocs """
3860 duplicity.backend.register_backend(u'gdocs', PyDriveBackend)
3861+=======
3862+duplicity.backend.register_backend('pydrive', PyDriveBackend)
3863+""" pydrive is an alternate way to access gdocs """
3864+duplicity.backend.register_backend('pydrive+gdocs', PyDriveBackend)
3865+""" register pydrive as the default way to access gdocs """
3866+duplicity.backend.register_backend('gdocs', PyDriveBackend)
3867+>>>>>>> MERGE-SOURCE
3868
3869 duplicity.backend.uses_netloc.extend([u'pydrive', u'pydrive+gdocs', u'gdocs'])
3870
3871=== modified file 'duplicity/backends/rsyncbackend.py'
3872--- duplicity/backends/rsyncbackend.py 2018-11-29 19:00:15 +0000
3873+++ duplicity/backends/rsyncbackend.py 2019-03-04 12:09:45 +0000
3874@@ -155,6 +155,11 @@
3875 util.ignore_missing(os.unlink, file)
3876 os.rmdir(dir)
3877
3878+<<<<<<< TREE
3879
3880 duplicity.backend.register_backend(u"rsync", RsyncBackend)
3881 duplicity.backend.uses_netloc.extend([u'rsync'])
3882+=======
3883+duplicity.backend.register_backend("rsync", RsyncBackend)
3884+duplicity.backend.uses_netloc.extend(['rsync'])
3885+>>>>>>> MERGE-SOURCE
3886
3887=== modified file 'duplicity/backends/ssh_paramiko_backend.py'
3888--- duplicity/backends/ssh_paramiko_backend.py 2018-12-23 16:52:31 +0000
3889+++ duplicity/backends/ssh_paramiko_backend.py 2019-03-04 12:09:45 +0000
3890@@ -103,8 +103,13 @@
3891 """
3892 def missing_host_key(self, client, hostname, key):
3893 fp = hexlify(key.get_fingerprint())
3894+<<<<<<< TREE
3895 fingerprint = u':'.join(a + b for a, b in list(zip(fp[::2], fp[1::2])))
3896 question = u"""The authenticity of host '%s' can't be established.
3897+=======
3898+ fingerprint = ':'.join(a + b for a, b in list(zip(fp[::2], fp[1::2])))
3899+ question = """The authenticity of host '%s' can't be established.
3900+>>>>>>> MERGE-SOURCE
3901 %s key fingerprint is %s.
3902 Are you sure you want to continue connecting (yes/no)? """ % (hostname,
3903 key.get_name().upper(),
3904
3905=== modified file 'duplicity/backends/ssh_pexpect_backend.py'
3906--- duplicity/backends/ssh_pexpect_backend.py 2019-02-25 16:30:59 +0000
3907+++ duplicity/backends/ssh_pexpect_backend.py 2019-03-04 12:09:45 +0000
3908@@ -297,7 +297,13 @@
3909 commandline = (u"%s %s %s" % (self.sftp_command, globals.ssh_options, self.host_string))
3910 self.run_sftp_command(commandline, commands)
3911
3912+<<<<<<< TREE
3913
3914 duplicity.backend.register_backend(u"pexpect+sftp", SSHPExpectBackend)
3915 duplicity.backend.register_backend(u"pexpect+scp", SSHPExpectBackend)
3916 duplicity.backend.uses_netloc.extend([u'pexpect+sftp', u'pexpect+scp'])
3917+=======
3918+duplicity.backend.register_backend("pexpect+sftp", SSHPExpectBackend)
3919+duplicity.backend.register_backend("pexpect+scp", SSHPExpectBackend)
3920+duplicity.backend.uses_netloc.extend(['pexpect+sftp', 'pexpect+scp'])
3921+>>>>>>> MERGE-SOURCE
3922
3923=== modified file 'duplicity/backends/swiftbackend.py'
3924--- duplicity/backends/swiftbackend.py 2018-11-29 19:00:15 +0000
3925+++ duplicity/backends/swiftbackend.py 2019-03-04 12:09:45 +0000
3926@@ -22,7 +22,6 @@
3927 import os
3928
3929 import duplicity.backend
3930-from duplicity import globals
3931 from duplicity import log
3932 from duplicity import util
3933 from duplicity.errors import BackendException
3934@@ -112,9 +111,12 @@
3935 else:
3936 self.prefix = u''
3937
3938+<<<<<<< TREE
3939 policy = globals.swift_storage_policy
3940 policy_header = u'X-Storage-Policy'
3941
3942+=======
3943+>>>>>>> MERGE-SOURCE
3944 container_metadata = None
3945 try:
3946 self.conn = Connection(**conn_kwargs)
3947@@ -129,15 +131,17 @@
3948 if container_metadata is None:
3949 log.Info(u"Creating container %s" % self.container)
3950 try:
3951- headers = dict([[policy_header, policy]]) if policy else None
3952- self.conn.put_container(self.container, headers=headers)
3953+ self.conn.put_container(self.container)
3954 except Exception as e:
3955 log.FatalError(u"Container creation failed: %s %s"
3956 % (e.__class__.__name__, str(e)),
3957 log.ErrorCode.connection_failed)
3958+<<<<<<< TREE
3959 elif policy and container_metadata[policy_header.lower()] != policy:
3960 log.FatalError(u"Container '%s' exists but its storage policy is '%s' not '%s'."
3961 % (self.container, container_metadata[policy_header.lower()], policy))
3962+=======
3963+>>>>>>> MERGE-SOURCE
3964
3965 def _error_code(self, operation, e):
3966 if isinstance(e, self.resp_exc):
3967
3968=== modified file 'duplicity/backends/sxbackend.py'
3969--- duplicity/backends/sxbackend.py 2018-07-23 14:55:39 +0000
3970+++ duplicity/backends/sxbackend.py 2019-03-04 12:09:45 +0000
3971@@ -49,5 +49,9 @@
3972 commandline = u"sxrm {0}/{1}".format(self.url_string, filename)
3973 self.subprocess_popen(commandline)
3974
3975+<<<<<<< TREE
3976
3977 duplicity.backend.register_backend(u"sx", SXBackend)
3978+=======
3979+duplicity.backend.register_backend("sx", SXBackend)
3980+>>>>>>> MERGE-SOURCE
3981
3982=== modified file 'duplicity/backends/tahoebackend.py'
3983--- duplicity/backends/tahoebackend.py 2018-11-29 19:00:15 +0000
3984+++ duplicity/backends/tahoebackend.py 2019-03-04 12:09:45 +0000
3985@@ -73,7 +73,13 @@
3986 return output.split(b'\n') if output else []
3987
3988 def _delete(self, filename):
3989+<<<<<<< TREE
3990 self.run(u"tahoe", u"rm", self.get_remote_path(filename))
3991
3992
3993 duplicity.backend.register_backend(u"tahoe", TAHOEBackend)
3994+=======
3995+ self.run("tahoe", "rm", self.get_remote_path(filename))
3996+
3997+duplicity.backend.register_backend("tahoe", TAHOEBackend)
3998+>>>>>>> MERGE-SOURCE
3999
4000=== modified file 'duplicity/backends/webdavbackend.py'
4001--- duplicity/backends/webdavbackend.py 2018-12-23 16:52:31 +0000
4002+++ duplicity/backends/webdavbackend.py 2019-03-04 12:09:45 +0000
4003@@ -260,11 +260,19 @@
4004 try:
4005 return self.get_kerberos_authorization()
4006 except ImportError:
4007+<<<<<<< TREE
4008 log.Warn(_(u"python-kerberos needed to use kerberos \
4009+=======
4010+ log.Warn(_("python-kerberos needed to use kerberos \
4011+>>>>>>> MERGE-SOURCE
4012 authorization, falling back to basic auth."))
4013 return self.get_basic_authorization()
4014 except Exception as e:
4015+<<<<<<< TREE
4016 log.Warn(_(u"Kerberos authorization failed: %s.\
4017+=======
4018+ log.Warn(_("Kerberos authorization failed: %s.\
4019+>>>>>>> MERGE-SOURCE
4020 Falling back to basic auth.") % e)
4021 return self.get_basic_authorization()
4022 elif token.lower() == u'basic':
4023@@ -277,9 +285,15 @@
4024 return urllib2.parse_keqv_list(urllib2.parse_http_list(challenge_string))
4025
4026 def get_kerberos_authorization(self):
4027+<<<<<<< TREE
4028 import kerberos # pylint: disable=import-error
4029 _, ctx = kerberos.authGSSClientInit(u"HTTP@%s" % self.conn.host)
4030 kerberos.authGSSClientStep(ctx, u"")
4031+=======
4032+ import kerberos # pylint: disable=import-error
4033+ _, ctx = kerberos.authGSSClientInit("HTTP@%s" % self.conn.host)
4034+ kerberos.authGSSClientStep(ctx, "")
4035+>>>>>>> MERGE-SOURCE
4036 tgt = kerberos.authGSSClientResponse(ctx)
4037 return u'Negotiate %s' % tgt
4038
4039@@ -287,8 +301,13 @@
4040 u"""
4041 Returns the basic auth header
4042 """
4043+<<<<<<< TREE
4044 auth_string = u'%s:%s' % (self.username, self.password)
4045 return u'Basic %s' % base64.encodestring(auth_string).strip()
4046+=======
4047+ auth_string = '%s:%s' % (self.username, self.password)
4048+ return 'Basic %s' % "".join(base64.encodestring(auth_string).split())
4049+>>>>>>> MERGE-SOURCE
4050
4051 def get_digest_authorization(self, path):
4052 u"""
4053@@ -474,9 +493,17 @@
4054 if response:
4055 response.close()
4056
4057+<<<<<<< TREE
4058
4059 duplicity.backend.register_backend(u"http", WebDAVBackend)
4060 duplicity.backend.register_backend(u"https", WebDAVBackend)
4061 duplicity.backend.register_backend(u"webdav", WebDAVBackend)
4062 duplicity.backend.register_backend(u"webdavs", WebDAVBackend)
4063 duplicity.backend.uses_netloc.extend([u'http', u'https', u'webdav', u'webdavs'])
4064+=======
4065+duplicity.backend.register_backend("http", WebDAVBackend)
4066+duplicity.backend.register_backend("https", WebDAVBackend)
4067+duplicity.backend.register_backend("webdav", WebDAVBackend)
4068+duplicity.backend.register_backend("webdavs", WebDAVBackend)
4069+duplicity.backend.uses_netloc.extend(['http', 'https', 'webdav', 'webdavs'])
4070+>>>>>>> MERGE-SOURCE
4071
4072=== modified file 'duplicity/collections.py'
4073--- duplicity/collections.py 2019-02-22 20:25:02 +0000
4074+++ duplicity/collections.py 2019-03-04 12:09:45 +0000
4075@@ -32,7 +32,7 @@
4076
4077 import types
4078 import gettext
4079-import sys
4080+
4081
4082 from duplicity import log
4083 from duplicity import file_naming
4084@@ -44,12 +44,15 @@
4085 from duplicity import util
4086 from duplicity.gpg import GPGError
4087
4088+<<<<<<< TREE
4089 # For type testing against both int and long types that works in python 2/3
4090 if sys.version_info < (3,):
4091 integer_types = (int, int)
4092 else:
4093 integer_types = (int,)
4094
4095+=======
4096+>>>>>>> MERGE-SOURCE
4097
4098 class CollectionsError(Exception):
4099 pass
4100@@ -73,7 +76,6 @@
4101 self.end_time = None # will be set if inc
4102 self.partial = False # true if a partial backup
4103 self.encrypted = False # true if an encrypted backup
4104- self.files_changed = []
4105 self.action = action
4106
4107 def is_complete(self):
4108@@ -138,10 +140,6 @@
4109 self.encrypted = bool(pr.encrypted)
4110 self.info_set = True
4111
4112- def set_files_changed(self):
4113- mf = self.get_manifest()
4114- self.files_changed = mf.get_files_changed()
4115-
4116 def set_manifest(self, remote_filename):
4117 u"""
4118 Add local and remote manifest filenames to backup set
4119@@ -150,8 +148,13 @@
4120 remote_filename)
4121 self.remote_manifest_name = remote_filename
4122
4123+<<<<<<< TREE
4124 if self.action not in [u"collection-status", u"replicate"]:
4125 local_filename_list = globals.archive_dir_path.listdir()
4126+=======
4127+ if self.action not in ["collection-status"]:
4128+ local_filename_list = globals.archive_dir.listdir()
4129+>>>>>>> MERGE-SOURCE
4130 else:
4131 local_filename_list = []
4132 for local_filename in local_filename_list:
4133@@ -161,9 +164,7 @@
4134 pr.start_time == self.start_time and
4135 pr.end_time == self.end_time):
4136 self.local_manifest_path = \
4137- globals.archive_dir_path.append(local_filename)
4138-
4139- self.set_files_changed()
4140+ globals.archive_dir.append(local_filename)
4141 break
4142
4143 def delete(self):
4144@@ -177,8 +178,13 @@
4145 except Exception:
4146 log.Debug(_(u"BackupSet.delete: missing %s") % [util.fsdecode(f) for f in rfn])
4147 pass
4148+<<<<<<< TREE
4149 if self.action not in [u"collection-status", u"replicate"]:
4150 local_filename_list = globals.archive_dir_path.listdir()
4151+=======
4152+ if self.action not in ["collection-status"]:
4153+ local_filename_list = globals.archive_dir.listdir()
4154+>>>>>>> MERGE-SOURCE
4155 else:
4156 local_filename_list = []
4157 for lfn in local_filename_list:
4158@@ -187,7 +193,7 @@
4159 pr.start_time == self.start_time and
4160 pr.end_time == self.end_time):
4161 try:
4162- globals.archive_dir_path.append(lfn).delete()
4163+ globals.archive_dir.append(lfn).delete()
4164 except Exception:
4165 log.Debug(_(u"BackupSet.delete: missing %s") % [util.fsdecode(f) for f in lfn])
4166 pass
4167@@ -242,8 +248,13 @@
4168 """
4169 assert self.local_manifest_path
4170 manifest_buffer = self.local_manifest_path.get_data()
4171+<<<<<<< TREE
4172 log.Info(_(u"Processing local manifest %s (%s)") % (
4173 self.local_manifest_path.name, len(manifest_buffer)))
4174+=======
4175+ log.Info(_("Processing local manifest %s (%s)") % (
4176+ self.local_manifest_path.name, len(manifest_buffer)))
4177+>>>>>>> MERGE-SOURCE
4178 return manifest.Manifest().from_string(manifest_buffer)
4179
4180 def get_remote_manifest(self):
4181@@ -254,11 +265,21 @@
4182 try:
4183 manifest_buffer = self.backend.get_data(self.remote_manifest_name)
4184 except GPGError as message:
4185+<<<<<<< TREE
4186 log.Error(_(u"Error processing remote manifest (%s): %s") %
4187 (util.fsdecode(self.remote_manifest_name), util.uexc(message)))
4188+=======
4189+ log.Error(_("Error processing remote manifest (%s): %s") %
4190+ (util.ufn(self.remote_manifest_name), util.uexc(message)))
4191+>>>>>>> MERGE-SOURCE
4192 return None
4193+<<<<<<< TREE
4194 log.Info(_(u"Processing remote manifest %s (%s)") % (
4195 util.fsdecode(self.remote_manifest_name), len(manifest_buffer)))
4196+=======
4197+ log.Info(_("Processing remote manifest %s (%s)") % (
4198+ util.ufn(self.remote_manifest_name), len(manifest_buffer)))
4199+>>>>>>> MERGE-SOURCE
4200 return manifest.Manifest().from_string(manifest_buffer)
4201
4202 def get_manifest(self):
4203@@ -298,9 +319,6 @@
4204 return self.end_time
4205 assert 0, u"Neither self.time nor self.end_time set"
4206
4207- def get_files_changed(self):
4208- return self.files_changed
4209-
4210 def __len__(self):
4211 u"""
4212 Return the number of volumes in the set
4213@@ -482,19 +500,19 @@
4214 Return new SignatureChain.
4215
4216 local should be true iff the signature chain resides in
4217- globals.archive_dir_path and false if the chain is in
4218+ globals.archive_dir and false if the chain is in
4219 globals.backend.
4220
4221- @param local: True if sig chain in globals.archive_dir_path
4222+ @param local: True if sig chain in globals.archive_dir
4223 @type local: Boolean
4224
4225 @param location: Where the sig chain is located
4226- @type location: globals.archive_dir_path or globals.backend
4227+ @type location: globals.archive_dir or globals.backend
4228 """
4229 if local:
4230- self.archive_dir_path, self.backend = location, None
4231+ self.archive_dir, self.backend = location, None
4232 else:
4233- self.archive_dir_path, self.backend = None, location
4234+ self.archive_dir, self.backend = None, location
4235 self.fullsig = None # filename of full signature
4236 self.inclist = [] # list of filenames of incremental signatures
4237 self.start_time, self.end_time = None, None
4238@@ -503,8 +521,13 @@
4239 u"""
4240 Local or Remote and List of files in the set
4241 """
4242+<<<<<<< TREE
4243 if self.archive_dir_path:
4244 place = _(u"local")
4245+=======
4246+ if self.archive_dir:
4247+ place = _("local")
4248+>>>>>>> MERGE-SOURCE
4249 else:
4250 place = _(u"remote")
4251 filelist = []
4252@@ -518,14 +541,24 @@
4253 Check to make sure times are in whole seconds
4254 """
4255 for time in time_list:
4256+<<<<<<< TREE
4257 if type(time) not in integer_types:
4258 assert 0, u"Time %s in %s wrong type" % (time, time_list)
4259+=======
4260+ if type(time) not in (types.LongType, types.IntType):
4261+ assert 0, "Time %s in %s wrong type" % (time, time_list)
4262+>>>>>>> MERGE-SOURCE
4263
4264 def islocal(self):
4265+<<<<<<< TREE
4266 u"""
4267 Return true if represents a signature chain in archive_dir_path
4268- """
4269- if self.archive_dir_path:
4270+=======
4271+ """
4272+ Return true if represents a signature chain in archive_dir
4273+>>>>>>> MERGE-SOURCE
4274+ """
4275+ if self.archive_dir:
4276 return True
4277 else:
4278 return False
4279@@ -562,11 +595,17 @@
4280 optionally at a certain time
4281 """
4282 assert self.fullsig
4283- if self.archive_dir_path: # local
4284+ if self.archive_dir: # local
4285 def filename_to_fileobj(filename):
4286+<<<<<<< TREE
4287 u"""Open filename in archive_dir_path, return filtered fileobj"""
4288 sig_dp = path.DupPath(self.archive_dir_path.name, (filename,))
4289 return sig_dp.filtered_open(u"rb")
4290+=======
4291+ """Open filename in archive_dir, return filtered fileobj"""
4292+ sig_dp = path.DupPath(self.archive_dir.name, (filename,))
4293+ return sig_dp.filtered_open("rb")
4294+>>>>>>> MERGE-SOURCE
4295 else:
4296 filename_to_fileobj = self.backend.get_fileobj_read
4297 return [filename_to_fileobj(f) for f in self.get_filenames(time)]
4298@@ -576,11 +615,11 @@
4299 Remove all files in signature set
4300 """
4301 # Try to delete in opposite order, so something useful even if aborted
4302- if self.archive_dir_path:
4303+ if self.archive_dir:
4304 for i in range(len(self.inclist) - 1, -1, -1):
4305- self.archive_dir_path.append(self.inclist[i]).delete()
4306+ self.archive_dir.append(self.inclist[i]).delete()
4307 if not keep_full:
4308- self.archive_dir_path.append(self.fullsig).delete()
4309+ self.archive_dir.append(self.fullsig).delete()
4310 else:
4311 assert self.backend
4312 inclist_copy = self.inclist[:]
4313@@ -610,12 +649,17 @@
4314 u"""
4315 Hold information about available chains and sets
4316 """
4317+<<<<<<< TREE
4318 def __init__(self, backend, archive_dir_path, action):
4319 u"""
4320+=======
4321+ def __init__(self, backend, archive_dir, action):
4322+ """
4323+>>>>>>> MERGE-SOURCE
4324 Make new object. Does not set values
4325 """
4326 self.backend = backend
4327- self.archive_dir_path = archive_dir_path
4328+ self.archive_dir = archive_dir
4329 self.action = action
4330
4331 # Will hold (signature chain, backup chain) pair of active
4332@@ -640,8 +684,13 @@
4333 u"""
4334 Return summary of the collection, suitable for printing to log
4335 """
4336+<<<<<<< TREE
4337 l = [u"backend %s" % (self.backend.__class__.__name__,),
4338 u"archive-dir %s" % (self.archive_dir_path,)]
4339+=======
4340+ l = ["backend %s" % (self.backend.__class__.__name__,),
4341+ "archive-dir %s" % (self.archive_dir,)]
4342+>>>>>>> MERGE-SOURCE
4343
4344 for i in range(len(self.other_backup_chains)):
4345 # A bit of a misnomer. Chain might have a sig.
4346@@ -665,7 +714,11 @@
4347 u"-----------------",
4348 _(u"Connecting with backend: %s") %
4349 (self.backend.__class__.__name__,),
4350+<<<<<<< TREE
4351 _(u"Archive dir: %s") % (self.archive_dir_path.uc_name if self.archive_dir_path else u'None',)]
4352+=======
4353+ _("Archive dir: %s") % (util.ufn(self.archive_dir.name),)]
4354+>>>>>>> MERGE-SOURCE
4355
4356 l.append(u"\n" +
4357 ngettext(u"Found %d secondary backup chain.",
4358@@ -703,8 +756,13 @@
4359 return u"\n".join(l)
4360
4361 def set_values(self, sig_chain_warning=1):
4362+<<<<<<< TREE
4363 u"""
4364 Set values from archive_dir_path and backend.
4365+=======
4366+ """
4367+ Set values from archive_dir and backend.
4368+>>>>>>> MERGE-SOURCE
4369
4370 Returns self for convenience. If sig_chain_warning is set to None,
4371 do not warn about unnecessary sig chains. This is because there may
4372@@ -720,8 +778,13 @@
4373 len(backend_filename_list))
4374
4375 # get local filename list
4376+<<<<<<< TREE
4377 if self.action not in [u"collection-status", u"replicate"]:
4378 local_filename_list = self.archive_dir_path.listdir()
4379+=======
4380+ if self.action not in ["collection-status"]:
4381+ local_filename_list = self.archive_dir.listdir()
4382+>>>>>>> MERGE-SOURCE
4383 else:
4384 local_filename_list = []
4385 log.Debug(ngettext(u"%d file exists in cache",
4386@@ -909,8 +972,13 @@
4387 return ([p[1] for p in time_set_pairs], incomplete_sets)
4388
4389 def get_signature_chains(self, local, filelist=None):
4390+<<<<<<< TREE
4391 u"""
4392 Find chains in archive_dir_path (if local is true) or backend
4393+=======
4394+ """
4395+ Find chains in archive_dir (if local is true) or backend
4396+>>>>>>> MERGE-SOURCE
4397
4398 Use filelist if given, otherwise regenerate. Return value is
4399 pair (list of chains, list of signature paths not in any
4400@@ -920,8 +988,13 @@
4401 if filelist is not None:
4402 return filelist
4403 elif local:
4404+<<<<<<< TREE
4405 if self.action not in [u"collection-status", u"replicate"]:
4406 return self.archive_dir_path.listdir()
4407+=======
4408+ if self.action not in ["collection-status"]:
4409+ return self.archive_dir.listdir()
4410+>>>>>>> MERGE-SOURCE
4411 else:
4412 return []
4413 else:
4414@@ -932,7 +1005,7 @@
4415 Return new empty signature chain
4416 """
4417 if local:
4418- return SignatureChain(True, self.archive_dir_path)
4419+ return SignatureChain(True, self.archive_dir)
4420 else:
4421 return SignatureChain(False, self.backend)
4422
4423@@ -1196,6 +1269,7 @@
4424 old_sets = [s for s in chain.get_all_sets() if s.get_time() < t]
4425 result_sets.extend(old_sets)
4426 return self.sort_sets(result_sets)
4427+<<<<<<< TREE
4428
4429 def get_file_changed_record(self, filepath):
4430 u"""
4431@@ -1246,3 +1320,5 @@
4432
4433 l.append(u"-------------------------")
4434 return u"\n".join(l)
4435+=======
4436+>>>>>>> MERGE-SOURCE
4437
4438=== modified file 'duplicity/commandline.py'
4439--- duplicity/commandline.py 2019-01-25 17:08:40 +0000
4440+++ duplicity/commandline.py 2019-03-04 12:09:45 +0000
4441@@ -19,8 +19,12 @@
4442 # along with duplicity; if not, write to the Free Software Foundation,
4443 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4444
4445+<<<<<<< TREE
4446 u"""Parse command line, check for consistency, and set globals"""
4447 from __future__ import print_function
4448+=======
4449+"""Parse command line, check for consistency, and set globals"""
4450+>>>>>>> MERGE-SOURCE
4451
4452 from builtins import filter
4453 from builtins import str
4454@@ -58,8 +62,8 @@
4455 collection_status = None # Will be set to true if collection-status command given
4456 cleanup = None # Set to true if cleanup command given
4457 verify = None # Set to true if verify command given
4458-replicate = None # Set to true if replicate command given
4459
4460+<<<<<<< TREE
4461 commands = [u"cleanup",
4462 u"collection-status",
4463 u"full",
4464@@ -71,6 +75,18 @@
4465 u"restore",
4466 u"verify",
4467 u"replicate"
4468+=======
4469+commands = ["cleanup",
4470+ "collection-status",
4471+ "full",
4472+ "incremental",
4473+ "list-current-files",
4474+ "remove-older-than",
4475+ "remove-all-but-n-full",
4476+ "remove-all-inc-of-but-n-full",
4477+ "restore",
4478+ "verify",
4479+>>>>>>> MERGE-SOURCE
4480 ]
4481
4482
4483@@ -203,8 +219,12 @@
4484 optparse.Option.take_action(
4485 self, action, dest, opt, value, values, parser)
4486
4487+<<<<<<< TREE
4488
4489 u"""
4490+=======
4491+"""
4492+>>>>>>> MERGE-SOURCE
4493 Fix:
4494 File "/usr/lib/pythonX.X/optparse.py", line XXXX, in print_help
4495 file.write(self.format_help().encode(encoding, "replace"))
4496@@ -245,7 +265,7 @@
4497 def parse_cmdline_options(arglist):
4498 u"""Parse argument list"""
4499 global select_opts, select_files, full_backup
4500- global list_current, collection_status, cleanup, remove_time, verify, replicate
4501+ global list_current, collection_status, cleanup, remove_time, verify
4502
4503 def set_log_fd(fd):
4504 if fd < 1:
4505@@ -270,7 +290,11 @@
4506 log.ErrorCode.cant_open_filelist)
4507
4508 def print_ver(o, s, v, p):
4509+<<<<<<< TREE
4510 print(u"duplicity %s" % (globals.version))
4511+=======
4512+ print "duplicity %s" % (globals.version)
4513+>>>>>>> MERGE-SOURCE
4514 sys.exit(0)
4515
4516 def add_rename(o, s, v, p):
4517@@ -391,9 +415,15 @@
4518 # whole root.
4519 # TRANSL: Used in usage help to represent a Unix-style path name. Example:
4520 # --archive-dir <path>
4521+<<<<<<< TREE
4522 parser.add_option(u"--file-to-restore", u"-r", action=u"callback", type=u"file",
4523 metavar=_(u"path"), dest=u"restore_dir",
4524 callback=lambda o, s, v, p: setattr(p.values, u"restore_dir", util.fsencode(v.strip(u'/'))))
4525+=======
4526+ parser.add_option("--file-to-restore", "-r", action="callback", type="file",
4527+ metavar=_("path"), dest="restore_dir",
4528+ callback=lambda o, s, v, p: setattr(p.values, "restore_dir", v.strip('/')))
4529+>>>>>>> MERGE-SOURCE
4530
4531 # Used to confirm certain destructive operations like deleting old files.
4532 parser.add_option(u"--force", action=u"store_true")
4533@@ -577,6 +607,7 @@
4534 parser.add_option("--s3-kms-key-id", action=u"store", dest="s3_kms_key_id")
4535 parser.add_option("--s3-kms-grant", action=u"store", dest="s3_kms_grant")
4536
4537+<<<<<<< TREE
4538 # Option to specify a Swift container storage policy.
4539 parser.add_option(u"--swift-storage-policy", type=u"string", metavar=_(u"policy"))
4540
4541@@ -598,6 +629,8 @@
4542 # Standard storage tier used for storring backup files (Hot|Cool|Archive).
4543 parser.add_option(u"--azure-blob-tier", type=u"string", metavar=_(u"Hot|Cool|Archive"))
4544
4545+=======
4546+>>>>>>> MERGE-SOURCE
4547 # scp command to use (ssh pexpect backend)
4548 parser.add_option(u"--scp-command", metavar=_(u"command"))
4549
4550@@ -662,18 +695,21 @@
4551 parser.add_option(u"--volsize", type=u"int", action=u"callback", metavar=_(u"number"),
4552 callback=lambda o, s, v, p: setattr(p.values, u"volsize", v * 1024 * 1024))
4553
4554+<<<<<<< TREE
4555 # If set, collect only the file status, not the whole root.
4556 parser.add_option(u"--file-changed", action=u"callback", type=u"file",
4557 metavar=_(u"path"), dest=u"file_changed",
4558 callback=lambda o, s, v, p: setattr(p.values, u"file_changed", v.rstrip(u'/')))
4559
4560+=======
4561+>>>>>>> MERGE-SOURCE
4562 # delay time before next try after a failure of a backend operation
4563 # TRANSL: Used in usage help. Example:
4564 # --backend-retry-delay <seconds>
4565 parser.add_option(u"--backend-retry-delay", type=u"int", metavar=_(u"seconds"))
4566
4567 # parse the options
4568- (options, args) = parser.parse_args(arglist)
4569+ (options, args) = parser.parse_args()
4570
4571 # Copy all arguments and their values to the globals module. Don't copy
4572 # attributes that are 'hidden' (start with an underscore) or whose name is
4573@@ -743,9 +779,12 @@
4574 num_expect = 1
4575 elif cmd == u"verify":
4576 verify = True
4577+<<<<<<< TREE
4578 elif cmd == u"replicate":
4579 replicate = True
4580 num_expect = 2
4581+=======
4582+>>>>>>> MERGE-SOURCE
4583
4584 if len(args) != num_expect:
4585 command_line_error(u"Expected %d args, got %d" % (num_expect, len(args)))
4586@@ -764,12 +803,16 @@
4587 elif len(args) == 1:
4588 backend_url = args[0]
4589 elif len(args) == 2:
4590+<<<<<<< TREE
4591 if replicate:
4592 if not backend.is_backend_url(args[0]) or not backend.is_backend_url(args[1]):
4593 command_line_error(u"Two URLs expected for replicate.")
4594 src_backend_url, backend_url = args[0], args[1]
4595 else:
4596 lpath, backend_url = args_to_path_backend(args[0], args[1]) # @UnusedVariable
4597+=======
4598+ lpath, backend_url = args_to_path_backend(args[0], args[1]) # @UnusedVariable
4599+>>>>>>> MERGE-SOURCE
4600 else:
4601 command_line_error(u"Too many arguments")
4602
4603@@ -780,8 +823,13 @@
4604 set_archive_dir(expand_archive_dir(globals.archive_dir,
4605 globals.backup_name))
4606
4607+<<<<<<< TREE
4608 log.Info(_(u"Using archive dir: %s") % (globals.archive_dir_path.uc_name,))
4609 log.Info(_(u"Using backup name: %s") % (globals.backup_name,))
4610+=======
4611+ log.Info(_("Using archive dir: %s") % (util.ufn(globals.archive_dir.name),))
4612+ log.Info(_("Using backup name: %s") % (globals.backup_name,))
4613+>>>>>>> MERGE-SOURCE
4614
4615 return args
4616
4617@@ -944,7 +992,6 @@
4618 duplicity remove-older-than %(time)s [%(options)s] %(target_url)s
4619 duplicity remove-all-but-n-full %(count)s [%(options)s] %(target_url)s
4620 duplicity remove-all-inc-of-but-n-full %(count)s [%(options)s] %(target_url)s
4621- duplicity replicate %(source_url)s %(target_url)s
4622
4623 """ % dict
4624
4625@@ -964,7 +1011,6 @@
4626 scp://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
4627 ssh://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
4628 swift://%(container_name)s
4629- pca://%(container_name)s
4630 tahoe://%(alias)s/%(directory)s
4631 webdav://%(user)s[:%(password)s]@%(other_host)s/%(some_dir)s
4632 webdavs://%(user)s[:%(password)s]@%(other_host)s/%(some_dir)s
4633@@ -991,8 +1037,7 @@
4634 remove-older-than <%(time)s> <%(target_url)s>
4635 remove-all-but-n-full <%(count)s> <%(target_url)s>
4636 remove-all-inc-of-but-n-full <%(count)s> <%(target_url)s>
4637- verify <%(target_url)s> <%(source_dir)s>
4638- replicate <%(source_url)s> <%(target_url)s>""" % dict
4639+ verify <%(target_url)s> <%(source_dir)s>""" % dict
4640
4641 return msg
4642
4643@@ -1004,12 +1049,19 @@
4644 os.makedirs(dirstring)
4645 except Exception:
4646 pass
4647+<<<<<<< TREE
4648 archive_dir_path = path.Path(dirstring)
4649 if not archive_dir_path.isdir():
4650 log.FatalError(_(u"Specified archive directory '%s' does not exist, "
4651 u"or is not a directory") % (archive_dir_path.uc_name,),
4652+=======
4653+ archive_dir = path.Path(dirstring)
4654+ if not archive_dir.isdir():
4655+ log.FatalError(_("Specified archive directory '%s' does not exist, "
4656+ "or is not a directory") % (util.ufn(archive_dir.name),),
4657+>>>>>>> MERGE-SOURCE
4658 log.ErrorCode.bad_archive_dir)
4659- globals.archive_dir_path = archive_dir_path
4660+ globals.archive_dir = archive_dir
4661
4662
4663 def set_sign_key(sign_key):
4664@@ -1094,8 +1146,13 @@
4665
4666
4667 def check_consistency(action):
4668+<<<<<<< TREE
4669 u"""Final consistency check, see if something wrong with command line"""
4670 global full_backup, select_opts, list_current, collection_status, cleanup, replicate
4671+=======
4672+ """Final consistency check, see if something wrong with command line"""
4673+ global full_backup, select_opts, list_current
4674+>>>>>>> MERGE-SOURCE
4675
4676 def assert_only_one(arglist):
4677 u"""Raises error if two or more of the elements of arglist are true"""
4678@@ -1105,9 +1162,15 @@
4679 n += 1
4680 assert n <= 1, u"Invalid syntax, two conflicting modes specified"
4681
4682+<<<<<<< TREE
4683 if action in [u"list-current", u"collection-status",
4684 u"cleanup", u"remove-old", u"remove-all-but-n-full", u"remove-all-inc-of-but-n-full", u"replicate"]:
4685 assert_only_one([list_current, collection_status, cleanup, replicate,
4686+=======
4687+ if action in ["list-current", "collection-status",
4688+ "cleanup", "remove-old", "remove-all-but-n-full", "remove-all-inc-of-but-n-full"]:
4689+ assert_only_one([list_current, collection_status, cleanup,
4690+>>>>>>> MERGE-SOURCE
4691 globals.remove_time is not None])
4692 elif action == u"restore" or action == u"verify":
4693 if full_backup:
4694@@ -1153,8 +1216,14 @@
4695 sign_key=src.sign_key,
4696 recipients=src.recipients,
4697 hidden_recipients=src.hidden_recipients)
4698+<<<<<<< TREE
4699 log.Debug(_(u"GPG binary is %s, version %s") %
4700 ((globals.gpg_binary or u'gpg'), globals.gpg_profile.gpg_version))
4701+=======
4702+ log.Debug(_("GPG binary is %s, version %s") %
4703+ ((globals.gpg_binary or 'gpg'),
4704+ "%d.%d.%d" % globals.gpg_profile.gpg_version))
4705+>>>>>>> MERGE-SOURCE
4706
4707 # we can now try to import all the backends
4708 backend.import_backends()
4709@@ -1185,11 +1254,22 @@
4710 "file:///usr/local". See the man page for more information.""") % (args[0],),
4711 log.ErrorCode.bad_url)
4712 elif len(args) == 2:
4713+<<<<<<< TREE
4714 if replicate:
4715 globals.src_backend = backend.get_backend(args[0])
4716 globals.backend = backend.get_backend(args[1])
4717 action = u"replicate"
4718+=======
4719+ # Figure out whether backup or restore
4720+ backup, local_pathname = set_backend(args[0], args[1])
4721+ if backup:
4722+ if full_backup:
4723+ action = "full"
4724+ else:
4725+ action = "inc"
4726+>>>>>>> MERGE-SOURCE
4727 else:
4728+<<<<<<< TREE
4729 # Figure out whether backup or restore
4730 backup, local_pathname = set_backend(args[0], args[1])
4731 if backup:
4732@@ -1197,15 +1277,29 @@
4733 action = u"full"
4734 else:
4735 action = u"inc"
4736+=======
4737+ if verify:
4738+ action = "verify"
4739+>>>>>>> MERGE-SOURCE
4740 else:
4741+<<<<<<< TREE
4742 if verify:
4743 action = u"verify"
4744 else:
4745 action = u"restore"
4746+=======
4747+ action = "restore"
4748+>>>>>>> MERGE-SOURCE
4749
4750+<<<<<<< TREE
4751 process_local_dir(action, local_pathname)
4752 if action in [u'full', u'inc', u'verify']:
4753 set_selection()
4754+=======
4755+ process_local_dir(action, local_pathname)
4756+ if action in ['full', 'inc', 'verify']:
4757+ set_selection()
4758+>>>>>>> MERGE-SOURCE
4759 elif len(args) > 2:
4760 raise AssertionError(u"this code should not be reachable")
4761
4762
4763=== modified file 'duplicity/compilec.py'
4764--- duplicity/compilec.py 2018-12-04 20:50:28 +0000
4765+++ duplicity/compilec.py 2019-03-04 12:09:45 +0000
4766@@ -22,6 +22,7 @@
4767
4768 import sys
4769 import os
4770+<<<<<<< TREE
4771
4772 # Avoid conflict on python 2 with collections.py vs. built-in collections module
4773 sp = sys.path
4774@@ -29,6 +30,9 @@
4775 # https://github.com/PyCQA/pylint/issues/73
4776 from distutils.core import setup, Extension # pylint: disable=import-error,no-name-in-module
4777 sys.path = sp
4778+=======
4779+from distutils.core import setup, Extension
4780+>>>>>>> MERGE-SOURCE
4781
4782 assert len(sys.argv) == 1
4783 sys.argv.append("build")
4784
4785=== modified file 'duplicity/diffdir.py'
4786--- duplicity/diffdir.py 2018-11-29 19:00:15 +0000
4787+++ duplicity/diffdir.py 2019-03-04 12:09:45 +0000
4788@@ -92,7 +92,7 @@
4789 """
4790 global stats
4791 stats = statistics.StatsDeltaProcess()
4792- if isinstance(dirsig_fileobj_list, list):
4793+ if isinstance(dirsig_fileobj_list, types.ListType):
4794 sig_iter = combine_path_iters([sigtar2path_iter(x) for x
4795 in dirsig_fileobj_list])
4796 else:
4797@@ -227,7 +227,7 @@
4798 else:
4799 ti.name = b"deleted/" + b"/".join(sig_path.index)
4800 sigTarFile.addfile(ti)
4801- stats.add_deleted_file(sig_path)
4802+ stats.add_deleted_file()
4803 yield ROPath(sig_path.index)
4804 elif not sig_path or new_path != sig_path:
4805 # Must calculate new signature and create delta
4806@@ -294,7 +294,7 @@
4807 while 1:
4808 if not relem1:
4809 try:
4810- relem1 = next(riter1)
4811+ relem1 = riter1.next()
4812 except StopIteration:
4813 if relem2:
4814 yield (None, relem2)
4815@@ -304,7 +304,7 @@
4816 index1 = relem1.index
4817 if not relem2:
4818 try:
4819- relem2 = next(riter2)
4820+ relem2 = riter2.next()
4821 except StopIteration:
4822 if relem1:
4823 yield (relem1, None)
4824@@ -345,7 +345,7 @@
4825 Represent the next element as a triple, to help sorting
4826 """
4827 try:
4828- path = next(path_iter_list[iter_index])
4829+ path = path_iter_list[iter_index].next()
4830 except StopIteration:
4831 return None
4832 return (path.index, iter_index, path)
4833@@ -385,7 +385,7 @@
4834 """
4835 global stats
4836 stats = statistics.StatsDeltaProcess()
4837- if isinstance(sig_infp_list, list):
4838+ if isinstance(sig_infp_list, types.ListType):
4839 sig_path_iter = get_combined_path_iter(sig_infp_list)
4840 else:
4841 sig_path_iter = sigtar2path_iter(sig_infp_list)
4842@@ -541,7 +541,11 @@
4843 result = self.process_continued() # pylint: disable=assignment-from-no-return
4844 else:
4845 # Below a StopIteration exception will just be passed upwards
4846+<<<<<<< TREE
4847 result = self.process(next(self.input_iter)) # pylint: disable=assignment-from-no-return
4848+=======
4849+ result = self.process(self.input_iter.next())
4850+>>>>>>> MERGE-SOURCE
4851 block_number = self.process_next_vol_number
4852 self.offset += len(result.data)
4853 self.previous_index = result.index
4854
4855=== modified file 'duplicity/dup_threading.py'
4856--- duplicity/dup_threading.py 2018-11-29 19:00:15 +0000
4857+++ duplicity/dup_threading.py 2019-03-04 12:09:45 +0000
4858@@ -28,12 +28,15 @@
4859 at least python 2.5.)
4860 """
4861
4862+<<<<<<< TREE
4863 from future import standard_library
4864 standard_library.install_aliases()
4865 from builtins import object
4866 import sys
4867 from duplicity import errors
4868
4869+=======
4870+>>>>>>> MERGE-SOURCE
4871 _threading_supported = True
4872
4873 try:
4874@@ -48,6 +51,10 @@
4875 import dummy_threading as threading
4876 _threading_supported = False
4877
4878+import sys
4879+
4880+from duplicity import errors
4881+
4882
4883 def threading_supported():
4884 u"""
4885
4886=== modified file 'duplicity/dup_time.py'
4887=== modified file 'duplicity/file_naming.py'
4888--- duplicity/file_naming.py 2018-11-29 19:00:15 +0000
4889+++ duplicity/file_naming.py 2019-03-04 12:09:45 +0000
4890@@ -448,11 +448,3 @@
4891 self.encrypted = encrypted # true if gpg encrypted
4892
4893 self.partial = partial
4894-
4895- def __eq__(self, other):
4896- return self.type == other.type and \
4897- self.manifest == other.manifest and \
4898- self.time == other.time and \
4899- self.start_time == other.start_time and \
4900- self.end_time == other.end_time and \
4901- self.partial == other.partial
4902
4903=== modified file 'duplicity/globals.py'
4904--- duplicity/globals.py 2019-01-25 17:08:40 +0000
4905+++ duplicity/globals.py 2019-03-04 12:09:45 +0000
4906@@ -58,9 +58,14 @@
4907 # contains the signatures and manifests of the relevent backup
4908 # collection), and for checkpoint state between volumes.
4909 # NOTE: this gets expanded in duplicity.commandline
4910+<<<<<<< TREE
4911 os.environ[u"XDG_CACHE_HOME"] = os.getenv(u"XDG_CACHE_HOME", os.path.expanduser(u"~/.cache"))
4912 archive_dir = os.path.expandvars(u"$XDG_CACHE_HOME/duplicity")
4913 archive_dir_path = None
4914+=======
4915+os.environ["XDG_CACHE_HOME"] = os.getenv("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
4916+archive_dir = os.path.expandvars("$XDG_CACHE_HOME/duplicity")
4917+>>>>>>> MERGE-SOURCE
4918
4919 # config dir for future use
4920 os.environ[u"XDG_CONFIG_HOME"] = os.getenv(u"XDG_CONFIG_HOME", os.path.expanduser(u"~/.config"))
4921@@ -220,6 +225,7 @@
4922 # Use server side encryption in s3
4923 s3_use_sse = False
4924
4925+<<<<<<< TREE
4926 # Use server side kms encryption in s3
4927 s3_use_sse_kms = False
4928 s3_kms_key_id = None
4929@@ -240,6 +246,8 @@
4930 # Standard storage tier used for storring backup blobs (Hot|Cool|Archive).
4931 azure_blob_tier = None
4932
4933+=======
4934+>>>>>>> MERGE-SOURCE
4935 # Whether to use the full email address as the user name when
4936 # logging into an imap server. If false just the user name
4937 # part of the email address is used.
4938@@ -321,11 +329,9 @@
4939 # Whether to enable gio backend
4940 use_gio = False
4941
4942-# If set, collect only the file status, not the whole root.
4943-file_changed = None
4944-
4945 # delay (in seconds) before next operation after failure
4946 backend_retry_delay = 30
4947+<<<<<<< TREE
4948
4949 # default filesystem encoding
4950 # In Python 2 it seems that sys.getfilesystemencoding() will normally return
4951@@ -333,3 +339,12 @@
4952 # either 'ascii' or None. Both are bogus, so default to 'utf-8' if it does.
4953 fsencoding = sys.getfilesystemencoding()
4954 fsencoding = fsencoding if fsencoding not in [u'ascii', u'ANSI_X3.4-1968', None] else u'utf-8'
4955+=======
4956+
4957+# default filesystem encoding
4958+# In Python 2 it seems that sys.getfilesystemencoding() will normally return
4959+# 'utf-8' or some other sane encoding, but will sometimes fail and return
4960+# either 'ascii' or None. Both are bogus, so default to 'utf-8' if it does.
4961+fsencoding = sys.getfilesystemencoding()
4962+fsencoding = fsencoding if fsencoding not in ['ascii', None] else 'utf-8'
4963+>>>>>>> MERGE-SOURCE
4964
4965=== modified file 'duplicity/globmatch.py'
4966--- duplicity/globmatch.py 2018-11-29 19:00:15 +0000
4967+++ duplicity/globmatch.py 2019-03-04 12:09:45 +0000
4968@@ -56,8 +56,13 @@
4969 return list(map(glob_to_regex, prefixes))
4970
4971
4972+<<<<<<< TREE
4973 def select_fn_from_glob(glob_str, include, ignore_case=False):
4974 u"""Return a function test_fn(path) which
4975+=======
4976+def path_matches_glob_fn(glob_str, include, ignore_case=False):
4977+ """Return a function test_fn(path) which
4978+>>>>>>> MERGE-SOURCE
4979 tests whether path matches glob, as per the Unix shell rules, taking as
4980 arguments a path, a glob string and include (0 indicating that the glob
4981 string is an exclude glob and 1 indicating that it is an include glob,
4982@@ -66,16 +71,18 @@
4983 1 - if the file should be included
4984 2 - if the folder should be scanned for any included/excluded files
4985 None - if the selection function has nothing to say about the file
4986-
4987- Note: including a folder implicitly includes everything within it.
4988 """
4989 assert isinstance(glob_str, str)
4990 glob_ends_w_slash = False
4991
4992+<<<<<<< TREE
4993 if glob_str == u"/":
4994 # If the glob string is '/', it implicitly includes everything
4995 glob_str = u"/**"
4996 elif glob_str[-1] == u"/":
4997+=======
4998+ if glob_str != "/" and glob_str[-1] == "/":
4999+>>>>>>> MERGE-SOURCE
5000 glob_ends_w_slash = True
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches