duplicity 3.0.5__tar.gz → 3.0.6.dev7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/CHANGELOG.md +13 -0
- {duplicity-3.0.5/duplicity.egg-info → duplicity-3.0.6.dev7}/PKG-INFO +5 -16
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/__init__.py +2 -2
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/__main__.py +1 -1
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backend.py +40 -60
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/multibackend.py +20 -16
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/s3_boto3_backend.py +40 -18
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/ssh_pexpect_backend.py +1 -1
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/swiftbackend.py +3 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/dup_main.py +5 -3
- {duplicity-3.0.5 → duplicity-3.0.6.dev7/duplicity.egg-info}/PKG-INFO +5 -16
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity.egg-info/requires.txt +2 -14
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/man/duplicity.1 +2 -2
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/af_ZA/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/ca_ES/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/en_AU/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/en_PR/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/en_US/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/he_IL/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/sr_SP/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/vi_VN/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/zh_HK/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/zh_MO/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/zh_SG/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/zh_TW/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/pyproject.toml +70 -13
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/requirements.dev +1 -2
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/requirements.txt +2 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/setup.py +10 -1
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/AUTHORS.md +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/COPYING +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/README-LOG.md +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/README-REPO.md +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/README-TESTING.md +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/README.md +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/_librsyncmodule.c +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/argparse311.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backend_pool.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/__init__.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/_cf_cloudfiles.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/_cf_pyrax.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/_testbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/adbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/azurebackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/b2backend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/boxbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/cfbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/dpbxbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/gdocsbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/gdrivebackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/giobackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/hsibackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/hubicbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/idrivedbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/imapbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/jottacloudbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/lftpbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/localbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/mediafirebackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/megabackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/megav2backend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/megav3backend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/ncftpbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/onedrivebackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/par2backend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/pcabackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/pydrivebackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/pyrax_identity/__init__.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/pyrax_identity/hubic.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/rclonebackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/rsyncbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/slatebackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/ssh_paramiko_backend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/sxbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/tahoebackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/webdavbackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/backends/xorrisobackend.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/cached_ops.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/cli_data.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/cli_main.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/cli_util.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/config.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/diffdir.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/dup_collections.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/dup_tarfile.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/dup_temp.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/dup_time.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/errors.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/file_naming.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/filechunkio.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/globmatch.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/gpg.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/gpginterface.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/lazy.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/librsync.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/log.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/manifest.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/patchdir.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/path.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/progress.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/robust.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/selection.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/statistics.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/tempdir.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity/util.py +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity.egg-info/SOURCES.txt +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity.egg-info/dependency_links.txt +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity.egg-info/entry_points.txt +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/duplicity.egg-info/top_level.txt +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/ar_SA/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/cs_CZ/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/da_DK/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/de_AT/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/de_DE/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/el_GR/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/en_GB/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/es_EM/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/es_ES/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/es_MX/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/es_PR/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/es_US/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/fi_FI/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/fr_FR/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/hu_HU/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/it_IT/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/ja_JP/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/ko_KR/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/nl_BE/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/nl_NL/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/nl_SR/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/no_NO/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/pl_PL/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/pt_BR/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/pt_PT/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/ro_RO/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/ru_BY/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/ru_MD/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/ru_RU/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/ru_UA/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/sv_SE/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/tr_TR/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/uk_UA/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/po/zh_CN/duplicity.mo +0 -0
- {duplicity-3.0.5 → duplicity-3.0.6.dev7}/setup.cfg +0 -0
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## rel.3.0.5.1 (2025-06-25)
|
|
5
|
+
|
|
6
|
+
### Changes
|
|
7
|
+
|
|
8
|
+
* Fixes for LP builds. See #877. [Kenneth Loafman]
|
|
9
|
+
|
|
10
|
+
### Fix
|
|
11
|
+
|
|
12
|
+
* Revert "Fix build-system.requires and requirements.txt" [Kenneth Loafman]
|
|
13
|
+
|
|
14
|
+
This reverts commit 3683aa4dd8c0a5fa4d70eee256a853310ffa9a87.
|
|
15
|
+
|
|
16
|
+
|
|
4
17
|
## rel.3.0.5 (2025-06-19)
|
|
5
18
|
|
|
6
19
|
### New
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: duplicity
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.6.dev7
|
|
4
4
|
Summary: Encrypted backup using rsync algorithm
|
|
5
5
|
Author-email: Kenneth Loafman <kenneth@loafman.com>
|
|
6
6
|
Maintainer: Edgar Soldin, Thomas Laubrock
|
|
7
|
-
License: GPL-2.0-or-later
|
|
8
7
|
Project-URL: Homepage, http://duplicity.us
|
|
9
8
|
Project-URL: Download, https://gitlab.com/duplicity/duplicity/-/releases
|
|
10
9
|
Project-URL: Issues, https://gitlab.com/duplicity/duplicity/-/issues
|
|
@@ -12,6 +11,7 @@ Project-URL: Contact, https://lists.nongnu.org/mailman/listinfo/duplicity-talk
|
|
|
12
11
|
Project-URL: Documentation, http://duplicity.us
|
|
13
12
|
Project-URL: Repository, https://gitlab.com/duplicity/duplicity
|
|
14
13
|
Project-URL: Changelog, https://gitlab.com/duplicity/duplicity/-/blob/main/CHANGELOG.md
|
|
14
|
+
Platform: any
|
|
15
15
|
Classifier: Development Status :: 6 - Mature
|
|
16
16
|
Classifier: Environment :: Console
|
|
17
17
|
Classifier: Operating System :: MacOS
|
|
@@ -25,11 +25,13 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
25
25
|
Classifier: Programming Language :: Python :: 3.12
|
|
26
26
|
Classifier: Programming Language :: Python :: 3.13
|
|
27
27
|
Classifier: Topic :: System :: Archiving :: Backup
|
|
28
|
-
Requires-Python: <3.
|
|
28
|
+
Requires-Python: <3.15,>=3.8
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
License-File: COPYING
|
|
31
31
|
License-File: AUTHORS.md
|
|
32
32
|
Requires-Dist: fasteners>=0.19
|
|
33
|
+
Requires-Dist: python-gettext>=5.0
|
|
34
|
+
Requires-Dist: setuptools>=78.1.0
|
|
33
35
|
Requires-Dist: azure-storage-blob
|
|
34
36
|
Requires-Dist: b2sdk
|
|
35
37
|
Requires-Dist: boto3
|
|
@@ -53,19 +55,6 @@ Requires-Dist: pyrax
|
|
|
53
55
|
Requires-Dist: python-swiftclient
|
|
54
56
|
Requires-Dist: requests
|
|
55
57
|
Requires-Dist: requests-oauthlib
|
|
56
|
-
Provides-Extra: dev
|
|
57
|
-
Requires-Dist: setuptools>=68.1.0; extra == "dev"
|
|
58
|
-
Requires-Dist: black==24.8.0; extra == "dev"
|
|
59
|
-
Requires-Dist: coverage; extra == "dev"
|
|
60
|
-
Requires-Dist: pycodestyle; extra == "dev"
|
|
61
|
-
Requires-Dist: pylint; extra == "dev"
|
|
62
|
-
Requires-Dist: pytest; extra == "dev"
|
|
63
|
-
Requires-Dist: pytest-cov; extra == "dev"
|
|
64
|
-
Requires-Dist: gitchangelog; extra == "dev"
|
|
65
|
-
Requires-Dist: myst-parser; extra == "dev"
|
|
66
|
-
Requires-Dist: pystache; extra == "dev"
|
|
67
|
-
Requires-Dist: sphinx; extra == "dev"
|
|
68
|
-
Requires-Dist: sphinx-rtd-theme; extra == "dev"
|
|
69
58
|
Dynamic: license-file
|
|
70
59
|
|
|
71
60
|
# REQUIREMENTS
|
|
@@ -96,7 +96,7 @@ def dup_run():
|
|
|
96
96
|
# For backend errors, don't show an ugly stack trace by
|
|
97
97
|
# default. But do with sufficient verbosity.
|
|
98
98
|
log.Info(_("Backend error detail: %s") % util.exception_traceback())
|
|
99
|
-
log.FatalError(f"{e.__class__.__name__}: {util.uexc(e)}", log.ErrorCode.
|
|
99
|
+
log.FatalError(f"{e.__class__.__name__}: {util.uexc(e)}", log.ErrorCode.backend_error, e.__class__.__name__)
|
|
100
100
|
|
|
101
101
|
except Exception as e:
|
|
102
102
|
util.release_lockfile()
|
|
@@ -57,7 +57,6 @@ from duplicity.util import exception_traceback
|
|
|
57
57
|
|
|
58
58
|
_backends = {}
|
|
59
59
|
_backend_prefixes = {}
|
|
60
|
-
_last_exception = None
|
|
61
60
|
|
|
62
61
|
# These URL schemes have a backend with a notion of an RFC "network location".
|
|
63
62
|
# The 'file' and 's3+http' schemes should not be in this list.
|
|
@@ -369,72 +368,53 @@ def retry(operation, fatal=True):
|
|
|
369
368
|
# have to return a decorator function (which itself returns a function!)
|
|
370
369
|
def outer_retry(fn):
|
|
371
370
|
def inner_retry(self, *args):
|
|
372
|
-
global _last_exception
|
|
373
|
-
errors_fatal, errors_default = config.are_errors_fatal.get(operation, (True, None))
|
|
374
371
|
for n in range(1, config.num_retries + 1):
|
|
375
372
|
try:
|
|
376
373
|
return fn(self, *args)
|
|
377
374
|
except FatalBackendException as e:
|
|
378
|
-
|
|
379
|
-
if not errors_fatal:
|
|
380
|
-
# backend wants to report and ignore errors
|
|
381
|
-
return errors_default
|
|
382
|
-
else:
|
|
383
|
-
# die on fatal errors
|
|
384
|
-
raise e
|
|
375
|
+
raise
|
|
385
376
|
except Exception as e:
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
#
|
|
392
|
-
|
|
393
|
-
at_end =
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
if at_end and fatal:
|
|
400
|
-
|
|
401
|
-
def make_filename(f):
|
|
402
|
-
if isinstance(f, path.ROPath):
|
|
403
|
-
return util.escape(f.uc_name)
|
|
404
|
-
else:
|
|
405
|
-
return util.escape(f)
|
|
406
|
-
|
|
407
|
-
extra = " ".join(
|
|
408
|
-
[operation] + [make_filename(x) for x in args if (x and isinstance(x, str))]
|
|
409
|
-
)
|
|
410
|
-
if multiprocessing.parent_process():
|
|
411
|
-
# running as a child process we need to raise an exception to signal an issue
|
|
412
|
-
log.Error(
|
|
413
|
-
_("Giving up after %s attempts. %s: %s. (for trace back: set log level DEBUG)")
|
|
414
|
-
% (n, e.__class__.__name__, util.uexc(e)),
|
|
415
|
-
code=code,
|
|
416
|
-
extra=extra,
|
|
417
|
-
)
|
|
418
|
-
e.code = code
|
|
419
|
-
raise
|
|
377
|
+
# retry on anything else
|
|
378
|
+
log.Debug(_("Backtrace of previous error: %s") % exception_traceback())
|
|
379
|
+
at_end = n == config.num_retries
|
|
380
|
+
code = _get_code_from_exception(self.backend, operation, e)
|
|
381
|
+
if code == log.ErrorCode.backend_not_found:
|
|
382
|
+
# If we tried to do something, but the file just isn't there,
|
|
383
|
+
# no need to retry.
|
|
384
|
+
at_end = True
|
|
385
|
+
if at_end and fatal:
|
|
386
|
+
|
|
387
|
+
def make_filename(f):
|
|
388
|
+
if isinstance(f, path.ROPath):
|
|
389
|
+
return util.escape(f.uc_name)
|
|
420
390
|
else:
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
391
|
+
return util.escape(f)
|
|
392
|
+
|
|
393
|
+
extra = " ".join([operation] + [make_filename(x) for x in args if (x and isinstance(x, str))])
|
|
394
|
+
log.Error(
|
|
395
|
+
_("Giving up after %s attempts. %s: %s. (for trace back: set log level DEBUG)")
|
|
396
|
+
% (n, e.__class__.__name__, util.uexc(e)),
|
|
397
|
+
code=code,
|
|
398
|
+
extra=extra,
|
|
399
|
+
)
|
|
400
|
+
e.code = code
|
|
401
|
+
# Ensure it's a BackendException, so that __main__ top-level handler exits with
|
|
402
|
+
# code backend_error.
|
|
403
|
+
if not isinstance(e, BackendException):
|
|
404
|
+
e = BackendException(str(e), code=e.code)
|
|
405
|
+
raise e
|
|
406
|
+
else:
|
|
407
|
+
log.Warn(
|
|
408
|
+
_("Attempt of %s Nr. %s failed. %s: %s")
|
|
409
|
+
% (fn.__name__, n, e.__class__.__name__, util.uexc(e))
|
|
410
|
+
)
|
|
411
|
+
if not at_end:
|
|
412
|
+
if isinstance(e, TemporaryLoadException):
|
|
413
|
+
time.sleep(3 * config.backend_retry_delay) # wait longer before trying again
|
|
426
414
|
else:
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
)
|
|
431
|
-
if not at_end:
|
|
432
|
-
if isinstance(e, TemporaryLoadException):
|
|
433
|
-
time.sleep(3 * config.backend_retry_delay) # wait longer before trying again
|
|
434
|
-
else:
|
|
435
|
-
time.sleep(config.backend_retry_delay) # wait a bit before trying again
|
|
436
|
-
if hasattr(self.backend, "_retry_cleanup"):
|
|
437
|
-
self.backend._retry_cleanup()
|
|
415
|
+
time.sleep(config.backend_retry_delay) # wait a bit before trying again
|
|
416
|
+
if hasattr(self.backend, "_retry_cleanup"):
|
|
417
|
+
self.backend._retry_cleanup()
|
|
438
418
|
|
|
439
419
|
return inner_retry
|
|
440
420
|
|
|
@@ -288,14 +288,17 @@ class MultiBackend(duplicity.backend.Backend):
|
|
|
288
288
|
)
|
|
289
289
|
raise BackendException("failed to write")
|
|
290
290
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
log.
|
|
297
|
-
|
|
298
|
-
|
|
291
|
+
if self.__write_cursor == first:
|
|
292
|
+
if passed:
|
|
293
|
+
break
|
|
294
|
+
else:
|
|
295
|
+
# If we've looped around, and none of them passed, fail
|
|
296
|
+
log.Log(
|
|
297
|
+
_("MultiBackend: failed to write %s. Tried all backing stores and none succeeded")
|
|
298
|
+
% source_path,
|
|
299
|
+
log.ERROR,
|
|
300
|
+
)
|
|
301
|
+
raise BackendException("failed to write")
|
|
299
302
|
|
|
300
303
|
def _get(self, remote_filename, local_path):
|
|
301
304
|
# since the backend operations will be retried, we can't
|
|
@@ -325,17 +328,18 @@ class MultiBackend(duplicity.backend.Backend):
|
|
|
325
328
|
def _list(self):
|
|
326
329
|
lists = []
|
|
327
330
|
for s in self.__stores:
|
|
328
|
-
|
|
329
|
-
|
|
331
|
+
try:
|
|
332
|
+
l = s.list()
|
|
333
|
+
except BackendException as e:
|
|
334
|
+
l = []
|
|
335
|
+
last_exception = e
|
|
336
|
+
else:
|
|
337
|
+
last_exception = None
|
|
330
338
|
log.Notice(_("MultiBackend: %s: %d files") % (s.backend.parsed_url.strip_auth(), len(l)))
|
|
331
|
-
if len(l) == 0 and
|
|
339
|
+
if len(l) == 0 and last_exception:
|
|
332
340
|
log.Warn(
|
|
333
|
-
_(
|
|
334
|
-
f"Exception during list of {s.backend.parsed_url.strip_auth()}: "
|
|
335
|
-
f"{util.uexc(duplicity.backend._last_exception)}"
|
|
336
|
-
)
|
|
341
|
+
_(f"Exception during list of {s.backend.parsed_url.strip_auth()}: " f"{util.uexc(last_exception)}")
|
|
337
342
|
)
|
|
338
|
-
duplicity.backend._last_exception = None
|
|
339
343
|
lists.append(l)
|
|
340
344
|
# combine the lists into a single flat list w/o duplicates via set:
|
|
341
345
|
result = list({item for sublist in lists for item in sublist})
|
|
@@ -31,6 +31,8 @@ from duplicity.errors import (
|
|
|
31
31
|
BackendException,
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
+
global boto3, botocore, ClientError, S3UploadFailedError, TransferConfig
|
|
35
|
+
|
|
34
36
|
|
|
35
37
|
# Note: current gaps with the old boto backend include:
|
|
36
38
|
# - Glacier restore to S3 not implemented. Should this
|
|
@@ -66,6 +68,25 @@ class S3Boto3Backend(duplicity.backend.Backend):
|
|
|
66
68
|
"""
|
|
67
69
|
|
|
68
70
|
def __init__(self, parsed_url):
|
|
71
|
+
global boto3, botocore, ClientError, S3UploadFailedError, TransferConfig
|
|
72
|
+
import boto3
|
|
73
|
+
import botocore
|
|
74
|
+
from boto3.s3.transfer import S3UploadFailedError, TransferConfig
|
|
75
|
+
from botocore.exceptions import ClientError
|
|
76
|
+
|
|
77
|
+
if not (boto3.__version__ < "1.36.0" and botocore.__version__ < "1.36.0"):
|
|
78
|
+
# TODO: remove this workaround when issue #870 is fixed.
|
|
79
|
+
# https://github.com/boto/boto3/issues/2913
|
|
80
|
+
log.Warn(
|
|
81
|
+
"WARNING: Using boto3 >= 1,36.0 may result in errors, so we qre applying\n"
|
|
82
|
+
"the workaround for https://gitlab.com/duplicity/duplicity/-/issues/870\n"
|
|
83
|
+
" export AWS_REQUEST_CHECKSUM_CALCULATION=when_required\n"
|
|
84
|
+
" export AWS_RESPONSE_CHECKSUM_VALIDATION=when_required\n"
|
|
85
|
+
"NOTE: This workaround is temporary and will be removed when issue is fixed.\n."
|
|
86
|
+
)
|
|
87
|
+
os.environ["AWS_REQUEST_CHECKSUM_CALCULATION"] = "when_required"
|
|
88
|
+
os.environ["AWS_RESPONSE_CHECKSUM_VALIDATION"] = "when_required"
|
|
89
|
+
|
|
69
90
|
duplicity.backend.Backend.__init__(self, parsed_url)
|
|
70
91
|
|
|
71
92
|
# This folds the null prefix and all null parts, which means that:
|
|
@@ -89,10 +110,6 @@ class S3Boto3Backend(duplicity.backend.Backend):
|
|
|
89
110
|
self.tracker = UploadProgressTracker()
|
|
90
111
|
|
|
91
112
|
def reset_connection(self):
|
|
92
|
-
import boto3
|
|
93
|
-
import botocore
|
|
94
|
-
from botocore.exceptions import ClientError
|
|
95
|
-
|
|
96
113
|
self.bucket = None
|
|
97
114
|
self.s3 = boto3.resource(
|
|
98
115
|
"s3",
|
|
@@ -116,8 +133,6 @@ class S3Boto3Backend(duplicity.backend.Backend):
|
|
|
116
133
|
self.bucket = self.s3.Bucket(self.bucket_name) # only set if bucket is thought to exist.
|
|
117
134
|
|
|
118
135
|
def _put(self, local_source_path, remote_filename):
|
|
119
|
-
from boto3.s3.transfer import TransferConfig
|
|
120
|
-
|
|
121
136
|
if not self.s3:
|
|
122
137
|
self.reset_connection()
|
|
123
138
|
|
|
@@ -178,16 +193,24 @@ class S3Boto3Backend(duplicity.backend.Backend):
|
|
|
178
193
|
key = self.key_prefix + remote_filename
|
|
179
194
|
|
|
180
195
|
log.Info(f"Uploading {self.straight_url}/{remote_filename} to {storage_class} Storage")
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
196
|
+
try:
|
|
197
|
+
self.s3.Object(self.bucket.name, key).upload_file(
|
|
198
|
+
local_source_path.uc_name,
|
|
199
|
+
Callback=tracker.progress_cb,
|
|
200
|
+
Config=transfer_config,
|
|
201
|
+
ExtraArgs=extra_args,
|
|
202
|
+
)
|
|
203
|
+
except S3UploadFailedError as e:
|
|
204
|
+
if boto3.__version__ > "1.36.0" or botocore.__version__ > "1.36.0":
|
|
205
|
+
log.FatalError(
|
|
206
|
+
f"Failed to upload file {remote_filename}, got S3UploadFailedError\n"
|
|
207
|
+
f"See https://gitlab.com/duplicity/duplicity/-/issues/870 for details.\n"
|
|
208
|
+
f"Quick fix is: [sudo] pip3 install boto3<1.36.0 botocore<1.36.0"
|
|
209
|
+
)
|
|
210
|
+
else:
|
|
211
|
+
raise e
|
|
187
212
|
|
|
188
213
|
def _get(self, remote_filename, local_path):
|
|
189
|
-
from botocore.exceptions import ClientError
|
|
190
|
-
|
|
191
214
|
if not self.s3:
|
|
192
215
|
self.reset_connection()
|
|
193
216
|
|
|
@@ -198,8 +221,9 @@ class S3Boto3Backend(duplicity.backend.Backend):
|
|
|
198
221
|
except ClientError as ios:
|
|
199
222
|
if ios.response["Error"]["Code"] == "InvalidObjectState":
|
|
200
223
|
log.FatalError(
|
|
201
|
-
f"File {remote_filename} seems to be in a long term storage,
|
|
202
|
-
f"
|
|
224
|
+
f"File {remote_filename} seems to be in a long term storage,"
|
|
225
|
+
f"Please use AWS Console/API to initiate restore.\n"
|
|
226
|
+
f"API-Error: {ios}"
|
|
203
227
|
)
|
|
204
228
|
else:
|
|
205
229
|
raise ios
|
|
@@ -230,8 +254,6 @@ class S3Boto3Backend(duplicity.backend.Backend):
|
|
|
230
254
|
if not self.s3:
|
|
231
255
|
self.reset_connection()
|
|
232
256
|
|
|
233
|
-
import botocore
|
|
234
|
-
|
|
235
257
|
remote_filename = os.fsdecode(remote_filename)
|
|
236
258
|
key = self.key_prefix + remote_filename
|
|
237
259
|
content_length = -1
|
|
@@ -79,7 +79,7 @@ class SSHPExpectBackend(duplicity.backend.Backend):
|
|
|
79
79
|
# make sure remote_dir is always valid
|
|
80
80
|
if parsed_url.path:
|
|
81
81
|
# remove leading '/'
|
|
82
|
-
self.remote_dir =
|
|
82
|
+
self.remote_dir = re.sub(r"^/", r"", parsed_url.path, 1)
|
|
83
83
|
else:
|
|
84
84
|
self.remote_dir = "."
|
|
85
85
|
self.remote_prefix = f"{self.remote_dir}/"
|
|
@@ -25,6 +25,8 @@ from duplicity import config
|
|
|
25
25
|
from duplicity import log
|
|
26
26
|
from duplicity.errors import BackendException
|
|
27
27
|
|
|
28
|
+
global Connection, ClientException, SwiftService, SwiftUploadObject
|
|
29
|
+
|
|
28
30
|
|
|
29
31
|
class SwiftBackend(duplicity.backend.Backend):
|
|
30
32
|
"""
|
|
@@ -34,6 +36,7 @@ class SwiftBackend(duplicity.backend.Backend):
|
|
|
34
36
|
def __init__(self, parsed_url):
|
|
35
37
|
duplicity.backend.Backend.__init__(self, parsed_url)
|
|
36
38
|
|
|
39
|
+
global Connection, ClientException, SwiftService, SwiftUploadObject
|
|
37
40
|
try:
|
|
38
41
|
from swiftclient.service import SwiftUploadObject
|
|
39
42
|
from swiftclient.service import SwiftService
|
|
@@ -376,7 +376,8 @@ def write_multivol(backup_type, tarblock_iter, man_outfp, sig_outfp, backend):
|
|
|
376
376
|
transfer_success = False
|
|
377
377
|
manifest_written = False
|
|
378
378
|
|
|
379
|
-
def collect_put_results(
|
|
379
|
+
def collect_put_results(backend_pooler, command2vol_map: Dict[int, CommandMetaData]):
|
|
380
|
+
bytes_written = 0
|
|
380
381
|
for result in backend_pooler.results_since_last_call():
|
|
381
382
|
track_id = result.track_id
|
|
382
383
|
size = result.result
|
|
@@ -392,6 +393,7 @@ def write_multivol(backup_type, tarblock_iter, man_outfp, sig_outfp, backend):
|
|
|
392
393
|
f"Transfer of {command2vol_map[track_id].path_obj.get_filename()} with id {track_id} and size "
|
|
393
394
|
f"{size} took {result.get_runtime()}"
|
|
394
395
|
)
|
|
396
|
+
return bytes_written
|
|
395
397
|
|
|
396
398
|
def write_manifest_in_sequence(mf, mf_file, command2vol_map: Dict[int, CommandMetaData]):
|
|
397
399
|
"""
|
|
@@ -499,7 +501,7 @@ def write_multivol(backup_type, tarblock_iter, man_outfp, sig_outfp, backend):
|
|
|
499
501
|
progress.report_transfer(0, tdp.getsize())
|
|
500
502
|
track_id = backend_pooler.command_throttled(backend.put_validated.__name__, args=(tdp, dest_filename))
|
|
501
503
|
command2vol_map[track_id] = CommandMetaData(vol_num, tdp, vi)
|
|
502
|
-
collect_put_results(
|
|
504
|
+
bytes_written += collect_put_results(backend_pooler, command2vol_map)
|
|
503
505
|
write_manifest_in_sequence(mf, man_outfp, command2vol_map)
|
|
504
506
|
except (Exception, SystemExit) as e:
|
|
505
507
|
# ensure pool processes terminate clean
|
|
@@ -529,7 +531,7 @@ def write_multivol(backup_type, tarblock_iter, man_outfp, sig_outfp, backend):
|
|
|
529
531
|
# wait for background commands, collect some stats and shutdown clean.
|
|
530
532
|
log.Debug("Collecting remaining results from backend pool.")
|
|
531
533
|
while True and backend_pooler:
|
|
532
|
-
collect_put_results(
|
|
534
|
+
bytes_written += collect_put_results(backend_pooler, command2vol_map)
|
|
533
535
|
write_manifest_in_sequence(mf, man_outfp, command2vol_map)
|
|
534
536
|
if backend_pooler.get_queue_length() == 0:
|
|
535
537
|
break
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: duplicity
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.6.dev7
|
|
4
4
|
Summary: Encrypted backup using rsync algorithm
|
|
5
5
|
Author-email: Kenneth Loafman <kenneth@loafman.com>
|
|
6
6
|
Maintainer: Edgar Soldin, Thomas Laubrock
|
|
7
|
-
License: GPL-2.0-or-later
|
|
8
7
|
Project-URL: Homepage, http://duplicity.us
|
|
9
8
|
Project-URL: Download, https://gitlab.com/duplicity/duplicity/-/releases
|
|
10
9
|
Project-URL: Issues, https://gitlab.com/duplicity/duplicity/-/issues
|
|
@@ -12,6 +11,7 @@ Project-URL: Contact, https://lists.nongnu.org/mailman/listinfo/duplicity-talk
|
|
|
12
11
|
Project-URL: Documentation, http://duplicity.us
|
|
13
12
|
Project-URL: Repository, https://gitlab.com/duplicity/duplicity
|
|
14
13
|
Project-URL: Changelog, https://gitlab.com/duplicity/duplicity/-/blob/main/CHANGELOG.md
|
|
14
|
+
Platform: any
|
|
15
15
|
Classifier: Development Status :: 6 - Mature
|
|
16
16
|
Classifier: Environment :: Console
|
|
17
17
|
Classifier: Operating System :: MacOS
|
|
@@ -25,11 +25,13 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
25
25
|
Classifier: Programming Language :: Python :: 3.12
|
|
26
26
|
Classifier: Programming Language :: Python :: 3.13
|
|
27
27
|
Classifier: Topic :: System :: Archiving :: Backup
|
|
28
|
-
Requires-Python: <3.
|
|
28
|
+
Requires-Python: <3.15,>=3.8
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
License-File: COPYING
|
|
31
31
|
License-File: AUTHORS.md
|
|
32
32
|
Requires-Dist: fasteners>=0.19
|
|
33
|
+
Requires-Dist: python-gettext>=5.0
|
|
34
|
+
Requires-Dist: setuptools>=78.1.0
|
|
33
35
|
Requires-Dist: azure-storage-blob
|
|
34
36
|
Requires-Dist: b2sdk
|
|
35
37
|
Requires-Dist: boto3
|
|
@@ -53,19 +55,6 @@ Requires-Dist: pyrax
|
|
|
53
55
|
Requires-Dist: python-swiftclient
|
|
54
56
|
Requires-Dist: requests
|
|
55
57
|
Requires-Dist: requests-oauthlib
|
|
56
|
-
Provides-Extra: dev
|
|
57
|
-
Requires-Dist: setuptools>=68.1.0; extra == "dev"
|
|
58
|
-
Requires-Dist: black==24.8.0; extra == "dev"
|
|
59
|
-
Requires-Dist: coverage; extra == "dev"
|
|
60
|
-
Requires-Dist: pycodestyle; extra == "dev"
|
|
61
|
-
Requires-Dist: pylint; extra == "dev"
|
|
62
|
-
Requires-Dist: pytest; extra == "dev"
|
|
63
|
-
Requires-Dist: pytest-cov; extra == "dev"
|
|
64
|
-
Requires-Dist: gitchangelog; extra == "dev"
|
|
65
|
-
Requires-Dist: myst-parser; extra == "dev"
|
|
66
|
-
Requires-Dist: pystache; extra == "dev"
|
|
67
|
-
Requires-Dist: sphinx; extra == "dev"
|
|
68
|
-
Requires-Dist: sphinx-rtd-theme; extra == "dev"
|
|
69
58
|
Dynamic: license-file
|
|
70
59
|
|
|
71
60
|
# REQUIREMENTS
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
fasteners>=0.19
|
|
2
|
+
python-gettext>=5.0
|
|
3
|
+
setuptools>=78.1.0
|
|
2
4
|
azure-storage-blob
|
|
3
5
|
b2sdk
|
|
4
6
|
boto3
|
|
@@ -22,17 +24,3 @@ pyrax
|
|
|
22
24
|
python-swiftclient
|
|
23
25
|
requests
|
|
24
26
|
requests-oauthlib
|
|
25
|
-
|
|
26
|
-
[dev]
|
|
27
|
-
setuptools>=68.1.0
|
|
28
|
-
black==24.8.0
|
|
29
|
-
coverage
|
|
30
|
-
pycodestyle
|
|
31
|
-
pylint
|
|
32
|
-
pytest
|
|
33
|
-
pytest-cov
|
|
34
|
-
gitchangelog
|
|
35
|
-
myst-parser
|
|
36
|
-
pystache
|
|
37
|
-
sphinx
|
|
38
|
-
sphinx-rtd-theme
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH DUPLICITY 1 "
|
|
1
|
+
.TH DUPLICITY 1 "August 02, 2025" "Version 3.0.6.dev7" "User Manuals" \" -*- nroff -*-
|
|
2
2
|
.\" disable justification (adjust text to left margin only)
|
|
3
3
|
.\" command line examples stay readable through that
|
|
4
4
|
.ad l
|
|
@@ -22,7 +22,7 @@ source_url target_directory
|
|
|
22
22
|
|
|
23
23
|
.B duplicity collection-status
|
|
24
24
|
.I [options] [--file-changed <relpath>] [--show-changes-in-set <index>]
|
|
25
|
-
[--jsonstat]
|
|
25
|
+
[--jsonstat] target_url
|
|
26
26
|
|
|
27
27
|
.B duplicity list-current-files
|
|
28
28
|
.I [options] [--time time]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "duplicity"
|
|
3
|
-
version = "3.0.
|
|
4
|
-
dynamic = ["dependencies"
|
|
3
|
+
version = "3.0.6.dev7"
|
|
4
|
+
dynamic = ["dependencies"]
|
|
5
5
|
description = "Encrypted backup using rsync algorithm"
|
|
6
6
|
authors = [
|
|
7
7
|
{ name = "Kenneth Loafman", email = "kenneth@loafman.com" },
|
|
@@ -11,9 +11,9 @@ maintainers = [
|
|
|
11
11
|
{ name = "Thomas Laubrock" },
|
|
12
12
|
]
|
|
13
13
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
14
|
-
requires-python = ">= 3.8, < 3.
|
|
15
|
-
#
|
|
16
|
-
license =
|
|
14
|
+
requires-python = ">= 3.8, < 3.15"
|
|
15
|
+
# not all LP builders will take license=
|
|
16
|
+
#license = "GPL-2.0-or-later"
|
|
17
17
|
classifiers = [
|
|
18
18
|
"Development Status :: 6 - Mature",
|
|
19
19
|
"Environment :: Console",
|
|
@@ -32,7 +32,14 @@ classifiers = [
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
[build-system]
|
|
35
|
-
requires = [
|
|
35
|
+
requires = [
|
|
36
|
+
"build>=1.1",
|
|
37
|
+
"pip>=24.0",
|
|
38
|
+
"pipx>=1.5",
|
|
39
|
+
"packaging>=20.0",
|
|
40
|
+
"setuptools>=78.1.0",
|
|
41
|
+
"wheel>=0.42.0",
|
|
42
|
+
]
|
|
36
43
|
build-backend = "setuptools.build_meta"
|
|
37
44
|
|
|
38
45
|
|
|
@@ -50,13 +57,37 @@ Repository = "https://gitlab.com/duplicity/duplicity"
|
|
|
50
57
|
Changelog = "https://gitlab.com/duplicity/duplicity/-/blob/main/CHANGELOG.md"
|
|
51
58
|
|
|
52
59
|
|
|
60
|
+
[tool.setuptools]
|
|
61
|
+
platforms = [
|
|
62
|
+
"any"
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
|
|
53
66
|
[tool.setuptools.dynamic]
|
|
54
|
-
dependencies = {
|
|
55
|
-
optional-dependencies.dev = { file = "requirements.dev" }
|
|
67
|
+
dependencies = {file = ["requirements.txt"]}
|
|
56
68
|
|
|
57
69
|
|
|
58
70
|
[tool.setuptools.packages.find]
|
|
59
|
-
|
|
71
|
+
where = [
|
|
72
|
+
".",
|
|
73
|
+
]
|
|
74
|
+
include = [
|
|
75
|
+
"duplicity",
|
|
76
|
+
"duplicity.backends",
|
|
77
|
+
"duplicity.backends.pyrax_identity",
|
|
78
|
+
]
|
|
79
|
+
exclude = [
|
|
80
|
+
".*",
|
|
81
|
+
"Makefile",
|
|
82
|
+
"crowdin.yml",
|
|
83
|
+
"debian*",
|
|
84
|
+
"docs*",
|
|
85
|
+
"readthedocs.yaml",
|
|
86
|
+
"snap*",
|
|
87
|
+
"testing*",
|
|
88
|
+
"tools*",
|
|
89
|
+
"venv*",
|
|
90
|
+
]
|
|
60
91
|
|
|
61
92
|
|
|
62
93
|
[tool.black]
|
|
@@ -97,17 +128,43 @@ testpaths = [
|
|
|
97
128
|
|
|
98
129
|
|
|
99
130
|
[tool.cibuildwheel]
|
|
131
|
+
|
|
132
|
+
[tool.cibuildwheel.config-settings]
|
|
133
|
+
build-option = "--use-pep517"
|
|
134
|
+
|
|
135
|
+
[tool.cibuildwheel.linux]
|
|
100
136
|
archs = [
|
|
101
137
|
"x86_64",
|
|
138
|
+
"aarch64",
|
|
102
139
|
]
|
|
103
140
|
build = [
|
|
104
|
-
"cp{
|
|
141
|
+
"cp{39,310,311,312,313}-manylinux_aarch64",
|
|
142
|
+
"cp{39,310,311,312,313}-manylinux_x86_64",
|
|
105
143
|
]
|
|
106
144
|
before-build = [
|
|
107
145
|
# WARNING: wheel builds are Centos based, not Debian.
|
|
108
|
-
"yum
|
|
109
|
-
"yum install -y
|
|
110
|
-
"
|
|
146
|
+
"yum update -y",
|
|
147
|
+
"yum install -y gcc gcc-c++ make git intltool librsync-devel",
|
|
148
|
+
"yum install -y libffi-devel openssl-devel openssl tzdata",
|
|
149
|
+
"yum install -y libxml2-devel libxslt-devel",
|
|
150
|
+
"python -m pip install -q -r requirements.txt",
|
|
151
|
+
"python ./setup.py build_ext",
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
[tool.cibuildwheel.macos.environment]
|
|
155
|
+
MACOSX_DEPLOYMENT_TARGET="15.0"
|
|
156
|
+
|
|
157
|
+
[tool.cibuildwheel.macos]
|
|
158
|
+
archs = [
|
|
159
|
+
"x86_64",
|
|
160
|
+
"arm64",
|
|
161
|
+
]
|
|
162
|
+
build = [
|
|
163
|
+
"cp{39,310,311,312,313}-macosx_arm64",
|
|
164
|
+
"cp{39,310,311,312,313}-macosx_x86_64",
|
|
165
|
+
]
|
|
166
|
+
before-build = [
|
|
167
|
+
"python -m pip install -q -r requirements.txt",
|
|
111
168
|
"python ./setup.py build_ext",
|
|
112
169
|
]
|
|
113
170
|
|
|
@@ -42,7 +42,7 @@ if not ((3, 8) <= sys.version_info[:2]):
|
|
|
42
42
|
print("Sorry, duplicity requires version 3.8 thru 3.13 of Python.", file=sys.stderr)
|
|
43
43
|
sys.exit(1)
|
|
44
44
|
|
|
45
|
-
Version: str = "3.0.
|
|
45
|
+
Version: str = "3.0.6.dev7"
|
|
46
46
|
reldate: str = time.strftime("%B %d, %Y", time.gmtime(int(os.environ.get("SOURCE_DATE_EPOCH", time.time()))))
|
|
47
47
|
|
|
48
48
|
# READTHEDOCS uses setup.py sdist but can't handle extensions
|
|
@@ -279,6 +279,15 @@ class SetVersionCommand(Command):
|
|
|
279
279
|
|
|
280
280
|
|
|
281
281
|
setup(
|
|
282
|
+
packages=[
|
|
283
|
+
"duplicity",
|
|
284
|
+
"duplicity.backends",
|
|
285
|
+
"duplicity.backends.pyrax_identity",
|
|
286
|
+
],
|
|
287
|
+
package_dir={
|
|
288
|
+
"duplicity": "duplicity",
|
|
289
|
+
"duplicity.backends": "duplicity/backends",
|
|
290
|
+
},
|
|
282
291
|
ext_modules=ext_modules,
|
|
283
292
|
data_files=get_data_files(),
|
|
284
293
|
include_package_data=True,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|