vvz-file-backup 0.1.1__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.
- vvz_file_backup-0.1.1/MANIFEST.in +6 -0
- vvz_file_backup-0.1.1/PKG-INFO +6 -0
- vvz_file_backup-0.1.1/README.md +31 -0
- vvz_file_backup-0.1.1/build.sh +126 -0
- vvz_file_backup-0.1.1/docs/CATALOG_DIRECTORY.md +50 -0
- vvz_file_backup-0.1.1/docs/PIPELINE_STUB_MANIFEST.md +65 -0
- vvz_file_backup-0.1.1/docs/STAGE0.md +50 -0
- vvz_file_backup-0.1.1/docs/USER_GUIDE.md +101 -0
- vvz_file_backup-0.1.1/docs/catalog-directory-validation.json +14 -0
- vvz_file_backup-0.1.1/docs/package-api-matrix.json +49235 -0
- vvz_file_backup-0.1.1/docs/planner/matrix.md +52 -0
- vvz_file_backup-0.1.1/docs/planner/relations.md +90 -0
- vvz_file_backup-0.1.1/docs/planner/results.md +277 -0
- vvz_file_backup-0.1.1/docs/validation-evidence.json +63 -0
- vvz_file_backup-0.1.1/examples/01_backup_lifecycle.py +72 -0
- vvz_file_backup-0.1.1/examples/02_catalog_browse.py +51 -0
- vvz_file_backup-0.1.1/examples/03_restore_and_preview.py +88 -0
- vvz_file_backup-0.1.1/examples/04_verify_and_chain_failure.py +58 -0
- vvz_file_backup-0.1.1/examples/05_typed_errors_and_conflicts.py +78 -0
- vvz_file_backup-0.1.1/examples/06_catalog_configuration.py +57 -0
- vvz_file_backup-0.1.1/examples/07_metadata_and_schemas.py +63 -0
- vvz_file_backup-0.1.1/examples/08_help_and_info.py +45 -0
- vvz_file_backup-0.1.1/examples/09_thin_cli.py +70 -0
- vvz_file_backup-0.1.1/examples/10_offline_installed_restore.py +52 -0
- vvz_file_backup-0.1.1/examples/11_recover_catalog.py +60 -0
- vvz_file_backup-0.1.1/examples/manifest.json +15 -0
- vvz_file_backup-0.1.1/pipeline/__main__.py +2 -0
- vvz_file_backup-0.1.1/pipeline/cases.py +334 -0
- vvz_file_backup-0.1.1/pipeline/catalog_cases.py +131 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_backup.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_backup_get_schema.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_backup_metadata.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_build_publication.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_cli_backup.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_cli_boundary.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_cli_help.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_cli_info.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_cli_inspect_point.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_cli_list_files.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_cli_list_points.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_cli_recover_catalog.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_cli_restore.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_cli_restore_file.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_cli_verify.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_distribution.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_examples.py +4 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_help.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_help_get_schema.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_help_metadata.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_info.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_info_get_schema.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_info_metadata.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_inspect_point.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_inspect_point_get_schema.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_inspect_point_metadata.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_list_files.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_list_files_get_schema.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_list_files_metadata.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_list_points.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_list_points_get_schema.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_list_points_metadata.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_published_artifact.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_recover_catalog.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_recover_catalog_get_schema.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_recover_catalog_metadata.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_restore.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_restore_file.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_restore_file_get_schema.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_restore_file_metadata.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_restore_get_schema.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_restore_metadata.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_verify.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_verify_get_schema.py +5 -0
- vvz_file_backup-0.1.1/pipeline/checks/check_package_verify_metadata.py +5 -0
- vvz_file_backup-0.1.1/pipeline/examples_checks.py +91 -0
- vvz_file_backup-0.1.1/pipeline/fixtures.py +4 -0
- vvz_file_backup-0.1.1/pipeline/helpers.py +4 -0
- vvz_file_backup-0.1.1/pipeline/integration_cases.py +338 -0
- vvz_file_backup-0.1.1/pipeline/main.py +2 -0
- vvz_file_backup-0.1.1/pipeline/matrix.json +49955 -0
- vvz_file_backup-0.1.1/pipeline/packaging_checks.py +444 -0
- vvz_file_backup-0.1.1/pipeline/run.py +5 -0
- vvz_file_backup-0.1.1/pipeline/runner.py +99 -0
- vvz_file_backup-0.1.1/pyproject.toml +27 -0
- vvz_file_backup-0.1.1/setup.cfg +4 -0
- vvz_file_backup-0.1.1/src/file_backup/__init__.py +60 -0
- vvz_file_backup-0.1.1/src/file_backup/_archives.py +100 -0
- vvz_file_backup-0.1.1/src/file_backup/_catalog.py +87 -0
- vvz_file_backup-0.1.1/src/file_backup/_configuration.py +40 -0
- vvz_file_backup-0.1.1/src/file_backup/_namespace.py +16 -0
- vvz_file_backup-0.1.1/src/file_backup/_operations.py +356 -0
- vvz_file_backup-0.1.1/src/file_backup/_resources.py +7 -0
- vvz_file_backup-0.1.1/src/file_backup/_validation.py +82 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/__init__.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/execute/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/execute/implementation.py +12 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/execute/metadata.json +73 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/execute/schema.json +50 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/get_schema/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/get_schema/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/get_schema/metadata.json +53 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/get_schema/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/metadata/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/metadata/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/metadata/metadata.json +53 -0
- vvz_file_backup-0.1.1/src/file_backup/api/backup/metadata/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/__init__.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/execute/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/execute/implementation.py +66 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/execute/metadata.json +34 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/execute/schema.json +23 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/get_schema/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/get_schema/implementation.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/get_schema/metadata.json +20 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/get_schema/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/metadata/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/metadata/implementation.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/metadata/metadata.json +20 -0
- vvz_file_backup-0.1.1/src/file_backup/api/help/metadata/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/USER_GUIDE.md +101 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/__init__.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/execute/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/execute/implementation.py +79 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/execute/metadata.json +34 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/execute/schema.json +19 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/get_schema/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/get_schema/implementation.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/get_schema/metadata.json +20 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/get_schema/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/metadata/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/metadata/implementation.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/metadata/metadata.json +20 -0
- vvz_file_backup-0.1.1/src/file_backup/api/info/metadata/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/__init__.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/execute/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/execute/implementation.py +12 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/execute/metadata.json +64 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/execute/schema.json +42 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/get_schema/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/get_schema/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/get_schema/metadata.json +44 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/get_schema/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/metadata/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/metadata/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/metadata/metadata.json +44 -0
- vvz_file_backup-0.1.1/src/file_backup/api/inspect_point/metadata/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/__init__.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/execute/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/execute/implementation.py +12 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/execute/metadata.json +64 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/execute/schema.json +42 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/get_schema/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/get_schema/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/get_schema/metadata.json +44 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/get_schema/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/metadata/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/metadata/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/metadata/metadata.json +44 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_files/metadata/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/__init__.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/execute/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/execute/implementation.py +12 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/execute/metadata.json +55 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/execute/schema.json +37 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/get_schema/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/get_schema/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/get_schema/metadata.json +35 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/get_schema/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/metadata/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/metadata/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/metadata/metadata.json +35 -0
- vvz_file_backup-0.1.1/src/file_backup/api/list_points/metadata/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/__init__.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/execute/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/execute/implementation.py +12 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/execute/metadata.json +82 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/execute/schema.json +55 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/get_schema/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/get_schema/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/get_schema/metadata.json +62 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/get_schema/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/metadata/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/metadata/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/metadata/metadata.json +62 -0
- vvz_file_backup-0.1.1/src/file_backup/api/recover_catalog/metadata/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/__init__.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/execute/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/execute/implementation.py +12 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/execute/metadata.json +82 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/execute/schema.json +55 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/get_schema/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/get_schema/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/get_schema/metadata.json +62 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/get_schema/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/metadata/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/metadata/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/metadata/metadata.json +62 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore/metadata/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/__init__.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/execute/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/execute/implementation.py +12 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/execute/metadata.json +100 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/execute/schema.json +68 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/get_schema/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/get_schema/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/get_schema/metadata.json +80 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/get_schema/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/metadata/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/metadata/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/metadata/metadata.json +80 -0
- vvz_file_backup-0.1.1/src/file_backup/api/restore_file/metadata/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/__init__.py +15 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/execute/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/execute/implementation.py +12 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/execute/metadata.json +64 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/execute/schema.json +42 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/get_schema/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/get_schema/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/get_schema/metadata.json +44 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/get_schema/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/metadata/__init__.py +1 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/metadata/implementation.py +11 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/metadata/metadata.json +44 -0
- vvz_file_backup-0.1.1/src/file_backup/api/verify/metadata/schema.json +6 -0
- vvz_file_backup-0.1.1/src/file_backup/cli.py +332 -0
- vvz_file_backup-0.1.1/src/file_backup/errors.py +100 -0
- vvz_file_backup-0.1.1/src/file_backup/types.py +159 -0
- vvz_file_backup-0.1.1/src/vvz_file_backup.egg-info/PKG-INFO +6 -0
- vvz_file_backup-0.1.1/src/vvz_file_backup.egg-info/SOURCES.txt +230 -0
- vvz_file_backup-0.1.1/src/vvz_file_backup.egg-info/dependency_links.txt +1 -0
- vvz_file_backup-0.1.1/src/vvz_file_backup.egg-info/entry_points.txt +2 -0
- vvz_file_backup-0.1.1/src/vvz_file_backup.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# File Backup package
|
|
2
|
+
|
|
3
|
+
`vvz-file-backup` backs up regular-file trees into immutable full and incremental points, lists and verifies saved data, and restores a whole tree or one selected file. The Python API is the primary interface. The installed `file-backup` command is a thin adapter for shell use.
|
|
4
|
+
|
|
5
|
+
## Runnable examples
|
|
6
|
+
|
|
7
|
+
Start with the [examples directory](examples/). Each script has a module docstring that explains when to use it, its inputs and filesystem effects, its results, expected errors, and an exact invocation. Every example is standalone: it imports the installed `file_backup` package, uses a private temporary workspace, and can be run from any current directory.
|
|
8
|
+
|
|
9
|
+
| Example | Usage covered |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| [`01_backup_lifecycle.py`](examples/01_backup_lifecycle.py) | Full and incremental points, unchanged detection, deletions, previews, saved points, and full-base fallback |
|
|
12
|
+
| [`02_catalog_browse.py`](examples/02_catalog_browse.py) | Listing points, inspecting lineage, and listing files |
|
|
13
|
+
| [`03_restore_and_preview.py`](examples/03_restore_and_preview.py) | Full and selective restore, previews, overwrite, and destination conflicts |
|
|
14
|
+
| [`04_verify_and_chain_failure.py`](examples/04_verify_and_chain_failure.py) | Integrity verification and a missing incremental dependency |
|
|
15
|
+
| [`05_typed_errors_and_conflicts.py`](examples/05_typed_errors_and_conflicts.py) | Validation, missing point/file, conflict errors, and safe failure effects |
|
|
16
|
+
| [`06_catalog_configuration.py`](examples/06_catalog_configuration.py) | Explicit catalog directory, config mapping, and default priority |
|
|
17
|
+
| [`07_metadata_and_schemas.py`](examples/07_metadata_and_schemas.py) | Metadata and schema accessors for all public operation classes |
|
|
18
|
+
| [`08_help_and_info.py`](examples/08_help_and_info.py) | Metadata-driven help and installed guide sections |
|
|
19
|
+
| [`09_thin_cli.py`](examples/09_thin_cli.py) | JSON command-line results and typed CLI errors |
|
|
20
|
+
| [`10_offline_installed_restore.py`](examples/10_offline_installed_restore.py) | Installed-package import and offline archive/restore flow |
|
|
21
|
+
| [`11_recover_catalog.py`](examples/11_recover_catalog.py) | Preview and recover a validated catalog copy |
|
|
22
|
+
|
|
23
|
+
Run an example from any directory after installing the package:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
python /path/to/file-backup/examples/01_backup_lifecycle.py
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The machine-readable [`manifest.json`](examples/manifest.json) maps each script to its public capability coverage. The package pipeline executes the listed scripts independently against a clean installed build. Distribution packaging must include this examples directory and manifest so the same guide remains available after installation.
|
|
30
|
+
|
|
31
|
+
The normative method, parameter, result, relationship, and side-effect contract is in [`docs/package-api-matrix.json`](docs/package-api-matrix.json). Use it for exhaustive integration details; start with the runnable examples for practical usage.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
# Never trace credentials inherited from the caller, including with bash -x.
|
|
4
|
+
set +x
|
|
5
|
+
|
|
6
|
+
PACKAGE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
PYTHON="${FILE_BACKUP_PYTHON:-python}"
|
|
8
|
+
cd "$PACKAGE_ROOT"
|
|
9
|
+
|
|
10
|
+
error() { echo "ERROR: $*" >&2; exit 1; }
|
|
11
|
+
info() { echo "INFO: $*"; }
|
|
12
|
+
|
|
13
|
+
[[ $# -eq 0 ]] || error "This command accepts no arguments; set FILE_BACKUP_VERSION for an explicit package version"
|
|
14
|
+
[[ ! -L "$PACKAGE_ROOT/pyproject.toml" && -f "$PACKAGE_ROOT/pyproject.toml" ]] \
|
|
15
|
+
|| error "Package pyproject.toml must be a regular file"
|
|
16
|
+
command -v "$PYTHON" >/dev/null 2>&1 || error "Python is required: $PYTHON"
|
|
17
|
+
|
|
18
|
+
VERSION="$($PYTHON - "$PACKAGE_ROOT/pyproject.toml" "${FILE_BACKUP_VERSION:-}" <<'PY'
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
import re
|
|
21
|
+
import sys
|
|
22
|
+
import tomllib
|
|
23
|
+
from packaging.version import InvalidVersion, Version
|
|
24
|
+
|
|
25
|
+
path = Path(sys.argv[1])
|
|
26
|
+
requested_text = sys.argv[2]
|
|
27
|
+
project = tomllib.loads(path.read_text(encoding="utf-8"))["project"]
|
|
28
|
+
if project.get("name") != "vvz-file-backup":
|
|
29
|
+
raise SystemExit("Package distribution name must be vvz-file-backup")
|
|
30
|
+
current_text = project["version"]
|
|
31
|
+
try:
|
|
32
|
+
current = Version(current_text)
|
|
33
|
+
except InvalidVersion:
|
|
34
|
+
raise SystemExit(f"Current package version is not valid PEP 440: {current_text}")
|
|
35
|
+
|
|
36
|
+
if requested_text:
|
|
37
|
+
try:
|
|
38
|
+
requested = Version(requested_text)
|
|
39
|
+
except InvalidVersion:
|
|
40
|
+
raise SystemExit(f"Requested package version is not valid PEP 440: {requested_text}")
|
|
41
|
+
if requested <= current:
|
|
42
|
+
raise SystemExit(
|
|
43
|
+
f"Requested package version {requested_text} must be greater than current version {current_text}"
|
|
44
|
+
)
|
|
45
|
+
target_text = requested_text
|
|
46
|
+
else:
|
|
47
|
+
release = list(current.release)
|
|
48
|
+
if not release:
|
|
49
|
+
raise SystemExit(f"Current package version has no release numbers: {current_text}")
|
|
50
|
+
release[-1] += 1
|
|
51
|
+
epoch = f"{current.epoch}!" if current.epoch else ""
|
|
52
|
+
target_text = epoch + ".".join(str(number) for number in release)
|
|
53
|
+
print(target_text)
|
|
54
|
+
PY
|
|
55
|
+
)" || error "Unable to select the file-backup package version"
|
|
56
|
+
|
|
57
|
+
# Persist the selected independent package version before building so the
|
|
58
|
+
# sdist and wheel metadata agree with the next root release state.
|
|
59
|
+
"$PYTHON" - "$PACKAGE_ROOT/pyproject.toml" "$VERSION" <<'PY'
|
|
60
|
+
import json
|
|
61
|
+
from pathlib import Path
|
|
62
|
+
import re
|
|
63
|
+
import sys
|
|
64
|
+
import tomllib
|
|
65
|
+
|
|
66
|
+
path = Path(sys.argv[1])
|
|
67
|
+
text = path.read_text(encoding="utf-8")
|
|
68
|
+
project = tomllib.loads(text)["project"]
|
|
69
|
+
updated, count = re.subn(
|
|
70
|
+
r'(?m)^(version\s*=\s*)"[^\"]+"$',
|
|
71
|
+
lambda match: f'{match.group(1)}"{sys.argv[2]}"',
|
|
72
|
+
text,
|
|
73
|
+
count=1,
|
|
74
|
+
)
|
|
75
|
+
if count != 1 or updated == text and project["version"] != sys.argv[2]:
|
|
76
|
+
raise SystemExit("Unable to update the package version in pyproject.toml")
|
|
77
|
+
|
|
78
|
+
metadata_paths = sorted((path.parent / "src/file_backup/api").rglob("metadata.json"))
|
|
79
|
+
if len(metadata_paths) != 30:
|
|
80
|
+
raise SystemExit(f"Expected 30 API metadata files, found {len(metadata_paths)}")
|
|
81
|
+
metadata_updates = []
|
|
82
|
+
for metadata_path in metadata_paths:
|
|
83
|
+
metadata = json.loads(metadata_path.read_text(encoding="utf-8"))
|
|
84
|
+
if not isinstance(metadata, dict) or "version" not in metadata:
|
|
85
|
+
raise SystemExit(f"API metadata has no version field: {metadata_path}")
|
|
86
|
+
metadata["version"] = sys.argv[2]
|
|
87
|
+
metadata_updates.append(
|
|
88
|
+
(metadata_path, json.dumps(metadata, ensure_ascii=False, indent=2) + "\n")
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
path.write_text(updated, encoding="utf-8")
|
|
92
|
+
for metadata_path, metadata_text in metadata_updates:
|
|
93
|
+
metadata_path.write_text(metadata_text, encoding="utf-8")
|
|
94
|
+
PY
|
|
95
|
+
|
|
96
|
+
if [[ -n "${PYPI_API_TOKEN:-}" ]]; then
|
|
97
|
+
export TWINE_USERNAME="__token__"
|
|
98
|
+
export TWINE_PASSWORD="$PYPI_API_TOKEN"
|
|
99
|
+
elif [[ -z "${TWINE_USERNAME:-}" || -z "${TWINE_PASSWORD:-}" ]]; then
|
|
100
|
+
[[ -f "${HOME}/.pypirc" ]] \
|
|
101
|
+
|| error "PyPI credentials are required: PYPI_API_TOKEN, TWINE_USERNAME/TWINE_PASSWORD, or ~/.pypirc"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
BUILD_DIR="$(mktemp -d "${TMPDIR:-/tmp}/vvz-file-backup-dist.XXXXXX")"
|
|
105
|
+
cleanup() { rm -rf -- "$BUILD_DIR"; }
|
|
106
|
+
trap cleanup EXIT
|
|
107
|
+
|
|
108
|
+
info "Building vvz-file-backup $VERSION"
|
|
109
|
+
"$PYTHON" -m build --sdist --wheel --outdir "$BUILD_DIR" "$PACKAGE_ROOT"
|
|
110
|
+
|
|
111
|
+
WHEEL="vvz_file_backup-${VERSION}-py3-none-any.whl"
|
|
112
|
+
SDIST="vvz_file_backup-${VERSION}.tar.gz"
|
|
113
|
+
[[ -f "$BUILD_DIR/$WHEEL" && ! -L "$BUILD_DIR/$WHEEL" ]] \
|
|
114
|
+
|| error "Expected wheel was not built: $WHEEL"
|
|
115
|
+
[[ -f "$BUILD_DIR/$SDIST" && ! -L "$BUILD_DIR/$SDIST" ]] \
|
|
116
|
+
|| error "Expected sdist was not built: $SDIST"
|
|
117
|
+
shopt -s nullglob
|
|
118
|
+
ARTIFACTS=("$BUILD_DIR"/*)
|
|
119
|
+
[[ ${#ARTIFACTS[@]} -eq 2 ]] || error "Build produced unexpected artifacts for vvz-file-backup $VERSION"
|
|
120
|
+
|
|
121
|
+
"$PYTHON" -m twine check "${ARTIFACTS[@]}"
|
|
122
|
+
info "Running final package examples check"
|
|
123
|
+
"$PYTHON" "$PACKAGE_ROOT/pipeline/run.py" package_examples
|
|
124
|
+
info "Publishing vvz-file-backup $VERSION to PyPI"
|
|
125
|
+
"$PYTHON" -m twine upload --non-interactive \
|
|
126
|
+
--repository-url https://upload.pypi.org/legacy/ "${ARTIFACTS[@]}"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Configurable SQLite catalog directory
|
|
2
|
+
|
|
3
|
+
The eight repository operations (backup, list_points, inspect_point, list_files,
|
|
4
|
+
restore, restore_file, verify, recover_catalog) accept two keyword-only arguments:
|
|
5
|
+
`catalog_directory: str | None = None` and
|
|
6
|
+
`config: Mapping[str, object] | None = None`.
|
|
7
|
+
|
|
8
|
+
Resolution order is an explicit non-None argument, `config['catalog_directory']`,
|
|
9
|
+
then the exported string constant `file_backup.DEFAULT_CATALOG_DIRECTORY = '.'`.
|
|
10
|
+
The eight CLI commands accept `--catalog-directory DIR` and `--config JSONFILE`
|
|
11
|
+
with the same priority. Config-file paths resolve from the process working
|
|
12
|
+
directory; catalog paths resolve from the repository. No environment or ambient
|
|
13
|
+
configuration source is introduced.
|
|
14
|
+
|
|
15
|
+
Omitted/None config means an empty mapping. An empty mapping selects the default.
|
|
16
|
+
Only the key `catalog_directory` is accepted; a present value must be a nonempty,
|
|
17
|
+
NUL-free string. A present null, unknown key, wrong type, empty string or NUL is
|
|
18
|
+
ArgumentError even when an explicit directory wins. The caller's mapping is not
|
|
19
|
+
mutated. CLI JSON must be a UTF-8 object; missing/unreadable/malformed config is
|
|
20
|
+
ArgumentError (exit 2, empty stdout, typed error on stderr).
|
|
21
|
+
|
|
22
|
+
Relative catalog directory paths, including `..`, normalize against repository;
|
|
23
|
+
absolute directories are accepted. Symlink components and an existing regular
|
|
24
|
+
file in place of a directory are ArgumentError. The selected database is
|
|
25
|
+
`<resolved-directory>/catalog.sqlite3`; SQLite temporary sidecars and lock files
|
|
26
|
+
belong there. Archives remain at `<repository>/archives`. The default therefore
|
|
27
|
+
keeps the catalog on the backup repository's volume. Reading and dry-run calls
|
|
28
|
+
create no database, directory, archive or checkpoint.
|
|
29
|
+
|
|
30
|
+
No implicit migration, fallback or active database replacement occurs. A missing
|
|
31
|
+
selected database while archives exist raises CatalogError, including when a
|
|
32
|
+
valid catalog remains at the old/default location. Recovery is the exception:
|
|
33
|
+
recover_catalog accepts an absent active catalog with a valid supplied copy and
|
|
34
|
+
writes only its new destination. An empty repository may be
|
|
35
|
+
initialized at the selected directory. Selecting an already-placed valid copy
|
|
36
|
+
for the same archive repository is supported; existing catalog/archive bytes
|
|
37
|
+
remain unchanged. recover_catalog still writes its new destination only and does
|
|
38
|
+
not install it. Backup's source and selected catalog directory must be disjoint;
|
|
39
|
+
restore destinations must be outside the selected catalog directory. Recovery's
|
|
40
|
+
destination cannot be the selected active database.
|
|
41
|
+
|
|
42
|
+
The complete machine contract is `package-api-matrix.json`:
|
|
43
|
+
`catalog_directory_contract`, updated input cells/schema/signatures and
|
|
44
|
+
`catalog_directory_delta.new_case_ids`. All 40 original rows, 472 original cases,
|
|
45
|
+
14 relation cases and four packaging scenarios are retained. 318 focused cases
|
|
46
|
+
are appended, for 790 total. Existing service rows are separate and preserved.
|
|
47
|
+
The native planner tables remain historical projections; the full JSON annex
|
|
48
|
+
governs this TODO-only change. No PLAN/HRS/MRS/G/T/A/freeze operation is required
|
|
49
|
+
or performed under the user's explicit boundary. Runtime acceptance remains the
|
|
50
|
+
tester's matrix/check RED followed by the same mapped GREEN and full pipeline.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# File Backup Pipeline Stub Manifest
|
|
2
|
+
|
|
3
|
+
Status: **NOT_IMPLEMENTED**. These declarations do not execute checks and provide no product GREEN.
|
|
4
|
+
|
|
5
|
+
## Source and scope
|
|
6
|
+
|
|
7
|
+
- Source matrix: `docs/package-api-matrix.json` (mutable stage-0 design).
|
|
8
|
+
- Mapping totals: 40 rows, 472 cases, 14 relation cases, 4 packaging scenarios, 490 mappings.
|
|
9
|
+
- Declared checks: 44; each check function raises `NotImplementedError`.
|
|
10
|
+
- Matrix mapping: `pipeline/matrix.json`; every mapping retains its scenario ID, future inputs and source expected result/error/side-effect contract where present. Packaging scenarios whose source defines assertions only are marked as lacking explicit error/side-effect contracts.
|
|
11
|
+
- Runner, CLI entrypoint, fixtures and helpers are declarations that raise `NotImplementedError`; no parser, dispatch, coverage algorithm or test algorithm is present.
|
|
12
|
+
|
|
13
|
+
## Check declarations
|
|
14
|
+
|
|
15
|
+
- `package_backup` -> `pipeline/checks/check_package_backup.py`; `check_package_backup() -> None`; **NOT_IMPLEMENTED**.
|
|
16
|
+
- `package_backup_get_schema` -> `pipeline/checks/check_package_backup_get_schema.py`; `check_package_backup_get_schema() -> None`; **NOT_IMPLEMENTED**.
|
|
17
|
+
- `package_backup_metadata` -> `pipeline/checks/check_package_backup_metadata.py`; `check_package_backup_metadata() -> None`; **NOT_IMPLEMENTED**.
|
|
18
|
+
- `package_build_publication` -> `pipeline/checks/check_package_build_publication.py`; `check_package_build_publication() -> None`; **NOT_IMPLEMENTED**.
|
|
19
|
+
- `package_cli_backup` -> `pipeline/checks/check_package_cli_backup.py`; `check_package_cli_backup() -> None`; **NOT_IMPLEMENTED**.
|
|
20
|
+
- `package_cli_boundary` -> `pipeline/checks/check_package_cli_boundary.py`; `check_package_cli_boundary() -> None`; **NOT_IMPLEMENTED**.
|
|
21
|
+
- `package_cli_help` -> `pipeline/checks/check_package_cli_help.py`; `check_package_cli_help() -> None`; **NOT_IMPLEMENTED**.
|
|
22
|
+
- `package_cli_info` -> `pipeline/checks/check_package_cli_info.py`; `check_package_cli_info() -> None`; **NOT_IMPLEMENTED**.
|
|
23
|
+
- `package_cli_inspect_point` -> `pipeline/checks/check_package_cli_inspect_point.py`; `check_package_cli_inspect_point() -> None`; **NOT_IMPLEMENTED**.
|
|
24
|
+
- `package_cli_list_files` -> `pipeline/checks/check_package_cli_list_files.py`; `check_package_cli_list_files() -> None`; **NOT_IMPLEMENTED**.
|
|
25
|
+
- `package_cli_list_points` -> `pipeline/checks/check_package_cli_list_points.py`; `check_package_cli_list_points() -> None`; **NOT_IMPLEMENTED**.
|
|
26
|
+
- `package_cli_recover_catalog` -> `pipeline/checks/check_package_cli_recover_catalog.py`; `check_package_cli_recover_catalog() -> None`; **NOT_IMPLEMENTED**.
|
|
27
|
+
- `package_cli_restore` -> `pipeline/checks/check_package_cli_restore.py`; `check_package_cli_restore() -> None`; **NOT_IMPLEMENTED**.
|
|
28
|
+
- `package_cli_restore_file` -> `pipeline/checks/check_package_cli_restore_file.py`; `check_package_cli_restore_file() -> None`; **NOT_IMPLEMENTED**.
|
|
29
|
+
- `package_cli_verify` -> `pipeline/checks/check_package_cli_verify.py`; `check_package_cli_verify() -> None`; **NOT_IMPLEMENTED**.
|
|
30
|
+
- `package_distribution` -> `pipeline/checks/check_package_distribution.py`; `check_package_distribution() -> None`; **NOT_IMPLEMENTED**.
|
|
31
|
+
- `package_help` -> `pipeline/checks/check_package_help.py`; `check_package_help() -> None`; **NOT_IMPLEMENTED**.
|
|
32
|
+
- `package_help_get_schema` -> `pipeline/checks/check_package_help_get_schema.py`; `check_package_help_get_schema() -> None`; **NOT_IMPLEMENTED**.
|
|
33
|
+
- `package_help_metadata` -> `pipeline/checks/check_package_help_metadata.py`; `check_package_help_metadata() -> None`; **NOT_IMPLEMENTED**.
|
|
34
|
+
- `package_info` -> `pipeline/checks/check_package_info.py`; `check_package_info() -> None`; **NOT_IMPLEMENTED**.
|
|
35
|
+
- `package_info_get_schema` -> `pipeline/checks/check_package_info_get_schema.py`; `check_package_info_get_schema() -> None`; **NOT_IMPLEMENTED**.
|
|
36
|
+
- `package_info_metadata` -> `pipeline/checks/check_package_info_metadata.py`; `check_package_info_metadata() -> None`; **NOT_IMPLEMENTED**.
|
|
37
|
+
- `package_inspect_point` -> `pipeline/checks/check_package_inspect_point.py`; `check_package_inspect_point() -> None`; **NOT_IMPLEMENTED**.
|
|
38
|
+
- `package_inspect_point_get_schema` -> `pipeline/checks/check_package_inspect_point_get_schema.py`; `check_package_inspect_point_get_schema() -> None`; **NOT_IMPLEMENTED**.
|
|
39
|
+
- `package_inspect_point_metadata` -> `pipeline/checks/check_package_inspect_point_metadata.py`; `check_package_inspect_point_metadata() -> None`; **NOT_IMPLEMENTED**.
|
|
40
|
+
- `package_list_files` -> `pipeline/checks/check_package_list_files.py`; `check_package_list_files() -> None`; **NOT_IMPLEMENTED**.
|
|
41
|
+
- `package_list_files_get_schema` -> `pipeline/checks/check_package_list_files_get_schema.py`; `check_package_list_files_get_schema() -> None`; **NOT_IMPLEMENTED**.
|
|
42
|
+
- `package_list_files_metadata` -> `pipeline/checks/check_package_list_files_metadata.py`; `check_package_list_files_metadata() -> None`; **NOT_IMPLEMENTED**.
|
|
43
|
+
- `package_list_points` -> `pipeline/checks/check_package_list_points.py`; `check_package_list_points() -> None`; **NOT_IMPLEMENTED**.
|
|
44
|
+
- `package_list_points_get_schema` -> `pipeline/checks/check_package_list_points_get_schema.py`; `check_package_list_points_get_schema() -> None`; **NOT_IMPLEMENTED**.
|
|
45
|
+
- `package_list_points_metadata` -> `pipeline/checks/check_package_list_points_metadata.py`; `check_package_list_points_metadata() -> None`; **NOT_IMPLEMENTED**.
|
|
46
|
+
- `package_published_artifact` -> `pipeline/checks/check_package_published_artifact.py`; `check_package_published_artifact() -> None`; **NOT_IMPLEMENTED**.
|
|
47
|
+
- `package_recover_catalog` -> `pipeline/checks/check_package_recover_catalog.py`; `check_package_recover_catalog() -> None`; **NOT_IMPLEMENTED**.
|
|
48
|
+
- `package_recover_catalog_get_schema` -> `pipeline/checks/check_package_recover_catalog_get_schema.py`; `check_package_recover_catalog_get_schema() -> None`; **NOT_IMPLEMENTED**.
|
|
49
|
+
- `package_recover_catalog_metadata` -> `pipeline/checks/check_package_recover_catalog_metadata.py`; `check_package_recover_catalog_metadata() -> None`; **NOT_IMPLEMENTED**.
|
|
50
|
+
- `package_restore` -> `pipeline/checks/check_package_restore.py`; `check_package_restore() -> None`; **NOT_IMPLEMENTED**.
|
|
51
|
+
- `package_restore_file` -> `pipeline/checks/check_package_restore_file.py`; `check_package_restore_file() -> None`; **NOT_IMPLEMENTED**.
|
|
52
|
+
- `package_restore_file_get_schema` -> `pipeline/checks/check_package_restore_file_get_schema.py`; `check_package_restore_file_get_schema() -> None`; **NOT_IMPLEMENTED**.
|
|
53
|
+
- `package_restore_file_metadata` -> `pipeline/checks/check_package_restore_file_metadata.py`; `check_package_restore_file_metadata() -> None`; **NOT_IMPLEMENTED**.
|
|
54
|
+
- `package_restore_get_schema` -> `pipeline/checks/check_package_restore_get_schema.py`; `check_package_restore_get_schema() -> None`; **NOT_IMPLEMENTED**.
|
|
55
|
+
- `package_restore_metadata` -> `pipeline/checks/check_package_restore_metadata.py`; `check_package_restore_metadata() -> None`; **NOT_IMPLEMENTED**.
|
|
56
|
+
- `package_verify` -> `pipeline/checks/check_package_verify.py`; `check_package_verify() -> None`; **NOT_IMPLEMENTED**.
|
|
57
|
+
- `package_verify_get_schema` -> `pipeline/checks/check_package_verify_get_schema.py`; `check_package_verify_get_schema() -> None`; **NOT_IMPLEMENTED**.
|
|
58
|
+
- `package_verify_metadata` -> `pipeline/checks/check_package_verify_metadata.py`; `check_package_verify_metadata() -> None`; **NOT_IMPLEMENTED**.
|
|
59
|
+
|
|
60
|
+
## Boundaries
|
|
61
|
+
|
|
62
|
+
- No `pipeline` command, test, build, install, publication, deployment, push or synchronization was run.
|
|
63
|
+
- No product API, existing package asset, root build script or service pipeline was changed.
|
|
64
|
+
- No PLAN/HRS/MRS/G/T/A or cascade artifact was read or changed.
|
|
65
|
+
- All check bodies explicitly raise `NotImplementedError`; the mapping status is `NOT_IMPLEMENTED`.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Package matrix documentary handoff
|
|
2
|
+
|
|
3
|
+
The current scope is TODO-only by explicit user instruction. Do not create, read,
|
|
4
|
+
mutate, import, freeze or validate PLAN/HRS/MRS/G/T/A artifacts for this task.
|
|
5
|
+
This document supersedes the original stage-0 candidate/skeleton handoff.
|
|
6
|
+
|
|
7
|
+
The full authority is package-api-matrix.json, retained as backup_package_stage0
|
|
8
|
+
in project matrix TODO 368a1d2b-5d42-419a-b50b-9f4f8e6e7f81. Project identity is
|
|
9
|
+
ff997eab-d809-4cb9-b805-9dff4df60c6d. Root TODO is
|
|
10
|
+
55bc5124-9708-46c3-b56c-fbc29ea239b1; execution map is
|
|
11
|
+
c052cd96-0967-4842-8176-b598eab7354a. The separate 45 service rows are preserved.
|
|
12
|
+
The examples requirement is root child 2ed43027-2943-4e29-a17c-bb01f1f27e34.
|
|
13
|
+
|
|
14
|
+
The annex contains 40 call rows (30 Python methods, 10 CLI commands), 790 cases,
|
|
15
|
+
8 parameter relations with 14 original relation cases, and 5 packaging scenarios:
|
|
16
|
+
790 + 14 + 5 = 809 required executable mappings. The 318 catalog/config cases
|
|
17
|
+
supplement all 472 original cases. PKG05 supplements the four original packaging
|
|
18
|
+
scenarios. No original focused case, result assertion or server row is waived.
|
|
19
|
+
|
|
20
|
+
The three planner/*.md files are documentary native-dialect projections. They
|
|
21
|
+
retain required Russian headers/grammar and reserved {fb01} source tokens while
|
|
22
|
+
their explanatory prose is English. They describe 40 rows, 76 relation entries
|
|
23
|
+
and 262 shallow result cases. API config projects its JSON-object subset and
|
|
24
|
+
catalog_directory its non-null string subset. Full Mapping/null/omission, config
|
|
25
|
+
key validation, path semantics, typed errors, dynamic results, chains and file
|
|
26
|
+
effects require the full annex. No runtime import/lint verdict is claimed.
|
|
27
|
+
|
|
28
|
+
Catalog priority is explicit API/CLI > config > DEFAULT_CATALOG_DIRECTORY='.'.
|
|
29
|
+
Default catalog.sqlite3 is on the repository volume. See CATALOG_DIRECTORY.md
|
|
30
|
+
and the annex for validation, no-silent-migration and recovery exceptions.
|
|
31
|
+
|
|
32
|
+
The tester owns executable matrix/checks and runtime evidence. Canonical
|
|
33
|
+
examples acceptance is `python file-backup/pipeline/run.py package_examples`.
|
|
34
|
+
The complete `python file-backup/pipeline/run.py --all` runs every other check
|
|
35
|
+
first and package_examples LAST as its final stage. All examples must execute
|
|
36
|
+
adequately; expected errors are caught and asserted; no skip/XFAIL. English
|
|
37
|
+
module docstrings explain purpose, when/why, invocation, prerequisites, files,
|
|
38
|
+
results, effects and errors. Documentation in examples and product code is
|
|
39
|
+
English. build.sh must require successful current-candidate examples BEFORE
|
|
40
|
+
twine upload; any failure is nonzero and blocks publication. Candidate example
|
|
41
|
+
acceptance never depends on a prior publication.
|
|
42
|
+
|
|
43
|
+
This update verifies documentary consistency only. It does not claim a current
|
|
44
|
+
runtime pipeline GREEN, installed-package success or publication. Reuse the
|
|
45
|
+
separate tester/build owner's exact evidence for those states; do not rerun them
|
|
46
|
+
merely because these projections changed.
|
|
47
|
+
|
|
48
|
+
Server obligations remain separate: latest-only document export, an hourly
|
|
49
|
+
worker, a separately mounted backup volume, server API/matrix checks and deployed
|
|
50
|
+
integration acceptance. The package matrix does not replace the server matrix.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# File Backup User Guide
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Overview](#overview) - `file-backup://info/overview`
|
|
6
|
+
- [Backup](#backup) - `file-backup://info/backup`
|
|
7
|
+
- [Restore](#restore) - `file-backup://info/restore`
|
|
8
|
+
- [Catalog](#catalog) - `file-backup://info/catalog`
|
|
9
|
+
- [Errors](#errors) - `file-backup://info/errors`
|
|
10
|
+
- [Release](#release) - `file-backup://info/release`
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
File Backup is a standalone Python package for saving completed filesystem slices and restoring
|
|
15
|
+
them later. Its Python API is available from `file_backup`; its command-line program is
|
|
16
|
+
`file-backup`. Both interfaces use the same operation methods and result contracts.
|
|
17
|
+
|
|
18
|
+
The package stores its catalog and archives under the repository directory supplied to an
|
|
19
|
+
operation. It reads regular files from the source tree and does not preserve ownership, modes,
|
|
20
|
+
timestamps, symbolic links, or empty directories. Keep the source unchanged for the duration of a
|
|
21
|
+
backup call.
|
|
22
|
+
|
|
23
|
+
Use `file-backup help` for command and parameter guidance, or `file-backup info` to print this
|
|
24
|
+
guide's table of contents. The Python equivalents are `Help.execute()` and `Info.execute()`.
|
|
25
|
+
|
|
26
|
+
## Backup
|
|
27
|
+
|
|
28
|
+
Call `Backup.execute(repository, source)` or `file-backup backup --repository PATH --source PATH`
|
|
29
|
+
to save a completed source tree. The first saved point is full. Later calls save additions,
|
|
30
|
+
changes, and deletion tombstones relative to the previous successful point. A byte-for-byte
|
|
31
|
+
unchanged source creates no archive or saved point. If the full archive needed to continue a chain
|
|
32
|
+
is missing, the next successful backup starts a new full chain.
|
|
33
|
+
|
|
34
|
+
`dry_run=True` or `--dry-run` returns a preview without creating or changing the catalog, archive,
|
|
35
|
+
or checkpoint. The result identifies whether the operation would create a full point, an
|
|
36
|
+
incremental point, or no point.
|
|
37
|
+
|
|
38
|
+
## Restore
|
|
39
|
+
|
|
40
|
+
Use `Restore.execute(repository, point, destination)` to restore one exact saved point. The
|
|
41
|
+
destination must be absent or empty. The package checks the complete required archive chain and
|
|
42
|
+
content digests before publishing restored files. A missing or corrupt dependency fails the
|
|
43
|
+
operation; it does not return a partial restore or substitute a nearby point.
|
|
44
|
+
|
|
45
|
+
Use `RestoreFile.execute(repository, point, path, destination)` to restore one live relative path.
|
|
46
|
+
The destination file is not replaced unless `overwrite=True` is supplied. A file deleted at the
|
|
47
|
+
selected point is unavailable at that point, even if an older point contains it. Both restore
|
|
48
|
+
operations support a no-write `dry_run` preview.
|
|
49
|
+
|
|
50
|
+
The CLI forms are `file-backup restore --repository PATH --point UUID --destination PATH` and
|
|
51
|
+
`file-backup restore-file --repository PATH --point UUID --path RELATIVE_PATH --destination PATH`.
|
|
52
|
+
|
|
53
|
+
## Catalog
|
|
54
|
+
|
|
55
|
+
`ListPoints.execute(repository)` lists committed saved points in completion order. Use
|
|
56
|
+
`InspectPoint.execute(repository, point)` for one point's identity and chain, and
|
|
57
|
+
`ListFiles.execute(repository, point)` for its live files. `Verify.execute(repository, point)`
|
|
58
|
+
checks the catalog bindings, archive chain, manifest, and referenced file contents.
|
|
59
|
+
|
|
60
|
+
All eight repository operations accept the keyword-only `catalog_directory` and `config`
|
|
61
|
+
arguments. The selected SQLite file is `catalog.sqlite3` under the selected directory; archives
|
|
62
|
+
remain under `<repository>/archives`. The default is the repository directory itself, exposed as
|
|
63
|
+
`file_backup.DEFAULT_CATALOG_DIRECTORY == "."`. Relative catalog directory values, including
|
|
64
|
+
`..`, resolve from the repository. An absolute catalog directory is also accepted.
|
|
65
|
+
|
|
66
|
+
Selection priority is explicit `catalog_directory`, then `config["catalog_directory"]`, then the
|
|
67
|
+
default constant. A `None` explicit value means unspecified. `config` may be omitted or `None`;
|
|
68
|
+
otherwise it must contain only the nonempty, NUL-free string key `catalog_directory`. Config is
|
|
69
|
+
validated even when an explicit directory takes priority. No environment or ambient config is
|
|
70
|
+
read. The CLI forms are `--catalog-directory DIR` and `--config JSONFILE`; the JSON file path is
|
|
71
|
+
relative to the process working directory, and its UTF-8 JSON object is decoded before the API
|
|
72
|
+
call.
|
|
73
|
+
|
|
74
|
+
The package does not migrate, copy, or fall back to another catalog. If the selected catalog is
|
|
75
|
+
missing while archives exist, the operation fails even when another catalog file is present.
|
|
76
|
+
Read-only operations and dry runs create no catalog directory or database.
|
|
77
|
+
|
|
78
|
+
`RecoverCatalog.execute(repository, destination, catalog_copy)` validates a caller-supplied
|
|
79
|
+
consistent SQLite backup against the repository archives and writes a validated copy to a new
|
|
80
|
+
destination. It does not infer points from loose archive files and does not replace the active
|
|
81
|
+
catalog. Switching an installation to a recovered catalog is a separate offline administrative
|
|
82
|
+
operation.
|
|
83
|
+
|
|
84
|
+
## Errors
|
|
85
|
+
|
|
86
|
+
Operations raise typed `FileBackupError` subclasses. Each error has a stable `code`, a readable
|
|
87
|
+
`message`, and a `context` mapping with operation-specific fields. Argument errors identify the
|
|
88
|
+
parameter and violation. Missing points, files, archives, corrupt content, broken chains, I/O
|
|
89
|
+
failures, catalog failures, and conflicts have distinct error types.
|
|
90
|
+
|
|
91
|
+
The CLI catches package errors at its boundary. Argument, command-selection, and information
|
|
92
|
+
section-selection errors exit with status 2. Other package errors exit with status 1. Errors are
|
|
93
|
+
written to standard error with their stable code and context; standard output remains empty.
|
|
94
|
+
|
|
95
|
+
## Release
|
|
96
|
+
|
|
97
|
+
The `vvz-file-backup` distribution contains the importable `file_backup` package, its JSON schema
|
|
98
|
+
and metadata resources, and the installed guide used by `Info.execute()`. It is designed to build
|
|
99
|
+
and install independently of doc-store and adapter packages. Use the package's own build and
|
|
100
|
+
release instructions when preparing a distribution; do not copy credentials into command output
|
|
101
|
+
or logs.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"status": "GREEN documentary only; runtime acceptance pending",
|
|
3
|
+
"rule": "CFG-CONTRACT immutable completion criterion",
|
|
4
|
+
"command": "python tmp/validate_catalog_matrix.py",
|
|
5
|
+
"exit_code": 0,
|
|
6
|
+
"matrix_sha256": "9bda0048146ac20520157f2a4cb98d47f3d306eae53d1fb9f059685125dd780d",
|
|
7
|
+
"rows": 40,
|
|
8
|
+
"cases": 790,
|
|
9
|
+
"new_cases": 318,
|
|
10
|
+
"original_cases_preserved": 472,
|
|
11
|
+
"original_result_contracts_preserved": 472,
|
|
12
|
+
"original_relation_cases_preserved": 14,
|
|
13
|
+
"original_packaging_scenarios_preserved": 4
|
|
14
|
+
}
|