FileBackup 0.4.4__tar.gz → 0.5.2__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.
Files changed (57) hide show
  1. {filebackup-0.4.4 → filebackup-0.5.2}/.copier-answers.yml +1 -1
  2. {filebackup-0.4.4 → filebackup-0.5.2}/.github/workflows/CICD_impl.yml +8 -0
  3. filebackup-0.5.2/.gitignore +16 -0
  4. {filebackup-0.4.4 → filebackup-0.5.2}/BuildBinary.py +49 -6
  5. {filebackup-0.4.4 → filebackup-0.5.2}/DEVELOPMENT.md +1 -1
  6. {filebackup-0.4.4 → filebackup-0.5.2}/PKG-INFO +8 -6
  7. {filebackup-0.4.4 → filebackup-0.5.2}/README.md +6 -4
  8. {filebackup-0.4.4 → filebackup-0.5.2}/pyproject.toml +18 -8
  9. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/CommandLine/OffsiteEntryPoint.py +7 -0
  10. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/Offsite.py +191 -150
  11. filebackup-0.5.2/src/FileBackup/__init__.py +8 -0
  12. {filebackup-0.4.4 → filebackup-0.5.2}/tests/CommandLine/EntryPoint_UnitTest.py +3 -0
  13. {filebackup-0.4.4 → filebackup-0.5.2}/uv.lock +330 -250
  14. filebackup-0.4.4/.gitignore +0 -7
  15. filebackup-0.4.4/src/FileBackup/__init__.py +0 -12
  16. {filebackup-0.4.4 → filebackup-0.5.2}/.github/CODEOWNERS +0 -0
  17. {filebackup-0.4.4 → filebackup-0.5.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  18. {filebackup-0.4.4 → filebackup-0.5.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  19. {filebackup-0.4.4 → filebackup-0.5.2}/.github/ISSUE_TEMPLATE/custom.md +0 -0
  20. {filebackup-0.4.4 → filebackup-0.5.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  21. {filebackup-0.4.4 → filebackup-0.5.2}/.github/actions/release_impl/action.yml +0 -0
  22. {filebackup-0.4.4 → filebackup-0.5.2}/.github/pull_request_template.md +0 -0
  23. {filebackup-0.4.4 → filebackup-0.5.2}/.github/release_sources.yaml +0 -0
  24. {filebackup-0.4.4 → filebackup-0.5.2}/.github/workflows/CICD.yml +0 -0
  25. {filebackup-0.4.4 → filebackup-0.5.2}/.github/workflows/codeql.yml +0 -0
  26. {filebackup-0.4.4 → filebackup-0.5.2}/.pre-commit-config.yaml +0 -0
  27. {filebackup-0.4.4 → filebackup-0.5.2}/.python-version +0 -0
  28. {filebackup-0.4.4 → filebackup-0.5.2}/CODE_OF_CONDUCT.md +0 -0
  29. {filebackup-0.4.4 → filebackup-0.5.2}/CONTRIBUTING.md +0 -0
  30. {filebackup-0.4.4 → filebackup-0.5.2}/GOVERNANCE.md +0 -0
  31. {filebackup-0.4.4 → filebackup-0.5.2}/LICENSE +0 -0
  32. {filebackup-0.4.4 → filebackup-0.5.2}/MAINTAINERS.md +0 -0
  33. {filebackup-0.4.4 → filebackup-0.5.2}/SECURITY.md +0 -0
  34. {filebackup-0.4.4 → filebackup-0.5.2}/minisign_key.pub +0 -0
  35. {filebackup-0.4.4 → filebackup-0.5.2}/src/AutoGitSemVer.yaml +0 -0
  36. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/CommandLine/CommandLineArguments.py +0 -0
  37. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/CommandLine/EntryPoint.py +0 -0
  38. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/CommandLine/MirrorEntryPoint.py +0 -0
  39. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/CommandLine/__init__.py +0 -0
  40. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/DataStore/FastGlacierDataStore.py +0 -0
  41. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/DataStore/FileSystemDataStore.py +0 -0
  42. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/DataStore/Interfaces/BulkStorageDataStore.py +0 -0
  43. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/DataStore/Interfaces/DataStore.py +0 -0
  44. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/DataStore/Interfaces/FileBasedDataStore.py +0 -0
  45. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/DataStore/Interfaces/__init__.py +0 -0
  46. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/DataStore/S3BrowserDataStore.py +0 -0
  47. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/DataStore/SFTPDataStore.py +0 -0
  48. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/DataStore/__init__.py +0 -0
  49. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/Impl/Common.py +0 -0
  50. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/Impl/__init__.py +0 -0
  51. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/Mirror.py +0 -0
  52. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/Snapshot.py +0 -0
  53. {filebackup-0.4.4 → filebackup-0.5.2}/src/FileBackup/py.typed +0 -0
  54. {filebackup-0.4.4 → filebackup-0.5.2}/tests/Mirror_UnitTest.py +0 -0
  55. {filebackup-0.4.4 → filebackup-0.5.2}/tests/Offsite_UnitTest.py +0 -0
  56. {filebackup-0.4.4 → filebackup-0.5.2}/tests/Snapshot_UnitTest.py +0 -0
  57. {filebackup-0.4.4 → filebackup-0.5.2}/tests/TestHelpers.py +0 -0
@@ -6,7 +6,7 @@
6
6
  # available at https://github.com/gt-sse-center/copier-UvScaffolding.
7
7
  #
8
8
 
9
- _commit: v0.2.0
9
+ _commit: v0.2.4
10
10
  _src_path: .
11
11
  author_email: github@DavidBrownell.com
12
12
  author_name: David Brownell
@@ -66,6 +66,9 @@ jobs:
66
66
  python-version: ${{ matrix.python_version }}
67
67
  enable-cache: true
68
68
 
69
+ - name: Install Dependencies
70
+ run: uv sync --frozen
71
+
69
72
  - name: Run pre-commit scripts
70
73
  run: uv run pre-commit run --verbose
71
74
 
@@ -250,6 +253,9 @@ jobs:
250
253
  python-version: ${{ inputs.python_package_version }}
251
254
  enable-cache: true
252
255
 
256
+ - name: Install Dependencies
257
+ run: uv sync --frozen
258
+
253
259
  - name: Build Binary
254
260
  run: uv run python BuildBinary.py Build --verbose
255
261
 
@@ -261,6 +267,8 @@ jobs:
261
267
  with:
262
268
  name: Binary.${{ matrix.os }}
263
269
  path: FileBackup-${{ env.PACKAGE_VERSION }}.*
270
+
271
+ # ----------------------------------------------------------------------
264
272
  validate_binary:
265
273
  needs: [python_package, build_binary]
266
274
 
@@ -0,0 +1,16 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+ .coverage
12
+ .DS_Store
13
+ .vscode
14
+ coverage.xml
15
+ minisign_key.pri
16
+ post_generation_instructions.html
@@ -1,15 +1,21 @@
1
1
  import os
2
2
  import shutil
3
+ import textwrap
4
+ import uuid
3
5
 
4
6
  from pathlib import Path
5
7
  from typing import Annotated, Optional
6
8
 
7
9
  import typer
8
10
 
11
+ from dbrownell_Common.ContextlibEx import ExitStack
9
12
  from dbrownell_Common import SubprocessEx
10
13
  from dbrownell_Common.Streams.DoneManager import DoneManager, Flags as DoneManagerFlags
14
+ import inflect
11
15
  from typer.core import TyperGroup
12
16
 
17
+ import FileBackup
18
+
13
19
 
14
20
  # ----------------------------------------------------------------------
15
21
  class NaturalOrderGrouper(TyperGroup):
@@ -46,12 +52,49 @@ def Build(
46
52
  with DoneManager.CreateCommandLine(
47
53
  flags=DoneManagerFlags.Create(verbose=verbose, debug=debug),
48
54
  ) as dm:
49
- command_line = "cxfreeze --script src/FileBackup/CommandLine/EntryPoint.py --target-name=FileBackup"
50
-
51
- dm.WriteVerbose(f"Command line: {command_line}\n\n")
52
-
53
- with dm.YieldStream() as stream:
54
- dm.result = SubprocessEx.Stream(command_line, stream)
55
+ # inflect uses the typeguard library, which relies on inspect to read the source code of
56
+ # inflect to enforce that arguments are the correct types when invoking functions. This
57
+ # works fine when running the application normally, but does not work by default with
58
+ # cx_Freeze because it does not include the source code of inflect in the built binary. This
59
+ # means that typeguard can't determine the types of the arguments, which causes it to raise
60
+ # an exception. The fix is to include the inflect source code in the built binary so that
61
+ # typeguard can find the function's types and not raise an exception.
62
+ inflect_filename = Path(inflect.__file__).relative_to(Path(__file__).parent)
63
+
64
+ configuration_filename = Path("setup{}.py".format(str(uuid.uuid4()).replace("-", "")))
65
+
66
+ configuration_filename.write_text(
67
+ textwrap.dedent(
68
+ f"""\
69
+ from cx_Freeze import setup, Executable
70
+
71
+ setup(
72
+ name = "FileBackup",
73
+ version = "{FileBackup.__version__}",
74
+ options = {{
75
+ "build_exe": {{
76
+ "include_files": [
77
+ (r"{inflect_filename}", "lib/inflect/{inflect_filename.name}"),
78
+ ],
79
+ "packages": []
80
+ }},
81
+ }},
82
+ executables = [
83
+ Executable(
84
+ "src/FileBackup/CommandLine/EntryPoint.py",
85
+ target_name="FileBackup",
86
+ base=None,
87
+ ),
88
+ ],
89
+ )
90
+ """,
91
+ ),
92
+ encoding="utf-8",
93
+ )
94
+
95
+ with ExitStack(configuration_filename.unlink):
96
+ with dm.YieldStream() as stream:
97
+ dm.result = SubprocessEx.Stream(f'python "{configuration_filename}" build_exe', stream)
55
98
 
56
99
 
57
100
  # ----------------------------------------------------------------------
@@ -19,7 +19,7 @@
19
19
  | Automated Testing | `uv run pytest` or<br/>`uv run pytest --no-cov` | Run automated tests using [pytest](https://docs.pytest.org/) and extract code coverage using [coverage](https://coverage.readthedocs.io/) based on settings in `pyproject.toml`. | :white_check_mark: | :white_check_mark: |
20
20
  | Semantic Version Generation | `uv run python -m AutoGitSemVer.scripts.UpdatePythonVersion ./src/FileBackup/__init__.py ./src` | Generate a new [Semantic Version](https://semver.org/) based on git commits using [AutoGitSemVer](https://github.com/davidbrownell/AutoGitSemVer). Version information is stored in `./src/FileBackup/__init__.py`. | | :white_check_mark: |
21
21
  | Python Package Creation | `uv build` | Create a python package using [uv](https://github.com/astral-sh/uv) based on settings in `pyproject.toml`. Generated packages will be written to `./dist`. | | :white_check_mark: |
22
- | Sign Artifacts | `uv run --with py-minisign python -c "import minisign; minisign.SecretKey.from_file(<temp_filename>).sign_file(<filename>, trusted_comment='<package_name> v<package_version>', drop_signature=True)` | Signs artifacts using [py-minisign](https://github.com/x13a/py-minisign). Note that the private key is stored as a [GitHub secret](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions). | | :white_check_mark: |
22
+ | Sign Artifacts | `uv run python -c "import minisign; minisign.SecretKey.from_file(<temp_filename>).sign_file(<filename>, trusted_comment='<package_name> v<package_version>', drop_signature=True)` | Signs artifacts using [py-minisign](https://github.com/x13a/py-minisign). Note that the private key is stored as a [GitHub secret](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions). | | :white_check_mark: |
23
23
  | Python Package Publishing | `uv publish` | Publish a python package to [PyPi](https://pypi.org/) using [uv](https://github.com/astral-sh/uv) based on settings in `pyproject.toml`. | | :white_check_mark: |
24
24
 
25
25
  ## Contributing Changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: FileBackup
3
- Version: 0.4.4
3
+ Version: 0.5.2
4
4
  Summary: Tool for creating and restoring file system backups.
5
5
  Project-URL: Homepage, https://github.com/davidbrownell/FileBackup
6
6
  Project-URL: Documentation, https://github.com/davidbrownell/FileBackup
@@ -28,7 +28,7 @@ Classifier: Topic :: System :: Archiving :: Mirroring
28
28
  Classifier: Topic :: System :: Systems Administration
29
29
  Classifier: Topic :: Utilities
30
30
  Requires-Python: >=3.10
31
- Requires-Dist: dbrownell-common>=0.14.6
31
+ Requires-Dist: dbrownell-common>=0.15.0
32
32
  Requires-Dist: paramiko>=3.5.1
33
33
  Requires-Dist: typer>=0.15.3
34
34
  Description-Content-Type: text/markdown
@@ -59,7 +59,7 @@ Description-Content-Type: text/markdown
59
59
  ## Overview
60
60
  TODO: Complete this section
61
61
 
62
- ### How to use FileBackup
62
+ ### How to use `FileBackup`
63
63
  TODO: Complete this section
64
64
 
65
65
  <!-- Content below this delimiter will be copied to the generated README.md file. DO NOT REMOVE THIS COMMENT, as it will cause regeneration to fail. -->
@@ -72,11 +72,13 @@ TODO: Complete this section
72
72
  | Via [pip](https://pip.pypa.io/en/stable/) | `pip install FileBackup` |
73
73
 
74
74
  ### Verifying Signed Artifacts
75
- Artifacts are signed and validated using [py-minisign](https://github.com/x13a/py-minisign) and the public key in the file `./minisign_key.pub`.
75
+ Artifacts are signed and verified using [py-minisign](https://github.com/x13a/py-minisign) and the public key in the file `./minisign_key.pub`.
76
76
 
77
77
  To verify that an artifact is valid, visit [the latest release](https://github.com/davidbrownell/FileBackup/releases/latest) and download the `.minisign` signature file that corresponds to the artifact, then run the following command, replacing `<filename>` with the name of the artifact to be verified:
78
78
 
79
- `uv run --with py-minisign python -c "import minisign; minisign.PublicKey.from_file('minisign_key.pub').verify_file('<filename>')"`
79
+ ```shell
80
+ uv run --with py-minisign python -c "import minisign; minisign.PublicKey.from_file('minisign_key.pub').verify_file('<filename>'); print('The file has been verified.')"
81
+ ```
80
82
 
81
83
  ## Development
82
84
  Please visit [Contributing](https://github.com/davidbrownell/FileBackup/blob/main/CONTRIBUTING.md) and [Development](https://github.com/davidbrownell/FileBackup/blob/main/DEVELOPMENT.md) for information on contributing to this project.
@@ -94,4 +96,4 @@ Additional information can be found at these locations.
94
96
  | Security | [SECURITY.md](https://github.com/davidbrownell/FileBackup/blob/main/SECURITY.md) | Information about how to privately report security issues associated with this project. |
95
97
 
96
98
  ## License
97
- FileBackup is licensed under the <a href="https://choosealicense.com/licenses/MIT/" target="_blank">MIT</a> license.
99
+ `FileBackup` is licensed under the <a href="https://choosealicense.com/licenses/MIT/" target="_blank">MIT</a> license.
@@ -24,7 +24,7 @@
24
24
  ## Overview
25
25
  TODO: Complete this section
26
26
 
27
- ### How to use FileBackup
27
+ ### How to use `FileBackup`
28
28
  TODO: Complete this section
29
29
 
30
30
  <!-- Content below this delimiter will be copied to the generated README.md file. DO NOT REMOVE THIS COMMENT, as it will cause regeneration to fail. -->
@@ -37,11 +37,13 @@ TODO: Complete this section
37
37
  | Via [pip](https://pip.pypa.io/en/stable/) | `pip install FileBackup` |
38
38
 
39
39
  ### Verifying Signed Artifacts
40
- Artifacts are signed and validated using [py-minisign](https://github.com/x13a/py-minisign) and the public key in the file `./minisign_key.pub`.
40
+ Artifacts are signed and verified using [py-minisign](https://github.com/x13a/py-minisign) and the public key in the file `./minisign_key.pub`.
41
41
 
42
42
  To verify that an artifact is valid, visit [the latest release](https://github.com/davidbrownell/FileBackup/releases/latest) and download the `.minisign` signature file that corresponds to the artifact, then run the following command, replacing `<filename>` with the name of the artifact to be verified:
43
43
 
44
- `uv run --with py-minisign python -c "import minisign; minisign.PublicKey.from_file('minisign_key.pub').verify_file('<filename>')"`
44
+ ```shell
45
+ uv run --with py-minisign python -c "import minisign; minisign.PublicKey.from_file('minisign_key.pub').verify_file('<filename>'); print('The file has been verified.')"
46
+ ```
45
47
 
46
48
  ## Development
47
49
  Please visit [Contributing](https://github.com/davidbrownell/FileBackup/blob/main/CONTRIBUTING.md) and [Development](https://github.com/davidbrownell/FileBackup/blob/main/DEVELOPMENT.md) for information on contributing to this project.
@@ -59,4 +61,4 @@ Additional information can be found at these locations.
59
61
  | Security | [SECURITY.md](https://github.com/davidbrownell/FileBackup/blob/main/SECURITY.md) | Information about how to privately report security issues associated with this project. |
60
62
 
61
63
  ## License
62
- FileBackup is licensed under the <a href="https://choosealicense.com/licenses/MIT/" target="_blank">MIT</a> license.
64
+ `FileBackup` is licensed under the <a href="https://choosealicense.com/licenses/MIT/" target="_blank">MIT</a> license.
@@ -7,7 +7,7 @@ authors = [
7
7
  ]
8
8
  requires-python = ">= 3.10"
9
9
  dependencies = [
10
- "dbrownell-common>=0.14.6",
10
+ "dbrownell-common>=0.15.0",
11
11
  "paramiko>=3.5.1",
12
12
  "typer>=0.15.3",
13
13
  ]
@@ -23,7 +23,7 @@ keywords = [
23
23
  license = "MIT"
24
24
 
25
25
  classifiers = [
26
- "Development Status :: 4 - Beta", # TODO
26
+ "Development Status :: 4 - Beta",
27
27
  "Environment :: Console",
28
28
  "Intended Audience :: Developers",
29
29
  "Intended Audience :: End Users/Desktop",
@@ -58,20 +58,21 @@ build-backend = "hatchling.build"
58
58
 
59
59
  [dependency-groups]
60
60
  dev = [
61
- "autogitsemver>=0.8.0",
61
+ "autogitsemver>=0.8.4",
62
62
  "cx-freeze>=8.3.0",
63
- "dbrownell-commitemojis>=0.1.3",
63
+ "dbrownell-commitemojis>=0.1.4",
64
64
  "pre-commit>=4.2.0",
65
- "pytest>=8.3.5",
66
- "pytest-cov>=6.1.1",
67
- "ruff>=0.11.8",
65
+ "py-minisign>=0.12.0",
66
+ "pytest>=8.4.1",
67
+ "pytest-cov>=6.2.1",
68
+ "ruff>=0.12.3",
68
69
  ]
69
70
 
70
71
  [tool.hatch.version]
71
72
  path = "src/FileBackup/__init__.py"
72
73
 
73
74
  [tool.pytest.ini_options]
74
- addopts = "--verbose -vv --capture=no --cov=FileBackup --cov-fail-under=85.0"
75
+ addopts = "--verbose -vv --capture=no --cov=FileBackup --cov-report term --cov-report xml:coverage.xml --cov-fail-under=85.0"
75
76
  python_files = [
76
77
  "**/*Test.py",
77
78
  ]
@@ -87,12 +88,21 @@ ignore = [
87
88
  "ANN003", # Missing type annotation for `**kwargs`
88
89
  "BLE001", # Do not catch blind exception: `Exception`
89
90
  "COM812", # Trailing comma missing
91
+ "D105", # Missing docstring in magic method
92
+ "D107", # Missing docstring in `__init__` method
90
93
  "D202", # No blank lines allowed after function docstring
91
94
  "E501", # Line too long
95
+ "FIX002", # Line contains TODO, consider resolving the issue
92
96
  "I001", # Import block is un-sorted or un-formatted
93
97
  "N802", # Function name `xxx` should be lowercase
94
98
  "N999", # Invalid module name
99
+ "RSE102", # Unnecessary parentheses on raise exception
95
100
  "S101", # Use of assert detected
101
+ "TC006", # Add quotes to type expression in `typing.cast()`
102
+ "TD002", # Missing author in TODO
103
+ "TD003", # Missing issue link for this TODO
104
+ "TRY002", # Create your own exception
105
+ "TRY300", # Consider moving this statement to an `else` block
96
106
  "UP032", # Use f-string instead of `format` call
97
107
  ]
98
108
 
@@ -241,6 +241,12 @@ def Restore( # pylint: disable=dangerous-default-value
241
241
  help="Working directory to use when decompressing archives; provide this value during a dry run and subsequent execution to only download and extract the backup content once.",
242
242
  ),
243
243
  ] = None,
244
+ continue_on_errors: Annotated[
245
+ bool,
246
+ typer.Option(
247
+ "--continue-on-errors", help="Continue restoring files even if some files cannot be restored."
248
+ ),
249
+ ] = False,
244
250
  ) -> None:
245
251
  """Restores content from an offsite data store."""
246
252
 
@@ -263,6 +269,7 @@ def Restore( # pylint: disable=dangerous-default-value
263
269
  quiet=quiet,
264
270
  dry_run=dry_run,
265
271
  overwrite=overwrite,
272
+ continue_on_errors=continue_on_errors,
266
273
  )
267
274
 
268
275