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
=== modified file 'CHANGELOG'
--- CHANGELOG 2019-02-25 16:30:59 +0000
+++ CHANGELOG 2019-03-04 12:09:45 +0000
@@ -1,3 +1,4 @@
1<<<<<<< TREE
1New in v0.8.00 (2019/??/??)2New in v0.8.00 (2019/??/??)
2---------------------------3---------------------------
3* Merged in lp:~aaron-whitehouse/duplicity/remove-python264* Merged in lp:~aaron-whitehouse/duplicity/remove-python26
@@ -128,46 +129,183 @@
128 - change util.uexc() back to bare uexc()129 - change util.uexc() back to bare uexc()
129* Fixed bug #1668750 - Don't mask backend errors130* Fixed bug #1668750 - Don't mask backend errors
130 - added exception prints to module import errors131 - added exception prints to module import errors
132=======
133New in v0.7.19 (2019/??/??)
134-----------------------------
135* Fixed bug #1798206 and bug #1798504
136 - Made paramiko a global with import during __init__ so it would
137 not be loaded unless needed.
138* Merged in lp:~mterry/duplicity/pydrive-root-0.7
139 - Just a tiny fix to clean up the temporary file we create to find the root ID.
140 It's a little surprising for the user if they wind up with this file called
141 "i_am_in_root" that they don't know where it came from. Almost sounds like
142 they were hacked.
143
144
145New in v0.7.18.2 (2018/10/17)
146-----------------------------
147* Fixed bug #1788558 again
148 - If we get None for size skip check.
149
150
151New in v0.7.18.1 (2018/08/27)
152-----------------------------
153* Fixed bug #1788558
154 - Treat None as zero when printing log.
155* Revert fix for bug #1788599.
156 - Was causing problems with directory names
157
158
159New in v0.7.18 (2018/08/21)
160---------------------------
161* Fixed bug #1756550 Online html man page is showing a 0 byte file
162* Partial fix of bug #1734144 with patch from Joris van Eijden
163 - Note: this is really just a partial fix for now, since it only covers
164 the case where the local size does not yet match the remote size. A
165 case where -1 is the returned length is not fixed.
166 - Number of retries is now same as globals.num_retries.
167 - Added standoff delay of 0.5 sec per attempt.
168* Fixed bug #1764432 with patch from Robke Geenen
169 - Just join the parts together.
170* Fixed bug #1717935 with suggestion from strainu
171 - Use urllib.quote_plus() to properly quote pathnames passed via URL
172* Fixed bug #1780617 Test fail when GnuPG >= 2.2.8
173 - Relevant change in GnuPG 2.2.8: https://dev.gnupg.org/T3981
174 - Added '--ignore-mdc-error' to all gpg calls made.
175* Fixed bug #1785520 with patch from Chris Hunt
176 - Fix for B2 version 1.3.4 just released
177* Fix a 2to3 error in ssh_paramiko_backend.py
178
179
180New in v0.7.17 (2018/02/26)
181---------------------------
182* Removed changes made in bug #1044715 Provide a file history feature
183 - Changes required too much memory to carry in the manifest
184 - The option --file-changed in collection-status is now invalid
185 - This will close bugs: #1730451, #896728, #1526557, #1550176
186 - Starting a full backup will be needed to fully utilize this fix
187* Fix update of Launchpad Translations. Translations were not being picked
188 up on a daily basis and we got several months behind.
189
190
191New in v0.7.16 (2018/01/12)
192---------------------------
193* Fixed bug #1733057 AttributeError: 'GPGError' object has no attribute 'decode'
194 - Replaced call to util.ufn() with call to util.uexc(). Stupid typo!
195* More fixes for Unicode handling
196 - Default to 'utf-8' if sys.getfilesystemencoding() returns 'ascii' or None
197 - Fixed bug #1386373 with suggestion from Eugene Morozov
198* Patched in lp:~crosser/duplicity/fix-oauth-flow
199 - Fixed bug #1638236 "BackendException with oauth2client 4.0.0"
200* Patched in lp:~crosser/duplicity/dpbx-fix-file-listing
201 - Fixed bug #1639664 "Dropbox support needs to be updated for Dropbox SDK v7.1"
202* Patched in lp:~crosser/duplicity/fix-small-file-upload
203 - Fixed small file upload changes made in Dropbox SDK v7.1
204* Fix pylint error in webdavbackend.py
205
206
207New in v0.7.15 (2017/11/13)
208---------------------------
209* Fixed bug introduced in new megabackend.py where process_commandline()
210 takes a string not a list. Now it takes both.
211* Updated web page for new megabackend requirements.
212* Patched in lp:~mterry/duplicity/more-decode-issues
213 - Here's some fixes for another couple UnicodeDecodeErrors.
214 - The duplicity/dup_time.py fixes when a user passes a utf8 date string (or a string with bogus
215 utf8 characters, but they have to really try to do that). This is bug 1334436.
216 - The bin/duplicity change from str(e) to util.uexc(e) fixes bug 1324188.
217 - The rest of the changes (util.exception_traceback and bin/duplicity changes to use it) are to
218 make the printing of exceptions prettier. Without this, if you see a French exception, you see
219 "accept\xe9es" instead of "acceptées".
220 - You can test all of these changes in one simple line:
221 $ LANGUAGE=fr duplicity remove-older-than $'accept\xffées'
222* Fix backend.py to allow string, list, and tuple types to support megabackend.py.
223* Fixed bug #1715650 with patch from Mattheww S
224 - Fix to make duplicity attempt a get first, then create, a container
225 in order to support container ACLs.
226* Fixed bug #1714663 "Volume signed by XXXXXXXXXXXXXXXX, not XXXXXXXX"
227 - Normalized comparison length to min length of compared keys before comparison
228 - Avoids comparing mix of short, long, or fingerprint size keys.
229* Merged in lp:~mterry/duplicity/rename-dep
230 - Make rename command a dependency for LP build
231* Fixed bug #1654756 with new b2backend.py module from Vincent Rouille
232 - Faster (big files are uploaded in chunks)
233 - Added upload progress reporting support
234* Fixed bug #1448094 with patch from Wolfgang Rohdewald
235 - Don't log incremental deletes for chains that have no incrementals
236* Fixed bug #1724144 "--gpg-options unused with some commands"
237 - Add --gpg-options to get version run command
238* Fixed bug #1720159 - Cannot allocate memory with large manifest file since 0.7.03
239 - filelist is not read if --file-changed option in collection-status not present
240 - This will keep memory usage lower in non collection-status operations
241* Fixed bug #1723890 with patch from Killian Lackhove
242 - Fixes error handling in pydrivebackend.py
243* Fixed bug #1730902 GPG Error Handling
244 - use util.ufn() not str() to handle encoding
245
246
247New in v0.7.14 (2017/08/31)
248---------------------------
249* Merged in lp:~dawgfoto/duplicity/skip_sync_collection_status
250 - collection-status should not sync metadata
251 - up-to-date local metadata is not needed as collection-status is
252 generated from remote file list
253 - syncing metadata might require to download several GBs
254* Fixed slowness in 'collection-status' by basing the status on the
255 remote system only. The local cache is treated as empty.
256* Fixed encrypted remote manifest handling to merely put out a non-fatal
257 error message and continue if the private key is not available.
258* Patched in lp:~mterry/duplicity/giobackend-display-name
259 - giobackend: handle a wider variety of gio backends by making less assumptions;
260 in particular, this fixes the google-drive: backend
261* Fixed bug #1709047 with suggestion from Gary Hasson
262 - fixed so default was to use original filename
263* Fixed PEP8 errors in bin/duplicity
264* Merged in lp:~mterry/duplicity/gio_child_for_display_name_0.7
265 - gio: be slightly more correct and get child GFiles based on display name
266* Fixed bug #1711905 with suggestion from Schneider
267 - log.Warn was invoked with log.warn in webdavbackend.py
268* Merged in lp:~mterry/duplicity/gpg-tag-versions
269 - Support gpg versions numbers that have tags on them.
270 - This can happen if you build gpg from git trunk (e.g. 2.1.15-beta20). Or if you run
271 against the freedesktop flatpak runtime (e.g. 2.1.14-unknown).
272* Fixed bug #1394386 with new module megabackend.py from Tomas Vondra
273 - uses megatools from https://megatools.megous.com/ instead of mega.py library
274 which has been deprecated
275 - fixed copyright and PEP8 issues
276 - replaced subprocess.call() with self.subprocess_popen() to standardize
277* Fixed bug #1713640 with patch from Aleksandar Ivanisevic
278 - replace 2.7 syntax with 2.6 equivalent
279* Fixed bug #1538333 Assertion error in manifest.py: assert filecount == ...
280 - Made sure to never pass .part files as true manifest files
281 - Changed assert to log.Error to warn about truncated/corrupt filelist
282 - Added unit test to make sure detection works
283 - Note: while this condition is serious, it will not affect the basic backup and restore
284 functions. Interactive options like --list-files-changed and --file-changed will not
285 work correctly for this backup set, so it is advised to run a full backup as soon as
286 possible after this error occurs.
287* Fixed bug #1638033 Remove leading slash on --file-to-restore
288 - code already used rstrip('/') so change to just strip('/')
289
290
291New in v0.7.13.1 (2017/06/18)
292-----------------------------
293* Fixed problem in dist/makedist when building on Mac where AppleDouble
294 files were being created in the tarball. See:
295 https://superuser.com/questions/61185/why-do-i-get-files-like-foo-in-my-tarball-on-os-x
296
297
298New in v0.7.13 (2017/06/12)
299---------------------------
300>>>>>>> MERGE-SOURCE
131* Fixed bug #1680682 with patch supplied from Dave Allan301* Fixed bug #1680682 with patch supplied from Dave Allan
132 - Only specify --pinentry-mode=loopback when --use-agent is not specified302 - Only specify --pinentry-mode=loopback when --use-agent is not specified
133* Fixed man page that had 'cancel' instead of 'loopback' for pinentry mode303* Fixed man page that had 'cancel' instead of 'loopback' for pinentry mode
134* Fixed bug #1684312 with suggestion from Wade Rossman304* Fixed bug #1684312 with suggestion from Wade Rossman
135 - Use shutil.copyfile instead of os.system('cp ...')305 - Use shutil.copyfile instead of os.system('cp ...')
136 - Should reduce overhead of os.system() memory usage.306 - Should reduce overhead of os.system() memory usage.
137* Merged in lp:~dernils/duplicity/testing
138 - Fixed minor stuff in requirements.txt.
139 - Added a Dockerfile for testing.
140 - Minor changes to README files.
141 - Added README-TESTING with some information on testing.
142* Merged in lp:~dernils/duplicity/documentation
143 - Minor changes to README-REPO, README-TESTING
144 - Also redo the changes to requirements.txt and Dockerfile
145* Merged in lp:~dawgfoto/duplicity/replicate
146 - Add replicate command to replicate a backup (or backup
147 sets older than a given time) to another backend, leveraging
148 duplicity's backend and compression/encryption infrastructure.
149* Fixed some incoming PyLint and PEP-8 errors.
150* Merged in lp:~marix/duplicity/add-azure-arguments
151 - Using the Azure backend to store large amounts of data we found that
152 performance is sub-optimal. The changes on this branch add command line
153 parameters to fine-tune some parameters of the Azure storage library,
154 allowing to push write performance towards Azure above 1 Gb/s for large
155 back-ups. If a user does not provide the parameters the defaults of the
156 Azure storage library will continue to be used.
157* Replace incoming non-ASCII chars in commandline.py
158* bzr does not honor perms so fix the perms at the start of the testing and
159 avoid annoying error regarding testing/gnupg having too lenient perms
160* Merged in lp:~dernils/duplicity/DockerfileConvenience
161 - Added a few tools to the Dockerfile that make life easier
162* Fixed bug #1320832 with suggestion from Oskar Wycislak307* Fixed bug #1320832 with suggestion from Oskar Wycislak
163 - Use chunks instead of reading it all in swiftbackend308 - Use chunks instead of reading it all in swiftbackend
164* Merged in lp:~dernils/duplicity/DockerfileConvenience
165 - Add a few files that are the beginning of further infrastructure based
166 on docker. It contains a Dockerfile for a simple ftp server (used for
167 backend testing) and a setup script that can be used to set up the
168 complete test environment.
169* Moved Dockerfile for duplicitytest into testinfrastructure/duplicity_test
170* Moved some things around in testing/infrastructure to clean up
171* Fixed bug #1689632 with patch from Howard Kaye309* Fixed bug #1689632 with patch from Howard Kaye
172 - On MacOS, the tempfile.TemporaryFile call erroneously raises an310 - On MacOS, the tempfile.TemporaryFile call erroneously raises an
173 IOError exception saying that too many files are open. This causes311 IOError exception saying that too many files are open. This causes
@@ -176,17 +314,6 @@
176 - swap from lockfile to fasteners module314 - swap from lockfile to fasteners module
177 - use an fcntl() style lock for process lock of duplicity cache315 - use an fcntl() style lock for process lock of duplicity cache
178 - lockfile will now clear if duplicity is killed or crashes316 - lockfile will now clear if duplicity is killed or crashes
179* Merged in lp:~aaron-whitehouse/duplicity/tox_pylint_fixes
180 - Changes needed to run-tests without pylint E0401(import-error) errors
181* Merged in lp:~xlucas/duplicity/swift-storage-policies
182 - This brings support for Swift storage policies: when using a Swift
183 backend, you can specify the policy containers should be operating on.
184 - This is similar to AWS Cloud Storage classes (ia, rrs, glacier and so on).
185* Merged in lp:~dernils/duplicity/Dockerfile
186 - Added another backend to the docker test infrastructure, updated the setup
187 for testing and updated the documentation.
188* Merged in lp:~dernils/duplicity/Dockerfile
189 - Now have subnet name and IP of the subnet for testing as a variable.
190* May have finally fixed bug #1556553, "Too many open files...".317* May have finally fixed bug #1556553, "Too many open files...".
191 - Applied patch from Howard Kaye, question #631423. The fix is to dup318 - Applied patch from Howard Kaye, question #631423. The fix is to dup
192 the file descriptor, and then close the file in the deallocator319 the file descriptor, and then close the file in the deallocator
@@ -203,19 +330,13 @@
203* Fix bug #1672540 with patch from Benoit Nadeau330* Fix bug #1672540 with patch from Benoit Nadeau
204 - Rename would fail to move par files when moving across filesystems.331 - Rename would fail to move par files when moving across filesystems.
205 - Patch uses shutil.move() to do the rename instead.332 - Patch uses shutil.move() to do the rename instead.
206* Merged in lp:~dernils/duplicity/docker-compose
207 - Test Infrastructure now utilizing docker-compose
208* Merged in lp:~aaron-whitehouse/duplicity/08-fix-man-verify
209 - Fix description of --verify and --compare-data in the man page. Now
210 clarifies that verify compares the restored files to hashes stored at
211 backup date, while --compare-data compares restored files to files
212 in target_path.
213* Fixed bug #1265765 with patches from Matthias Larisch and Edgar Soldin333* Fixed bug #1265765 with patches from Matthias Larisch and Edgar Soldin
214 - SSH Paramiko backend now uses BufferedFile implementation to enable334 - SSH Paramiko backend now uses BufferedFile implementation to enable
215 collecting the entire list of files on the backend.335 collecting the entire list of files on the backend.
216* Copy.com is gone so remove copycombackend.py.336* Copy.com is gone so remove copycombackend.py.
217* Merged in lp:~xlucas/duplicity/swift-multibackend-bug337* Merged in lp:~xlucas/duplicity/swift-multibackend-bug
218 - Fix a bug when swift backend is used in a multibackend configuration.338 - Fix a bug when swift backend is used in a multibackend configuration.
339<<<<<<< TREE
219* Fixed problem in dist/makedist when building on Mac where AppleDouble340* Fixed problem in dist/makedist when building on Mac where AppleDouble
220 files were being created in the tarball. See:341 files were being created in the tarball. See:
221 https://superuser.com/questions/61185/why-do-i-get-files-like-foo-in-my-tarball-on-os-x342 https://superuser.com/questions/61185/why-do-i-get-files-like-foo-in-my-tarball-on-os-x
@@ -404,6 +525,116 @@
404 (Hot,Cool,Archive) used for uploaded files.525 (Hot,Cool,Archive) used for uploaded files.
405* Merged in lp:~vam9/duplicity/0.8-series-s3-kms-support526* Merged in lp:~vam9/duplicity/0.8-series-s3-kms-support
406 - Added s3 kms server side encryption support with kms-grants support.527 - Added s3 kms server side encryption support with kms-grants support.
528=======
529* Merged in lp:~duplicity-team/duplicity/po-updates
530
531
532New in v0.7.12 (2017/03/21)
533---------------------------
534* Fixed bug #1623342 with patch supplied by Daniel Jakots
535 - Failing test on OpenBSD because tar/gtar not found
536* Fixed bug #1654220 with patch supplied by Kenneth Newwood
537 - Duplicity fails on MacOS because GPG version parsing fails
538* Fixed bug #1655268 "--gpg-binary option not working"
539 - If gpg binary is specified rebuild gpg profile using new binary location
540* Fixed bug #1658283 "Duplicity 0.7.11 broken with GnuPG 2.0"
541 - Made gpg version check more robust than just major version
542 - Now use --pinentry-mode=loopback on gpg 2.1 and greater
543 - Removed check for non-Linux systems, a false problem
544* Merged in lp:~matthew-t-bentley/duplicity/duplicity
545 - Sets a user agent. Backblaze asked for this in case there are errors that originate
546 from the Duplicity B2 backend
547 - Only retrieves a new upload URL when the current one expires, to bring it in line
548 with their best practices for integrations: https://www.backblaze.com/b2/docs/integration_checklist.html
549* Add detail about import exceptions in onedrivebackend.py
550* Fixed bug #1657916 with patch supplied by Daniel Harvey
551 - B2 provider cannot handle two backups in the same bucket
552* Fixed bug #1603704 with patch supplied by Maciej Bliziński
553 - Crash with UnicodeEncodeError
554* Some fixes to gpg.py to handle gpg1 & gpg2 & gpg2.1 commandline issues
555 - --gpg-agent is optional on gpg1, but on gpg2 it is used automatically
556 - --pinentry-mode is not a valid opt until gpg2.1, so condition on that
557* Fixed bug #1367675 - IMAP Backend does not work with Yahoo server
558 - added the split() as needed in 'nums=list[0].strip().split(" ")'
559 - the other fixes mentioned in the bug report comments were already done
560* Fixed bug #1671852 - Code regression caused by revision 1108
561 - change util.uexc() back to bare uexc()
562* Fixed bug #1668750 - Don't mask backend errors
563 - added exception prints to module import errors
564
565
566New in v0.7.11 (2016/12/31)
567---------------------------
568* Fixed bugs #815510 and #1615480
569 - Changed default --volsize to 200MB
570* Merged in lp:~mstoll-de/duplicity/duplicity
571 - Backblaze announced a new domain for the b2 api
572* Merged in lp:~aaron-whitehouse/duplicity/bug_1620085_exclude-if-present-locked-folder
573 - Fixes Bug #1620085: --exclude-if-present gives OSError looking for tag in locked folders
574* Fixed bug #1623342 with patch from Daniel Jakots
575 - failing test on OpenBSD because tar/gtar not found
576* Merged in lp:~mwilck/duplicity/duplicity
577 - GPG: enable truly non-interactive operation with gpg2
578 - This patch fixes the IMO unexpected behavior that, when using GnuPG2, a pass phrase dialog always pops up for
579 saving backups. This is particularly annoying when trying to do unattended / fully automatic backups.
580* Fixed bug #1621194 with code from Tornhoof
581 - Do backup to google drive working without a service account
582* Fixed bug #1642098 - does not create PAR2 archives when '--par2-options' is used
583 - Missing space between par2-options plus default options
584* Fix bug using 40-char sign keys, from Richard McGraw on mail list
585 - Remove truncation of argument and adjust comments
586* Merged in lp:~dernils/duplicity/robust-dropbox-backend
587 - Added new command line option --backend-retry-delay
588 that allows to determine the time that duplicity sleeps
589 before retrying after an error has occured.
590 - Added some robustness to dpbxbackend.py that ensures re-authentication
591 happens in case that a socket is changed (e.g. due to a forced reconnect
592 of a dynamic internet connection).
593* Merged in lp:~ed.so/duplicity/manpage.fixes
594 - Fix html output via rman on the website
595* Merged in lp:~horgh/duplicity/copy-symlink-targets-721599
596 - Add --copy-links to copy symlink contents, not just the link itself.
597* Merged in lp:~aaron-whitehouse/duplicity/Bug_1624725_files_within_folder_slash
598 - Fixed Bug #1624725, so that an include glob ending in "/" now includes folder contents (for globs with
599 and without special characters). This preserves the behaviour that an expression ending in "/" only
600 matches a folder, but now the contents of any matching folder is included.
601* Fix problem with gpg2 in yakety and zesty
602* Fix Bug #1642813 with patch from Ravi
603 - If stat() returns None, don't attempt to set perms.
604* Merged in lp:~breunigs/duplicity/amazondrive3
605 - As reported on the mailinglist, if a space is entered while duplicity asks for the URL, it fails.
606 Since all important spaces are URL encoded anyway, this should be fine even if there are spaces in
607 the URL at all. I also patched it in the onedrive backend, because it must have similar issues.
608* Prep for 0.7.11
609
610
611New in v0.7.10 (2016/08/20)
612---------------------------
613* Merged in lp:~mwilck/duplicity/0.7-series
614 - Speedup of path_matches_glob() by about 8x. See
615 https://code.launchpad.net/~mwilck/duplicity/0.7-series/+merge/301332
616 for more details.
617* Remove -w from setsid in functional tests.
618* Fixed conflict in merge from Martin Wilck and applied
619 - https://code.launchpad.net/~mwilck/duplicity/0.7-series/+merge/301492
620 - merge fixes setsid usage in functional testing.
621* Fixed bug #1612472 with patch from David Cuthbert
622 - Restore from S3 fails with --with-prefix-archive if prefix includes '/'
623* Merged in lp:~arashad.ahamad/duplicity/duplicity_latest
624 - Changes for connecting to IBM Bluemix ObjectStorage. See man page.
625* Merged in lp:~fenisilius/duplicity/acd_init_mkdir
626 - Allow duplicity to create remote folder
627
628
629New in v0.7.09 (2016/07/24)
630---------------------------
631* Fixed bug #1600692 with patch from Wolfgang Rohdewald
632 - Allow symlink to have optional trailing slash during verify.
633* Merged in lp:~aaron-whitehouse/duplicity/07-fix_deja_dup_error_on_locked_files
634 - Revert log.Error to log.Warn, as it was prior to the merge in rev 1224,
635 as this was affecting other applications (e.g. deja dup; Bug #1605939).
636* Merged in lp:~duplicity-team/duplicity/po-updates
637>>>>>>> MERGE-SOURCE
407638
408639
409New in v0.7.08 (2016/07/02)640New in v0.7.08 (2016/07/02)
@@ -444,6 +675,7 @@
444 - Set line length error length to 120 (matching tox.ini) for PEP8 and675 - Set line length error length to 120 (matching tox.ini) for PEP8 and
445 fixed E501(line too long) errors.676 fixed E501(line too long) errors.
446* Merged in lp:~duplicity-team/duplicity/po-updates677* Merged in lp:~duplicity-team/duplicity/po-updates
678<<<<<<< TREE
447* Merged in lp:~aaron-whitehouse/duplicity/08-unicode679* Merged in lp:~aaron-whitehouse/duplicity/08-unicode
448 - Many strings have been changed to unicode for better handling of international680 - Many strings have been changed to unicode for better handling of international
449 characters and to make the transition to Python 3 significantly easier, primarily681 characters and to make the transition to Python 3 significantly easier, primarily
@@ -463,6 +695,10 @@
463 they were hacked.695 they were hacked.
464* Fixed bug #1817375 with hint from mgorse696* Fixed bug #1817375 with hint from mgorse
465 - Added 'global pexpect' at end of imports697 - Added 'global pexpect' at end of imports
698=======
699* Fix bug using 40-char sign keys, from Richard McGraw on mail list
700 - Remove truncation of argument and adjust comments
701>>>>>>> MERGE-SOURCE
466702
467703
468New in v0.7.07.1 (2016/04/19)704New in v0.7.07.1 (2016/04/19)
@@ -480,6 +716,9 @@
480* Fixed bug #1570293 duplicity is very slow due to excessive fsync716* Fixed bug #1570293 duplicity is very slow due to excessive fsync
481 - removed flush() after write.717 - removed flush() after write.
482 - revert to previous version718 - revert to previous version
719* Merged in lp:~aaron-whitehouse/duplicity/07-fix_deja_dup_error_on_locked_files
720 - Revert log.Error to log.Warn, as it was prior to the merge in rev 1224,
721 as this was affecting other applications (e.g. deja dup; Bug #1605939).
483722
484723
485New in v0.7.07 (2016/04/10)724New in v0.7.07 (2016/04/10)
@@ -732,9 +971,6 @@
732* Merged in lp:~ed.so/duplicity/gpg.binary971* Merged in lp:~ed.so/duplicity/gpg.binary
733 - new parameter --gpg-binary allows user to point to a different gpg binary,972 - new parameter --gpg-binary allows user to point to a different gpg binary,
734 not necessarily in path973 not necessarily in path
735* Merged in lp:~ed.so/duplicity/gpg.binary
736 - new parameter --gpg-binary allows user to point to a different gpg binary,
737 not necessarily in path
738* Merged in lp:~aaron-whitehouse/duplicity/fix_POTFILES.in_and_run-tests974* Merged in lp:~aaron-whitehouse/duplicity/fix_POTFILES.in_and_run-tests
739 - Fixed two filename references in po/POTFILES.in, a mistake which crept in in975 - Fixed two filename references in po/POTFILES.in, a mistake which crept in in
740 rev 1093 and caused testing/run-tests to fail with "IndexError: list index976 rev 1093 and caused testing/run-tests to fail with "IndexError: list index
741977
=== modified file 'Changelog.GNU'
--- Changelog.GNU 2019-02-25 16:30:59 +0000
+++ Changelog.GNU 2019-03-04 12:09:45 +0000
@@ -1,3 +1,4 @@
1<<<<<<< TREE
12019-02-25 Kenneth Loafman <kenneth@loafman.com>22019-02-25 Kenneth Loafman <kenneth@loafman.com>
23
3 * Merged in lp:~mgorse/duplicity/0.8-series4 * Merged in lp:~mgorse/duplicity/0.8-series
@@ -333,43 +334,271 @@
333 - giobackend: handle a wider variety of gio backends by making less assumptions;334 - giobackend: handle a wider variety of gio backends by making less assumptions;
334 in particular, this fixes the google-drive: backend335 in particular, this fixes the google-drive: backend
335336
337=======
3382019-02-25 Kenneth Loafman <kenneth@loafman.com>
339
340 * Merged in lp:~mterry/duplicity/pydrive-root-0.7
341 - Just a tiny fix to clean up the temporary file we create to find the root ID.
342 It's a little surprising for the user if they wind up with this file called
343 "i_am_in_root" that they don't know where it came from. Almost sounds like
344 they were hacked.
345
3462018-10-17 Kenneth Loafman <kenneth@loafman.com>
347
348 * Fixed bug #1798206 and bug #1798504
349 - Made paramiko a global with import during __init__ so it would
350 not be loaded unless needed.
351
3522018-10-17 Kenneth Loafman <kenneth@loafman.com>
353
354 * Prep for 0.7.18.2
355
3562018-08-27 Kenneth Loafman <kenneth@loafman.com>
357
358 * Fixed bug #1788558 again
359 - If we get None for size skip check.
360
3612018-08-27 Kenneth Loafman <kenneth@loafman.com>
362
363 * Prep for 0.7.18.1
364
3652018-08-26 Kenneth Loafman <kenneth@loafman.com>
366
367 * Fixed bug #1788558
368 - Treat None as zero when printing log.
369 * Revert fix for bug #1788599.
370 - Was causing problems with directory names
371
3722018-08-21 Kenneth Loafman <kenneth@loafman.com>
373
374 * Fix a 2to3 error in ssh_paramiko_backend.py
375 * Merged in lp:~duplicity-team/duplicity/po-updates
376 * Prep for 0.7.18
377
3782018-08-11 Kenneth Loafman <kenneth@loafman.com>
379
380 * Fixed bug #1785520 with patch from Chris Hunt
381 - Fix for B2 version 1.3.4 just released
382
3832018-07-08 Kenneth Loafman <kenneth@loafman.com>
384
385 * Fixed bug #1780617 Test fail when GnuPG >= 2.2.8
386 - Relevant change in GnuPG 2.2.8: https://dev.gnupg.org/T3981
387 - Added '--ignore-mdc-error' to all gpg calls made.
388
3892018-05-07 Kenneth Loafman <kenneth@loafman.com>
390
391 * Fixed bug #1717935 with suggestion from strainu
392 - Use urllib.quote_plus() to properly quote pathnames passed via URL
393
3942018-05-01 Kenneth Loafman <kenneth@loafman.com>
395
396 * More fixes for bug #1734144
397 - Number of retries is now same as globals.num_retries.
398 - Added standoff delay of 0.5 sec per attempt.
399 * Fixed bug #1764432 with patch from Robke Geenen
400 - Just join the parts together.
401
4022018-04-04 Kenneth Loafman <kenneth@loafman.com>
403
404 * Partial fix of bug #1734144 with patch from Joris van Eijden
405 - Note: this is really just a partial fix for now, since it only covers
406 the case where the local size does not yet match the remote size. A
407 case where -1 is the returned length is not fixed.
408
4092018-03-17 Kenneth Loafman <kenneth@loafman.com>
410
411 * Fixed bug #1756550 Online html man page is showing a 0 byte file
412
4132018-02-26 Kenneth Loafman <kenneth@loafman.com>
414
415 * Fix update of Launchpad Translations. Translations were not being picked
416 up on a daily basis and we got several months behind.
417 * Prep for 0.7.17
418
4192018-02-01 Kenneth Loafman <kenneth@loafman.com>
420
421 * Removed changes made in bug #1044715 Provide a file history feature
422 - Changes required too much memory to carry in the manifest
423 - The option --file-changed in collection-status is now invalid
424 - This will close bugs: #1730451, #896728, #1526557, #1550176
425 - Starting a full backup will be needed to fully utilize this fix
426
4272018-01-12 Kenneth Loafman <kenneth@loafman.com>
428
429 * Fix pylint error in webdavbackend.py
430 * Prep for 0.7.16
431
4322017-11-28 Kenneth Loafman <kenneth@loafman.com>
433
434 * Patched in lp:~crosser/duplicity/fix-small-file-upload
435 - Fixed small file upload changes made in Dropbox SDK v7.1
436
4372017-11-25 Kenneth Loafman <kenneth@loafman.com>
438
439 * Patched in lp:~crosser/duplicity/fix-oauth-flow
440 - Fixed bug #1638236 "BackendException with oauth2client 4.0.0"
441 * Patched in lp:~crosser/duplicity/dpbx-fix-file-listing
442 - Fixed bug #1639664 "Dropbox support needs to be updated for Dropbox SDK v7.1"
443
4442017-11-23 Kenneth Loafman <kenneth@loafman.com>
445
446 * More fixes for Unicode handling
447 - Default to 'utf-8' if sys.getfilesystemencoding() returns 'ascii' or None
448 - Fixed bug #1386373 with suggestion from Eugene Morozov
449
4502017-11-18 Kenneth Loafman <kenneth@loafman.com>
451
452 * Fixed bug #1733057 AttributeError: 'GPGError' object has no attribute 'decode'
453 - Replaced call to util.ufn() with call to util.uexc(). Stupid typo!
454
4552017-11-09 Kenneth Loafman <kenneth@loafman.com>
456
457 * Prep for 0.7.15
458
4592017-11-09 Kenneth Loafman <kenneth@loafman.com>
460
461 * Fixed bug #1730902 GPG Error Handling
462 - use util.ufn() not str() to handle encoding
463
4642017-11-01 Kenneth Loafman <kenneth@loafman.com>
465
466 * Fixed bug #1723890 with patch from Killian Lackhove
467 - Fixes error handling in pydrivebackend.py
468
4692017-10-31 Kenneth Loafman <kenneth@loafman.com>
470
471 * Fixed bug #1720159 - Cannot allocate memory with large manifest file since 0.7.03
472 - filelist is not read if --file-changed option in collection-status not present
473 - This will keep memory usage lower in non collection-status operations
474
4752017-10-26 Kenneth Loafman <kenneth@loafman.com>
476
477 * Fixed bug #1448094 with patch from Tomáš Zvala
478 - Don't log incremental deletes for chains that have no incrementals
479 * Fixed bug #1724144 "--gpg-options unused with some commands"
480 - Add --gpg-options to get version run command
481
4822017-10-16 Kenneth Loafman <kenneth@loafman.com>
483
484 * Fixed bug #1654756 with new b2backend.py module from Vincent Rouille
485 - Faster (big files are uploaded in chunks)
486 - Added upload progress reporting support
487
4882017-10-12 Kenneth Loafman <kenneth@loafman.com>
489
490 * Merged in lp:~mterry/duplicity/rename-dep
491 - Make rename command a dependency for LP build
492
4932017-09-22 Kenneth Loafman <kenneth@loafman.com>
494
495 * Fixed bug #1714663 "Volume signed by XXXXXXXXXXXXXXXX, not XXXXXXXX"
496 - Normalized comparison length to min length of compared keys before comparison
497 - Avoids comparing mix of short, long, or fingerprint size keys.
498
4992017-09-13 Kenneth Loafman <kenneth@loafman.com>
500
501 * Fixed bug #1715650 with patch from Mattheww S
502 - Fix to make duplicity attempt a get first, then create, a container
503 in order to support container ACLs.
504
5052017-09-07 Kenneth Loafman <kenneth@loafman.com>
506
507 * Merged in lp:~mterry/duplicity/more-decode-issues
508 - Here's some fixes for another couple UnicodeDecodeErrors.
509 - The duplicity/dup_time.py fixes when a user passes a utf8 date string (or a string with bogus
510 utf8 characters, but they have to really try to do that). This is bug 1334436.
511 - The bin/duplicity change from str(e) to util.uexc(e) fixes bug 1324188.
512 - The rest of the changes (util.exception_traceback and bin/duplicity changes to use it) are to
513 make the printing of exceptions prettier. Without this, if you see a French exception, you see
514 "accept\xe9es" instead of "acceptées".
515 - You can test all of these changes in one simple line:
516 $ LANGUAGE=fr duplicity remove-older-than $'accept\xffées'
517 * Fix backend.py to allow string, list, and tuple types to support megabackend.py.
518
5192017-09-06 Kenneth Loafman <kenneth@loafman.com>
520
521 * Fixed bug introduced in new megabackend.py where process_commandline()
522 takes a string not a list. Now it takes both.
523 * Updated web page for new megabackend requirements.
524
5252017-08-31 Kenneth Loafman <kenneth@loafman.com>
526
527 * Fixed bug #1538333 Assertion error in manifest.py: assert filecount == ...
528 - Made sure to never pass .part files as true manifest files
529 - Changed assert to log.Error to warn about truncated/corrupt filelist
530 - Added unit test to make sure detection works
531 - Note: while this condition is serious, it will not affect the basic backup and restore
532 functions. Interactive options like --list-files-changed and --file-changed will not
533 work correctly for this backup set, so it is advised to run a full backup as soon as
534 possible after this error occurs.
535 * Fixed bug #1638033 Remove leading slash on --file-to-restore
536 - code already used rstrip('/') so change to just strip('/')
537 * Prep for 0.7.14
538
5392017-08-29 Kenneth Loafman <kenneth@loafman.com>
540
541 * Fixed bug #1394386 with new module megabackend.py from Tomas Vondra
542 - uses megatools from https://megatools.megous.com/ instead of mega.py library
543 which has been deprecated
544 - fixed copyright and PEP8 issues
545 - replaced subprocess.call() with self.subprocess_popen() to standardize
546 * Fixed bug #1713640 with patch from Aleksandar Ivanisevic
547 - replace 2.7 syntax with 2.6 equivalent
548
5492017-08-28 Kenneth Loafman <kenneth@loafman.com>
550
551 * Fixed bug #1711905 with suggestion from Schneider
552 - log.Warn was invoked with log.warn in webdavbackend.py
553 * Merged in lp:~mterry/duplicity/gpg-tag-versions
554 - Support gpg versions numbers that have tags on them.
555 - This can happen if you build gpg from git trunk (e.g. 2.1.15-beta20). Or if you run
556 against the freedesktop flatpak runtime (e.g. 2.1.14-unknown).
557
5582017-08-15 Kenneth Loafman <kenneth@loafman.com>
559
560 * Fixed bug #1709047 with suggestion from Gary Hasson
561 - fixed so default was to use original filename
562 * Fixed PEP8 errors in bin/duplicity
563 * Merged in lp:~mterry/duplicity/gio_child_for_display_name_0.7
564 - gio: be slightly more correct and get child GFiles based on display name
565
5662017-08-06 Kenneth Loafman <kenneth@loafman.com>
567
568 * Patched in lp:~mterry/duplicity/giobackend-display-name
569 - giobackend: handle a wider variety of gio backends by making less assumptions;
570 in particular, this fixes the google-drive: backend
571
572>>>>>>> MERGE-SOURCE
3362017-07-20 Kenneth Loafman <kenneth@loafman.com>5732017-07-20 Kenneth Loafman <kenneth@loafman.com>
337574
338 * Fixed encrypted remote manifest handling to merely put out a non-fatal575 * Fixed encrypted remote manifest handling to merely put out a non-fatal
339 error message and continue if the private key is not available.576 error message and continue if the private key is not available.
340577
3412017-07-19 Kenneth Loafman <kenneth@loafman.com>5782017-07-18 Kenneth Loafman <kenneth@loafman.com>
342579
343 * Fixed slowness in 'collection-status' by basing the status on the580 * Fixed slowness in 'collection-status' by basing the status on the
344 remote system only. The local cache is treated as empty.581 remote system only. The local cache is treated as empty.
345582
3462017-07-11 Kenneth Loafman <kenneth@loafman.com>5832017-07-11 Kenneth Loafman <kenneth@loafman.com>
347584
348 * Patched in lp:~dawgfoto/duplicity/skip_sync_collection_status585 * Merged in lp:~dawgfoto/duplicity/skip_sync_collection_status
349 - collection-status should not sync metadata586 - collection-status should not sync metadata
350 - up-to-date local metadata is not needed as collection-status is587 - up-to-date local metadata is not needed as collection-status is
351 generated from remote file list588 generated from remote file list
352 - syncing metadata might require to download several GBs589 - syncing metadata might require to download several GBs
353590
3542017-06-30 Kenneth Loafman <kenneth@loafman.com>5912017-06-18 Kenneth Loafman <kenneth@loafman.com>
355
356 * Merged in lp:~xlucas/duplicity/multibackend-prefix-affinity
357 - Support prefix affinity in multibackend.
358 * Merged in lp:~xlucas/duplicity/pca-backend
359 - Add support for OVH Public Cloud Archive backend.
360 * Fixed PEP8 and 2to3 issues.
361
3622017-06-23 Kenneth Loafman <kenneth@loafman.com>
363
364 * Merged in lp:~dawgfoto/duplicity/replicate
365 - Add integration test for newly added replicate command.
366 - Also see https://code.launchpad.net/~dawgfoto/duplicity/replicate/+merge/322836.
367
3682017-06-19 Kenneth Loafman <kenneth@loafman.com>
369592
370 * Fixed problem in dist/makedist when building on Mac where AppleDouble593 * Fixed problem in dist/makedist when building on Mac where AppleDouble
371 files were being created in the tarball. See:594 files were being created in the tarball. See:
372 https://superuser.com/questions/61185/why-do-i-get-files-like-foo-in-my-tarball-on-os-x595 https://superuser.com/questions/61185/why-do-i-get-files-like-foo-in-my-tarball-on-os-x
596 * Prep for 0.17.13.1
597
5982017-06-10 Kenneth Loafman <kenneth@loafman.com>
599
600 * Merged in lp:~duplicity-team/duplicity/po-updates
601 * Prep for 0.7.13
373602
3742017-06-10 Kenneth Loafman <kenneth@loafman.com>6032017-06-10 Kenneth Loafman <kenneth@loafman.com>
375604
@@ -380,19 +609,6 @@
380 * Merged in lp:~xlucas/duplicity/swift-multibackend-bug609 * Merged in lp:~xlucas/duplicity/swift-multibackend-bug
381 - Fix a bug when swift backend is used in a multibackend configuration.610 - Fix a bug when swift backend is used in a multibackend configuration.
382611
3832017-06-04 Kenneth Loafman <kenneth@loafman.com>
384
385 * Merged in lp:~aaron-whitehouse/duplicity/08-fix-man-verify
386 - Fix description of --verify and --compare-data in the man page. Now
387 clarifies that verify compares the restored files to hashes stored at
388 backup date, while --compare-data compares restored files to files
389 in target_path.
390
3912017-06-03 Kenneth Loafman <kenneth@loafman.com>
392
393 * Merged in lp:~dernils/duplicity/docker-compose
394 - Test Infrastructure now utilizing docker-compose
395
3962017-06-02 Kenneth Loafman <kenneth@loafman.com>6122017-06-02 Kenneth Loafman <kenneth@loafman.com>
397613
398 * Fix bug #1672540 with patch from Benoit Nadeau614 * Fix bug #1672540 with patch from Benoit Nadeau
@@ -418,26 +634,6 @@
418 - Caveat: long incremental chains will still eat up a large number of file634 - Caveat: long incremental chains will still eat up a large number of file
419 descriptors. It's a very risky practice, so I'm not inclined to fix it.635 descriptors. It's a very risky practice, so I'm not inclined to fix it.
420636
4212017-05-15 Kenneth Loafman <kenneth@loafman.com>
422
423 * Merged in lp:~dernils/duplicity/Dockerfile
424 - Now have subnet name and IP of the subnet for testing as a variable.
425
4262017-05-14 Kenneth Loafman <kenneth@loafman.com>
427
428 * Merged in lp:~xlucas/duplicity/swift-storage-policies
429 - This brings support for Swift storage policies: when using a Swift
430 backend, you can specify the policy containers should be operating on.
431 - This is similar to AWS Cloud Storage classes (ia, rrs, glacier and so on).
432 * Merged in lp:~dernils/duplicity/Dockerfile
433 - Added another backend to the docker test infrastructure, updated the setup
434 for testing and updated the documentation.
435
4362017-05-12 Kenneth Loafman <kenneth@loafman.com>
437
438 * Merged in lp:~aaron-whitehouse/duplicity/tox_pylint_fixes
439 - Changes needed to run-tests without pylint E0401(import-error) errors
440
4412017-05-11 Kenneth Loafman <kenneth@loafman.com>6372017-05-11 Kenneth Loafman <kenneth@loafman.com>
442638
443 * Fixed bug #1320641 and others regarding lockfile639 * Fixed bug #1320641 and others regarding lockfile
@@ -452,53 +648,12 @@
452 IOError exception saying that too many files are open. This causes648 IOError exception saying that too many files are open. This causes
453 restores to fail randomly, after thousands of files have been restored.649 restores to fail randomly, after thousands of files have been restored.
454650
4552017-05-06 Kenneth Loafman <kenneth@loafman.com>6512017-05-07 Kenneth Loafman <kenneth@loafman.com>
456652
457 * Merged in lp:~dernils/duplicity/DockerfileConvenience
458 - Add a few files that are the beginning of further infrastructure based
459 on docker. It contains a Dockerfile for a simple ftp server (used for
460 backend testing) and a setup script that can be used to set up the
461 complete test environment.
462 * Moved Dockerfile for duplicitytest into testinfrastructure/duplicity_test
463 * Moved some things around in testing/infrastructure to clean up
464
4652017-05-05 Kenneth Loafman <kenneth@loafman.com>
466
467 * Merged in lp:~dernils/duplicity/DockerfileConvenience
468 - Added a few tools to the Dockerfile that make life easier
469 * Fixed bug #1320832 with suggestion from Oskar Wycislak653 * Fixed bug #1320832 with suggestion from Oskar Wycislak
470 - Use chunks instead of reading it all in swiftbackend654 - Use chunks instead of reading it all in swiftbackend
471655
4722017-05-04 Kenneth Loafman <kenneth@loafman.com>6562017-04-20 Kenneth Loafman <kenneth@loafman.com>
473
474 * Merged in lp:~dawgfoto/duplicity/replicate
475 - Add replicate command to replicate a backup (or backup
476 sets older than a given time) to another backend, leveraging
477 duplicity's backend and compression/encryption infrastructure.
478 * Fixed some incoming PyLint and PEP-8 errors.
479 * Merged in lp:~marix/duplicity/add-azure-arguments
480 - Using the Azure backend to store large amounts of data we found that
481 performance is sub-optimal. The changes on this branch add command line
482 parameters to fine-tune some parameters of the Azure storage library,
483 allowing to push write performance towards Azure above 1 Gb/s for large
484 back-ups. If a user does not provide the parameters the defaults of the
485 Azure storage library will continue to be used.
486 * Replace incoming non-ASCII chars in commandline.py
487 * bzr does not honor perms so fix the perms at the start of the testing and
488 avoid annoying error regarding testing/gnupg having too lenient perms
489
4902017-04-23 Kenneth Loafman <kenneth@loafman.com>
491
492 * Merged in lp:~dernils/duplicity/testing
493 - Fixed minor stuff in requirements.txt.
494 - Added a Dockerfile for testing.
495 - Minor changes to README files.
496 - Added README-TESTING with some information on testing.
497 * Merged in lp:~dernils/duplicity/documentation
498 - Minor changes to README-REPO, README-TESTING
499 - Also redo the changes to requirements.txt and Dockerfile
500
5012017-04-22 Kenneth Loafman <kenneth@loafman.com>
502657
503 * Fixed bug #1680682 with patch supplied from Dave Allan658 * Fixed bug #1680682 with patch supplied from Dave Allan
504 - Only specify --pinentry-mode=loopback when --use-agent is not specified659 - Only specify --pinentry-mode=loopback when --use-agent is not specified
@@ -507,6 +662,10 @@
507 - Use shutil.copyfile instead of os.system('cp ...')662 - Use shutil.copyfile instead of os.system('cp ...')
508 - Should reduce overhead of os.system() memory usage.663 - Should reduce overhead of os.system() memory usage.
509664
6652017-03-21 Kenneth Loafman <kenneth@loafman.com>
666
667 * Prep for 0.7.12
668
5102017-03-13 Kenneth Loafman <kenneth@loafman.com>6692017-03-13 Kenneth Loafman <kenneth@loafman.com>
511670
512 * Fixed bug #1668750 - Don't mask backend errors671 * Fixed bug #1668750 - Don't mask backend errors
@@ -517,55 +676,22 @@
517 * Fixed bug #1671852 - Code regression caused by revision 1108676 * Fixed bug #1671852 - Code regression caused by revision 1108
518 - change util.uexc() back to bare uexc()677 - change util.uexc() back to bare uexc()
519678
5202017-03-05 Kenneth Loafman <kenneth@loafman.com>
521
522 * Merged in p:~aaron-whitehouse/duplicity/pep8_E402_fixes
523 - Fixed PEP8 errors: E402 module level import not at top of file
524
5252017-03-02 Kenneth Loafman <kenneth@loafman.com>
526
527 * Merged in lp:~benoit.bertholon/duplicity/duplicity
528 - Use the globals.archive_dir variable to store only a string
529 in the case of a path, uses globals.archive_dir_path
530
5312017-02-21 Kenneth Loafman <kenneth@loafman.com>6792017-02-21 Kenneth Loafman <kenneth@loafman.com>
532680
533 * Merged in lp:~marix/duplicity/azure-storage-0.30.0-plus
534 - This makes the Azure backend compatible with version 0.30.0 and up of the
535 underlying azure-storage package.
536 * Merged in lp:~marix/duplicity/azure-storage-sas
537 - This branch adds support for Shared Access Signature to the Azure backend
538 which allows to run Duplicity with a minimal set of permissions.
539 * Merged in lp:~aaron-whitehouse/duplicity/pep8_test_fixes
540 - Fix PEP-8 testing by moving to using pycodestyle library.
541 - Temporarily add ignores to allow these tests to pass.
542 - Fix E305 PEP8 errors: expected 2 blank lines after class or function definition, found 1.
543 * Merged in lp:~benoit.bertholon/duplicity/duplicity
544 - Fixes bug #1666194 - ProcessCommandLine function called twice fail and arglist argument not used
545 * Fixed variable name change in last merge which broke a bunch of tests
546 - Changed archive_dir_root back to archive_dir
547 * Fixed bug #1367675 - IMAP Backend does not work with Yahoo server681 * Fixed bug #1367675 - IMAP Backend does not work with Yahoo server
548 - added the split() as needed in 'nums=list[0].strip().split(" ")'682 - added the split() as needed in 'nums=list[0].strip().split(" ")'
549 - the other fixes mentioned in the bug report comments were already done683 - the other fixes mentioned in the bug report comments were already done
550684
5512017-02-12 Kenneth Loafman <kenneth@loafman.com>
552
553 * Merged in lp:~aaron-whitehouse/duplicity/08-python-futurize-stage-1
554 - Made many of the safer changes for improved Python 3 support (python-future's futurize -stage1)
555 without functional change to the code (and leaving the isinstance(s, types.StringType) tests unchanged).
556 - Created Python 2/3 compatible tests for int and long.
557 - Update setup.py to show only Python 2.7 support.
558
5592017-02-11 Kenneth Loafman <kenneth@loafman.com>6852017-02-11 Kenneth Loafman <kenneth@loafman.com>
560686
561 * Fixed bug #1603704 with patch supplied by Maciej Bliziński687 * Fixed bug #1603704 with patch supplied by Maciej Bliziński
562 - Crash with UnicodeEncodeError688 - Crash with UnicodeEncodeError
689 * Some fixes to gpg.py to handle gpg1 & gpg2 & gpg2.1 commandline issues
690 - --gpg-agent is optional on gpg1, but on gpg2 it is used automatically
691 - --pinentry-mode is not a valid opt until gpg2.1, so condition on that
563692
5642017-02-08 Kenneth Loafman <kenneth@loafman.com>6932017-02-08 Kenneth Loafman <kenneth@loafman.com>
565694
566 * Merged in lp:~aaron-whitehouse/duplicity/08-refactor-unit-test-globmatch
567 - Rename path_matches_glob_fn to select_fn_from_glob, as this more accurately reflects the return value.
568 - Significantly refactored unit/test_globmatch.py to make this cleaner and clearer.
569 * Fixed bug #1657916 with patch supplied by Daniel Harvey695 * Fixed bug #1657916 with patch supplied by Daniel Harvey
570 - B2 provider cannot handle two backups in the same bucket696 - B2 provider cannot handle two backups in the same bucket
571697
@@ -573,13 +699,6 @@
573699
574 * Add detail about import exceptions in onedrivebackend.py700 * Add detail about import exceptions in onedrivebackend.py
575701
5762017-01-30 Kenneth Loafman <kenneth@loafman.com>
577
578 * Merged in lp:~aaron-whitehouse/duplicity/08-merge-glob-parsers
579 - Use a single code path for glob strings whether or not these contain special
580 characters/wildcards (glob_get_normal_sf) and remove glob_get_filename_sf and glob_get_tuple_sf.
581 - Remove run-tests-ve as this was identical to run-tests.
582
5832017-01-24 Kenneth Loafman <kenneth@loafman.com>7022017-01-24 Kenneth Loafman <kenneth@loafman.com>
584703
585 * Merged in lp:~matthew-t-bentley/duplicity/duplicity704 * Merged in lp:~matthew-t-bentley/duplicity/duplicity
@@ -588,6 +707,13 @@
588 - Only retrieves a new upload URL when the current one expires, to bring it in line707 - Only retrieves a new upload URL when the current one expires, to bring it in line
589 with their best practices for integrations: https://www.backblaze.com/b2/docs/integration_checklist.html708 with their best practices for integrations: https://www.backblaze.com/b2/docs/integration_checklist.html
590709
7102017-01-21 Kenneth Loafman <kenneth@loafman.com>
711
712 * Fixed bug #1658283 "Duplicity 0.7.11 broken with GnuPG 2.0"
713 - Made gpg version check more robust than just major version
714 - Now use --pinentry-mode=loopback on gpg 2.1 and greater
715 - Removed check for non-Linux systems, a false problem
716
5912017-01-19 Kenneth Loafman <kenneth@loafman.com>7172017-01-19 Kenneth Loafman <kenneth@loafman.com>
592718
593 * Fixed bug #1655268 "--gpg-binary option not working"719 * Fixed bug #1655268 "--gpg-binary option not working"
@@ -599,13 +725,10 @@
599 - Failing test on OpenBSD because tar/gtar not found725 - Failing test on OpenBSD because tar/gtar not found
600 * Fixed bug #1654220 with patch supplied by Kenneth Newwood726 * Fixed bug #1654220 with patch supplied by Kenneth Newwood
601 - Duplicity fails on MacOS because GPG version parsing fails727 - Duplicity fails on MacOS because GPG version parsing fails
602 * Merged in lp:~aaron-whitehouse/duplicity/0-8-merge_selection_tests728
603 - Merge in TestExcludeIfPresent from 0.7-series, which tests the behaviour of7292016-12-31 Kenneth Loafman <kenneth@loafman.com>
604 duplicity's --exclude-if-present option.730
605 - Move and rename TestTrailingSlash2 test (was duplicate name) as in 0.7-series.731 * Prep for 0.7.11
606 - Fix PEP error on adbackend.py.
607 - Add jottalib as a tox dep to fix pylint error.
608 - Remove unnecessary skipUnless Linux as per 0.7-series.
609732
6102016-12-29 Kenneth Loafman <kenneth@loafman.com>7332016-12-29 Kenneth Loafman <kenneth@loafman.com>
611734
@@ -616,9 +739,8 @@
616 Since all important spaces are URL encoded anyway, this should be fine even if there are spaces in739 Since all important spaces are URL encoded anyway, this should be fine even if there are spaces in
617 the URL at all. I also patched it in the onedrive backend, because it must have similar issues.740 the URL at all. I also patched it in the onedrive backend, because it must have similar issues.
618741
6192016-12-25 Kenneth Loafman <kenneth@loafman.com>7422016-12-24 Kenneth Loafman <kenneth@loafman.com>
620743
621 * Fix some issues with testing on MacOS
622 * Fix problem with gpg2 in yakety and zesty744 * Fix problem with gpg2 in yakety and zesty
623745
6242016-12-11 Kenneth Loafman <kenneth@loafman.com>7462016-12-11 Kenneth Loafman <kenneth@loafman.com>
@@ -652,21 +774,10 @@
652 * Fixed bug #1642098 - does not create PAR2 archives when '--par2-options' is used774 * Fixed bug #1642098 - does not create PAR2 archives when '--par2-options' is used
653 - Missing space between par2-options plus default options775 - Missing space between par2-options plus default options
654776
6552016-11-07 Kenneth Loafman <kenneth@loafman.com>
656
657 * Merged in lp:~breunigs/duplicity/amazondrive2
658 - Fixed variable renaming issue
659
6602016-11-01 Kenneth Loafman <kenneth@loafman.com>7772016-11-01 Kenneth Loafman <kenneth@loafman.com>
661778
662 * Fixed bug #1621194 with code from Tornhoof779 * Fixed bug #1621194 with code from Tornhoof
663 - Do backup to google drive working without a service account780 - Do backup to google drive working without a service account
664 * Merged in lp:~havard/duplicity/jottacloudbackend
665 - Adds support for a new backend, jottacloud.com, using the scheme `jottacloud:/<folder>`.
666 - Reverse-engineered library, `jottalib`: http://github.com/havardgulldahl/jottalib
667 - Here's how you set up jottalib https://github.com/havardgulldahl/jottalib/wiki
668 * Merged in lp:~breunigs/duplicity/amazondrive
669 - Provide a native backend for AmazonDrive
670781
6712016-10-22 Kenneth Loafman <kenneth@loafman.com>7822016-10-22 Kenneth Loafman <kenneth@loafman.com>
672783
@@ -680,6 +791,11 @@
680 * Fixed bug #1623342 with patch from Daniel Jakots791 * Fixed bug #1623342 with patch from Daniel Jakots
681 - failing test on OpenBSD because tar/gtar not found792 - failing test on OpenBSD because tar/gtar not found
682793
7942016-09-06 Kenneth Loafman <kenneth@loafman.com>
795
796 * Merged in lp:~aaron-whitehouse/duplicity/bug_1620085_exclude-if-present-locked-folder
797 - Fixes Bug #1620085: --exclude-if-present gives OSError looking for tag in locked folders
798
6832016-08-22 Kenneth Loafman <kenneth@loafman.com>7992016-08-22 Kenneth Loafman <kenneth@loafman.com>
684800
685 * Fixed bugs #815510 and #1615480801 * Fixed bugs #815510 and #1615480
@@ -687,6 +803,10 @@
687 * Merged in lp:~mstoll-de/duplicity/duplicity803 * Merged in lp:~mstoll-de/duplicity/duplicity
688 - Backblaze announced a new domain for the b2 api804 - Backblaze announced a new domain for the b2 api
689805
8062016-08-20 Kenneth Loafman <kenneth@loafman.com>
807
808 * Prep for 0.7.10
809
6902016-08-18 Kenneth Loafman <kenneth@loafman.com>8102016-08-18 Kenneth Loafman <kenneth@loafman.com>
691811
692 * Merged in lp:~fenisilius/duplicity/acd_init_mkdir812 * Merged in lp:~fenisilius/duplicity/acd_init_mkdir
@@ -707,27 +827,24 @@
707827
7082016-07-28 Kenneth Loafman <kenneth@loafman.com>8282016-07-28 Kenneth Loafman <kenneth@loafman.com>
709829
710 * Merged in lp:~mwilck/duplicity/duplicity830 * Merged in lp:~mwilck/duplicity/0.7-series
711 - Speedup of path_matches_glob() by about 8x. See831 - Speedup of path_matches_glob() by about 8x. See
712 https://code.launchpad.net/~mwilck/duplicity/duplicity/+merge/301268832 https://code.launchpad.net/~mwilck/duplicity/0.7-series/+merge/301332
713 for more details.833 for more details.
834 * Remove -w from setsid in functional tests.
714835
7152016-07-24 Kenneth Loafman <kenneth@loafman.com>8362016-07-24 Kenneth Loafman <kenneth@loafman.com>
716837
717 * Merged in lp:~aaron-whitehouse/duplicity/07-fix_deja_dup_error_on_locked_files838 * Merged in lp:~aaron-whitehouse/duplicity/07-fix_deja_dup_error_on_locked_files
718 - Revert log.Error to log.Warn, as it was prior to the merge in rev 1224,839 - Revert log.Error to log.Warn, as it was prior to the merge in rev 1224,
719 as this was affecting other applications (e.g. deja dup; Bug #1605939).840 as this was affecting other applications (e.g. deja dup; Bug #1605939).
841 * Prep for 0.7.09
720842
7212016-07-20 Kenneth Loafman <kenneth@loafman.com>8432016-07-20 Kenneth Loafman <kenneth@loafman.com>
722844
723 * Fixed bug #1600692 with patch from Wolfgang Rohdewald845 * Fixed bug #1600692 with patch from Wolfgang Rohdewald
724 - Allow symlink to have optional trailing slash during verify.846 - Allow symlink to have optional trailing slash during verify.
725847
7262016-07-03 Kenneth Loafman <kenneth@loafman.com>
727
728 * Merged in lp:~aaron-whitehouse/duplicity/remove-python26
729 - Remove Python 2.6 support references and tests.
730
7312016-07-02 Kenneth Loafman <kenneth@loafman.com>8482016-07-02 Kenneth Loafman <kenneth@loafman.com>
732849
733 * Merged in lp:~aaron-whitehouse/duplicity/PEP8_W503_fixes850 * Merged in lp:~aaron-whitehouse/duplicity/PEP8_W503_fixes
734851
=== modified file 'README'
--- README 2018-10-07 11:54:04 +0000
+++ README 2019-03-04 12:09:45 +0000
@@ -19,7 +19,11 @@
1919
20REQUIREMENTS:20REQUIREMENTS:
2121
22<<<<<<< TREE
22 * Python v2.723 * Python v2.7
24=======
25 * Python v2.6 or later
26>>>>>>> MERGE-SOURCE
23 * librsync v0.9.6 or later27 * librsync v0.9.6 or later
24 * GnuPG for encryption28 * GnuPG for encryption
25 * fasteners 0.14.1 or later for concurrency locking29 * fasteners 0.14.1 or later for concurrency locking
@@ -34,6 +38,7 @@
3438
35 * Python development files, normally found in module 'python-dev'.39 * Python development files, normally found in module 'python-dev'.
36 * librsync development files, normally found in module 'librsync-dev'.40 * librsync development files, normally found in module 'librsync-dev'.
41 * internationalization tools, normally found in module 'intltool'.
3742
3843
39A NOTE ON GnuPGInterface.py AND MULTIPLE GPG PROCESSES:44A NOTE ON GnuPGInterface.py AND MULTIPLE GPG PROCESSES:
4045
=== modified file 'README-REPO'
--- README-REPO 2017-07-11 14:55:38 +0000
+++ README-REPO 2019-03-04 12:09:45 +0000
@@ -26,3 +26,56 @@
26or26or
2727
28PYTHONPATH=$DUP_ROOT bin/rdiffdir28PYTHONPATH=$DUP_ROOT bin/rdiffdir
29
30-----------------------
31Running the unit tests:
32-----------------------
33
34To run all tests:
35cd testing; ./run-tests
36
37You can run specific tests using:
38tox -- -s [folder].[folder].[file].[class].[test]
39For example:
40tox -- -s testing.unit.test_selection
41or:
42tox -- -s testing.unit.test_selection.MatchingTest.test_tuple_include
43
44Note: some tests require rdiff and pylint to be installed on the system for
45them to pass.
46
47Please run all tests on your branch (run-tests) before proposing a merge, to
48ensure that all tests pass. The decorator @unittest.expectedFailure can be used
49to commit a known-failing test case without breaking the test suite, for
50example to exhibit the behaviour in a bug report before it has been fixed:
51
52if sys.version_info < (2, 7):
53 import unittest2 as unittest
54else:
55 import unittest
56
57
58class TestClass(unittest.TestCase):
59 """Test class to show expectedFailure"""
60
61 @unittest.expectedFailure
62 def test_expected_failure(self):
63 """Test behaviour of expectedFailure"""
64 self.assertEqual(1, 2)
65
66-----------------------------------------
67Testing against multiple Python versions:
68-----------------------------------------
69
70Duplicity currently supports Python versions v2.6 or later. Duplicity uses tox
71to make it easy to test your code against multiple Python versions. Running
72tests using the commands above will automatically test code against both
73Python v2.6 and v2.7, if you have both installed on your system. It will also
74test against the versions of dependencies used by the Launchpad build system.
75You can test against a single environment, e.g.
76tox -e py26
77for example if you are working on fixing a bug, but please do a full run-tests
78before submitting a merge request.
79
80For instructions on installing Python v2.6 on newer versions of Ubuntu, see
81https://launchpad.net/~fkrull/+archive/ubuntu/deadsnakes
2982
=== removed file 'README-TESTING'
--- README-TESTING 2017-05-14 07:17:59 +0000
+++ README-TESTING 1970-01-01 00:00:00 +0000
@@ -1,138 +0,0 @@
1# Testing duplicty
2
3## Introduction
4Duplicitys test concept bases on unit test.
5All tests are contained in the /testing folder of the main repository.
6
7As to see in the following sketch, there are several levels of testing duplicity and each can be used directly.
8
9 ┌─────────────────────┐
10 │ docker image │
11 ├─────────────────────┴────┐
12 │ │
13 │ ┌──────────────────┐ │
14 │ │ tox │ │
15 │ └──────────────────┘ │
16 │ │ │
17 │ ▼ │
18 │ ┌──────────────────┐ │
19 │ │ unittests │ │
20 │ └──────────────────┘ │
21 │ │ │
22 │ ▼ │
23 │ ┌──────────────────┐ │
24 │ │ duplicity │ │
25 │ └──────────────────┘ │
26 │ │
27 └──────────────────────────┘
281. Testing directly using __setup.py__
29Assuming that your machine has all the required dependencies installed, you can start all the unit tests by simply typing
30
31‘setup.py test‘
32
332. Using __tox__
34Tox 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
35runs the tests in each of the environments that are configured in the tox.ini file (see root folder of the repository)
36
37Duplicity uses tox to make it easy to test your code against multiple
38environments. Running tests using the commands above will automatically test
39code against different supported environments, including the versions of
40dependencies used by the Launchpad build system.
41
42A tox run can be started simply by typing
43
44‘tox‘
45
46from the main duplicity folder.
47
48You can run specific tests using:
49‘tox -- -s [folder].[folder].[file].[class].[test]‘
50For example:
51‘tox -- -s testing.unit.test_selection‘
52or:
53‘tox -- -s testing.unit.test_selection.MatchingTest.test_tuple_include‘
54
55You can test against a single environment, e.g.
56‘tox -e py27‘
57for example if you are working on fixing a bug, but please do a full run-tests
58before submitting a merge request.
59
60Note: some tests require rdiff and pylint to be installed on the system for
61them to pass.
62
63Please run all tests on your branch (run-tests) before proposing a merge, to
64ensure that all tests pass. The decorator @unittest.expectedFailure can be used
65to commit a known-failing test case without breaking the test suite, for
66example to exhibit the behaviour in a bug report before it has been fixed.
67
683. Via a __docker__ image
69Testing 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.
70Along with the tests, a docker image has been created (cf. Dockerfile in root folder of repo) that ensure the following things:
71- It bases on a clean Ubunut 16.04
72- It installs all the required packages that are needed for testing
73- It then branches the repository of duplicty to the folder /duplicty/testing within the docker image
74- And installs all the required python packages (as defined in the requirements.txt)
75Therewith, the docker image provides a clean and reproducible environment for executing the tests of duplicty.
76In order to get hands on the docker image you simply:
771) Install Docker on your machine (https://docs.docker.com/engine/installation/)
782) Start the image docker run -it dernils/duplicitytest /bin/bash (if you did not use the image before, it will be downloaded automatically)
793) At the prompt of the docker image type:
80‘cd /testing‘
81‘tox‘
82to start a run of the test cases.
83
84## Dependencies for testing
85If 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.
86
87## Working with test coverage
88Python makes it easy to determine, how well the tests cover the source code.
89
90You first run the tests __under observation__ of the coverage script:
91‘coverage run setup.py test‘
92After that, a report can be generated by the use of the command:
93‘coverage html --omit="testing/*,/usr/*"‘
94
95The report will be generated and stored in the folder htmlcov.
96
97## The wider picture - supporting containers for testing
98Testing 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.
99
100┌─────────────────────┐ ┌──────────────────────────────────────────┐
101│docker image │ │docker image │
102│dernils/duplicitytest│ │dernils/duplicity_testinfrastructure_ssh │
103├─────────────────────┴────┐ ├──────────────────────────────────────────┴──┐
104│ │ │ │
105│ ┌──────────────────┐ │ │ ┌──────────────────┐ │
106│ │ tox │ │ ┌──┼──▶│ sshd │ │
107│ └──────────────────┘ │ │ │ └──────────────────┘ │
108│ │ │ │ │ │
109│ ▼ │ │ └─────────────────────────────────────────────┘
110│ ┌──────────────────┐ │ │ ┌──────────────────────────────────────────┐
111│ │ unittests │ │ │ │docker image │
112│ └──────────────────┘ │ │ │dernils/duplicity_testinfrastructure_ftp │
113│ │ │ │ ├──────────────────────────────────────────┴──┐
114│ ▼ │ │ │ │
115│ ┌──────────────────┐ │ │ │ ┌──────────────────┐ │
116│ │ duplicity │◀───┼─┴──┼──▶│ pure-ftpd │ │
117│ └──────────────────┘ │ │ └──────────────────┘ │
118│ │ │ │ │
119└────────────┼─────────────┘ └─────────────────────────────────────────────┘
120
121
122
123 └────────────┐
124
125 Internet .─────────┼─────────.
126 _.────' │ `─────.
127 _.─' │ `──.
128 ,' ▼ `.
129 ; ┌──────────────────┐ :
130 : │ Dropbox │ ;
131 ╲ └──────────────────┘ ╱
132 `. ,'
133 `──. _.─'
134 `─────. _.────'
135 `─────────────────'
136
137The 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.
138
1390
=== modified file 'bin/duplicity'
--- bin/duplicity 2018-11-29 19:00:15 +0000
+++ bin/duplicity 2019-03-04 12:09:45 +0000
@@ -27,6 +27,7 @@
27# Please send mail to me or the mailing list if you find bugs or have27# Please send mail to me or the mailing list if you find bugs or have
28# any suggestions.28# any suggestions.
2929
30<<<<<<< TREE
30from builtins import filter31from builtins import filter
31from builtins import next32from builtins import next
32from builtins import map33from builtins import map
@@ -34,21 +35,33 @@
34from builtins import object35from builtins import object
35import duplicity.errors36import duplicity.errors
36import copy37import copy
38=======
39>>>>>>> MERGE-SOURCE
37import gzip40import gzip
38import os41import os
42import sys
43import time
44import types
45import traceback
39import platform46import platform
47import statvfs
48import resource
40import re49import re
50<<<<<<< TREE
41import resource51import resource
42from os import statvfs52from os import statvfs
43import sys53import sys
54=======
55>>>>>>> MERGE-SOURCE
44import threading56import threading
45import time57from datetime import datetime
46import traceback
47import types
48import fasteners58import fasteners
4959
50from datetime import datetime60from duplicity import log
51from duplicity import asyncscheduler61log.setup()
62
63import duplicity.errors
64
52from duplicity import collections65from duplicity import collections
53from duplicity import commandline66from duplicity import commandline
54from duplicity import diffdir67from duplicity import diffdir
@@ -57,17 +70,23 @@
57from duplicity import file_naming70from duplicity import file_naming
58from duplicity import globals71from duplicity import globals
59from duplicity import gpg72from duplicity import gpg
60from duplicity import log
61from duplicity import manifest73from duplicity import manifest
62from duplicity import patchdir74from duplicity import patchdir
63from duplicity import path75from duplicity import path
64from duplicity import progress
65from duplicity import robust76from duplicity import robust
66from duplicity import tempdir77from duplicity import tempdir
78from duplicity import asyncscheduler
67from duplicity import util79from duplicity import util
6880from duplicity import progress
81
82
83<<<<<<< TREE
69if u'--pydevd' in sys.argv or os.getenv(u'PYDEVD', None):84if u'--pydevd' in sys.argv or os.getenv(u'PYDEVD', None):
70 import pydevd # pylint: disable=import-error85 import pydevd # pylint: disable=import-error
86=======
87if '--pydevd' in sys.argv or os.getenv('PYDEVD', None):
88 import pydevd # @UnresolvedImport
89>>>>>>> MERGE-SOURCE
71 pydevd.settrace()90 pydevd.settrace()
72 # In a dev environment the path is screwed so fix it.91 # In a dev environment the path is screwed so fix it.
73 base = sys.path.pop(0)92 base = sys.path.pop(0)
@@ -75,8 +94,6 @@
75 base = os.path.sep.join(base)94 base = os.path.sep.join(base)
76 sys.path.insert(0, base)95 sys.path.insert(0, base)
7796
78log.setup()
79
80# If exit_val is not None, exit with given value at end.97# If exit_val is not None, exit with given value at end.
81exit_val = None98exit_val = None
8299
@@ -317,10 +334,31 @@
317 return start_index, start_block, end_index, end_block334 return start_index, start_block, end_index, end_block
318335
319 def validate_block(orig_size, dest_filename):336 def validate_block(orig_size, dest_filename):
337<<<<<<< TREE
320 info = backend.query_info([dest_filename])[dest_filename]338 info = backend.query_info([dest_filename])[dest_filename]
321 size = info[u'size']339 size = info[u'size']
322 if size is None:340 if size is None:
323 return # error querying file341 return # error querying file
342=======
343 """
344 Compare the remote size to the local one to ensure the transfer went
345 through.
346 Try to get the remote size 3 times because some systems take a little
347 time before they report the size accurately.
348 """
349 for attempt in range(0, globals.num_retries):
350 info = backend.query_info([dest_filename])[dest_filename]
351 size = info['size']
352 if size == orig_size:
353 break
354 if size is None:
355 return
356 log.Notice(_("Remote filesize %d for %s does not match local size %d, retrying.") %
357 (0 if size is None else size,
358 util.escape(dest_filename),
359 orig_size))
360 time.sleep(1 + (attempt * 0.5))
361>>>>>>> MERGE-SOURCE
324 if size != orig_size:362 if size != orig_size:
325 code_extra = u"%s %d %d" % (util.escape(dest_filename), orig_size, size)363 code_extra = u"%s %d %d" % (util.escape(dest_filename), orig_size, size)
326 log.FatalError(_(u"File %s was corrupted during upload.") % util.fsdecode(dest_filename),364 log.FatalError(_(u"File %s was corrupted during upload.") % util.fsdecode(dest_filename),
@@ -465,7 +503,6 @@
465503
466 # Upload the collection summary.504 # Upload the collection summary.
467 # bytes_written += write_manifest(mf, backup_type, backend)505 # bytes_written += write_manifest(mf, backup_type, backend)
468 mf.set_files_changed_info(diffdir.stats.get_delta_entries_file())
469506
470 return bytes_written507 return bytes_written
471508
@@ -474,7 +511,7 @@
474 u"""511 u"""
475 Return a fileobj opened for writing, save results as manifest512 Return a fileobj opened for writing, save results as manifest
476513
477 Save manifest in globals.archive_dir_path gzipped.514 Save manifest in globals.archive_dir gzipped.
478 Save them on the backend encrypted as needed.515 Save them on the backend encrypted as needed.
479516
480 @type man_type: string517 @type man_type: string
@@ -494,7 +531,7 @@
494 manifest=True,531 manifest=True,
495 encrypted=globals.encryption)532 encrypted=globals.encryption)
496533
497 fh = dup_temp.get_fileobj_duppath(globals.archive_dir_path,534 fh = dup_temp.get_fileobj_duppath(globals.archive_dir,
498 part_man_filename,535 part_man_filename,
499 perm_man_filename,536 perm_man_filename,
500 remote_man_filename)537 remote_man_filename)
@@ -524,7 +561,7 @@
524 remote_sig_filename = file_naming.get(sig_type, encrypted=globals.encryption,561 remote_sig_filename = file_naming.get(sig_type, encrypted=globals.encryption,
525 gzipped=globals.compression)562 gzipped=globals.compression)
526563
527 fh = dup_temp.get_fileobj_duppath(globals.archive_dir_path,564 fh = dup_temp.get_fileobj_duppath(globals.archive_dir,
528 part_sig_filename,565 part_sig_filename,
529 perm_sig_filename,566 perm_sig_filename,
530 remote_sig_filename,567 remote_sig_filename,
@@ -533,8 +570,13 @@
533570
534571
535def full_backup(col_stats):572def full_backup(col_stats):
573<<<<<<< TREE
536 u"""574 u"""
537 Do full backup of directory to backend, using archive_dir_path575 Do full backup of directory to backend, using archive_dir_path
576=======
577 """
578 Do full backup of directory to backend, using archive_dir
579>>>>>>> MERGE-SOURCE
538580
539 @type col_stats: CollectionStatus object581 @type col_stats: CollectionStatus object
540 @param col_stats: collection status582 @param col_stats: collection status
@@ -622,8 +664,13 @@
622664
623665
624def incremental_backup(sig_chain):666def incremental_backup(sig_chain):
667<<<<<<< TREE
625 u"""668 u"""
626 Do incremental backup of directory to backend, using archive_dir_path669 Do incremental backup of directory to backend, using archive_dir_path
670=======
671 """
672 Do incremental backup of directory to backend, using archive_dir
673>>>>>>> MERGE-SOURCE
627674
628 @rtype: void675 @rtype: void
629 @return: void676 @return: void
@@ -836,6 +883,7 @@
836 def check_signature():883 def check_signature():
837 u"""Thunk run when closing volume file"""884 u"""Thunk run when closing volume file"""
838 actual_sig = fileobj.fileobj.get_signature()885 actual_sig = fileobj.fileobj.get_signature()
886<<<<<<< TREE
839 actual_sig = u"None" if actual_sig is None else actual_sig887 actual_sig = u"None" if actual_sig is None else actual_sig
840 sign_key = globals.gpg_profile.sign_key888 sign_key = globals.gpg_profile.sign_key
841 sign_key = u"None" if sign_key is None else sign_key889 sign_key = u"None" if sign_key is None else sign_key
@@ -843,6 +891,15 @@
843 if actual_sig[ofs:] != sign_key[ofs:]:891 if actual_sig[ofs:] != sign_key[ofs:]:
844 log.FatalError(_(u"Volume was signed by key %s, not %s") %892 log.FatalError(_(u"Volume was signed by key %s, not %s") %
845 (actual_sig[ofs:], sign_key[ofs:]),893 (actual_sig[ofs:], sign_key[ofs:]),
894=======
895 actual_sig = "None" if actual_sig is None else actual_sig
896 sign_key = globals.gpg_profile.sign_key
897 sign_key = "None" if sign_key is None else sign_key
898 ofs = -min(len(actual_sig), len(sign_key))
899 if actual_sig[ofs:] != sign_key[ofs:]:
900 log.FatalError(_("Volume was signed by key %s, not %s") %
901 (actual_sig[ofs:], sign_key[ofs:]),
902>>>>>>> MERGE-SOURCE
846 log.ErrorCode.unsigned_volume)903 log.ErrorCode.unsigned_volume)
847904
848 fileobj.addhook(check_signature)905 fileobj.addhook(check_signature)
@@ -907,7 +964,7 @@
907 col_stats.backend.delete(ext_remote)964 col_stats.backend.delete(ext_remote)
908 for fn in ext_local:965 for fn in ext_local:
909 try:966 try:
910 globals.archive_dir_path.append(fn).delete()967 globals.archive_dir.append(fn).delete()
911 except Exception:968 except Exception:
912 pass969 pass
913 else:970 else:
@@ -1011,6 +1068,7 @@
1011 _(u"Rerun command with --force option to actually delete."))1068 _(u"Rerun command with --force option to actually delete."))
10121069
10131070
1071<<<<<<< TREE
1014def replicate():1072def replicate():
1015 u"""1073 u"""
1016 Replicate backup files from one remote to another, possibly encrypting or adding parity.1074 Replicate backup files from one remote to another, possibly encrypting or adding parity.
@@ -1127,6 +1185,8 @@
1127 globals.backend.close()1185 globals.backend.close()
11281186
11291187
1188=======
1189>>>>>>> MERGE-SOURCE
1130def sync_archive():1190def sync_archive():
1131 u"""1191 u"""
1132 Synchronize local archive manifest file and sig chains to remote archives.1192 Synchronize local archive manifest file and sig chains to remote archives.
@@ -1199,7 +1259,7 @@
1199 return (pr, loc_name, fn)1259 return (pr, loc_name, fn)
12001260
1201 def remove_local(fn):1261 def remove_local(fn):
1202 del_name = globals.archive_dir_path.append(fn).name1262 del_name = globals.archive_dir.append(fn).name
12031263
1204 log.Notice(_(u"Deleting local %s (not authoritative at backend).") %1264 log.Notice(_(u"Deleting local %s (not authoritative at backend).") %
1205 util.fsdecode(del_name))1265 util.fsdecode(del_name))
@@ -1266,14 +1326,14 @@
1266 else:1326 else:
1267 gpg.GzipWriteFile(src_iter, tdp.name, size=sys.maxsize)1327 gpg.GzipWriteFile(src_iter, tdp.name, size=sys.maxsize)
1268 tdp.setdata()1328 tdp.setdata()
1269 tdp.move(globals.archive_dir_path.append(loc_name))1329 tdp.move(globals.archive_dir.append(loc_name))
12701330
1271 # get remote metafile list1331 # get remote metafile list
1272 remlist = globals.backend.list()1332 remlist = globals.backend.list()
1273 remote_metafiles, ignored, rem_needpass = get_metafiles(remlist)1333 remote_metafiles, ignored, rem_needpass = get_metafiles(remlist)
12741334
1275 # get local metafile list1335 # get local metafile list
1276 loclist = globals.archive_dir_path.listdir()1336 loclist = globals.archive_dir.listdir()
1277 local_metafiles, local_partials, loc_needpass = get_metafiles(loclist)1337 local_metafiles, local_partials, loc_needpass = get_metafiles(loclist)
12781338
1279 # we have the list of metafiles on both sides. remote is always1339 # we have the list of metafiles on both sides. remote is always
@@ -1496,7 +1556,11 @@
1496 # determine what action we're performing and process command line1556 # determine what action we're performing and process command line
1497 action = commandline.ProcessCommandLine(sys.argv[1:])1557 action = commandline.ProcessCommandLine(sys.argv[1:])
14981558
1559<<<<<<< TREE
1499 globals.lockpath = os.path.join(globals.archive_dir_path.name, b"lockfile")1560 globals.lockpath = os.path.join(globals.archive_dir_path.name, b"lockfile")
1561=======
1562 globals.lockpath = os.path.join(globals.archive_dir.name, "lockfile")
1563>>>>>>> MERGE-SOURCE
1500 globals.lockfile = fasteners.process_lock.InterProcessLock(globals.lockpath)1564 globals.lockfile = fasteners.process_lock.InterProcessLock(globals.lockpath)
1501 log.Debug(_(u"Acquiring lockfile %s") % globals.lockpath)1565 log.Debug(_(u"Acquiring lockfile %s") % globals.lockpath)
1502 if not globals.lockfile.acquire(blocking=False):1566 if not globals.lockfile.acquire(blocking=False):
@@ -1527,12 +1591,16 @@
1527 check_resources(action)1591 check_resources(action)
15281592
1529 # check archive synch with remote, fix if needed1593 # check archive synch with remote, fix if needed
1594<<<<<<< TREE
1530 if action not in [u"collection-status", u"replicate"]:1595 if action not in [u"collection-status", u"replicate"]:
1596=======
1597 if action not in ["collection-status"]:
1598>>>>>>> MERGE-SOURCE
1531 sync_archive()1599 sync_archive()
15321600
1533 # get current collection status1601 # get current collection status
1534 col_stats = collections.CollectionsStatus(globals.backend,1602 col_stats = collections.CollectionsStatus(globals.backend,
1535 globals.archive_dir_path,1603 globals.archive_dir,
1536 action).set_values()1604 action).set_values()
15371605
1538 while True:1606 while True:
@@ -1563,7 +1631,7 @@
1563 log.Notice(_(u"Cleaning up previous partial %s backup set, restarting." % action))1631 log.Notice(_(u"Cleaning up previous partial %s backup set, restarting." % action))
1564 last_backup.delete()1632 last_backup.delete()
1565 col_stats = collections.CollectionsStatus(globals.backend,1633 col_stats = collections.CollectionsStatus(globals.backend,
1566 globals.archive_dir_path,1634 globals.archive_dir,
1567 action).set_values()1635 action).set_values()
1568 continue1636 continue
1569 break1637 break
@@ -1592,12 +1660,18 @@
1592 verify(col_stats)1660 verify(col_stats)
1593 elif action == u"list-current":1661 elif action == u"list-current":
1594 list_current(col_stats)1662 list_current(col_stats)
1663<<<<<<< TREE
1595 elif action == u"collection-status":1664 elif action == u"collection-status":
1596 if not globals.file_changed:1665 if not globals.file_changed:
1597 log.PrintCollectionStatus(col_stats, True)1666 log.PrintCollectionStatus(col_stats, True)
1598 else:1667 else:
1599 log.PrintCollectionFileChangedStatus(col_stats, globals.file_changed, True)1668 log.PrintCollectionFileChangedStatus(col_stats, globals.file_changed, True)
1600 elif action == u"cleanup":1669 elif action == u"cleanup":
1670=======
1671 elif action == "collection-status":
1672 log.PrintCollectionStatus(col_stats, True)
1673 elif action == "cleanup":
1674>>>>>>> MERGE-SOURCE
1601 cleanup(col_stats)1675 cleanup(col_stats)
1602 elif action == u"remove-old":1676 elif action == u"remove-old":
1603 remove_old(col_stats)1677 remove_old(col_stats)
@@ -1605,8 +1679,11 @@
1605 remove_all_but_n_full(col_stats)1679 remove_all_but_n_full(col_stats)
1606 elif action == u"sync":1680 elif action == u"sync":
1607 sync_archive()1681 sync_archive()
1682<<<<<<< TREE
1608 elif action == u"replicate":1683 elif action == u"replicate":
1609 replicate()1684 replicate()
1685=======
1686>>>>>>> MERGE-SOURCE
1610 else:1687 else:
1611 assert action == u"inc" or action == u"full", action1688 assert action == u"inc" or action == u"full", action
1612 # the passphrase for full and inc is used by --sign-key1689 # the passphrase for full and inc is used by --sign-key
@@ -1665,8 +1742,13 @@
1665 finally:1742 finally:
1666 tempdir.default().cleanup()1743 tempdir.default().cleanup()
16671744
1745<<<<<<< TREE
16681746
1669if __name__ == u"__main__":1747if __name__ == u"__main__":
1748=======
1749
1750if __name__ == "__main__":
1751>>>>>>> MERGE-SOURCE
1670 try:1752 try:
16711753
1672 # import cProfile1754 # import cProfile
@@ -1703,8 +1785,13 @@
1703 # For gpg errors, don't show an ugly stack trace by1785 # For gpg errors, don't show an ugly stack trace by
1704 # default. But do with sufficient verbosity.1786 # default. But do with sufficient verbosity.
1705 util.release_lockfile()1787 util.release_lockfile()
1788<<<<<<< TREE
1706 log.Info(_(u"GPG error detail: %s")1789 log.Info(_(u"GPG error detail: %s")
1707 % util.exception_traceback())1790 % util.exception_traceback())
1791=======
1792 log.Info(_("GPG error detail: %s")
1793 % util.exception_traceback())
1794>>>>>>> MERGE-SOURCE
1708 log.FatalError(u"%s: %s" % (e.__class__.__name__, e.args[0]),1795 log.FatalError(u"%s: %s" % (e.__class__.__name__, e.args[0]),
1709 log.ErrorCode.gpg_failed,1796 log.ErrorCode.gpg_failed,
1710 e.__class__.__name__)1797 e.__class__.__name__)
@@ -1713,8 +1800,13 @@
1713 util.release_lockfile()1800 util.release_lockfile()
1714 # For user errors, don't show an ugly stack trace by1801 # For user errors, don't show an ugly stack trace by
1715 # default. But do with sufficient verbosity.1802 # default. But do with sufficient verbosity.
1803<<<<<<< TREE
1716 log.Info(_(u"User error detail: %s")1804 log.Info(_(u"User error detail: %s")
1717 % util.exception_traceback())1805 % util.exception_traceback())
1806=======
1807 log.Info(_("User error detail: %s")
1808 % util.exception_traceback())
1809>>>>>>> MERGE-SOURCE
1718 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),1810 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),
1719 log.ErrorCode.user_error,1811 log.ErrorCode.user_error,
1720 e.__class__.__name__)1812 e.__class__.__name__)
@@ -1723,15 +1815,24 @@
1723 util.release_lockfile()1815 util.release_lockfile()
1724 # For backend errors, don't show an ugly stack trace by1816 # For backend errors, don't show an ugly stack trace by
1725 # default. But do with sufficient verbosity.1817 # default. But do with sufficient verbosity.
1818<<<<<<< TREE
1726 log.Info(_(u"Backend error detail: %s")1819 log.Info(_(u"Backend error detail: %s")
1727 % util.exception_traceback())1820 % util.exception_traceback())
1821=======
1822 log.Info(_("Backend error detail: %s")
1823 % util.exception_traceback())
1824>>>>>>> MERGE-SOURCE
1728 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),1825 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),
1729 log.ErrorCode.user_error,1826 log.ErrorCode.user_error,
1730 e.__class__.__name__)1827 e.__class__.__name__)
17311828
1732 except Exception as e:1829 except Exception as e:
1733 util.release_lockfile()1830 util.release_lockfile()
1831<<<<<<< TREE
1734 if u"Forced assertion for testing" in util.uexc(e):1832 if u"Forced assertion for testing" in util.uexc(e):
1833=======
1834 if "Forced assertion for testing" in util.uexc(e):
1835>>>>>>> MERGE-SOURCE
1735 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),1836 log.FatalError(u"%s: %s" % (e.__class__.__name__, util.uexc(e)),
1736 log.ErrorCode.exception,1837 log.ErrorCode.exception,
1737 e.__class__.__name__)1838 e.__class__.__name__)
17381839
=== modified file 'bin/duplicity.1'
--- bin/duplicity.1 2019-01-26 16:36:27 +0000
+++ bin/duplicity.1 2019-03-04 12:09:45 +0000
@@ -21,7 +21,7 @@
21source_url target_directory21source_url target_directory
2222
23.B duplicity collection-status23.B duplicity collection-status
24.I [options] [--file-changed <relpath>]24.I [options]
25target_url25target_url
2626
27.B duplicity list-current-files27.B duplicity list-current-files
@@ -48,10 +48,6 @@
48.I [options] [--force] [--extra-clean]48.I [options] [--force] [--extra-clean]
49target_url49target_url
5050
51.B duplicity replicate
52.I [options] [--time time]
53source_url target_url
54
55.SH DESCRIPTION51.SH DESCRIPTION
56Duplicity incrementally backs up files and folders into52Duplicity incrementally backs up files and folders into
57tar-format volumes encrypted with GnuPG and places them to a53tar-format volumes encrypted with GnuPG and places them to a
@@ -168,28 +164,23 @@
168164
169.TP165.TP
170.BI "verify " "[--compare-data] [--time <time>] [--file-to-restore <rel_path>] <url> <local_path>"166.BI "verify " "[--compare-data] [--time <time>] [--file-to-restore <rel_path>] <url> <local_path>"
171Verify tests the integrity of the backup archives at the remote location by downloading each file167Restore backup contents temporarily file by file and compare against the local path's contents.
172and checking both that it can restore the archive and that the restored file matches the signature168duplicity will exit with a non-zero error level if any files are different.
173of that file stored in the backup, i.e. compares the archived file with its hash value from archival169On verbosity level info (4) or higher, a message for each file that has
174time. Verify does not actually restore and will not overwrite any local files. Duplicity170changed will be logged.
175will exit with a non-zero error level if any files do not match the signature stored in the archive
176for that file. On verbosity level 4 or higher, it will log a message for each file that differs
177from the stored signature. Files must be downloaded to the local machine in order to compare them.
178Verify does not compare the backed-up version of the file to the current local copy of the files
179unless the --compare-data option is used (see below).
180.br171.br
181The172The
182.I --file-to-restore173.I --file-to-restore
183option restricts verify to that file or folder.174option restricts verify to that file or folder.
184The175The
185.I --time176.I --time
186option allows to select a backup to verify.177option allows to select a backup to verify against.
187The178The
188.I --compare-data179.I --compare-data
189option enables data comparison (see below).180option enables data comparison (see below).
190181
191.TP182.TP
192.BI "collection-status " "[--file-changed <relpath>]" "<url>"183.BI "collection-status " "<url>"
193Summarize the status of the backup repository by printing the chains184Summarize the status of the backup repository by printing the chains
194and sets found, and the number of volumes in each.185and sets found, and the number of volumes in each.
195186
@@ -252,19 +243,6 @@
252.I --force243.I --force
253will be needed to delete the files instead of just listing them.244will be needed to delete the files instead of just listing them.
254245
255.TP
256.BI "replicate " "[--time time] <source_url> <target_url>"
257Replicate backup sets from source to target backend. Files will be
258(re)-encrypted and (re)-compressed depending on normal backend
259options. Signatures and volumes will not get recomputed, thus options like
260.BI --volsize
261or
262.BI --max-blocksize
263have no effect.
264When
265.I --time time
266is given, only backup sets older than time will be replicated.
267
268.SH OPTIONS246.SH OPTIONS
269247
270.TP248.TP
@@ -349,14 +327,8 @@
349327
350.TP328.TP
351.BI --compare-data329.BI --compare-data
352Enable data comparison of regular files on action verify. This conducts a330Enable data comparison of regular files on action verify.
353verify as described above to verify the integrity of the backup archives,331This is disabled by default for performance reasons.
354but additionally compares restored files to those in target_directory.
355Duplicity will not replace any files in target_directory. Duplicity will
356exit with a non-zero error level if the files do not correctly verify or
357if any files from the archive differ from those in target_directory. On
358verbosity level 4 or higher, it will log a message for each file that
359differs from its equivalent in target_directory.
360332
361.TP333.TP
362.BI --copy-links334.BI --copy-links
@@ -465,15 +437,6 @@
465argument for more information.437argument for more information.
466438
467.TP439.TP
468.BI "--file-changed " path
469This option may be given in collection-status mode, causing only
470.I path
471status to be collect instead of the entire contents of the backup archive.
472.I path
473should be given relative to the root of the directory backed up.
474
475
476.TP
477.BI "--file-prefix, --file-prefix-manifest, --file-prefix-archive, --file-prefix-signature440.BI "--file-prefix, --file-prefix-manifest, --file-prefix-archive, --file-prefix-signature
478Adds a prefix to all files, manifest files, archive files, and/or signature files.441Adds a prefix to all files, manifest files, archive files, and/or signature files.
479442
@@ -816,6 +779,7 @@
816when uploading to S3 to ensure you kill connections to slow S3 endpoints.779when uploading to S3 to ensure you kill connections to slow S3 endpoints.
817780
818.TP781.TP
782<<<<<<< TREE
819.BI "--azure-blob-tier"783.BI "--azure-blob-tier"
820Standard storage tier used for backup files (Hot|Cool|Archive).784Standard storage tier used for backup files (Hot|Cool|Archive).
821785
@@ -839,6 +803,8 @@
839blob size exceeds 64MB. The default values is 2.803blob size exceeds 64MB. The default values is 2.
840804
841.TP805.TP
806=======
807>>>>>>> MERGE-SOURCE
842.BI "--scp-command " command808.BI "--scp-command " command
843.B (only ssh pexpect backend with --use-scp enabled)809.B (only ssh pexpect backend with --use-scp enabled)
844The810The
@@ -948,13 +914,6 @@
948.BR "A NOTE ON SSL CERTIFICATE VERIFICATION" .914.BR "A NOTE ON SSL CERTIFICATE VERIFICATION" .
949915
950.TP916.TP
951.BI --swift-storage-policy
952Use this storage policy when operating on Swift containers.
953.br
954See also
955.BR "A NOTE ON SWIFT (OPENSTACK OBJECT STORAGE) ACCESS" .
956
957.TP
958.BI "--tempdir " directory917.BI "--tempdir " directory
959Use this existing directory for duplicity temporary files instead of918Use this existing directory for duplicity temporary files instead of
960the system default, which is usually the /tmp directory. This option919the system default, which is usually the /tmp directory. This option
@@ -1093,15 +1052,6 @@
1093Formats of each of the URL schemes follow:1052Formats of each of the URL schemes follow:
10941053
1095.PP1054.PP
1096.B "Amazon Drive Backend"
1097.PP
1098.RS
1099ad://some_dir
1100.PP
1101See also
1102.B "A NOTE ON AMAZON DRIVE"
1103.RE
1104.PP
1105.BR "Azure"1055.BR "Azure"
1106.PP1056.PP
1107.RS1057.RS
@@ -1266,15 +1216,6 @@
1266.B "A NOTE ON SWIFT (OPENSTACK OBJECT STORAGE) ACCESS"1216.B "A NOTE ON SWIFT (OPENSTACK OBJECT STORAGE) ACCESS"
1267.RE1217.RE
1268.PP1218.PP
1269.BR "Public Cloud Archive" " (OVH)"
1270.PP
1271.RS
1272pca://container_name[/prefix]
1273.PP
1274See also
1275.B "A NOTE ON PCA ACCESS"
1276.RE
1277.PP
1278.B "Tahoe-LAFS"1219.B "Tahoe-LAFS"
1279.PP1220.PP
1280.RS1221.RS
@@ -1584,25 +1525,6 @@
1584which aren't followed by 'foo'. However, it wouldn't match /home even1525which aren't followed by 'foo'. However, it wouldn't match /home even
1585if /home/ben/1234567 existed.1526if /home/ben/1234567 existed.
15861527
1587.SH A NOTE ON AMAZON DRIVE
1588.IP 1.
1589The API Keys used for Amazon Drive have not been granted production limits.
1590Amazon do not say what the development limits are and are not replying to
1591to requests to whitelist duplicity. A related tool, acd_cli, was demoted to
1592development limits, but continues to work fine except for cases of excessive
1593usage. If you experience throttling and similar issues with Amazon Drive using
1594this backend, please report them to the mailing list.
1595.IR
1596.IP 2.
1597If you previously used the
1598.BI acd+acdcli
1599backend, it is strongly recommended to update to the
1600.BI ad
1601backend instead, since it interfaces directly with Amazon Drive. You will need
1602to setup the OAuth once again, but can otherwise keep your backups and config.
1603.IR
1604.RE
1605
1606.SH A NOTE ON AZURE ACCESS1528.SH A NOTE ON AZURE ACCESS
1607The Azure backend requires the Microsoft Azure Storage SDK for Python to be1529The Azure backend requires the Microsoft Azure Storage SDK for Python to be
1608installed on the system.1530installed on the system.
@@ -1610,13 +1532,9 @@
1610.B REQUIREMENTS1532.B REQUIREMENTS
1611above.1533above.
16121534
1613It uses environment variables for authentification:1535It uses two environment variables for authentification:
1614.BR AZURE_ACCOUNT_NAME " (required),"1536.BR AZURE_ACCOUNT_NAME " (required),"
1615.BR AZURE_ACCOUNT_KEY " (optional),1537.BR AZURE_ACCOUNT_KEY " (required)"
1616.BR AZURE_SHARED_ACCESS_SIGNATURE " (optional)."
1617One of
1618.BR AZURE_ACCOUNT_KEY " or"
1619.BR AZURE_SHARED_ACCESS_SIGNATURE " is required."
16201538
1621A container name must be a valid DNS name, conforming to the following naming1539A container name must be a valid DNS name, conforming to the following naming
1622rules:1540rules:
@@ -1753,13 +1671,8 @@
17531671
1754.SH A NOTE ON FILENAME PREFIXES1672.SH A NOTE ON FILENAME PREFIXES
17551673
1756Filename prefixes can be used in1674Filename prefixes can be used in conjunction with S3 lifecycle rules to transition
1757.B "multi backend "1675archive files to Glacier, while keeping metadata (signature and manifest files) on S3.
1758with
1759.B "mirror "
1760mode to define affinity rules. They can also be used in conjunction with
1761S3 lifecycle rules to transition archive files to Glacier, while keeping
1762metadata (signature and manifest files) on S3.
17631676
1764Duplicity does not require access to archive files except when restoring from backup.1677Duplicity does not require access to archive files except when restoring from backup.
17651678
@@ -1876,8 +1789,7 @@
1876 "name" : "FOO",1789 "name" : "FOO",
1877 "value" : "bar"1790 "value" : "bar"
1878 }1791 }
1879 ],1792 ]
1880 "prefixes": ["prefix1_", "prefix2_"]
1881 },1793 },
1882 {1794 {
1883 "url": "file:///path/to/dir"1795 "url": "file:///path/to/dir"
@@ -2093,40 +2005,6 @@
2093.B SWIFT_AUTHVERSION2005.B SWIFT_AUTHVERSION
2094is unspecified, it will default to version 1.2006is unspecified, it will default to version 1.
20952007
2096.SH A NOTE ON PCA ACCESS
2097PCA is a long-term data archival solution by OVH. It runs a slightly modified
2098version of Openstack Swift introducing latency in the data retrieval process.
2099It is a good pick for a
2100.BR "multi backend "
2101configuration where receiving volumes while an other backend is used to store
2102manifests and signatures.
2103
2104.br
2105The backend requires python-switclient to be installed on the system.
2106python-keystoneclient is also needed to interact with OpenStack's Keystone
2107Identity service.
2108See
2109.B REQUIREMENTS
2110above.
2111
2112It uses following environment variables for authentification:
2113.BR PCA_USERNAME " (required),"
2114.BR PCA_PASSWORD " (required),"
2115.BR PCA_AUTHURL " (required),"
2116.BR PCA_USERID " (optional),"
2117.BR PCA_TENANTID " (optional, but either the tenant name or tenant id must be supplied)"
2118.BR PCA_REGIONNAME " (optional),"
2119.BR PCA_TENANTNAME " (optional, but either the tenant name or tenant id must be supplied)"
2120
2121If the user was previously authenticated, the following environment
2122variables can be used instead:
2123.BR PCA_PREAUTHURL " (required),"
2124.BR PCA_PREAUTHTOKEN " (required)"
2125
2126If
2127.B PCA_AUTHVERSION
2128is unspecified, it will default to version 2.
2129
2130.SH A NOTE ON MEDIAFIRE BACKEND2008.SH A NOTE ON MEDIAFIRE BACKEND
2131This backend requires2009This backend requires
2132.B mediafire2010.B mediafire
@@ -2237,13 +2115,6 @@
22372115
2238Some backends also require additional components (probably available as packages for your specific platform):2116Some backends also require additional components (probably available as packages for your specific platform):
2239.TP2117.TP
2240.BR "Amazon Drive backend"
2241.B python-requests
2242- http://python-requests.org
2243.br
2244.B python-requests-oauthlib
2245- https://github.com/requests/requests-oauthlib
2246.TP
2247.BR "azure backend" " (Azure Blob Storage Service)"2118.BR "azure backend" " (Azure Blob Storage Service)"
2248.B Microsoft Azure Storage SDK for Python2119.B Microsoft Azure Storage SDK for Python
2249- https://pypi.python.org/pypi/azure-storage/2120- https://pypi.python.org/pypi/azure-storage/
@@ -2260,10 +2131,6 @@
2260.B Dropbox Python SDK2131.B Dropbox Python SDK
2261- https://www.dropbox.com/developers/reference/sdk2132- https://www.dropbox.com/developers/reference/sdk
2262.TP2133.TP
2263.BR "copy backend" " (Copy.com)"
2264.B python-urllib3
2265- https://github.com/shazow/urllib3
2266.TP
2267.BR "gdocs gdata backend" " (legacy Google Docs backend)"2134.BR "gdocs gdata backend" " (legacy Google Docs backend)"
2268.B Google Data APIs Python Client Library2135.B Google Data APIs Python Client Library
2269- http://code.google.com/p/gdata-python-client/2136- http://code.google.com/p/gdata-python-client/
22702137
=== modified file 'debian/control'
=== renamed file 'docs/Makefile' => 'docs/Makefile.THIS'
=== removed directory 'docs/_static'
=== removed directory 'docs/_templates'
=== renamed file 'docs/conf.py' => 'docs/conf.py.THIS'
=== removed file 'docs/duplicity.asyncscheduler.rst'
--- docs/duplicity.asyncscheduler.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.asyncscheduler.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.asyncscheduler module
2===============================
3
4.. automodule:: duplicity.asyncscheduler
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backend.rst'
--- docs/duplicity.backend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backend module
2========================
3
4.. automodule:: duplicity.backend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.azurebackend.rst'
--- docs/duplicity.backends.azurebackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.azurebackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.azurebackend module
2======================================
3
4.. automodule:: duplicity.backends.azurebackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.b2backend.rst'
--- docs/duplicity.backends.b2backend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.b2backend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.b2backend module
2===================================
3
4.. automodule:: duplicity.backends.b2backend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.botobackend.rst'
--- docs/duplicity.backends.botobackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.botobackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.botobackend module
2=====================================
3
4.. automodule:: duplicity.backends.botobackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.cfbackend.rst'
--- docs/duplicity.backends.cfbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.cfbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.cfbackend module
2===================================
3
4.. automodule:: duplicity.backends.cfbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.dpbxbackend.rst'
--- docs/duplicity.backends.dpbxbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.dpbxbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.dpbxbackend module
2=====================================
3
4.. automodule:: duplicity.backends.dpbxbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.gdocsbackend.rst'
--- docs/duplicity.backends.gdocsbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.gdocsbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.gdocsbackend module
2======================================
3
4.. automodule:: duplicity.backends.gdocsbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.giobackend.rst'
--- docs/duplicity.backends.giobackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.giobackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.giobackend module
2====================================
3
4.. automodule:: duplicity.backends.giobackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.hsibackend.rst'
--- docs/duplicity.backends.hsibackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.hsibackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.hsibackend module
2====================================
3
4.. automodule:: duplicity.backends.hsibackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.hubicbackend.rst'
--- docs/duplicity.backends.hubicbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.hubicbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.hubicbackend module
2======================================
3
4.. automodule:: duplicity.backends.hubicbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.imapbackend.rst'
--- docs/duplicity.backends.imapbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.imapbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.imapbackend module
2=====================================
3
4.. automodule:: duplicity.backends.imapbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.lftpbackend.rst'
--- docs/duplicity.backends.lftpbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.lftpbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.lftpbackend module
2=====================================
3
4.. automodule:: duplicity.backends.lftpbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.localbackend.rst'
--- docs/duplicity.backends.localbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.localbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.localbackend module
2======================================
3
4.. automodule:: duplicity.backends.localbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.mediafirebackend.rst'
--- docs/duplicity.backends.mediafirebackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.mediafirebackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.mediafirebackend module
2==========================================
3
4.. automodule:: duplicity.backends.mediafirebackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.megabackend.rst'
--- docs/duplicity.backends.megabackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.megabackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.megabackend module
2=====================================
3
4.. automodule:: duplicity.backends.megabackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.multibackend.rst'
--- docs/duplicity.backends.multibackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.multibackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.multibackend module
2======================================
3
4.. automodule:: duplicity.backends.multibackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.ncftpbackend.rst'
--- docs/duplicity.backends.ncftpbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.ncftpbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.ncftpbackend module
2======================================
3
4.. automodule:: duplicity.backends.ncftpbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.onedrivebackend.rst'
--- docs/duplicity.backends.onedrivebackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.onedrivebackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.onedrivebackend module
2=========================================
3
4.. automodule:: duplicity.backends.onedrivebackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.par2backend.rst'
--- docs/duplicity.backends.par2backend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.par2backend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.par2backend module
2=====================================
3
4.. automodule:: duplicity.backends.par2backend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.pydrivebackend.rst'
--- docs/duplicity.backends.pydrivebackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.pydrivebackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.pydrivebackend module
2========================================
3
4.. automodule:: duplicity.backends.pydrivebackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== renamed file 'docs/duplicity.backends.pyrax_identity.hubic.rst' => 'docs/duplicity.backends.pyrax_identity.hubic.rst.THIS'
=== renamed file 'docs/duplicity.backends.pyrax_identity.rst' => 'docs/duplicity.backends.pyrax_identity.rst.THIS'
=== renamed file 'docs/duplicity.backends.rst' => 'docs/duplicity.backends.rst.THIS'
=== removed file 'docs/duplicity.backends.rsyncbackend.rst'
--- docs/duplicity.backends.rsyncbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.rsyncbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.rsyncbackend module
2======================================
3
4.. automodule:: duplicity.backends.rsyncbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== renamed file 'docs/duplicity.backends.ssh_paramiko_backend.rst' => 'docs/duplicity.backends.ssh_paramiko_backend.rst.THIS'
=== renamed file 'docs/duplicity.backends.ssh_pexpect_backend.rst' => 'docs/duplicity.backends.ssh_pexpect_backend.rst.THIS'
=== removed file 'docs/duplicity.backends.swiftbackend.rst'
--- docs/duplicity.backends.swiftbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.swiftbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.swiftbackend module
2======================================
3
4.. automodule:: duplicity.backends.swiftbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.sxbackend.rst'
--- docs/duplicity.backends.sxbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.sxbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.sxbackend module
2===================================
3
4.. automodule:: duplicity.backends.sxbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.tahoebackend.rst'
--- docs/duplicity.backends.tahoebackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.tahoebackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.tahoebackend module
2======================================
3
4.. automodule:: duplicity.backends.tahoebackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.backends.webdavbackend.rst'
--- docs/duplicity.backends.webdavbackend.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.backends.webdavbackend.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.backends.webdavbackend module
2=======================================
3
4.. automodule:: duplicity.backends.webdavbackend
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== renamed file 'docs/duplicity.cached_ops.rst' => 'docs/duplicity.cached_ops.rst.THIS'
=== removed file 'docs/duplicity.collections.rst'
--- docs/duplicity.collections.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.collections.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.collections module
2============================
3
4.. automodule:: duplicity.collections
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.commandline.rst'
--- docs/duplicity.commandline.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.commandline.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.commandline module
2============================
3
4.. automodule:: duplicity.commandline
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.diffdir.rst'
--- docs/duplicity.diffdir.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.diffdir.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.diffdir module
2========================
3
4.. automodule:: duplicity.diffdir
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== renamed file 'docs/duplicity.dup_temp.rst' => 'docs/duplicity.dup_temp.rst.THIS'
=== renamed file 'docs/duplicity.dup_threading.rst' => 'docs/duplicity.dup_threading.rst.THIS'
=== renamed file 'docs/duplicity.dup_time.rst' => 'docs/duplicity.dup_time.rst.THIS'
=== removed file 'docs/duplicity.errors.rst'
--- docs/duplicity.errors.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.errors.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.errors module
2=======================
3
4.. automodule:: duplicity.errors
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== renamed file 'docs/duplicity.file_naming.rst' => 'docs/duplicity.file_naming.rst.THIS'
=== removed file 'docs/duplicity.filechunkio.rst'
--- docs/duplicity.filechunkio.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.filechunkio.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.filechunkio module
2============================
3
4.. automodule:: duplicity.filechunkio
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.globals.rst'
--- docs/duplicity.globals.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.globals.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.globals module
2========================
3
4.. automodule:: duplicity.globals
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.globmatch.rst'
--- docs/duplicity.globmatch.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.globmatch.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.globmatch module
2==========================
3
4.. automodule:: duplicity.globmatch
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.gpg.rst'
--- docs/duplicity.gpg.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.gpg.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.gpg module
2====================
3
4.. automodule:: duplicity.gpg
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.gpginterface.rst'
--- docs/duplicity.gpginterface.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.gpginterface.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.gpginterface module
2=============================
3
4.. automodule:: duplicity.gpginterface
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.lazy.rst'
--- docs/duplicity.lazy.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.lazy.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.lazy module
2=====================
3
4.. automodule:: duplicity.lazy
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.librsync.rst'
--- docs/duplicity.librsync.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.librsync.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.librsync module
2=========================
3
4.. automodule:: duplicity.librsync
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.log.rst'
--- docs/duplicity.log.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.log.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.log module
2====================
3
4.. automodule:: duplicity.log
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.manifest.rst'
--- docs/duplicity.manifest.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.manifest.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.manifest module
2=========================
3
4.. automodule:: duplicity.manifest
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.patchdir.rst'
--- docs/duplicity.patchdir.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.patchdir.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.patchdir module
2=========================
3
4.. automodule:: duplicity.patchdir
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.path.rst'
--- docs/duplicity.path.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.path.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.path module
2=====================
3
4.. automodule:: duplicity.path
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.progress.rst'
--- docs/duplicity.progress.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.progress.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.progress module
2=========================
3
4.. automodule:: duplicity.progress
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.robust.rst'
--- docs/duplicity.robust.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.robust.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.robust module
2=======================
3
4.. automodule:: duplicity.robust
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== renamed file 'docs/duplicity.rst' => 'docs/duplicity.rst.THIS'
=== removed file 'docs/duplicity.selection.rst'
--- docs/duplicity.selection.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.selection.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.selection module
2==========================
3
4.. automodule:: duplicity.selection
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.statistics.rst'
--- docs/duplicity.statistics.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.statistics.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.statistics module
2===========================
3
4.. automodule:: duplicity.statistics
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.tarfile.rst'
--- docs/duplicity.tarfile.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.tarfile.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.tarfile module
2========================
3
4.. automodule:: duplicity.tarfile
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.tempdir.rst'
--- docs/duplicity.tempdir.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.tempdir.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.tempdir module
2========================
3
4.. automodule:: duplicity.tempdir
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/duplicity.util.rst'
--- docs/duplicity.util.rst 2018-07-24 16:17:12 +0000
+++ docs/duplicity.util.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1duplicity.util module
2=====================
3
4.. automodule:: duplicity.util
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== renamed file 'docs/index.rst' => 'docs/index.rst.THIS'
=== renamed file 'docs/make.bat' => 'docs/make.bat.THIS'
=== renamed file 'docs/testing.functional.rst' => 'docs/testing.functional.rst.THIS'
=== renamed file 'docs/testing.functional.test_badupload.rst' => 'docs/testing.functional.test_badupload.rst.THIS'
=== renamed file 'docs/testing.functional.test_cleanup.rst' => 'docs/testing.functional.test_cleanup.rst.THIS'
=== renamed file 'docs/testing.functional.test_final.rst' => 'docs/testing.functional.test_final.rst.THIS'
=== renamed file 'docs/testing.functional.test_log.rst' => 'docs/testing.functional.test_log.rst.THIS'
=== renamed file 'docs/testing.functional.test_rdiffdir.rst' => 'docs/testing.functional.test_rdiffdir.rst.THIS'
=== renamed file 'docs/testing.functional.test_restart.rst' => 'docs/testing.functional.test_restart.rst.THIS'
=== renamed file 'docs/testing.functional.test_selection.rst' => 'docs/testing.functional.test_selection.rst.THIS'
=== renamed file 'docs/testing.functional.test_verify.rst' => 'docs/testing.functional.test_verify.rst.THIS'
=== removed file 'docs/testing.overrides.gettext.rst'
--- docs/testing.overrides.gettext.rst 2018-07-24 16:17:12 +0000
+++ docs/testing.overrides.gettext.rst 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1testing.overrides.gettext module
2================================
3
4.. automodule:: testing.overrides.gettext
5 :members:
6 :undoc-members:
7 :show-inheritance:
80
=== removed file 'docs/testing.overrides.rst'
--- docs/testing.overrides.rst 2018-07-24 16:17:12 +0000
+++ docs/testing.overrides.rst 1970-01-01 00:00:00 +0000
@@ -1,17 +0,0 @@
1testing.overrides package
2=========================
3
4Submodules
5----------
6
7.. toctree::
8
9 testing.overrides.gettext
10
11Module contents
12---------------
13
14.. automodule:: testing.overrides
15 :members:
16 :undoc-members:
17 :show-inheritance:
180
=== renamed file 'docs/testing.rst' => 'docs/testing.rst.THIS'
=== renamed file 'docs/testing.test_code.rst' => 'docs/testing.test_code.rst.THIS'
=== removed file 'docs/testing.unit.rst'
--- docs/testing.unit.rst 2018-07-24 16:17:12 +0000
+++ docs/testing.unit.rst 1970-01-01 00:00:00 +0000
@@ -1,34 +0,0 @@
1testing.unit package
2====================
3
4Submodules
5----------
6
7.. toctree::
8
9 testing.unit.test_backend
10 testing.unit.test_backend_instance
11 testing.unit.test_collections
12 testing.unit.test_diffdir
13 testing.unit.test_dup_temp
14 testing.unit.test_dup_time
15 testing.unit.test_file_naming
16 testing.unit.test_globmatch
17 testing.unit.test_gpg
18 testing.unit.test_gpginterface
19 testing.unit.test_lazy
20 testing.unit.test_manifest
21 testing.unit.test_patchdir
22 testing.unit.test_path
23 testing.unit.test_selection
24 testing.unit.test_statistics
25 testing.unit.test_tarfile
26 testing.unit.test_tempdir
27
28Module contents
29---------------
30
31.. automodule:: testing.unit
32 :members:
33 :undoc-members:
34 :show-inheritance:
350
=== renamed file 'docs/testing.unit.test_backend.rst' => 'docs/testing.unit.test_backend.rst.THIS'
=== renamed file 'docs/testing.unit.test_backend_instance.rst' => 'docs/testing.unit.test_backend_instance.rst.THIS'
=== renamed file 'docs/testing.unit.test_collections.rst' => 'docs/testing.unit.test_collections.rst.THIS'
=== renamed file 'docs/testing.unit.test_diffdir.rst' => 'docs/testing.unit.test_diffdir.rst.THIS'
=== renamed file 'docs/testing.unit.test_dup_temp.rst' => 'docs/testing.unit.test_dup_temp.rst.THIS'
=== renamed file 'docs/testing.unit.test_dup_time.rst' => 'docs/testing.unit.test_dup_time.rst.THIS'
=== renamed file 'docs/testing.unit.test_file_naming.rst' => 'docs/testing.unit.test_file_naming.rst.THIS'
=== renamed file 'docs/testing.unit.test_globmatch.rst' => 'docs/testing.unit.test_globmatch.rst.THIS'
=== renamed file 'docs/testing.unit.test_gpg.rst' => 'docs/testing.unit.test_gpg.rst.THIS'
=== renamed file 'docs/testing.unit.test_gpginterface.rst' => 'docs/testing.unit.test_gpginterface.rst.THIS'
=== renamed file 'docs/testing.unit.test_lazy.rst' => 'docs/testing.unit.test_lazy.rst.THIS'
=== renamed file 'docs/testing.unit.test_manifest.rst' => 'docs/testing.unit.test_manifest.rst.THIS'
=== renamed file 'docs/testing.unit.test_patchdir.rst' => 'docs/testing.unit.test_patchdir.rst.THIS'
=== renamed file 'docs/testing.unit.test_path.rst' => 'docs/testing.unit.test_path.rst.THIS'
=== renamed file 'docs/testing.unit.test_selection.rst' => 'docs/testing.unit.test_selection.rst.THIS'
=== renamed file 'docs/testing.unit.test_statistics.rst' => 'docs/testing.unit.test_statistics.rst.THIS'
=== renamed file 'docs/testing.unit.test_tarfile.rst' => 'docs/testing.unit.test_tarfile.rst.THIS'
=== renamed file 'docs/testing.unit.test_tempdir.rst' => 'docs/testing.unit.test_tempdir.rst.THIS'
=== modified file 'duplicity/_librsyncmodule.c'
--- duplicity/_librsyncmodule.c 2018-12-05 03:48:47 +0000
+++ duplicity/_librsyncmodule.c 2019-03-04 12:09:45 +0000
@@ -330,7 +330,7 @@
330 fd = dup(fd);330 fd = dup(fd);
331 if (fd == -1) {331 if (fd == -1) {
332 char buf[256];332 char buf[256];
333 (void)strerror_r(errno, buf, sizeof(buf));333 strerror_r(errno, buf, sizeof(buf));
334 PyErr_SetString(PyExc_TypeError, buf);334 PyErr_SetString(PyExc_TypeError, buf);
335 return NULL;335 return NULL;
336 }336 }
337337
=== modified file 'duplicity/backend.py'
--- duplicity/backend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backend.py 2019-03-04 12:09:45 +0000
@@ -455,8 +455,13 @@
455 else:455 else:
456 return commandline456 return commandline
457457
458<<<<<<< TREE
458 def __subprocess_popen(self, args):459 def __subprocess_popen(self, args):
459 u"""460 u"""
461=======
462 def __subprocess_popen(self, args):
463 """
464>>>>>>> MERGE-SOURCE
460 For internal use.465 For internal use.
461 Execute the given command line, interpreted as a shell command.466 Execute the given command line, interpreted as a shell command.
462 Returns int Exitcode, string StdOut, string StdErr467 Returns int Exitcode, string StdOut, string StdErr
@@ -480,6 +485,7 @@
480485
481 Raise a BackendException on failure.486 Raise a BackendException on failure.
482 """487 """
488<<<<<<< TREE
483 import shlex489 import shlex
484490
485 if isinstance(commandline, (list, tuple)):491 if isinstance(commandline, (list, tuple)):
@@ -493,6 +499,21 @@
493 log.Info(_(u"Reading results of '%s'") % logstr)499 log.Info(_(u"Reading results of '%s'") % logstr)
494500
495 result, stdout, stderr = self.__subprocess_popen(args)501 result, stdout, stderr = self.__subprocess_popen(args)
502=======
503 import shlex
504
505 if isinstance(commandline, (types.ListType, types.TupleType)):
506 logstr = ' '.join(commandline)
507 args = commandline
508 else:
509 logstr = commandline
510 args = shlex.split(commandline)
511
512 logstr = self.munge_password(logstr)
513 log.Info(_("Reading results of '%s'") % logstr)
514
515 result, stdout, stderr = self.__subprocess_popen(args)
516>>>>>>> MERGE-SOURCE
496 if result != 0:517 if result != 0:
497 try:518 try:
498 ignores = self.popen_breaks[args[0]]519 ignores = self.popen_breaks[args[0]]
@@ -500,8 +521,13 @@
500 u""" ignore a predefined set of error codes """521 u""" ignore a predefined set of error codes """
501 return 0, u'', u''522 return 0, u'', u''
502 except (KeyError, ValueError):523 except (KeyError, ValueError):
524<<<<<<< TREE
503 raise BackendException(u"Error running '%s': returned %d, with output:\n%s" %525 raise BackendException(u"Error running '%s': returned %d, with output:\n%s" %
504 (logstr, result, stdout.decode() + u'\n' + stderr.decode()))526 (logstr, result, stdout.decode() + u'\n' + stderr.decode()))
527=======
528 raise BackendException("Error running '%s': returned %d, with output:\n%s" %
529 (logstr, result, stdout + '\n' + stderr))
530>>>>>>> MERGE-SOURCE
505 return result, stdout, stderr531 return result, stdout, stderr
506532
507533
@@ -573,7 +599,11 @@
573 # There shouldn't be any encoding errors for files we care599 # There shouldn't be any encoding errors for files we care
574 # about, since duplicity filenames are ascii. But user files600 # about, since duplicity filenames are ascii. But user files
575 # may be in the same directory. So just replace characters.601 # may be in the same directory. So just replace characters.
602<<<<<<< TREE
576 return util.fsencode(filename)603 return util.fsencode(filename)
604=======
605 return filename.encode(globals.fsencoding, 'replace')
606>>>>>>> MERGE-SOURCE
577 else:607 else:
578 return filename608 return filename
579609
580610
=== modified file 'duplicity/backends/_cf_pyrax.py'
--- duplicity/backends/_cf_pyrax.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/_cf_pyrax.py 2019-03-04 12:09:45 +0000
@@ -71,6 +71,7 @@
7171
72 self.client_exc = pyrax.exceptions.ClientException72 self.client_exc = pyrax.exceptions.ClientException
73 self.nso_exc = pyrax.exceptions.NoSuchObject73 self.nso_exc = pyrax.exceptions.NoSuchObject
74<<<<<<< TREE
7475
75 # query rackspace for the specified container name76 # query rackspace for the specified container name
76 try:77 try:
@@ -90,6 +91,27 @@
90 u"You may be using a read-only user that can view but not create containers.\n" +91 u"You may be using a read-only user that can view but not create containers.\n" +
91 u"Please check your credentials and permissions.",92 u"Please check your credentials and permissions.",
92 log.ErrorCode.backend_permission_denied)93 log.ErrorCode.backend_permission_denied)
94=======
95
96 # query rackspace for the specified container name
97 try:
98 self.container = pyrax.cloudfiles.get_container(container)
99 except pyrax.exceptions.Forbidden as e:
100 log.FatalError("%s : %s \n" % (e.__class__.__name__, util.uexc(e)) +
101 "Container may exist, but access was denied.\n" +
102 "If this container exists, please check its X-Container-Read/Write headers.\n" +
103 "Otherwise, please check your credentials and permissions.",
104 log.ErrorCode.backend_permission_denied)
105 except pyrax.exceptions.NoSuchContainer as e:
106 try:
107 self.container = pyrax.cloudfiles.create_container(container)
108 except pyrax.exceptions.Forbidden as e:
109 log.FatalError("%s : %s \n" % (e.__class__.__name__, util.uexc(e)) +
110 "Container does not exist, but creation was denied.\n" +
111 "You may be using a read-only user that can view but not create containers.\n" +
112 "Please check your credentials and permissions.",
113 log.ErrorCode.backend_permission_denied)
114>>>>>>> MERGE-SOURCE
93115
94 def _error_code(self, operation, e):116 def _error_code(self, operation, e):
95 if isinstance(e, self.nso_exc):117 if isinstance(e, self.nso_exc):
96118
=== added file 'duplicity/backends/acdclibackend.py.OTHER'
--- duplicity/backends/acdclibackend.py.OTHER 1970-01-01 00:00:00 +0000
+++ duplicity/backends/acdclibackend.py.OTHER 2019-03-04 12:09:45 +0000
@@ -0,0 +1,151 @@
1# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
2#
3# Copyright 2015 Stefan Breunig <stefan-duplicity@breunig.xyz>
4# Copyright 2015 Malay Shah <malays@gmail.com>
5# Based on the backend ncftpbackend.py
6#
7# This file is part of duplicity.
8#
9# Duplicity is free software; you can redistribute it and/or modify it
10# under the terms of the GNU General Public License as published by the
11# Free Software Foundation; either version 2 of the License, or (at your
12# option) any later version.
13#
14# Duplicity is distributed in the hope that it will be useful, but
15# WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17# General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with duplicity; if not, write to the Free Software Foundation,
21# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
23import os.path
24import urllib
25import string
26import json
27
28import duplicity.backend
29from duplicity import globals
30from duplicity import log
31from duplicity.errors import * # @UnusedWildImport
32from duplicity import tempdir
33
34
35class ACDBackend(duplicity.backend.Backend):
36 acd_cmd = 'acd_cli'
37 """Connect to remote store using acd_cli"""
38 def __init__(self, parsed_url):
39 duplicity.backend.Backend.__init__(self, parsed_url)
40
41 # we expect an error return, so go low-level and ignore it
42 try:
43 p = os.popen(self.acd_cmd + " version")
44 fout = p.read()
45 ret = p.close()
46 except Exception:
47 pass
48 # the expected error is 0
49 if ret is not None:
50 log.FatalError(self.acd_cmd + " not found: Please install acd_cli",
51 log.ErrorCode.backend_not_found)
52
53 self.parsed_url = parsed_url
54 self.url_string = duplicity.backend.strip_auth_from_url(self.parsed_url)
55
56 # Use an explicit directory name.
57 if self.url_string[-1] != '/':
58 self.url_string += '/'
59
60 self.subprocess_popen(self.acd_cmd + " sync")
61
62 # Initialize remote directory
63 remote_path = urllib.unquote(self.parsed_url.path.replace('///', '/')).rstrip()
64 commandline = self.acd_cmd + " ls '%s'" % (remote_path)
65 try:
66 self.subprocess_popen(commandline)
67 except BackendException as e:
68 if e.code == 50: # Remote directory not there, create a new one
69 commandline = self.acd_cmd + " mkdir '%s'" % remote_path
70 self.subprocess_popen(commandline)
71
72 def _put(self, source_path, remote_filename=None):
73 """Transfer source_path to remote_filename"""
74 if not remote_filename:
75 remote_filename = source_path.get_filename()
76
77 # WORKAROUND for acd_cli: cannot specify remote filename
78 # Link tmp file to the desired remote filename locally and upload
79 remote_path = urllib.unquote(self.parsed_url.path.replace('///', '/'))
80 local_real_duplicity_file = os.path.join(os.path.dirname(source_path.name), remote_filename.rstrip())
81
82 deleteFile = False
83 if(source_path.name != local_real_duplicity_file):
84 try:
85 os.symlink(source_path.name, local_real_duplicity_file)
86 deleteFile = True
87 except IOError as e:
88 log.FatalError("Unable to copy " + source_path.name + " to " + local_real_duplicity_file)
89
90 commandline = self.acd_cmd + " upload --force --overwrite '%s' '%s'" % \
91 (local_real_duplicity_file, remote_path)
92
93 try:
94 l = self.subprocess_popen(commandline)
95 finally:
96 if (deleteFile):
97 try:
98 os.remove(local_real_duplicity_file)
99 except OSError as e:
100 log.FatalError("Unable to remove file %s" % e)
101
102 def _get(self, remote_filename, local_path):
103 """Get remote filename, saving it to local_path"""
104 remote_path = os.path.join(urllib.unquote(self.parsed_url.path.replace('///', '/')), remote_filename).rstrip()
105 local_dir = os.path.dirname(local_path.name)
106 local_filename = os.path.basename(local_path.name)
107 commandline = self.acd_cmd + " download '%s' '%s'" % \
108 (remote_path, local_dir)
109 l = self.subprocess_popen(commandline)
110
111 # Keep the remote filename and move the file over
112 try:
113 os.rename(os.path.join(local_dir, remote_filename), local_path.name)
114 except IOError as e:
115 log.FatalError("Unable to move file %s" % e)
116
117 local_path.setdata()
118 if not local_path.exists():
119 raise BackendException("File %s not found" % local_path.name)
120
121 def _query(self, remote_filename):
122 remote_path = os.path.join(urllib.unquote(self.parsed_url.path.replace('///', '/')), remote_filename).rstrip()
123 commandline = self.acd_cmd + " metadata '%s'" % remote_path
124 node = self.subprocess_popen(commandline)
125 if (node[0] == 0 and node[1]):
126 try:
127 size = json.loads(node[1])['contentProperties']['size']
128 return {'size': size}
129 except ValueError as e:
130 raise BackendException('Malformed JSON: expected "contentProperties->size" member in %s' % node[1])
131 return {'size': -1}
132
133 def _list(self):
134 """List files in directory"""
135 def dir_split(str):
136 if (str):
137 return str.split()[2]
138 else:
139 return None
140 commandline = self.acd_cmd + " ls '%s'" % self.parsed_url.path.replace('///', '/')
141 l = self.subprocess_popen(commandline)
142 return [x for x in map(dir_split, l[1].split('\n')) if x]
143
144 def _delete(self, remote_filename):
145 """Delete remote_filename"""
146 remote_file_path = os.path.join(urllib.unquote(self.parsed_url.path.replace('///', '/')),
147 remote_filename).rstrip()
148 commandline = self.acd_cmd + " rm '%s'" % (remote_file_path)
149 self.subprocess_popen(commandline)
150
151duplicity.backend.register_backend("acd+acdcli", ACDBackend)
0152
=== renamed file 'duplicity/backends/adbackend.py' => 'duplicity/backends/adbackend.py.THIS'
=== modified file 'duplicity/backends/azurebackend.py'
--- duplicity/backends/azurebackend.py 2019-01-01 21:36:27 +0000
+++ duplicity/backends/azurebackend.py 2019-03-04 12:09:45 +0000
@@ -23,7 +23,6 @@
23import os23import os
2424
25import duplicity.backend25import duplicity.backend
26from duplicity import globals
27from duplicity import log26from duplicity import log
28from duplicity.errors import BackendException27from duplicity.errors import BackendException
2928
@@ -46,11 +45,15 @@
46 self.AzureConflictError = azure.WindowsAzureConflictError45 self.AzureConflictError = azure.WindowsAzureConflictError
47 else:46 else:
48 # v1.0.0 and above47 # v1.0.0 and above
48<<<<<<< TREE
49 import azure.storage.blob49 import azure.storage.blob
50 if hasattr(azure.storage.blob, u'BlobService'):50 if hasattr(azure.storage.blob, u'BlobService'):
51 from azure.storage.blob import BlobService51 from azure.storage.blob import BlobService
52 else:52 else:
53 from azure.storage.blob.blockblobservice import BlockBlobService as BlobService53 from azure.storage.blob.blockblobservice import BlockBlobService as BlobService
54=======
55 from azure.storage.blob import BlobService
56>>>>>>> MERGE-SOURCE
54 self.AzureMissingResourceError = azure.common.AzureMissingResourceHttpError57 self.AzureMissingResourceError = azure.common.AzureMissingResourceHttpError
55 self.AzureConflictError = azure.common.AzureConflictHttpError58 self.AzureConflictError = azure.common.AzureConflictHttpError
56 except ImportError as e:59 except ImportError as e:
@@ -58,7 +61,15 @@
58Azure backend requires Microsoft Azure Storage SDK for Python (https://pypi.python.org/pypi/azure-storage/).61Azure backend requires Microsoft Azure Storage SDK for Python (https://pypi.python.org/pypi/azure-storage/).
59Exception: %s""" % str(e))62Exception: %s""" % str(e))
6063
64 if 'AZURE_ACCOUNT_NAME' not in os.environ:
65 raise BackendException('AZURE_ACCOUNT_NAME environment variable not set.')
66 if 'AZURE_ACCOUNT_KEY' not in os.environ:
67 raise BackendException('AZURE_ACCOUNT_KEY environment variable not set.')
68 self.blob_service = BlobService(account_name=os.environ['AZURE_ACCOUNT_NAME'],
69 account_key=os.environ['AZURE_ACCOUNT_KEY'])
70
61 # TODO: validate container name71 # TODO: validate container name
72<<<<<<< TREE
62 self.container = parsed_url.path.lstrip(u'/')73 self.container = parsed_url.path.lstrip(u'/')
6374
64 if u'AZURE_ACCOUNT_NAME' not in os.environ:75 if u'AZURE_ACCOUNT_NAME' not in os.environ:
@@ -104,6 +115,9 @@
104 self.blob_service._BLOB_MAX_CHUNK_DATA_SIZE = globals.azure_max_block_size115 self.blob_service._BLOB_MAX_CHUNK_DATA_SIZE = globals.azure_max_block_size
105 116
106 def _create_container(self):117 def _create_container(self):
118=======
119 self.container = parsed_url.path.lstrip('/')
120>>>>>>> MERGE-SOURCE
107 try:121 try:
108 self.blob_service.create_container(self.container, fail_on_exist=True)122 self.blob_service.create_container(self.container, fail_on_exist=True)
109 except self.AzureConflictError:123 except self.AzureConflictError:
@@ -115,11 +129,15 @@
115 log.ErrorCode.connection_failed)129 log.ErrorCode.connection_failed)
116130
117 def _put(self, source_path, remote_filename):131 def _put(self, source_path, remote_filename):
132<<<<<<< TREE
118 kwargs = {}133 kwargs = {}
119 if globals.azure_max_connections:134 if globals.azure_max_connections:
120 kwargs[u'max_connections'] = globals.azure_max_connections135 kwargs[u'max_connections'] = globals.azure_max_connections
121136
137=======
138>>>>>>> MERGE-SOURCE
122 # https://azure.microsoft.com/en-us/documentation/articles/storage-python-how-to-use-blob-storage/#upload-a-blob-into-a-container139 # https://azure.microsoft.com/en-us/documentation/articles/storage-python-how-to-use-blob-storage/#upload-a-blob-into-a-container
140<<<<<<< TREE
123 try:141 try:
124 self.blob_service.create_blob_from_path(self.container, remote_filename, source_path.name, **kwargs)142 self.blob_service.create_blob_from_path(self.container, remote_filename, source_path.name, **kwargs)
125 except AttributeError: # Old versions use a different method name143 except AttributeError: # Old versions use a different method name
@@ -134,6 +152,10 @@
134 except AttributeError: # might not be available in old API152 except AttributeError: # might not be available in old API
135 pass153 pass
136 154
155=======
156 self.blob_service.put_block_blob_from_path(self.container, remote_filename, source_path.name)
157
158>>>>>>> MERGE-SOURCE
137 def _get(self, remote_filename, local_path):159 def _get(self, remote_filename, local_path):
138 # https://azure.microsoft.com/en-us/documentation/articles/storage-python-how-to-use-blob-storage/#download-blobs160 # https://azure.microsoft.com/en-us/documentation/articles/storage-python-how-to-use-blob-storage/#download-blobs
139 self.blob_service.get_blob_to_path(self.container, remote_filename, local_path.name)161 self.blob_service.get_blob_to_path(self.container, remote_filename, local_path.name)
@@ -156,16 +178,24 @@
156178
157 def _query(self, filename):179 def _query(self, filename):
158 prop = self.blob_service.get_blob_properties(self.container, filename)180 prop = self.blob_service.get_blob_properties(self.container, filename)
181<<<<<<< TREE
159 try:182 try:
160 info = {u'size': int(prop.properties.content_length)}183 info = {u'size': int(prop.properties.content_length)}
161 except AttributeError:184 except AttributeError:
162 # old versions directly returned the properties185 # old versions directly returned the properties
163 info = {u'size': int(prop[u'content-length'])}186 info = {u'size': int(prop[u'content-length'])}
164 return info187 return info
188=======
189 return {'size': int(prop['content-length'])}
190>>>>>>> MERGE-SOURCE
165191
166 def _error_code(self, operation, e):192 def _error_code(self, operation, e):
167 if isinstance(e, self.AzureMissingResourceError):193 if isinstance(e, self.AzureMissingResourceError):
168 return log.ErrorCode.backend_not_found194 return log.ErrorCode.backend_not_found
169195
196<<<<<<< TREE
170197
171duplicity.backend.register_backend(u'azure', AzureBackend)198duplicity.backend.register_backend(u'azure', AzureBackend)
199=======
200duplicity.backend.register_backend('azure', AzureBackend)
201>>>>>>> MERGE-SOURCE
172202
=== modified file 'duplicity/backends/b2backend.py'
--- duplicity/backends/b2backend.py 2018-12-27 16:43:07 +0000
+++ duplicity/backends/b2backend.py 2019-03-04 12:09:45 +0000
@@ -27,11 +27,15 @@
27from builtins import object27from builtins import object
28import os28import os
29import hashlib29import hashlib
30<<<<<<< TREE
30from urllib.parse import quote_plus # pylint: disable=import-error31from urllib.parse import quote_plus # pylint: disable=import-error
32=======
33>>>>>>> MERGE-SOURCE
3134
32import duplicity.backend35import duplicity.backend
33from duplicity.errors import BackendException, FatalBackendException36from duplicity.errors import BackendException, FatalBackendException
34from duplicity import log37from duplicity import log
38<<<<<<< TREE
35from duplicity import progress39from duplicity import progress
3640
3741
@@ -50,6 +54,30 @@
5054
51 def __exit__(self, exc_type, exc_val, exc_tb):55 def __exit__(self, exc_type, exc_val, exc_tb):
52 pass56 pass
57=======
58from duplicity import progress
59
60
61def progress_listener_factory():
62 u"""
63 Returns progress instance suitable for passing to b2.api.B2Api
64 methods.
65 """
66 class B2ProgressListener(b2.progress.AbstractProgressListener):
67 def __init__(self):
68 super(B2ProgressListener, self).__init__()
69
70 def set_total_bytes(self, total_byte_count):
71 self.total_byte_count = total_byte_count
72
73 def bytes_completed(self, byte_count):
74 progress.report_transfer(byte_count, self.total_byte_count)
75
76 def close(self):
77 super(B2ProgressListener, self).close()
78 return B2ProgressListener()
79
80>>>>>>> MERGE-SOURCE
5381
54class B2Backend(duplicity.backend.Backend):82class B2Backend(duplicity.backend.Backend):
55 u"""83 u"""
@@ -62,6 +90,7 @@
62 """90 """
63 duplicity.backend.Backend.__init__(self, parsed_url)91 duplicity.backend.Backend.__init__(self, parsed_url)
6492
93<<<<<<< TREE
65 # Import B2 API94 # Import B2 API
66 try:95 try:
67 global b296 global b2
@@ -77,6 +106,24 @@
77 self.parsed_url.hostname = u'B2'106 self.parsed_url.hostname = u'B2'
78107
79 account_id = parsed_url.username108 account_id = parsed_url.username
109=======
110 # Import B2 API
111 try:
112 global b2
113 import b2
114 import b2.api
115 import b2.account_info
116 import b2.download_dest
117 import b2.file_version
118 import b2.progress
119 except ImportError:
120 raise BackendException('B2 backend requires B2 Python APIs (pip install b2)')
121
122 self.service = b2.api.B2Api(b2.account_info.InMemoryAccountInfo())
123 self.parsed_url.hostname = 'B2'
124
125 account_id = parsed_url.username
126>>>>>>> MERGE-SOURCE
80 account_key = self.get_password()127 account_key = self.get_password()
81128
82 self.url_parts = [129 self.url_parts = [
@@ -86,13 +133,23 @@
86 self.username = self.url_parts.pop(0)133 self.username = self.url_parts.pop(0)
87 bucket_name = self.url_parts.pop(0)134 bucket_name = self.url_parts.pop(0)
88 else:135 else:
136<<<<<<< TREE
89 raise BackendException(u"B2 requires a bucket name")137 raise BackendException(u"B2 requires a bucket name")
90 self.path = u"".join([url_part + u"/" for url_part in self.url_parts])138 self.path = u"".join([url_part + u"/" for url_part in self.url_parts])
91 self.service.authorize_account(u'production', account_id, account_key)139 self.service.authorize_account(u'production', account_id, account_key)
92140
93 log.Log(u"B2 Backend (path= %s, bucket= %s, minimum_part_size= %s)" %141 log.Log(u"B2 Backend (path= %s, bucket= %s, minimum_part_size= %s)" %
94 (self.path, bucket_name, self.service.account_info.get_minimum_part_size()), log.INFO)142 (self.path, bucket_name, self.service.account_info.get_minimum_part_size()), log.INFO)
143=======
144 raise BackendException("B2 requires a bucket name")
145 self.path = "".join([url_part + "/" for url_part in self.url_parts])
146 self.service.authorize_account('production', account_id, account_key)
147
148 log.Log("B2 Backend (path= %s, bucket= %s, minimum_part_size= %s)" %
149 (self.path, bucket_name, self.service.account_info.get_minimum_part_size()), log.INFO)
150>>>>>>> MERGE-SOURCE
95 try:151 try:
152<<<<<<< TREE
96 self.bucket = self.service.get_bucket_by_name(bucket_name)153 self.bucket = self.service.get_bucket_by_name(bucket_name)
97 log.Log(u"Bucket found", log.INFO)154 log.Log(u"Bucket found", log.INFO)
98 except b2.exception.NonExistentBucket:155 except b2.exception.NonExistentBucket:
@@ -101,23 +158,46 @@
101 self.bucket = self.service.create_bucket(bucket_name, u'allPrivate')158 self.bucket = self.service.create_bucket(bucket_name, u'allPrivate')
102 except:159 except:
103 raise FatalBackendException(u"Bucket cannot be created")160 raise FatalBackendException(u"Bucket cannot be created")
161=======
162 self.bucket = self.service.get_bucket_by_name(bucket_name)
163 log.Log("Bucket found", log.INFO)
164 except b2.exception.NonExistentBucket:
165 try:
166 log.Log("Bucket not found, creating one", log.INFO)
167 self.bucket = self.service.create_bucket(bucket_name, 'allPrivate')
168 except:
169 raise FatalBackendException("Bucket cannot be created")
170>>>>>>> MERGE-SOURCE
104171
105 def _get(self, remote_filename, local_path):172 def _get(self, remote_filename, local_path):
106 u"""173 u"""
107 Download remote_filename to local_path174 Download remote_filename to local_path
108 """175 """
176<<<<<<< TREE
109 log.Log(u"Get: %s -> %s" % (self.path + remote_filename, local_path.name), log.INFO)177 log.Log(u"Get: %s -> %s" % (self.path + remote_filename, local_path.name), log.INFO)
110 self.bucket.download_file_by_name(quote_plus(self.path + remote_filename),178 self.bucket.download_file_by_name(quote_plus(self.path + remote_filename),
111 b2.download_dest.DownloadDestLocalFile(local_path.name))179 b2.download_dest.DownloadDestLocalFile(local_path.name))
180=======
181 log.Log("Get: %s -> %s" % (self.path + remote_filename, local_path.name), log.INFO)
182 self.bucket.download_file_by_name(self.path + remote_filename,
183 b2.download_dest.DownloadDestLocalFile(local_path.name))
184>>>>>>> MERGE-SOURCE
112185
113 def _put(self, source_path, remote_filename):186 def _put(self, source_path, remote_filename):
114 u"""187 u"""
115 Copy source_path to remote_filename188 Copy source_path to remote_filename
116 """189 """
190<<<<<<< TREE
117 log.Log(u"Put: %s -> %s" % (source_path.name, self.path + remote_filename), log.INFO)191 log.Log(u"Put: %s -> %s" % (source_path.name, self.path + remote_filename), log.INFO)
118 self.bucket.upload_local_file(source_path.name, quote_plus(self.path + remote_filename),192 self.bucket.upload_local_file(source_path.name, quote_plus(self.path + remote_filename),
119 content_type=u'application/pgp-encrypted',193 content_type=u'application/pgp-encrypted',
120 progress_listener=B2ProgressListener())194 progress_listener=B2ProgressListener())
195=======
196 log.Log("Put: %s -> %s" % (source_path.name, self.path + remote_filename), log.INFO)
197 self.bucket.upload_local_file(source_path.name, self.path + remote_filename,
198 content_type='application/pgp-encrypted',
199 progress_listener=progress_listener_factory())
200>>>>>>> MERGE-SOURCE
121201
122 def _list(self):202 def _list(self):
123 u"""203 u"""
@@ -130,14 +210,21 @@
130 u"""210 u"""
131 Delete filename from remote server211 Delete filename from remote server
132 """212 """
213<<<<<<< TREE
133 log.Log(u"Delete: %s" % self.path + filename, log.INFO)214 log.Log(u"Delete: %s" % self.path + filename, log.INFO)
134 file_version_info = self.file_info(quote_plus(self.path + filename))215 file_version_info = self.file_info(quote_plus(self.path + filename))
135 self.bucket.delete_file_version(file_version_info.id_, file_version_info.file_name)216 self.bucket.delete_file_version(file_version_info.id_, file_version_info.file_name)
217=======
218 log.Log("Delete: %s" % self.path + filename, log.INFO)
219 file_version_info = self.file_info(self.path + filename)
220 self.bucket.delete_file_version(file_version_info.id_, file_version_info.file_name)
221>>>>>>> MERGE-SOURCE
136222
137 def _query(self, filename):223 def _query(self, filename):
138 u"""224 u"""
139 Get size info of filename225 Get size info of filename
140 """226 """
227<<<<<<< TREE
141 log.Log(u"Query: %s" % self.path + filename, log.INFO)228 log.Log(u"Query: %s" % self.path + filename, log.INFO)
142 file_version_info = self.file_info(quote_plus(self.path + filename))229 file_version_info = self.file_info(quote_plus(self.path + filename))
143 return {u'size': file_version_info.size230 return {u'size': file_version_info.size
@@ -153,3 +240,20 @@
153240
154241
155duplicity.backend.register_backend(u"b2", B2Backend)242duplicity.backend.register_backend(u"b2", B2Backend)
243=======
244 log.Log("Query: %s" % self.path + filename, log.INFO)
245 file_version_info = self.file_info(self.path + filename)
246 return {'size': file_version_info.size
247 if file_version_info is not None and file_version_info.size is not None else -1}
248
249 def file_info(self, filename):
250 response = self.bucket.list_file_names(filename, 1)
251 for entry in response['files']:
252 file_version_info = b2.file_version.FileVersionInfoFactory.from_api_response(entry)
253 if file_version_info.file_name == filename:
254 return file_version_info
255 raise BackendException('File not found')
256
257
258duplicity.backend.register_backend("b2", B2Backend)
259>>>>>>> MERGE-SOURCE
156260
=== modified file 'duplicity/backends/dpbxbackend.py'
--- duplicity/backends/dpbxbackend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/dpbxbackend.py 2019-03-04 12:09:45 +0000
@@ -45,7 +45,21 @@
45from duplicity import log, globals45from duplicity import log, globals
46from duplicity import progress46from duplicity import progress
47from duplicity.errors import BackendException47from duplicity.errors import BackendException
48<<<<<<< TREE
48from duplicity.globals import num_retries49from duplicity.globals import num_retries
50=======
51import os
52import sys
53import traceback
54import urllib
55import re
56
57from dropbox import Dropbox
58from dropbox.exceptions import AuthError, BadInputError, ApiError
59from dropbox.files import UploadSessionCursor, CommitInfo, WriteMode, \
60 GetMetadataError, DeleteError, UploadSessionLookupError, ListFolderError
61from dropbox.oauth import DropboxOAuth2FlowNoRedirect
62>>>>>>> MERGE-SOURCE
49from requests.exceptions import ConnectionError63from requests.exceptions import ConnectionError
50import duplicity.backend64import duplicity.backend
5165
@@ -164,12 +178,23 @@
164 print(u'-' * 72)178 print(u'-' * 72)
165 auth_code = input(u"Enter the authorization code here: ").strip()179 auth_code = input(u"Enter the authorization code here: ").strip()
166 try:180 try:
181<<<<<<< TREE
167 log.Debug(u'dpbx,auth_flow.finish(%s)' % auth_code)182 log.Debug(u'dpbx,auth_flow.finish(%s)' % auth_code)
168 authresult = auth_flow.finish(auth_code)183 authresult = auth_flow.finish(auth_code)
184=======
185 log.Debug('dpbx,auth_flow.finish(%s)' % auth_code)
186 authresult = auth_flow.finish(auth_code)
187>>>>>>> MERGE-SOURCE
169 except Exception as e:188 except Exception as e:
189<<<<<<< TREE
170 raise BackendException(u'dpbx: Unable to obtain access token: %s' % e)190 raise BackendException(u'dpbx: Unable to obtain access token: %s' % e)
171 log.Info(u"dpbx: Authentication successfull")191 log.Info(u"dpbx: Authentication successfull")
172 self.save_access_token(authresult.access_token)192 self.save_access_token(authresult.access_token)
193=======
194 raise BackendException('dpbx: Unable to obtain access token: %s' % e)
195 log.Info("dpbx: Authentication successfull")
196 self.save_access_token(authresult.access_token)
197>>>>>>> MERGE-SOURCE
173198
174 def login(self):199 def login(self):
175 if self.load_access_token() is None:200 if self.load_access_token() is None:
@@ -403,10 +428,17 @@
403 # Do a long listing to avoid connection reset428 # Do a long listing to avoid connection reset
404 if not self.user_authenticated():429 if not self.user_authenticated():
405 self.login()430 self.login()
431<<<<<<< TREE
406 remote_dir = u'/' + urllib.parse.unquote(self.parsed_url.path.lstrip(u'/')).rstrip()432 remote_dir = u'/' + urllib.parse.unquote(self.parsed_url.path.lstrip(u'/')).rstrip()
407433
408 log.Debug(u'dpbx.files_list_folder(%s)' % remote_dir)434 log.Debug(u'dpbx.files_list_folder(%s)' % remote_dir)
435=======
436 remote_dir = '/' + urllib.unquote(self.parsed_url.path.lstrip('/')).rstrip()
437
438 log.Debug('dpbx.files_list_folder(%s)' % remote_dir)
439>>>>>>> MERGE-SOURCE
409 res = []440 res = []
441<<<<<<< TREE
410 try:442 try:
411 resp = self.api_client.files_list_folder(remote_dir)443 resp = self.api_client.files_list_folder(remote_dir)
412 log.Debug(u'dpbx.list(%s): %s' % (remote_dir, resp))444 log.Debug(u'dpbx.list(%s): %s' % (remote_dir, resp))
@@ -422,6 +454,23 @@
422 log.Debug(u'dpbx.list(%s): ignore missing folder (%s)' % (remote_dir, e))454 log.Debug(u'dpbx.list(%s): ignore missing folder (%s)' % (remote_dir, e))
423 else:455 else:
424 raise456 raise
457=======
458 try:
459 resp = self.api_client.files_list_folder(remote_dir)
460 log.Debug('dpbx.list(%s): %s' % (remote_dir, resp))
461
462 while True:
463 res.extend([entry.name for entry in resp.entries])
464 if not resp.has_more:
465 break
466 resp = self.api_client.files_list_folder_continue(resp.cursor)
467 except ApiError as e:
468 if (isinstance(e.error, ListFolderError) and e.error.is_path() and
469 e.error.get_path().is_not_found()):
470 log.Debug('dpbx.list(%s): ignore missing folder (%s)' % (remote_dir, e))
471 else:
472 raise
473>>>>>>> MERGE-SOURCE
425474
426 # Warn users of old version dpbx about automatically renamed files475 # Warn users of old version dpbx about automatically renamed files
427 self.check_renamed_files(res)476 self.check_renamed_files(res)
428477
=== modified file 'duplicity/backends/gdocsbackend.py'
--- duplicity/backends/gdocsbackend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/gdocsbackend.py 2019-03-04 12:09:45 +0000
@@ -193,7 +193,13 @@
193 # Done!193 # Done!
194 return result194 return result
195195
196<<<<<<< TREE
196197
197u""" gdata is an alternate way to access gdocs, currently 05/2015 lacking OAuth support """198u""" gdata is an alternate way to access gdocs, currently 05/2015 lacking OAuth support """
198duplicity.backend.register_backend(u'gdata+gdocs', GDocsBackend)199duplicity.backend.register_backend(u'gdata+gdocs', GDocsBackend)
199duplicity.backend.uses_netloc.extend([u'gdata+gdocs'])200duplicity.backend.uses_netloc.extend([u'gdata+gdocs'])
201=======
202""" gdata is an alternate way to access gdocs, currently 05/2015 lacking OAuth support """
203duplicity.backend.register_backend('gdata+gdocs', GDocsBackend)
204duplicity.backend.uses_netloc.extend(['gdata+gdocs'])
205>>>>>>> MERGE-SOURCE
200206
=== modified file 'duplicity/backends/giobackend.py'
--- duplicity/backends/giobackend.py 2018-07-23 14:55:39 +0000
+++ duplicity/backends/giobackend.py 2019-03-04 12:09:45 +0000
@@ -143,8 +143,13 @@
143 self.__copy_file(source_file, target_file)143 self.__copy_file(source_file, target_file)
144144
145 def _get(self, filename, local_path):145 def _get(self, filename, local_path):
146<<<<<<< TREE
146 from gi.repository import Gio # @UnresolvedImport # pylint: disable=import-error147 from gi.repository import Gio # @UnresolvedImport # pylint: disable=import-error
147 source_file = self.remote_file.get_child_for_display_name(filename)148 source_file = self.remote_file.get_child_for_display_name(filename)
149=======
150 from gi.repository import Gio # @UnresolvedImport
151 source_file = self.remote_file.get_child_for_display_name(filename)
152>>>>>>> MERGE-SOURCE
148 target_file = Gio.File.new_for_path(local_path.name)153 target_file = Gio.File.new_for_path(local_path.name)
149 self.__copy_file(source_file, target_file)154 self.__copy_file(source_file, target_file)
150155
@@ -169,11 +174,22 @@
169 target_file.delete(None)174 target_file.delete(None)
170175
171 def _query(self, filename):176 def _query(self, filename):
177<<<<<<< TREE
172 from gi.repository import Gio # @UnresolvedImport # pylint: disable=import-error178 from gi.repository import Gio # @UnresolvedImport # pylint: disable=import-error
173 target_file = self.remote_file.get_child_for_display_name(filename)179 target_file = self.remote_file.get_child_for_display_name(filename)
180=======
181 from gi.repository import Gio # @UnresolvedImport
182 target_file = self.remote_file.get_child_for_display_name(filename)
183>>>>>>> MERGE-SOURCE
174 info = target_file.query_info(Gio.FILE_ATTRIBUTE_STANDARD_SIZE,184 info = target_file.query_info(Gio.FILE_ATTRIBUTE_STANDARD_SIZE,
175 Gio.FileQueryInfoFlags.NONE, None)185 Gio.FileQueryInfoFlags.NONE, None)
186<<<<<<< TREE
176 return {u'size': info.get_size()}187 return {u'size': info.get_size()}
177188
178189
179duplicity.backend.register_backend_prefix(u'gio', GIOBackend)190duplicity.backend.register_backend_prefix(u'gio', GIOBackend)
191=======
192 return {'size': info.get_size()}
193
194duplicity.backend.register_backend_prefix('gio', GIOBackend)
195>>>>>>> MERGE-SOURCE
180196
=== modified file 'duplicity/backends/hsibackend.py'
--- duplicity/backends/hsibackend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/hsibackend.py 2019-03-04 12:09:45 +0000
@@ -65,6 +65,11 @@
65 commandline = u'%s "rm %s%s"' % (hsi_command, self.remote_prefix, filename)65 commandline = u'%s "rm %s%s"' % (hsi_command, self.remote_prefix, filename)
66 self.subprocess_popen(commandline)66 self.subprocess_popen(commandline)
6767
68<<<<<<< TREE
6869
69duplicity.backend.register_backend(u"hsi", HSIBackend)70duplicity.backend.register_backend(u"hsi", HSIBackend)
70duplicity.backend.uses_netloc.extend([u'hsi'])71duplicity.backend.uses_netloc.extend([u'hsi'])
72=======
73duplicity.backend.register_backend("hsi", HSIBackend)
74duplicity.backend.uses_netloc.extend(['hsi'])
75>>>>>>> MERGE-SOURCE
7176
=== modified file 'duplicity/backends/hubicbackend.py'
--- duplicity/backends/hubicbackend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/hubicbackend.py 2019-03-04 12:09:45 +0000
@@ -64,5 +64,9 @@
64 self.nso_exc = pyrax.exceptions.NoSuchObject64 self.nso_exc = pyrax.exceptions.NoSuchObject
65 self.container = pyrax.cloudfiles.create_container(container)65 self.container = pyrax.cloudfiles.create_container(container)
6666
67<<<<<<< TREE
6768
68duplicity.backend.register_backend(u"cf+hubic", HubicBackend)69duplicity.backend.register_backend(u"cf+hubic", HubicBackend)
70=======
71duplicity.backend.register_backend("cf+hubic", HubicBackend)
72>>>>>>> MERGE-SOURCE
6973
=== renamed file 'duplicity/backends/jottacloudbackend.py' => 'duplicity/backends/jottacloudbackend.py.THIS'
=== modified file 'duplicity/backends/lftpbackend.py'
--- duplicity/backends/lftpbackend.py 2019-02-21 21:42:26 +0000
+++ duplicity/backends/lftpbackend.py 2019-03-04 12:09:45 +0000
@@ -205,6 +205,7 @@
205 )205 )
206 log.Debug(u"CMD: %s" % commandline)206 log.Debug(u"CMD: %s" % commandline)
207 _, l, e = self.subprocess_popen(commandline)207 _, l, e = self.subprocess_popen(commandline)
208<<<<<<< TREE
208 log.Debug(u"STDERR:\n"209 log.Debug(u"STDERR:\n"
209 u"%s" % (e))210 u"%s" % (e))
210 log.Debug(u"STDOUT:\n"211 log.Debug(u"STDOUT:\n"
@@ -232,4 +233,32 @@
232 u'lftp+sftp',233 u'lftp+sftp',
233 u'lftp+webdav', u'lftp+webdavs',234 u'lftp+webdav', u'lftp+webdavs',
234 u'lftp+http', u'lftp+https']235 u'lftp+http', u'lftp+https']
236=======
237 log.Debug("STDERR:\n"
238 "%s" % (e))
239 log.Debug("STDOUT:\n"
240 "%s" % (l))
241
242duplicity.backend.register_backend("ftp", LFTPBackend)
243duplicity.backend.register_backend("ftps", LFTPBackend)
244duplicity.backend.register_backend("fish", LFTPBackend)
245duplicity.backend.register_backend("ftpes", LFTPBackend)
246
247duplicity.backend.register_backend("lftp+ftp", LFTPBackend)
248duplicity.backend.register_backend("lftp+ftps", LFTPBackend)
249duplicity.backend.register_backend("lftp+fish", LFTPBackend)
250duplicity.backend.register_backend("lftp+ftpes", LFTPBackend)
251duplicity.backend.register_backend("lftp+sftp", LFTPBackend)
252duplicity.backend.register_backend("lftp+webdav", LFTPBackend)
253duplicity.backend.register_backend("lftp+webdavs", LFTPBackend)
254duplicity.backend.register_backend("lftp+http", LFTPBackend)
255duplicity.backend.register_backend("lftp+https", LFTPBackend)
256
257duplicity.backend.uses_netloc.extend(['ftp', 'ftps', 'fish', 'ftpes',
258 'lftp+ftp', 'lftp+ftps',
259 'lftp+fish', 'lftp+ftpes',
260 'lftp+sftp',
261 'lftp+webdav', 'lftp+webdavs',
262 'lftp+http', 'lftp+https']
263>>>>>>> MERGE-SOURCE
235 )264 )
236265
=== modified file 'duplicity/backends/localbackend.py'
--- duplicity/backends/localbackend.py 2018-07-23 14:55:39 +0000
+++ duplicity/backends/localbackend.py 2019-03-04 12:09:45 +0000
@@ -71,7 +71,13 @@
71 target_file = self.remote_pathdir.append(filename)71 target_file = self.remote_pathdir.append(filename)
72 target_file.setdata()72 target_file.setdata()
73 size = target_file.getsize() if target_file.exists() else -173 size = target_file.getsize() if target_file.exists() else -1
74<<<<<<< TREE
74 return {u'size': size}75 return {u'size': size}
7576
7677
77duplicity.backend.register_backend(u"file", LocalBackend)78duplicity.backend.register_backend(u"file", LocalBackend)
79=======
80 return {'size': size}
81
82duplicity.backend.register_backend("file", LocalBackend)
83>>>>>>> MERGE-SOURCE
7884
=== modified file 'duplicity/backends/megabackend.py'
--- duplicity/backends/megabackend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/megabackend.py 2019-03-04 12:09:45 +0000
@@ -34,6 +34,7 @@
34 def __init__(self, parsed_url):34 def __init__(self, parsed_url):
35 duplicity.backend.Backend.__init__(self, parsed_url)35 duplicity.backend.Backend.__init__(self, parsed_url)
3636
37<<<<<<< TREE
37 # ensure all the necessary megatools binaries exist38 # ensure all the necessary megatools binaries exist
38 self._check_binary_exists(u'megals')39 self._check_binary_exists(u'megals')
39 self._check_binary_exists(u'megamkdir')40 self._check_binary_exists(u'megamkdir')
@@ -61,7 +62,37 @@
61 def _check_binary_exists(self, cmd):62 def _check_binary_exists(self, cmd):
62 u'checks that a specified command exists in the current path'63 u'checks that a specified command exists in the current path'
6364
65=======
66 # ensure all the necessary megatools binaries exist
67 self._check_binary_exists('megals')
68 self._check_binary_exists('megamkdir')
69 self._check_binary_exists('megaget')
70 self._check_binary_exists('megaput')
71 self._check_binary_exists('megarm')
72
73 # store some basic info
74 self._hostname = parsed_url.hostname
75
76 if parsed_url.password is None:
77 self._megarc = os.getenv('HOME') + '/.megarc'
78 else:
79 self._megarc = False
80 self._username = parsed_url.username
81 self._password = self.get_password()
82
83 # remote folder (Can we assume /Root prefix?)
84 self._root = '/Root'
85 self._folder = self._root + '/' + parsed_url.path[1:]
86
87 # make sure the remote folder exists (the whole path)
88 self._makedir_recursive(parsed_url.path[1:].split('/'))
89
90 def _check_binary_exists(self, cmd):
91 'checks that a specified command exists in the current path'
92
93>>>>>>> MERGE-SOURCE
64 try:94 try:
95<<<<<<< TREE
65 # ignore the output, we only need the return code96 # ignore the output, we only need the return code
66 subprocess.check_output([u'which', cmd])97 subprocess.check_output([u'which', cmd])
67 except Exception as e:98 except Exception as e:
@@ -90,10 +121,45 @@
90 self._make_dir(p)121 self._make_dir(p)
91 except:122 except:
92 pass123 pass
124=======
125 # ignore the output, we only need the return code
126 subprocess.check_output(['which', cmd])
127 except Exception as e:
128 raise BackendException("command '%s' not found, make sure megatools are installed" % (cmd,))
129
130 def _makedir(self, path):
131 'creates a remote directory'
132
133 if self._megarc:
134 cmd = ['megamkdir', '--config', self._megarc, path]
135 else:
136 cmd = ['megamkdir', '-u', self._username, '-p', self._password, path]
137
138 self.subprocess_popen(cmd)
139
140 def _makedir_recursive(self, path):
141 'creates a remote directory (recursively the whole path), ingores errors'
142
143 print ("mkdir: %s" % ('/'.join(path),))
144
145 p = self._root
146
147 for folder in path:
148 p = p + '/' + folder
149 try:
150 self._make_dir(p)
151 except:
152 pass
153>>>>>>> MERGE-SOURCE
93154
94 def _put(self, source_path, remote_filename):155 def _put(self, source_path, remote_filename):
156<<<<<<< TREE
95 u'uploads file to Mega (deletes it first, to ensure it does not exist)'157 u'uploads file to Mega (deletes it first, to ensure it does not exist)'
96158
159=======
160 'uploads file to Mega (deletes it first, to ensure it does not exist)'
161
162>>>>>>> MERGE-SOURCE
97 try:163 try:
98 self.delete(remote_filename)164 self.delete(remote_filename)
99 except Exception:165 except Exception:
@@ -102,16 +168,29 @@
102 self.upload(local_file=source_path.get_canonical(), remote_file=remote_filename)168 self.upload(local_file=source_path.get_canonical(), remote_file=remote_filename)
103169
104 def _get(self, remote_filename, local_path):170 def _get(self, remote_filename, local_path):
171<<<<<<< TREE
105 u'downloads file from Mega'172 u'downloads file from Mega'
106173
107 self.download(remote_file=remote_filename, local_file=local_path.name)174 self.download(remote_file=remote_filename, local_file=local_path.name)
175=======
176 'downloads file from Mega'
177
178 self.download(remote_file=remote_filename, local_file=local_path.name)
179>>>>>>> MERGE-SOURCE
108180
109 def _list(self):181 def _list(self):
182<<<<<<< TREE
110 u'list files in the backup folder'183 u'list files in the backup folder'
111184
112 return self.folder_contents(files_only=True)185 return self.folder_contents(files_only=True)
186=======
187 'list files in the backup folder'
188
189 return self.folder_contents(files_only=True)
190>>>>>>> MERGE-SOURCE
113191
114 def _delete(self, filename):192 def _delete(self, filename):
193<<<<<<< TREE
115 u'deletes remote '194 u'deletes remote '
116195
117 self.delete(remote_file=filename)196 self.delete(remote_file=filename)
@@ -178,3 +257,71 @@
178257
179duplicity.backend.register_backend(u'mega', MegaBackend)258duplicity.backend.register_backend(u'mega', MegaBackend)
180duplicity.backend.uses_netloc.extend([u'mega'])259duplicity.backend.uses_netloc.extend([u'mega'])
260=======
261 'deletes remote '
262
263 self.delete(remote_file=filename)
264
265 def folder_contents(self, files_only=False):
266 'lists contents of a folder, optionally ignoring subdirectories'
267
268 print ("megals: %s" % (self._folder,))
269
270 if self._megarc:
271 cmd = ['megals', '--config', self._megarc, self._folder]
272 else:
273 cmd = ['megals', '-u', self._username, '-p', self._password, self._folder]
274
275 files = subprocess.check_output(cmd)
276 files = files.strip().split('\n')
277
278 # remove the folder name, including the path separator
279 files = [f[len(self._folder) + 1:] for f in files]
280
281 # optionally ignore entries containing path separator (i.e. not files)
282 if files_only:
283 files = [f for f in files if '/' not in f]
284
285 return files
286
287 def download(self, remote_file, local_file):
288
289 print ("megaget: %s" % (remote_file,))
290
291 if self._megarc:
292 cmd = ['megaget', '--config', self._megarc, '--no-progress',
293 '--path', local_file, self._folder + '/' + remote_file]
294 else:
295 cmd = ['megaget', '-u', self._username, '-p', self._password, '--no-progress',
296 '--path', local_file, self._folder + '/' + remote_file]
297
298 self.subprocess_popen(cmd)
299
300 def upload(self, local_file, remote_file):
301
302 print ("megaput: %s" % (remote_file,))
303
304 if self._megarc:
305 cmd = ['megaput', '--config', self._megarc, '--no-progress',
306 '--path', self._folder + '/' + remote_file, local_file]
307 else:
308 cmd = ['megaput', '-u', self._username, '-p', self._password, '--no-progress',
309 '--path', self._folder + '/' + remote_file, local_file]
310
311 self.subprocess_popen(cmd)
312
313 def delete(self, remote_file):
314
315 print ("megarm: %s" % (remote_file,))
316
317 if self._megarc:
318 cmd = ['megarm', '--config', self._megarc, self._folder + '/' + remote_file]
319 else:
320 cmd = ['megarm', '-u', self._username, '-p', self._password, self._folder + '/' + remote_file]
321
322 self.subprocess_popen(cmd)
323
324
325duplicity.backend.register_backend('mega', MegaBackend)
326duplicity.backend.uses_netloc.extend(['mega'])
327>>>>>>> MERGE-SOURCE
181328
=== modified file 'duplicity/backends/multibackend.py'
--- duplicity/backends/multibackend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/multibackend.py 2019-03-04 12:09:45 +0000
@@ -44,7 +44,6 @@
4444
45 # the stores we are managing45 # the stores we are managing
46 __stores = []46 __stores = []
47 __affinities = {}
4847
49 # Set of known query paramaters48 # Set of known query paramaters
50 __knownQueryParameters = frozenset([49 __knownQueryParameters = frozenset([
@@ -188,6 +187,7 @@
188187
189 store = duplicity.backend.get_backend(url)188 store = duplicity.backend.get_backend(url)
190 self.__stores.append(store)189 self.__stores.append(store)
190<<<<<<< TREE
191191
192 # Prefix affinity192 # Prefix affinity
193 if u'prefixes' in config:193 if u'prefixes' in config:
@@ -201,11 +201,14 @@
201 else:201 else:
202 self.__affinities[prefix] = [store]202 self.__affinities[prefix] = [store]
203203
204=======
205>>>>>>> MERGE-SOURCE
204 # store_list = store.list()206 # store_list = store.list()
205 # log.Log(_("MultiBackend: at init, store %s has %s files")207 # log.Log(_("MultiBackend: at init, store %s has %s files")
206 # % (url, len(store_list)),208 # % (url, len(store_list)),
207 # log.INFO)209 # log.INFO)
208210
211<<<<<<< TREE
209 def _eligible_stores(self, filename):212 def _eligible_stores(self, filename):
210 if self.__affinities:213 if self.__affinities:
211 matching_prefixes = [k for k in list(self.__affinities.keys()) if filename.startswith(k)]214 matching_prefixes = [k for k in list(self.__affinities.keys()) if filename.startswith(k)]
@@ -217,23 +220,21 @@
217 # No affinity rule or no matching store for that prefix220 # No affinity rule or no matching store for that prefix
218 return self.__stores221 return self.__stores
219222
223=======
224>>>>>>> MERGE-SOURCE
220 def _put(self, source_path, remote_filename):225 def _put(self, source_path, remote_filename):
221 # Store an indication of whether any of these passed226 # Store an indication of whether any of these passed
222 passed = False227 passed = False
223
224 # Eligibile stores for this action
225 stores = self._eligible_stores(remote_filename)
226
227 # Mirror mode always starts at zero228 # Mirror mode always starts at zero
228 if self.__mode == u'mirror':229 if self.__mode == u'mirror':
229 self.__write_cursor = 0230 self.__write_cursor = 0
230231
231 first = self.__write_cursor232 first = self.__write_cursor
232 while True:233 while True:
233 store = stores[self.__write_cursor]234 store = self.__stores[self.__write_cursor]
234 try:235 try:
235 next = self.__write_cursor + 1236 next = self.__write_cursor + 1
236 if (next > len(stores) - 1):237 if (next > len(self.__stores) - 1):
237 next = 0238 next = 0
238 log.Log(_(u"MultiBackend: _put: write to store #%s (%s)")239 log.Log(_(u"MultiBackend: _put: write to store #%s (%s)")
239 % (self.__write_cursor, store.backend.parsed_url.url_string),240 % (self.__write_cursor, store.backend.parsed_url.url_string),
@@ -274,9 +275,7 @@
274 # before finally giving up). So we need to get the list first275 # before finally giving up). So we need to get the list first
275 # before we try to fetch276 # before we try to fetch
276 # ENHANCEME: maintain a cached list for each store277 # ENHANCEME: maintain a cached list for each store
277 stores = self._eligible_stores(remote_filename)278 for s in self.__stores:
278
279 for s in stores:
280 list = s.list()279 list = s.list()
281 if remote_filename in list:280 if remote_filename in list:
282 s.get(remote_filename, local_path)281 s.get(remote_filename, local_path)
@@ -307,16 +306,13 @@
307 def _delete(self, filename):306 def _delete(self, filename):
308 # Store an indication on whether any passed307 # Store an indication on whether any passed
309 passed = False308 passed = False
310
311 stores = self._eligible_stores(filename)
312
313 # since the backend operations will be retried, we can't309 # since the backend operations will be retried, we can't
314 # simply try to get from the store, if not found, move to the310 # simply try to get from the store, if not found, move to the
315 # next store (since each failure will be retried n times311 # next store (since each failure will be retried n times
316 # before finally giving up). So we need to get the list first312 # before finally giving up). So we need to get the list first
317 # before we try to delete313 # before we try to delete
318 # ENHANCEME: maintain a cached list for each store314 # ENHANCEME: maintain a cached list for each store
319 for s in stores:315 for s in self.__stores:
320 list = s.list()316 list = s.list()
321 if filename in list:317 if filename in list:
322 s._do_delete(filename)318 s._do_delete(filename)
@@ -333,5 +329,9 @@
333 log.ERROR)329 log.ERROR)
334# raise BackendException("failed to delete")330# raise BackendException("failed to delete")
335331
332<<<<<<< TREE
336333
337duplicity.backend.register_backend(u'multi', MultiBackend)334duplicity.backend.register_backend(u'multi', MultiBackend)
335=======
336duplicity.backend.register_backend('multi', MultiBackend)
337>>>>>>> MERGE-SOURCE
338338
=== modified file 'duplicity/backends/ncftpbackend.py'
--- duplicity/backends/ncftpbackend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/ncftpbackend.py 2019-03-04 12:09:45 +0000
@@ -122,6 +122,11 @@
122 (self.flags, filename, self.url_string)122 (self.flags, filename, self.url_string)
123 self.subprocess_popen(commandline)123 self.subprocess_popen(commandline)
124124
125<<<<<<< TREE
125126
126duplicity.backend.register_backend(u"ncftp+ftp", NCFTPBackend)127duplicity.backend.register_backend(u"ncftp+ftp", NCFTPBackend)
127duplicity.backend.uses_netloc.extend([u'ncftp+ftp'])128duplicity.backend.uses_netloc.extend([u'ncftp+ftp'])
129=======
130duplicity.backend.register_backend("ncftp+ftp", NCFTPBackend)
131duplicity.backend.uses_netloc.extend(['ncftp+ftp'])
132>>>>>>> MERGE-SOURCE
128133
=== modified file 'duplicity/backends/onedrivebackend.py'
--- duplicity/backends/onedrivebackend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/onedrivebackend.py 2019-03-04 12:09:45 +0000
@@ -348,5 +348,9 @@
348 def _retry_cleanup(self):348 def _retry_cleanup(self):
349 self.initialize_oauth2_session()349 self.initialize_oauth2_session()
350350
351<<<<<<< TREE
351352
352duplicity.backend.register_backend(u'onedrive', OneDriveBackend)353duplicity.backend.register_backend(u'onedrive', OneDriveBackend)
354=======
355duplicity.backend.register_backend('onedrive', OneDriveBackend)
356>>>>>>> MERGE-SOURCE
353357
=== modified file 'duplicity/backends/par2backend.py'
--- duplicity/backends/par2backend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/par2backend.py 2019-03-04 12:09:45 +0000
@@ -218,5 +218,9 @@
218 def close(self):218 def close(self):
219 self.wrapped_backend._close()219 self.wrapped_backend._close()
220220
221<<<<<<< TREE
221222
222backend.register_backend_prefix(u'par2', Par2Backend)223backend.register_backend_prefix(u'par2', Par2Backend)
224=======
225backend.register_backend_prefix('par2', Par2Backend)
226>>>>>>> MERGE-SOURCE
223227
=== renamed file 'duplicity/backends/pcabackend.py' => 'duplicity/backends/pcabackend.py.THIS'
=== modified file 'duplicity/backends/pydrivebackend.py'
--- duplicity/backends/pydrivebackend.py 2019-02-24 15:09:46 +0000
+++ duplicity/backends/pydrivebackend.py 2019-03-04 12:09:45 +0000
@@ -93,8 +93,13 @@
93 else:93 else:
94 file_in_root = self.drive.CreateFile({u'title': u'i_am_in_root'})94 file_in_root = self.drive.CreateFile({u'title': u'i_am_in_root'})
95 file_in_root.Upload()95 file_in_root.Upload()
96<<<<<<< TREE
96 parent_folder_id = file_in_root[u'parents'][0][u'id']97 parent_folder_id = file_in_root[u'parents'][0][u'id']
97 file_in_root.Delete()98 file_in_root.Delete()
99=======
100 parent_folder_id = file_in_root['parents'][0]['id']
101 file_in_root.Delete()
102>>>>>>> MERGE-SOURCE
98103
99 # Fetch destination folder entry and create hierarchy if required.104 # Fetch destination folder entry and create hierarchy if required.
100 folder_names = string.split(parsed_url.path, u'/')105 folder_names = string.split(parsed_url.path, u'/')
@@ -215,11 +220,19 @@
215 return log.ErrorCode.backend_permission_denied220 return log.ErrorCode.backend_permission_denied
216 return log.ErrorCode.backend_error221 return log.ErrorCode.backend_error
217222
223<<<<<<< TREE
218224
219duplicity.backend.register_backend(u'pydrive', PyDriveBackend)225duplicity.backend.register_backend(u'pydrive', PyDriveBackend)
220u""" pydrive is an alternate way to access gdocs """226u""" pydrive is an alternate way to access gdocs """
221duplicity.backend.register_backend(u'pydrive+gdocs', PyDriveBackend)227duplicity.backend.register_backend(u'pydrive+gdocs', PyDriveBackend)
222u""" register pydrive as the default way to access gdocs """228u""" register pydrive as the default way to access gdocs """
223duplicity.backend.register_backend(u'gdocs', PyDriveBackend)229duplicity.backend.register_backend(u'gdocs', PyDriveBackend)
230=======
231duplicity.backend.register_backend('pydrive', PyDriveBackend)
232""" pydrive is an alternate way to access gdocs """
233duplicity.backend.register_backend('pydrive+gdocs', PyDriveBackend)
234""" register pydrive as the default way to access gdocs """
235duplicity.backend.register_backend('gdocs', PyDriveBackend)
236>>>>>>> MERGE-SOURCE
224237
225duplicity.backend.uses_netloc.extend([u'pydrive', u'pydrive+gdocs', u'gdocs'])238duplicity.backend.uses_netloc.extend([u'pydrive', u'pydrive+gdocs', u'gdocs'])
226239
=== modified file 'duplicity/backends/rsyncbackend.py'
--- duplicity/backends/rsyncbackend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/rsyncbackend.py 2019-03-04 12:09:45 +0000
@@ -155,6 +155,11 @@
155 util.ignore_missing(os.unlink, file)155 util.ignore_missing(os.unlink, file)
156 os.rmdir(dir)156 os.rmdir(dir)
157157
158<<<<<<< TREE
158159
159duplicity.backend.register_backend(u"rsync", RsyncBackend)160duplicity.backend.register_backend(u"rsync", RsyncBackend)
160duplicity.backend.uses_netloc.extend([u'rsync'])161duplicity.backend.uses_netloc.extend([u'rsync'])
162=======
163duplicity.backend.register_backend("rsync", RsyncBackend)
164duplicity.backend.uses_netloc.extend(['rsync'])
165>>>>>>> MERGE-SOURCE
161166
=== modified file 'duplicity/backends/ssh_paramiko_backend.py'
--- duplicity/backends/ssh_paramiko_backend.py 2018-12-23 16:52:31 +0000
+++ duplicity/backends/ssh_paramiko_backend.py 2019-03-04 12:09:45 +0000
@@ -103,8 +103,13 @@
103 """103 """
104 def missing_host_key(self, client, hostname, key):104 def missing_host_key(self, client, hostname, key):
105 fp = hexlify(key.get_fingerprint())105 fp = hexlify(key.get_fingerprint())
106<<<<<<< TREE
106 fingerprint = u':'.join(a + b for a, b in list(zip(fp[::2], fp[1::2])))107 fingerprint = u':'.join(a + b for a, b in list(zip(fp[::2], fp[1::2])))
107 question = u"""The authenticity of host '%s' can't be established.108 question = u"""The authenticity of host '%s' can't be established.
109=======
110 fingerprint = ':'.join(a + b for a, b in list(zip(fp[::2], fp[1::2])))
111 question = """The authenticity of host '%s' can't be established.
112>>>>>>> MERGE-SOURCE
108%s key fingerprint is %s.113%s key fingerprint is %s.
109Are you sure you want to continue connecting (yes/no)? """ % (hostname,114Are you sure you want to continue connecting (yes/no)? """ % (hostname,
110 key.get_name().upper(),115 key.get_name().upper(),
111116
=== modified file 'duplicity/backends/ssh_pexpect_backend.py'
--- duplicity/backends/ssh_pexpect_backend.py 2019-02-25 16:30:59 +0000
+++ duplicity/backends/ssh_pexpect_backend.py 2019-03-04 12:09:45 +0000
@@ -297,7 +297,13 @@
297 commandline = (u"%s %s %s" % (self.sftp_command, globals.ssh_options, self.host_string))297 commandline = (u"%s %s %s" % (self.sftp_command, globals.ssh_options, self.host_string))
298 self.run_sftp_command(commandline, commands)298 self.run_sftp_command(commandline, commands)
299299
300<<<<<<< TREE
300301
301duplicity.backend.register_backend(u"pexpect+sftp", SSHPExpectBackend)302duplicity.backend.register_backend(u"pexpect+sftp", SSHPExpectBackend)
302duplicity.backend.register_backend(u"pexpect+scp", SSHPExpectBackend)303duplicity.backend.register_backend(u"pexpect+scp", SSHPExpectBackend)
303duplicity.backend.uses_netloc.extend([u'pexpect+sftp', u'pexpect+scp'])304duplicity.backend.uses_netloc.extend([u'pexpect+sftp', u'pexpect+scp'])
305=======
306duplicity.backend.register_backend("pexpect+sftp", SSHPExpectBackend)
307duplicity.backend.register_backend("pexpect+scp", SSHPExpectBackend)
308duplicity.backend.uses_netloc.extend(['pexpect+sftp', 'pexpect+scp'])
309>>>>>>> MERGE-SOURCE
304310
=== modified file 'duplicity/backends/swiftbackend.py'
--- duplicity/backends/swiftbackend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/swiftbackend.py 2019-03-04 12:09:45 +0000
@@ -22,7 +22,6 @@
22import os22import os
2323
24import duplicity.backend24import duplicity.backend
25from duplicity import globals
26from duplicity import log25from duplicity import log
27from duplicity import util26from duplicity import util
28from duplicity.errors import BackendException27from duplicity.errors import BackendException
@@ -112,9 +111,12 @@
112 else:111 else:
113 self.prefix = u''112 self.prefix = u''
114113
114<<<<<<< TREE
115 policy = globals.swift_storage_policy115 policy = globals.swift_storage_policy
116 policy_header = u'X-Storage-Policy'116 policy_header = u'X-Storage-Policy'
117117
118=======
119>>>>>>> MERGE-SOURCE
118 container_metadata = None120 container_metadata = None
119 try:121 try:
120 self.conn = Connection(**conn_kwargs)122 self.conn = Connection(**conn_kwargs)
@@ -129,15 +131,17 @@
129 if container_metadata is None:131 if container_metadata is None:
130 log.Info(u"Creating container %s" % self.container)132 log.Info(u"Creating container %s" % self.container)
131 try:133 try:
132 headers = dict([[policy_header, policy]]) if policy else None134 self.conn.put_container(self.container)
133 self.conn.put_container(self.container, headers=headers)
134 except Exception as e:135 except Exception as e:
135 log.FatalError(u"Container creation failed: %s %s"136 log.FatalError(u"Container creation failed: %s %s"
136 % (e.__class__.__name__, str(e)),137 % (e.__class__.__name__, str(e)),
137 log.ErrorCode.connection_failed)138 log.ErrorCode.connection_failed)
139<<<<<<< TREE
138 elif policy and container_metadata[policy_header.lower()] != policy:140 elif policy and container_metadata[policy_header.lower()] != policy:
139 log.FatalError(u"Container '%s' exists but its storage policy is '%s' not '%s'."141 log.FatalError(u"Container '%s' exists but its storage policy is '%s' not '%s'."
140 % (self.container, container_metadata[policy_header.lower()], policy))142 % (self.container, container_metadata[policy_header.lower()], policy))
143=======
144>>>>>>> MERGE-SOURCE
141145
142 def _error_code(self, operation, e):146 def _error_code(self, operation, e):
143 if isinstance(e, self.resp_exc):147 if isinstance(e, self.resp_exc):
144148
=== modified file 'duplicity/backends/sxbackend.py'
--- duplicity/backends/sxbackend.py 2018-07-23 14:55:39 +0000
+++ duplicity/backends/sxbackend.py 2019-03-04 12:09:45 +0000
@@ -49,5 +49,9 @@
49 commandline = u"sxrm {0}/{1}".format(self.url_string, filename)49 commandline = u"sxrm {0}/{1}".format(self.url_string, filename)
50 self.subprocess_popen(commandline)50 self.subprocess_popen(commandline)
5151
52<<<<<<< TREE
5253
53duplicity.backend.register_backend(u"sx", SXBackend)54duplicity.backend.register_backend(u"sx", SXBackend)
55=======
56duplicity.backend.register_backend("sx", SXBackend)
57>>>>>>> MERGE-SOURCE
5458
=== modified file 'duplicity/backends/tahoebackend.py'
--- duplicity/backends/tahoebackend.py 2018-11-29 19:00:15 +0000
+++ duplicity/backends/tahoebackend.py 2019-03-04 12:09:45 +0000
@@ -73,7 +73,13 @@
73 return output.split(b'\n') if output else []73 return output.split(b'\n') if output else []
7474
75 def _delete(self, filename):75 def _delete(self, filename):
76<<<<<<< TREE
76 self.run(u"tahoe", u"rm", self.get_remote_path(filename))77 self.run(u"tahoe", u"rm", self.get_remote_path(filename))
7778
7879
79duplicity.backend.register_backend(u"tahoe", TAHOEBackend)80duplicity.backend.register_backend(u"tahoe", TAHOEBackend)
81=======
82 self.run("tahoe", "rm", self.get_remote_path(filename))
83
84duplicity.backend.register_backend("tahoe", TAHOEBackend)
85>>>>>>> MERGE-SOURCE
8086
=== modified file 'duplicity/backends/webdavbackend.py'
--- duplicity/backends/webdavbackend.py 2018-12-23 16:52:31 +0000
+++ duplicity/backends/webdavbackend.py 2019-03-04 12:09:45 +0000
@@ -260,11 +260,19 @@
260 try:260 try:
261 return self.get_kerberos_authorization()261 return self.get_kerberos_authorization()
262 except ImportError:262 except ImportError:
263<<<<<<< TREE
263 log.Warn(_(u"python-kerberos needed to use kerberos \264 log.Warn(_(u"python-kerberos needed to use kerberos \
265=======
266 log.Warn(_("python-kerberos needed to use kerberos \
267>>>>>>> MERGE-SOURCE
264 authorization, falling back to basic auth."))268 authorization, falling back to basic auth."))
265 return self.get_basic_authorization()269 return self.get_basic_authorization()
266 except Exception as e:270 except Exception as e:
271<<<<<<< TREE
267 log.Warn(_(u"Kerberos authorization failed: %s.\272 log.Warn(_(u"Kerberos authorization failed: %s.\
273=======
274 log.Warn(_("Kerberos authorization failed: %s.\
275>>>>>>> MERGE-SOURCE
268 Falling back to basic auth.") % e)276 Falling back to basic auth.") % e)
269 return self.get_basic_authorization()277 return self.get_basic_authorization()
270 elif token.lower() == u'basic':278 elif token.lower() == u'basic':
@@ -277,9 +285,15 @@
277 return urllib2.parse_keqv_list(urllib2.parse_http_list(challenge_string))285 return urllib2.parse_keqv_list(urllib2.parse_http_list(challenge_string))
278286
279 def get_kerberos_authorization(self):287 def get_kerberos_authorization(self):
288<<<<<<< TREE
280 import kerberos # pylint: disable=import-error289 import kerberos # pylint: disable=import-error
281 _, ctx = kerberos.authGSSClientInit(u"HTTP@%s" % self.conn.host)290 _, ctx = kerberos.authGSSClientInit(u"HTTP@%s" % self.conn.host)
282 kerberos.authGSSClientStep(ctx, u"")291 kerberos.authGSSClientStep(ctx, u"")
292=======
293 import kerberos # pylint: disable=import-error
294 _, ctx = kerberos.authGSSClientInit("HTTP@%s" % self.conn.host)
295 kerberos.authGSSClientStep(ctx, "")
296>>>>>>> MERGE-SOURCE
283 tgt = kerberos.authGSSClientResponse(ctx)297 tgt = kerberos.authGSSClientResponse(ctx)
284 return u'Negotiate %s' % tgt298 return u'Negotiate %s' % tgt
285299
@@ -287,8 +301,13 @@
287 u"""301 u"""
288 Returns the basic auth header302 Returns the basic auth header
289 """303 """
304<<<<<<< TREE
290 auth_string = u'%s:%s' % (self.username, self.password)305 auth_string = u'%s:%s' % (self.username, self.password)
291 return u'Basic %s' % base64.encodestring(auth_string).strip()306 return u'Basic %s' % base64.encodestring(auth_string).strip()
307=======
308 auth_string = '%s:%s' % (self.username, self.password)
309 return 'Basic %s' % "".join(base64.encodestring(auth_string).split())
310>>>>>>> MERGE-SOURCE
292311
293 def get_digest_authorization(self, path):312 def get_digest_authorization(self, path):
294 u"""313 u"""
@@ -474,9 +493,17 @@
474 if response:493 if response:
475 response.close()494 response.close()
476495
496<<<<<<< TREE
477497
478duplicity.backend.register_backend(u"http", WebDAVBackend)498duplicity.backend.register_backend(u"http", WebDAVBackend)
479duplicity.backend.register_backend(u"https", WebDAVBackend)499duplicity.backend.register_backend(u"https", WebDAVBackend)
480duplicity.backend.register_backend(u"webdav", WebDAVBackend)500duplicity.backend.register_backend(u"webdav", WebDAVBackend)
481duplicity.backend.register_backend(u"webdavs", WebDAVBackend)501duplicity.backend.register_backend(u"webdavs", WebDAVBackend)
482duplicity.backend.uses_netloc.extend([u'http', u'https', u'webdav', u'webdavs'])502duplicity.backend.uses_netloc.extend([u'http', u'https', u'webdav', u'webdavs'])
503=======
504duplicity.backend.register_backend("http", WebDAVBackend)
505duplicity.backend.register_backend("https", WebDAVBackend)
506duplicity.backend.register_backend("webdav", WebDAVBackend)
507duplicity.backend.register_backend("webdavs", WebDAVBackend)
508duplicity.backend.uses_netloc.extend(['http', 'https', 'webdav', 'webdavs'])
509>>>>>>> MERGE-SOURCE
483510
=== modified file 'duplicity/collections.py'
--- duplicity/collections.py 2019-02-22 20:25:02 +0000
+++ duplicity/collections.py 2019-03-04 12:09:45 +0000
@@ -32,7 +32,7 @@
3232
33import types33import types
34import gettext34import gettext
35import sys35
3636
37from duplicity import log37from duplicity import log
38from duplicity import file_naming38from duplicity import file_naming
@@ -44,12 +44,15 @@
44from duplicity import util44from duplicity import util
45from duplicity.gpg import GPGError45from duplicity.gpg import GPGError
4646
47<<<<<<< TREE
47# For type testing against both int and long types that works in python 2/348# For type testing against both int and long types that works in python 2/3
48if sys.version_info < (3,):49if sys.version_info < (3,):
49 integer_types = (int, int)50 integer_types = (int, int)
50else:51else:
51 integer_types = (int,)52 integer_types = (int,)
5253
54=======
55>>>>>>> MERGE-SOURCE
5356
54class CollectionsError(Exception):57class CollectionsError(Exception):
55 pass58 pass
@@ -73,7 +76,6 @@
73 self.end_time = None # will be set if inc76 self.end_time = None # will be set if inc
74 self.partial = False # true if a partial backup77 self.partial = False # true if a partial backup
75 self.encrypted = False # true if an encrypted backup78 self.encrypted = False # true if an encrypted backup
76 self.files_changed = []
77 self.action = action79 self.action = action
7880
79 def is_complete(self):81 def is_complete(self):
@@ -138,10 +140,6 @@
138 self.encrypted = bool(pr.encrypted)140 self.encrypted = bool(pr.encrypted)
139 self.info_set = True141 self.info_set = True
140142
141 def set_files_changed(self):
142 mf = self.get_manifest()
143 self.files_changed = mf.get_files_changed()
144
145 def set_manifest(self, remote_filename):143 def set_manifest(self, remote_filename):
146 u"""144 u"""
147 Add local and remote manifest filenames to backup set145 Add local and remote manifest filenames to backup set
@@ -150,8 +148,13 @@
150 remote_filename)148 remote_filename)
151 self.remote_manifest_name = remote_filename149 self.remote_manifest_name = remote_filename
152150
151<<<<<<< TREE
153 if self.action not in [u"collection-status", u"replicate"]:152 if self.action not in [u"collection-status", u"replicate"]:
154 local_filename_list = globals.archive_dir_path.listdir()153 local_filename_list = globals.archive_dir_path.listdir()
154=======
155 if self.action not in ["collection-status"]:
156 local_filename_list = globals.archive_dir.listdir()
157>>>>>>> MERGE-SOURCE
155 else:158 else:
156 local_filename_list = []159 local_filename_list = []
157 for local_filename in local_filename_list:160 for local_filename in local_filename_list:
@@ -161,9 +164,7 @@
161 pr.start_time == self.start_time and164 pr.start_time == self.start_time and
162 pr.end_time == self.end_time):165 pr.end_time == self.end_time):
163 self.local_manifest_path = \166 self.local_manifest_path = \
164 globals.archive_dir_path.append(local_filename)167 globals.archive_dir.append(local_filename)
165
166 self.set_files_changed()
167 break168 break
168169
169 def delete(self):170 def delete(self):
@@ -177,8 +178,13 @@
177 except Exception:178 except Exception:
178 log.Debug(_(u"BackupSet.delete: missing %s") % [util.fsdecode(f) for f in rfn])179 log.Debug(_(u"BackupSet.delete: missing %s") % [util.fsdecode(f) for f in rfn])
179 pass180 pass
181<<<<<<< TREE
180 if self.action not in [u"collection-status", u"replicate"]:182 if self.action not in [u"collection-status", u"replicate"]:
181 local_filename_list = globals.archive_dir_path.listdir()183 local_filename_list = globals.archive_dir_path.listdir()
184=======
185 if self.action not in ["collection-status"]:
186 local_filename_list = globals.archive_dir.listdir()
187>>>>>>> MERGE-SOURCE
182 else:188 else:
183 local_filename_list = []189 local_filename_list = []
184 for lfn in local_filename_list:190 for lfn in local_filename_list:
@@ -187,7 +193,7 @@
187 pr.start_time == self.start_time and193 pr.start_time == self.start_time and
188 pr.end_time == self.end_time):194 pr.end_time == self.end_time):
189 try:195 try:
190 globals.archive_dir_path.append(lfn).delete()196 globals.archive_dir.append(lfn).delete()
191 except Exception:197 except Exception:
192 log.Debug(_(u"BackupSet.delete: missing %s") % [util.fsdecode(f) for f in lfn])198 log.Debug(_(u"BackupSet.delete: missing %s") % [util.fsdecode(f) for f in lfn])
193 pass199 pass
@@ -242,8 +248,13 @@
242 """248 """
243 assert self.local_manifest_path249 assert self.local_manifest_path
244 manifest_buffer = self.local_manifest_path.get_data()250 manifest_buffer = self.local_manifest_path.get_data()
251<<<<<<< TREE
245 log.Info(_(u"Processing local manifest %s (%s)") % (252 log.Info(_(u"Processing local manifest %s (%s)") % (
246 self.local_manifest_path.name, len(manifest_buffer)))253 self.local_manifest_path.name, len(manifest_buffer)))
254=======
255 log.Info(_("Processing local manifest %s (%s)") % (
256 self.local_manifest_path.name, len(manifest_buffer)))
257>>>>>>> MERGE-SOURCE
247 return manifest.Manifest().from_string(manifest_buffer)258 return manifest.Manifest().from_string(manifest_buffer)
248259
249 def get_remote_manifest(self):260 def get_remote_manifest(self):
@@ -254,11 +265,21 @@
254 try:265 try:
255 manifest_buffer = self.backend.get_data(self.remote_manifest_name)266 manifest_buffer = self.backend.get_data(self.remote_manifest_name)
256 except GPGError as message:267 except GPGError as message:
268<<<<<<< TREE
257 log.Error(_(u"Error processing remote manifest (%s): %s") %269 log.Error(_(u"Error processing remote manifest (%s): %s") %
258 (util.fsdecode(self.remote_manifest_name), util.uexc(message)))270 (util.fsdecode(self.remote_manifest_name), util.uexc(message)))
271=======
272 log.Error(_("Error processing remote manifest (%s): %s") %
273 (util.ufn(self.remote_manifest_name), util.uexc(message)))
274>>>>>>> MERGE-SOURCE
259 return None275 return None
276<<<<<<< TREE
260 log.Info(_(u"Processing remote manifest %s (%s)") % (277 log.Info(_(u"Processing remote manifest %s (%s)") % (
261 util.fsdecode(self.remote_manifest_name), len(manifest_buffer)))278 util.fsdecode(self.remote_manifest_name), len(manifest_buffer)))
279=======
280 log.Info(_("Processing remote manifest %s (%s)") % (
281 util.ufn(self.remote_manifest_name), len(manifest_buffer)))
282>>>>>>> MERGE-SOURCE
262 return manifest.Manifest().from_string(manifest_buffer)283 return manifest.Manifest().from_string(manifest_buffer)
263284
264 def get_manifest(self):285 def get_manifest(self):
@@ -298,9 +319,6 @@
298 return self.end_time319 return self.end_time
299 assert 0, u"Neither self.time nor self.end_time set"320 assert 0, u"Neither self.time nor self.end_time set"
300321
301 def get_files_changed(self):
302 return self.files_changed
303
304 def __len__(self):322 def __len__(self):
305 u"""323 u"""
306 Return the number of volumes in the set324 Return the number of volumes in the set
@@ -482,19 +500,19 @@
482 Return new SignatureChain.500 Return new SignatureChain.
483501
484 local should be true iff the signature chain resides in502 local should be true iff the signature chain resides in
485 globals.archive_dir_path and false if the chain is in503 globals.archive_dir and false if the chain is in
486 globals.backend.504 globals.backend.
487505
488 @param local: True if sig chain in globals.archive_dir_path506 @param local: True if sig chain in globals.archive_dir
489 @type local: Boolean507 @type local: Boolean
490508
491 @param location: Where the sig chain is located509 @param location: Where the sig chain is located
492 @type location: globals.archive_dir_path or globals.backend510 @type location: globals.archive_dir or globals.backend
493 """511 """
494 if local:512 if local:
495 self.archive_dir_path, self.backend = location, None513 self.archive_dir, self.backend = location, None
496 else:514 else:
497 self.archive_dir_path, self.backend = None, location515 self.archive_dir, self.backend = None, location
498 self.fullsig = None # filename of full signature516 self.fullsig = None # filename of full signature
499 self.inclist = [] # list of filenames of incremental signatures517 self.inclist = [] # list of filenames of incremental signatures
500 self.start_time, self.end_time = None, None518 self.start_time, self.end_time = None, None
@@ -503,8 +521,13 @@
503 u"""521 u"""
504 Local or Remote and List of files in the set522 Local or Remote and List of files in the set
505 """523 """
524<<<<<<< TREE
506 if self.archive_dir_path:525 if self.archive_dir_path:
507 place = _(u"local")526 place = _(u"local")
527=======
528 if self.archive_dir:
529 place = _("local")
530>>>>>>> MERGE-SOURCE
508 else:531 else:
509 place = _(u"remote")532 place = _(u"remote")
510 filelist = []533 filelist = []
@@ -518,14 +541,24 @@
518 Check to make sure times are in whole seconds541 Check to make sure times are in whole seconds
519 """542 """
520 for time in time_list:543 for time in time_list:
544<<<<<<< TREE
521 if type(time) not in integer_types:545 if type(time) not in integer_types:
522 assert 0, u"Time %s in %s wrong type" % (time, time_list)546 assert 0, u"Time %s in %s wrong type" % (time, time_list)
547=======
548 if type(time) not in (types.LongType, types.IntType):
549 assert 0, "Time %s in %s wrong type" % (time, time_list)
550>>>>>>> MERGE-SOURCE
523551
524 def islocal(self):552 def islocal(self):
553<<<<<<< TREE
525 u"""554 u"""
526 Return true if represents a signature chain in archive_dir_path555 Return true if represents a signature chain in archive_dir_path
527 """556=======
528 if self.archive_dir_path:557 """
558 Return true if represents a signature chain in archive_dir
559>>>>>>> MERGE-SOURCE
560 """
561 if self.archive_dir:
529 return True562 return True
530 else:563 else:
531 return False564 return False
@@ -562,11 +595,17 @@
562 optionally at a certain time595 optionally at a certain time
563 """596 """
564 assert self.fullsig597 assert self.fullsig
565 if self.archive_dir_path: # local598 if self.archive_dir: # local
566 def filename_to_fileobj(filename):599 def filename_to_fileobj(filename):
600<<<<<<< TREE
567 u"""Open filename in archive_dir_path, return filtered fileobj"""601 u"""Open filename in archive_dir_path, return filtered fileobj"""
568 sig_dp = path.DupPath(self.archive_dir_path.name, (filename,))602 sig_dp = path.DupPath(self.archive_dir_path.name, (filename,))
569 return sig_dp.filtered_open(u"rb")603 return sig_dp.filtered_open(u"rb")
604=======
605 """Open filename in archive_dir, return filtered fileobj"""
606 sig_dp = path.DupPath(self.archive_dir.name, (filename,))
607 return sig_dp.filtered_open("rb")
608>>>>>>> MERGE-SOURCE
570 else:609 else:
571 filename_to_fileobj = self.backend.get_fileobj_read610 filename_to_fileobj = self.backend.get_fileobj_read
572 return [filename_to_fileobj(f) for f in self.get_filenames(time)]611 return [filename_to_fileobj(f) for f in self.get_filenames(time)]
@@ -576,11 +615,11 @@
576 Remove all files in signature set615 Remove all files in signature set
577 """616 """
578 # Try to delete in opposite order, so something useful even if aborted617 # Try to delete in opposite order, so something useful even if aborted
579 if self.archive_dir_path:618 if self.archive_dir:
580 for i in range(len(self.inclist) - 1, -1, -1):619 for i in range(len(self.inclist) - 1, -1, -1):
581 self.archive_dir_path.append(self.inclist[i]).delete()620 self.archive_dir.append(self.inclist[i]).delete()
582 if not keep_full:621 if not keep_full:
583 self.archive_dir_path.append(self.fullsig).delete()622 self.archive_dir.append(self.fullsig).delete()
584 else:623 else:
585 assert self.backend624 assert self.backend
586 inclist_copy = self.inclist[:]625 inclist_copy = self.inclist[:]
@@ -610,12 +649,17 @@
610 u"""649 u"""
611 Hold information about available chains and sets650 Hold information about available chains and sets
612 """651 """
652<<<<<<< TREE
613 def __init__(self, backend, archive_dir_path, action):653 def __init__(self, backend, archive_dir_path, action):
614 u"""654 u"""
655=======
656 def __init__(self, backend, archive_dir, action):
657 """
658>>>>>>> MERGE-SOURCE
615 Make new object. Does not set values659 Make new object. Does not set values
616 """660 """
617 self.backend = backend661 self.backend = backend
618 self.archive_dir_path = archive_dir_path662 self.archive_dir = archive_dir
619 self.action = action663 self.action = action
620664
621 # Will hold (signature chain, backup chain) pair of active665 # Will hold (signature chain, backup chain) pair of active
@@ -640,8 +684,13 @@
640 u"""684 u"""
641 Return summary of the collection, suitable for printing to log685 Return summary of the collection, suitable for printing to log
642 """686 """
687<<<<<<< TREE
643 l = [u"backend %s" % (self.backend.__class__.__name__,),688 l = [u"backend %s" % (self.backend.__class__.__name__,),
644 u"archive-dir %s" % (self.archive_dir_path,)]689 u"archive-dir %s" % (self.archive_dir_path,)]
690=======
691 l = ["backend %s" % (self.backend.__class__.__name__,),
692 "archive-dir %s" % (self.archive_dir,)]
693>>>>>>> MERGE-SOURCE
645694
646 for i in range(len(self.other_backup_chains)):695 for i in range(len(self.other_backup_chains)):
647 # A bit of a misnomer. Chain might have a sig.696 # A bit of a misnomer. Chain might have a sig.
@@ -665,7 +714,11 @@
665 u"-----------------",714 u"-----------------",
666 _(u"Connecting with backend: %s") %715 _(u"Connecting with backend: %s") %
667 (self.backend.__class__.__name__,),716 (self.backend.__class__.__name__,),
717<<<<<<< TREE
668 _(u"Archive dir: %s") % (self.archive_dir_path.uc_name if self.archive_dir_path else u'None',)]718 _(u"Archive dir: %s") % (self.archive_dir_path.uc_name if self.archive_dir_path else u'None',)]
719=======
720 _("Archive dir: %s") % (util.ufn(self.archive_dir.name),)]
721>>>>>>> MERGE-SOURCE
669722
670 l.append(u"\n" +723 l.append(u"\n" +
671 ngettext(u"Found %d secondary backup chain.",724 ngettext(u"Found %d secondary backup chain.",
@@ -703,8 +756,13 @@
703 return u"\n".join(l)756 return u"\n".join(l)
704757
705 def set_values(self, sig_chain_warning=1):758 def set_values(self, sig_chain_warning=1):
759<<<<<<< TREE
706 u"""760 u"""
707 Set values from archive_dir_path and backend.761 Set values from archive_dir_path and backend.
762=======
763 """
764 Set values from archive_dir and backend.
765>>>>>>> MERGE-SOURCE
708766
709 Returns self for convenience. If sig_chain_warning is set to None,767 Returns self for convenience. If sig_chain_warning is set to None,
710 do not warn about unnecessary sig chains. This is because there may768 do not warn about unnecessary sig chains. This is because there may
@@ -720,8 +778,13 @@
720 len(backend_filename_list))778 len(backend_filename_list))
721779
722 # get local filename list780 # get local filename list
781<<<<<<< TREE
723 if self.action not in [u"collection-status", u"replicate"]:782 if self.action not in [u"collection-status", u"replicate"]:
724 local_filename_list = self.archive_dir_path.listdir()783 local_filename_list = self.archive_dir_path.listdir()
784=======
785 if self.action not in ["collection-status"]:
786 local_filename_list = self.archive_dir.listdir()
787>>>>>>> MERGE-SOURCE
725 else:788 else:
726 local_filename_list = []789 local_filename_list = []
727 log.Debug(ngettext(u"%d file exists in cache",790 log.Debug(ngettext(u"%d file exists in cache",
@@ -909,8 +972,13 @@
909 return ([p[1] for p in time_set_pairs], incomplete_sets)972 return ([p[1] for p in time_set_pairs], incomplete_sets)
910973
911 def get_signature_chains(self, local, filelist=None):974 def get_signature_chains(self, local, filelist=None):
975<<<<<<< TREE
912 u"""976 u"""
913 Find chains in archive_dir_path (if local is true) or backend977 Find chains in archive_dir_path (if local is true) or backend
978=======
979 """
980 Find chains in archive_dir (if local is true) or backend
981>>>>>>> MERGE-SOURCE
914982
915 Use filelist if given, otherwise regenerate. Return value is983 Use filelist if given, otherwise regenerate. Return value is
916 pair (list of chains, list of signature paths not in any984 pair (list of chains, list of signature paths not in any
@@ -920,8 +988,13 @@
920 if filelist is not None:988 if filelist is not None:
921 return filelist989 return filelist
922 elif local:990 elif local:
991<<<<<<< TREE
923 if self.action not in [u"collection-status", u"replicate"]:992 if self.action not in [u"collection-status", u"replicate"]:
924 return self.archive_dir_path.listdir()993 return self.archive_dir_path.listdir()
994=======
995 if self.action not in ["collection-status"]:
996 return self.archive_dir.listdir()
997>>>>>>> MERGE-SOURCE
925 else:998 else:
926 return []999 return []
927 else:1000 else:
@@ -932,7 +1005,7 @@
932 Return new empty signature chain1005 Return new empty signature chain
933 """1006 """
934 if local:1007 if local:
935 return SignatureChain(True, self.archive_dir_path)1008 return SignatureChain(True, self.archive_dir)
936 else:1009 else:
937 return SignatureChain(False, self.backend)1010 return SignatureChain(False, self.backend)
9381011
@@ -1196,6 +1269,7 @@
1196 old_sets = [s for s in chain.get_all_sets() if s.get_time() < t]1269 old_sets = [s for s in chain.get_all_sets() if s.get_time() < t]
1197 result_sets.extend(old_sets)1270 result_sets.extend(old_sets)
1198 return self.sort_sets(result_sets)1271 return self.sort_sets(result_sets)
1272<<<<<<< TREE
11991273
1200 def get_file_changed_record(self, filepath):1274 def get_file_changed_record(self, filepath):
1201 u"""1275 u"""
@@ -1246,3 +1320,5 @@
12461320
1247 l.append(u"-------------------------")1321 l.append(u"-------------------------")
1248 return u"\n".join(l)1322 return u"\n".join(l)
1323=======
1324>>>>>>> MERGE-SOURCE
12491325
=== modified file 'duplicity/commandline.py'
--- duplicity/commandline.py 2019-01-25 17:08:40 +0000
+++ duplicity/commandline.py 2019-03-04 12:09:45 +0000
@@ -19,8 +19,12 @@
19# along with duplicity; if not, write to the Free Software Foundation,19# along with duplicity; if not, write to the Free Software Foundation,
20# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA20# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2121
22<<<<<<< TREE
22u"""Parse command line, check for consistency, and set globals"""23u"""Parse command line, check for consistency, and set globals"""
23from __future__ import print_function24from __future__ import print_function
25=======
26"""Parse command line, check for consistency, and set globals"""
27>>>>>>> MERGE-SOURCE
2428
25from builtins import filter29from builtins import filter
26from builtins import str30from builtins import str
@@ -58,8 +62,8 @@
58collection_status = None # Will be set to true if collection-status command given62collection_status = None # Will be set to true if collection-status command given
59cleanup = None # Set to true if cleanup command given63cleanup = None # Set to true if cleanup command given
60verify = None # Set to true if verify command given64verify = None # Set to true if verify command given
61replicate = None # Set to true if replicate command given
6265
66<<<<<<< TREE
63commands = [u"cleanup",67commands = [u"cleanup",
64 u"collection-status",68 u"collection-status",
65 u"full",69 u"full",
@@ -71,6 +75,18 @@
71 u"restore",75 u"restore",
72 u"verify",76 u"verify",
73 u"replicate"77 u"replicate"
78=======
79commands = ["cleanup",
80 "collection-status",
81 "full",
82 "incremental",
83 "list-current-files",
84 "remove-older-than",
85 "remove-all-but-n-full",
86 "remove-all-inc-of-but-n-full",
87 "restore",
88 "verify",
89>>>>>>> MERGE-SOURCE
74 ]90 ]
7591
7692
@@ -203,8 +219,12 @@
203 optparse.Option.take_action(219 optparse.Option.take_action(
204 self, action, dest, opt, value, values, parser)220 self, action, dest, opt, value, values, parser)
205221
222<<<<<<< TREE
206223
207u"""224u"""
225=======
226"""
227>>>>>>> MERGE-SOURCE
208Fix:228Fix:
209 File "/usr/lib/pythonX.X/optparse.py", line XXXX, in print_help229 File "/usr/lib/pythonX.X/optparse.py", line XXXX, in print_help
210 file.write(self.format_help().encode(encoding, "replace"))230 file.write(self.format_help().encode(encoding, "replace"))
@@ -245,7 +265,7 @@
245def parse_cmdline_options(arglist):265def parse_cmdline_options(arglist):
246 u"""Parse argument list"""266 u"""Parse argument list"""
247 global select_opts, select_files, full_backup267 global select_opts, select_files, full_backup
248 global list_current, collection_status, cleanup, remove_time, verify, replicate268 global list_current, collection_status, cleanup, remove_time, verify
249269
250 def set_log_fd(fd):270 def set_log_fd(fd):
251 if fd < 1:271 if fd < 1:
@@ -270,7 +290,11 @@
270 log.ErrorCode.cant_open_filelist)290 log.ErrorCode.cant_open_filelist)
271291
272 def print_ver(o, s, v, p):292 def print_ver(o, s, v, p):
293<<<<<<< TREE
273 print(u"duplicity %s" % (globals.version))294 print(u"duplicity %s" % (globals.version))
295=======
296 print "duplicity %s" % (globals.version)
297>>>>>>> MERGE-SOURCE
274 sys.exit(0)298 sys.exit(0)
275299
276 def add_rename(o, s, v, p):300 def add_rename(o, s, v, p):
@@ -391,9 +415,15 @@
391 # whole root.415 # whole root.
392 # TRANSL: Used in usage help to represent a Unix-style path name. Example:416 # TRANSL: Used in usage help to represent a Unix-style path name. Example:
393 # --archive-dir <path>417 # --archive-dir <path>
418<<<<<<< TREE
394 parser.add_option(u"--file-to-restore", u"-r", action=u"callback", type=u"file",419 parser.add_option(u"--file-to-restore", u"-r", action=u"callback", type=u"file",
395 metavar=_(u"path"), dest=u"restore_dir",420 metavar=_(u"path"), dest=u"restore_dir",
396 callback=lambda o, s, v, p: setattr(p.values, u"restore_dir", util.fsencode(v.strip(u'/'))))421 callback=lambda o, s, v, p: setattr(p.values, u"restore_dir", util.fsencode(v.strip(u'/'))))
422=======
423 parser.add_option("--file-to-restore", "-r", action="callback", type="file",
424 metavar=_("path"), dest="restore_dir",
425 callback=lambda o, s, v, p: setattr(p.values, "restore_dir", v.strip('/')))
426>>>>>>> MERGE-SOURCE
397427
398 # Used to confirm certain destructive operations like deleting old files.428 # Used to confirm certain destructive operations like deleting old files.
399 parser.add_option(u"--force", action=u"store_true")429 parser.add_option(u"--force", action=u"store_true")
@@ -577,6 +607,7 @@
577 parser.add_option("--s3-kms-key-id", action=u"store", dest="s3_kms_key_id")607 parser.add_option("--s3-kms-key-id", action=u"store", dest="s3_kms_key_id")
578 parser.add_option("--s3-kms-grant", action=u"store", dest="s3_kms_grant")608 parser.add_option("--s3-kms-grant", action=u"store", dest="s3_kms_grant")
579609
610<<<<<<< TREE
580 # Option to specify a Swift container storage policy.611 # Option to specify a Swift container storage policy.
581 parser.add_option(u"--swift-storage-policy", type=u"string", metavar=_(u"policy"))612 parser.add_option(u"--swift-storage-policy", type=u"string", metavar=_(u"policy"))
582613
@@ -598,6 +629,8 @@
598 # Standard storage tier used for storring backup files (Hot|Cool|Archive).629 # Standard storage tier used for storring backup files (Hot|Cool|Archive).
599 parser.add_option(u"--azure-blob-tier", type=u"string", metavar=_(u"Hot|Cool|Archive"))630 parser.add_option(u"--azure-blob-tier", type=u"string", metavar=_(u"Hot|Cool|Archive"))
600631
632=======
633>>>>>>> MERGE-SOURCE
601 # scp command to use (ssh pexpect backend)634 # scp command to use (ssh pexpect backend)
602 parser.add_option(u"--scp-command", metavar=_(u"command"))635 parser.add_option(u"--scp-command", metavar=_(u"command"))
603636
@@ -662,18 +695,21 @@
662 parser.add_option(u"--volsize", type=u"int", action=u"callback", metavar=_(u"number"),695 parser.add_option(u"--volsize", type=u"int", action=u"callback", metavar=_(u"number"),
663 callback=lambda o, s, v, p: setattr(p.values, u"volsize", v * 1024 * 1024))696 callback=lambda o, s, v, p: setattr(p.values, u"volsize", v * 1024 * 1024))
664697
698<<<<<<< TREE
665 # If set, collect only the file status, not the whole root.699 # If set, collect only the file status, not the whole root.
666 parser.add_option(u"--file-changed", action=u"callback", type=u"file",700 parser.add_option(u"--file-changed", action=u"callback", type=u"file",
667 metavar=_(u"path"), dest=u"file_changed",701 metavar=_(u"path"), dest=u"file_changed",
668 callback=lambda o, s, v, p: setattr(p.values, u"file_changed", v.rstrip(u'/')))702 callback=lambda o, s, v, p: setattr(p.values, u"file_changed", v.rstrip(u'/')))
669703
704=======
705>>>>>>> MERGE-SOURCE
670 # delay time before next try after a failure of a backend operation706 # delay time before next try after a failure of a backend operation
671 # TRANSL: Used in usage help. Example:707 # TRANSL: Used in usage help. Example:
672 # --backend-retry-delay <seconds>708 # --backend-retry-delay <seconds>
673 parser.add_option(u"--backend-retry-delay", type=u"int", metavar=_(u"seconds"))709 parser.add_option(u"--backend-retry-delay", type=u"int", metavar=_(u"seconds"))
674710
675 # parse the options711 # parse the options
676 (options, args) = parser.parse_args(arglist)712 (options, args) = parser.parse_args()
677713
678 # Copy all arguments and their values to the globals module. Don't copy714 # Copy all arguments and their values to the globals module. Don't copy
679 # attributes that are 'hidden' (start with an underscore) or whose name is715 # attributes that are 'hidden' (start with an underscore) or whose name is
@@ -743,9 +779,12 @@
743 num_expect = 1779 num_expect = 1
744 elif cmd == u"verify":780 elif cmd == u"verify":
745 verify = True781 verify = True
782<<<<<<< TREE
746 elif cmd == u"replicate":783 elif cmd == u"replicate":
747 replicate = True784 replicate = True
748 num_expect = 2785 num_expect = 2
786=======
787>>>>>>> MERGE-SOURCE
749788
750 if len(args) != num_expect:789 if len(args) != num_expect:
751 command_line_error(u"Expected %d args, got %d" % (num_expect, len(args)))790 command_line_error(u"Expected %d args, got %d" % (num_expect, len(args)))
@@ -764,12 +803,16 @@
764 elif len(args) == 1:803 elif len(args) == 1:
765 backend_url = args[0]804 backend_url = args[0]
766 elif len(args) == 2:805 elif len(args) == 2:
806<<<<<<< TREE
767 if replicate:807 if replicate:
768 if not backend.is_backend_url(args[0]) or not backend.is_backend_url(args[1]):808 if not backend.is_backend_url(args[0]) or not backend.is_backend_url(args[1]):
769 command_line_error(u"Two URLs expected for replicate.")809 command_line_error(u"Two URLs expected for replicate.")
770 src_backend_url, backend_url = args[0], args[1]810 src_backend_url, backend_url = args[0], args[1]
771 else:811 else:
772 lpath, backend_url = args_to_path_backend(args[0], args[1]) # @UnusedVariable812 lpath, backend_url = args_to_path_backend(args[0], args[1]) # @UnusedVariable
813=======
814 lpath, backend_url = args_to_path_backend(args[0], args[1]) # @UnusedVariable
815>>>>>>> MERGE-SOURCE
773 else:816 else:
774 command_line_error(u"Too many arguments")817 command_line_error(u"Too many arguments")
775818
@@ -780,8 +823,13 @@
780 set_archive_dir(expand_archive_dir(globals.archive_dir,823 set_archive_dir(expand_archive_dir(globals.archive_dir,
781 globals.backup_name))824 globals.backup_name))
782825
826<<<<<<< TREE
783 log.Info(_(u"Using archive dir: %s") % (globals.archive_dir_path.uc_name,))827 log.Info(_(u"Using archive dir: %s") % (globals.archive_dir_path.uc_name,))
784 log.Info(_(u"Using backup name: %s") % (globals.backup_name,))828 log.Info(_(u"Using backup name: %s") % (globals.backup_name,))
829=======
830 log.Info(_("Using archive dir: %s") % (util.ufn(globals.archive_dir.name),))
831 log.Info(_("Using backup name: %s") % (globals.backup_name,))
832>>>>>>> MERGE-SOURCE
785833
786 return args834 return args
787835
@@ -944,7 +992,6 @@
944 duplicity remove-older-than %(time)s [%(options)s] %(target_url)s992 duplicity remove-older-than %(time)s [%(options)s] %(target_url)s
945 duplicity remove-all-but-n-full %(count)s [%(options)s] %(target_url)s993 duplicity remove-all-but-n-full %(count)s [%(options)s] %(target_url)s
946 duplicity remove-all-inc-of-but-n-full %(count)s [%(options)s] %(target_url)s994 duplicity remove-all-inc-of-but-n-full %(count)s [%(options)s] %(target_url)s
947 duplicity replicate %(source_url)s %(target_url)s
948995
949""" % dict996""" % dict
950997
@@ -964,7 +1011,6 @@
964 scp://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s1011 scp://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
965 ssh://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s1012 ssh://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
966 swift://%(container_name)s1013 swift://%(container_name)s
967 pca://%(container_name)s
968 tahoe://%(alias)s/%(directory)s1014 tahoe://%(alias)s/%(directory)s
969 webdav://%(user)s[:%(password)s]@%(other_host)s/%(some_dir)s1015 webdav://%(user)s[:%(password)s]@%(other_host)s/%(some_dir)s
970 webdavs://%(user)s[:%(password)s]@%(other_host)s/%(some_dir)s1016 webdavs://%(user)s[:%(password)s]@%(other_host)s/%(some_dir)s
@@ -991,8 +1037,7 @@
991 remove-older-than <%(time)s> <%(target_url)s>1037 remove-older-than <%(time)s> <%(target_url)s>
992 remove-all-but-n-full <%(count)s> <%(target_url)s>1038 remove-all-but-n-full <%(count)s> <%(target_url)s>
993 remove-all-inc-of-but-n-full <%(count)s> <%(target_url)s>1039 remove-all-inc-of-but-n-full <%(count)s> <%(target_url)s>
994 verify <%(target_url)s> <%(source_dir)s>1040 verify <%(target_url)s> <%(source_dir)s>""" % dict
995 replicate <%(source_url)s> <%(target_url)s>""" % dict
9961041
997 return msg1042 return msg
9981043
@@ -1004,12 +1049,19 @@
1004 os.makedirs(dirstring)1049 os.makedirs(dirstring)
1005 except Exception:1050 except Exception:
1006 pass1051 pass
1052<<<<<<< TREE
1007 archive_dir_path = path.Path(dirstring)1053 archive_dir_path = path.Path(dirstring)
1008 if not archive_dir_path.isdir():1054 if not archive_dir_path.isdir():
1009 log.FatalError(_(u"Specified archive directory '%s' does not exist, "1055 log.FatalError(_(u"Specified archive directory '%s' does not exist, "
1010 u"or is not a directory") % (archive_dir_path.uc_name,),1056 u"or is not a directory") % (archive_dir_path.uc_name,),
1057=======
1058 archive_dir = path.Path(dirstring)
1059 if not archive_dir.isdir():
1060 log.FatalError(_("Specified archive directory '%s' does not exist, "
1061 "or is not a directory") % (util.ufn(archive_dir.name),),
1062>>>>>>> MERGE-SOURCE
1011 log.ErrorCode.bad_archive_dir)1063 log.ErrorCode.bad_archive_dir)
1012 globals.archive_dir_path = archive_dir_path1064 globals.archive_dir = archive_dir
10131065
10141066
1015def set_sign_key(sign_key):1067def set_sign_key(sign_key):
@@ -1094,8 +1146,13 @@
10941146
10951147
1096def check_consistency(action):1148def check_consistency(action):
1149<<<<<<< TREE
1097 u"""Final consistency check, see if something wrong with command line"""1150 u"""Final consistency check, see if something wrong with command line"""
1098 global full_backup, select_opts, list_current, collection_status, cleanup, replicate1151 global full_backup, select_opts, list_current, collection_status, cleanup, replicate
1152=======
1153 """Final consistency check, see if something wrong with command line"""
1154 global full_backup, select_opts, list_current
1155>>>>>>> MERGE-SOURCE
10991156
1100 def assert_only_one(arglist):1157 def assert_only_one(arglist):
1101 u"""Raises error if two or more of the elements of arglist are true"""1158 u"""Raises error if two or more of the elements of arglist are true"""
@@ -1105,9 +1162,15 @@
1105 n += 11162 n += 1
1106 assert n <= 1, u"Invalid syntax, two conflicting modes specified"1163 assert n <= 1, u"Invalid syntax, two conflicting modes specified"
11071164
1165<<<<<<< TREE
1108 if action in [u"list-current", u"collection-status",1166 if action in [u"list-current", u"collection-status",
1109 u"cleanup", u"remove-old", u"remove-all-but-n-full", u"remove-all-inc-of-but-n-full", u"replicate"]:1167 u"cleanup", u"remove-old", u"remove-all-but-n-full", u"remove-all-inc-of-but-n-full", u"replicate"]:
1110 assert_only_one([list_current, collection_status, cleanup, replicate,1168 assert_only_one([list_current, collection_status, cleanup, replicate,
1169=======
1170 if action in ["list-current", "collection-status",
1171 "cleanup", "remove-old", "remove-all-but-n-full", "remove-all-inc-of-but-n-full"]:
1172 assert_only_one([list_current, collection_status, cleanup,
1173>>>>>>> MERGE-SOURCE
1111 globals.remove_time is not None])1174 globals.remove_time is not None])
1112 elif action == u"restore" or action == u"verify":1175 elif action == u"restore" or action == u"verify":
1113 if full_backup:1176 if full_backup:
@@ -1153,8 +1216,14 @@
1153 sign_key=src.sign_key,1216 sign_key=src.sign_key,
1154 recipients=src.recipients,1217 recipients=src.recipients,
1155 hidden_recipients=src.hidden_recipients)1218 hidden_recipients=src.hidden_recipients)
1219<<<<<<< TREE
1156 log.Debug(_(u"GPG binary is %s, version %s") %1220 log.Debug(_(u"GPG binary is %s, version %s") %
1157 ((globals.gpg_binary or u'gpg'), globals.gpg_profile.gpg_version))1221 ((globals.gpg_binary or u'gpg'), globals.gpg_profile.gpg_version))
1222=======
1223 log.Debug(_("GPG binary is %s, version %s") %
1224 ((globals.gpg_binary or 'gpg'),
1225 "%d.%d.%d" % globals.gpg_profile.gpg_version))
1226>>>>>>> MERGE-SOURCE
11581227
1159 # we can now try to import all the backends1228 # we can now try to import all the backends
1160 backend.import_backends()1229 backend.import_backends()
@@ -1185,11 +1254,22 @@
1185"file:///usr/local". See the man page for more information.""") % (args[0],),1254"file:///usr/local". See the man page for more information.""") % (args[0],),
1186 log.ErrorCode.bad_url)1255 log.ErrorCode.bad_url)
1187 elif len(args) == 2:1256 elif len(args) == 2:
1257<<<<<<< TREE
1188 if replicate:1258 if replicate:
1189 globals.src_backend = backend.get_backend(args[0])1259 globals.src_backend = backend.get_backend(args[0])
1190 globals.backend = backend.get_backend(args[1])1260 globals.backend = backend.get_backend(args[1])
1191 action = u"replicate"1261 action = u"replicate"
1262=======
1263 # Figure out whether backup or restore
1264 backup, local_pathname = set_backend(args[0], args[1])
1265 if backup:
1266 if full_backup:
1267 action = "full"
1268 else:
1269 action = "inc"
1270>>>>>>> MERGE-SOURCE
1192 else:1271 else:
1272<<<<<<< TREE
1193 # Figure out whether backup or restore1273 # Figure out whether backup or restore
1194 backup, local_pathname = set_backend(args[0], args[1])1274 backup, local_pathname = set_backend(args[0], args[1])
1195 if backup:1275 if backup:
@@ -1197,15 +1277,29 @@
1197 action = u"full"1277 action = u"full"
1198 else:1278 else:
1199 action = u"inc"1279 action = u"inc"
1280=======
1281 if verify:
1282 action = "verify"
1283>>>>>>> MERGE-SOURCE
1200 else:1284 else:
1285<<<<<<< TREE
1201 if verify:1286 if verify:
1202 action = u"verify"1287 action = u"verify"
1203 else:1288 else:
1204 action = u"restore"1289 action = u"restore"
1290=======
1291 action = "restore"
1292>>>>>>> MERGE-SOURCE
12051293
1294<<<<<<< TREE
1206 process_local_dir(action, local_pathname)1295 process_local_dir(action, local_pathname)
1207 if action in [u'full', u'inc', u'verify']:1296 if action in [u'full', u'inc', u'verify']:
1208 set_selection()1297 set_selection()
1298=======
1299 process_local_dir(action, local_pathname)
1300 if action in ['full', 'inc', 'verify']:
1301 set_selection()
1302>>>>>>> MERGE-SOURCE
1209 elif len(args) > 2:1303 elif len(args) > 2:
1210 raise AssertionError(u"this code should not be reachable")1304 raise AssertionError(u"this code should not be reachable")
12111305
12121306
=== modified file 'duplicity/compilec.py'
--- duplicity/compilec.py 2018-12-04 20:50:28 +0000
+++ duplicity/compilec.py 2019-03-04 12:09:45 +0000
@@ -22,6 +22,7 @@
2222
23import sys23import sys
24import os24import os
25<<<<<<< TREE
2526
26# Avoid conflict on python 2 with collections.py vs. built-in collections module27# Avoid conflict on python 2 with collections.py vs. built-in collections module
27sp = sys.path28sp = sys.path
@@ -29,6 +30,9 @@
29# https://github.com/PyCQA/pylint/issues/7330# https://github.com/PyCQA/pylint/issues/73
30from distutils.core import setup, Extension # pylint: disable=import-error,no-name-in-module31from distutils.core import setup, Extension # pylint: disable=import-error,no-name-in-module
31sys.path = sp32sys.path = sp
33=======
34from distutils.core import setup, Extension
35>>>>>>> MERGE-SOURCE
3236
33assert len(sys.argv) == 137assert len(sys.argv) == 1
34sys.argv.append("build")38sys.argv.append("build")
3539
=== modified file 'duplicity/diffdir.py'
--- duplicity/diffdir.py 2018-11-29 19:00:15 +0000
+++ duplicity/diffdir.py 2019-03-04 12:09:45 +0000
@@ -92,7 +92,7 @@
92 """92 """
93 global stats93 global stats
94 stats = statistics.StatsDeltaProcess()94 stats = statistics.StatsDeltaProcess()
95 if isinstance(dirsig_fileobj_list, list):95 if isinstance(dirsig_fileobj_list, types.ListType):
96 sig_iter = combine_path_iters([sigtar2path_iter(x) for x96 sig_iter = combine_path_iters([sigtar2path_iter(x) for x
97 in dirsig_fileobj_list])97 in dirsig_fileobj_list])
98 else:98 else:
@@ -227,7 +227,7 @@
227 else:227 else:
228 ti.name = b"deleted/" + b"/".join(sig_path.index)228 ti.name = b"deleted/" + b"/".join(sig_path.index)
229 sigTarFile.addfile(ti)229 sigTarFile.addfile(ti)
230 stats.add_deleted_file(sig_path)230 stats.add_deleted_file()
231 yield ROPath(sig_path.index)231 yield ROPath(sig_path.index)
232 elif not sig_path or new_path != sig_path:232 elif not sig_path or new_path != sig_path:
233 # Must calculate new signature and create delta233 # Must calculate new signature and create delta
@@ -294,7 +294,7 @@
294 while 1:294 while 1:
295 if not relem1:295 if not relem1:
296 try:296 try:
297 relem1 = next(riter1)297 relem1 = riter1.next()
298 except StopIteration:298 except StopIteration:
299 if relem2:299 if relem2:
300 yield (None, relem2)300 yield (None, relem2)
@@ -304,7 +304,7 @@
304 index1 = relem1.index304 index1 = relem1.index
305 if not relem2:305 if not relem2:
306 try:306 try:
307 relem2 = next(riter2)307 relem2 = riter2.next()
308 except StopIteration:308 except StopIteration:
309 if relem1:309 if relem1:
310 yield (relem1, None)310 yield (relem1, None)
@@ -345,7 +345,7 @@
345 Represent the next element as a triple, to help sorting345 Represent the next element as a triple, to help sorting
346 """346 """
347 try:347 try:
348 path = next(path_iter_list[iter_index])348 path = path_iter_list[iter_index].next()
349 except StopIteration:349 except StopIteration:
350 return None350 return None
351 return (path.index, iter_index, path)351 return (path.index, iter_index, path)
@@ -385,7 +385,7 @@
385 """385 """
386 global stats386 global stats
387 stats = statistics.StatsDeltaProcess()387 stats = statistics.StatsDeltaProcess()
388 if isinstance(sig_infp_list, list):388 if isinstance(sig_infp_list, types.ListType):
389 sig_path_iter = get_combined_path_iter(sig_infp_list)389 sig_path_iter = get_combined_path_iter(sig_infp_list)
390 else:390 else:
391 sig_path_iter = sigtar2path_iter(sig_infp_list)391 sig_path_iter = sigtar2path_iter(sig_infp_list)
@@ -541,7 +541,11 @@
541 result = self.process_continued() # pylint: disable=assignment-from-no-return541 result = self.process_continued() # pylint: disable=assignment-from-no-return
542 else:542 else:
543 # Below a StopIteration exception will just be passed upwards543 # Below a StopIteration exception will just be passed upwards
544<<<<<<< TREE
544 result = self.process(next(self.input_iter)) # pylint: disable=assignment-from-no-return545 result = self.process(next(self.input_iter)) # pylint: disable=assignment-from-no-return
546=======
547 result = self.process(self.input_iter.next())
548>>>>>>> MERGE-SOURCE
545 block_number = self.process_next_vol_number549 block_number = self.process_next_vol_number
546 self.offset += len(result.data)550 self.offset += len(result.data)
547 self.previous_index = result.index551 self.previous_index = result.index
548552
=== modified file 'duplicity/dup_threading.py'
--- duplicity/dup_threading.py 2018-11-29 19:00:15 +0000
+++ duplicity/dup_threading.py 2019-03-04 12:09:45 +0000
@@ -28,12 +28,15 @@
28at least python 2.5.)28at least python 2.5.)
29"""29"""
3030
31<<<<<<< TREE
31from future import standard_library32from future import standard_library
32standard_library.install_aliases()33standard_library.install_aliases()
33from builtins import object34from builtins import object
34import sys35import sys
35from duplicity import errors36from duplicity import errors
3637
38=======
39>>>>>>> MERGE-SOURCE
37_threading_supported = True40_threading_supported = True
3841
39try:42try:
@@ -48,6 +51,10 @@
48 import dummy_threading as threading51 import dummy_threading as threading
49 _threading_supported = False52 _threading_supported = False
5053
54import sys
55
56from duplicity import errors
57
5158
52def threading_supported():59def threading_supported():
53 u"""60 u"""
5461
=== modified file 'duplicity/dup_time.py'
=== modified file 'duplicity/file_naming.py'
--- duplicity/file_naming.py 2018-11-29 19:00:15 +0000
+++ duplicity/file_naming.py 2019-03-04 12:09:45 +0000
@@ -448,11 +448,3 @@
448 self.encrypted = encrypted # true if gpg encrypted448 self.encrypted = encrypted # true if gpg encrypted
449449
450 self.partial = partial450 self.partial = partial
451
452 def __eq__(self, other):
453 return self.type == other.type and \
454 self.manifest == other.manifest and \
455 self.time == other.time and \
456 self.start_time == other.start_time and \
457 self.end_time == other.end_time and \
458 self.partial == other.partial
459451
=== modified file 'duplicity/globals.py'
--- duplicity/globals.py 2019-01-25 17:08:40 +0000
+++ duplicity/globals.py 2019-03-04 12:09:45 +0000
@@ -58,9 +58,14 @@
58# contains the signatures and manifests of the relevent backup58# contains the signatures and manifests of the relevent backup
59# collection), and for checkpoint state between volumes.59# collection), and for checkpoint state between volumes.
60# NOTE: this gets expanded in duplicity.commandline60# NOTE: this gets expanded in duplicity.commandline
61<<<<<<< TREE
61os.environ[u"XDG_CACHE_HOME"] = os.getenv(u"XDG_CACHE_HOME", os.path.expanduser(u"~/.cache"))62os.environ[u"XDG_CACHE_HOME"] = os.getenv(u"XDG_CACHE_HOME", os.path.expanduser(u"~/.cache"))
62archive_dir = os.path.expandvars(u"$XDG_CACHE_HOME/duplicity")63archive_dir = os.path.expandvars(u"$XDG_CACHE_HOME/duplicity")
63archive_dir_path = None64archive_dir_path = None
65=======
66os.environ["XDG_CACHE_HOME"] = os.getenv("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
67archive_dir = os.path.expandvars("$XDG_CACHE_HOME/duplicity")
68>>>>>>> MERGE-SOURCE
6469
65# config dir for future use70# config dir for future use
66os.environ[u"XDG_CONFIG_HOME"] = os.getenv(u"XDG_CONFIG_HOME", os.path.expanduser(u"~/.config"))71os.environ[u"XDG_CONFIG_HOME"] = os.getenv(u"XDG_CONFIG_HOME", os.path.expanduser(u"~/.config"))
@@ -220,6 +225,7 @@
220# Use server side encryption in s3225# Use server side encryption in s3
221s3_use_sse = False226s3_use_sse = False
222227
228<<<<<<< TREE
223# Use server side kms encryption in s3229# Use server side kms encryption in s3
224s3_use_sse_kms = False230s3_use_sse_kms = False
225s3_kms_key_id = None231s3_kms_key_id = None
@@ -240,6 +246,8 @@
240# Standard storage tier used for storring backup blobs (Hot|Cool|Archive).246# Standard storage tier used for storring backup blobs (Hot|Cool|Archive).
241azure_blob_tier = None247azure_blob_tier = None
242248
249=======
250>>>>>>> MERGE-SOURCE
243# Whether to use the full email address as the user name when251# Whether to use the full email address as the user name when
244# logging into an imap server. If false just the user name252# logging into an imap server. If false just the user name
245# part of the email address is used.253# part of the email address is used.
@@ -321,11 +329,9 @@
321# Whether to enable gio backend329# Whether to enable gio backend
322use_gio = False330use_gio = False
323331
324# If set, collect only the file status, not the whole root.
325file_changed = None
326
327# delay (in seconds) before next operation after failure332# delay (in seconds) before next operation after failure
328backend_retry_delay = 30333backend_retry_delay = 30
334<<<<<<< TREE
329335
330# default filesystem encoding336# default filesystem encoding
331# In Python 2 it seems that sys.getfilesystemencoding() will normally return337# In Python 2 it seems that sys.getfilesystemencoding() will normally return
@@ -333,3 +339,12 @@
333# either 'ascii' or None. Both are bogus, so default to 'utf-8' if it does.339# either 'ascii' or None. Both are bogus, so default to 'utf-8' if it does.
334fsencoding = sys.getfilesystemencoding()340fsencoding = sys.getfilesystemencoding()
335fsencoding = fsencoding if fsencoding not in [u'ascii', u'ANSI_X3.4-1968', None] else u'utf-8'341fsencoding = fsencoding if fsencoding not in [u'ascii', u'ANSI_X3.4-1968', None] else u'utf-8'
342=======
343
344# default filesystem encoding
345# In Python 2 it seems that sys.getfilesystemencoding() will normally return
346# 'utf-8' or some other sane encoding, but will sometimes fail and return
347# either 'ascii' or None. Both are bogus, so default to 'utf-8' if it does.
348fsencoding = sys.getfilesystemencoding()
349fsencoding = fsencoding if fsencoding not in ['ascii', None] else 'utf-8'
350>>>>>>> MERGE-SOURCE
336351
=== modified file 'duplicity/globmatch.py'
--- duplicity/globmatch.py 2018-11-29 19:00:15 +0000
+++ duplicity/globmatch.py 2019-03-04 12:09:45 +0000
@@ -56,8 +56,13 @@
56 return list(map(glob_to_regex, prefixes))56 return list(map(glob_to_regex, prefixes))
5757
5858
59<<<<<<< TREE
59def select_fn_from_glob(glob_str, include, ignore_case=False):60def select_fn_from_glob(glob_str, include, ignore_case=False):
60 u"""Return a function test_fn(path) which61 u"""Return a function test_fn(path) which
62=======
63def path_matches_glob_fn(glob_str, include, ignore_case=False):
64 """Return a function test_fn(path) which
65>>>>>>> MERGE-SOURCE
61 tests whether path matches glob, as per the Unix shell rules, taking as66 tests whether path matches glob, as per the Unix shell rules, taking as
62 arguments a path, a glob string and include (0 indicating that the glob67 arguments a path, a glob string and include (0 indicating that the glob
63 string is an exclude glob and 1 indicating that it is an include glob,68 string is an exclude glob and 1 indicating that it is an include glob,
@@ -66,16 +71,18 @@
66 1 - if the file should be included71 1 - if the file should be included
67 2 - if the folder should be scanned for any included/excluded files72 2 - if the folder should be scanned for any included/excluded files
68 None - if the selection function has nothing to say about the file73 None - if the selection function has nothing to say about the file
69
70 Note: including a folder implicitly includes everything within it.
71 """74 """
72 assert isinstance(glob_str, str)75 assert isinstance(glob_str, str)
73 glob_ends_w_slash = False76 glob_ends_w_slash = False
7477
78<<<<<<< TREE
75 if glob_str == u"/":79 if glob_str == u"/":
76 # If the glob string is '/', it implicitly includes everything80 # If the glob string is '/', it implicitly includes everything
77 glob_str = u"/**"81 glob_str = u"/**"
78 elif glob_str[-1] == u"/":82 elif glob_str[-1] == u"/":
83=======
84 if glob_str != "/" and glob_str[-1] == "/":
85>>>>>>> MERGE-SOURCE
79 glob_ends_w_slash = True86 glob_ends_w_slash = True
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches