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