mirror of
https://github.com/borgmatic-collective/borgmatic.git
synced 2026-07-27 11:53:02 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bddc82951e | ||
|
|
3d15c51039 | ||
|
|
f9206c15e7 | ||
|
|
0da4b64838 | ||
|
|
85f06a900a | ||
|
|
bae8f983e0 | ||
|
|
89c0cd0af6 | ||
|
|
292d9cb2c7 | ||
|
|
181030c5d1 | ||
|
|
2600598359 | ||
|
|
9e649af2a3 | ||
|
|
370bc7e7f0 | ||
|
|
7cca1358fb | ||
|
|
67406b60b3 | ||
|
|
72fde728a4 | ||
|
|
d4433eeec1 | ||
|
|
d0b5244888 | ||
|
|
1ed207c6b1 | ||
|
|
5ef257ebb6 | ||
|
|
eb2b0b35c1 | ||
|
|
0f7ebcb4b7 | ||
|
|
51d2ce7963 | ||
|
|
0c4222037d | ||
|
|
25e8aad517 | ||
|
|
11ffd76cc6 | ||
|
|
68864395b5 |
@@ -1,5 +1,24 @@
|
||||
2.0.11
|
||||
* #957: Document borgmatic's limitations around parallelism—both its own and Borg's. See the
|
||||
documentation for more information:
|
||||
https://torsion.org/borgmatic/how-to/make-per-application-backups/#limitations
|
||||
* #1165: Fix for when the systemd service directories (RuntimeDirectory and StateDirectory) each
|
||||
contain multiple paths.
|
||||
* #1168: Fix for the "list", "info", and "delete" options in "extra_borg_options" being ignored
|
||||
when "--archive" is omitted with Borg 1.x.
|
||||
* #1169: Fix for a regression in the ZFS, LVM, and Btrfs hooks in which partial excludes of
|
||||
snapshot paths were ignored.
|
||||
* #1170: Fix for an inconsistent log level for Borg's last output line before exiting.
|
||||
* #1172: Add an "environment" option to the Sentry monitoring hook.
|
||||
* #1176: Fix the "--repository" flag not applying to command hooks.
|
||||
* Add a "rename" option to "extra_borg_options" to support passing arbitrary flags to "borg
|
||||
rename".
|
||||
* Add documentation on patterns and excludes:
|
||||
https://torsion.org/borgmatic/reference/configuration/patterns-and-excludes/
|
||||
* Drop support for Python 3.9, which has been end-of-lifed.
|
||||
|
||||
2.0.10
|
||||
* #427: Expand the "borg_extra_options" option to support passing arbitrary Borg flags to every
|
||||
* #427: Expand the "extra_borg_options" option to support passing arbitrary Borg flags to every
|
||||
Borg sub-command that borgmatic uses. As part of this, deprecate the "init" option under
|
||||
"borg_extra_options" in favor of "repo_create".
|
||||
* #942: Factor reference material out of the documentation how-to guides. This means there's now a
|
||||
|
||||
+19
-24
@@ -2,7 +2,6 @@ import logging
|
||||
|
||||
import borgmatic.borg.borg
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -19,26 +18,22 @@ def run_borg(
|
||||
'''
|
||||
Run the "borg" action for the given repository.
|
||||
'''
|
||||
if borg_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
borg_arguments.repository,
|
||||
):
|
||||
logger.info('Running arbitrary Borg command')
|
||||
archive_name = borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
borg_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
borgmatic.borg.borg.run_arbitrary_borg(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
options=borg_arguments.options,
|
||||
archive=archive_name,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
logger.info('Running arbitrary Borg command')
|
||||
archive_name = borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
borg_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
borgmatic.borg.borg.run_arbitrary_borg(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
options=borg_arguments.options,
|
||||
archive=archive_name,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import logging
|
||||
|
||||
import borgmatic.borg.break_lock
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -18,16 +17,12 @@ def run_break_lock(
|
||||
'''
|
||||
Run the "break-lock" action for the given repository.
|
||||
'''
|
||||
if break_lock_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
break_lock_arguments.repository,
|
||||
):
|
||||
logger.info('Breaking repository and cache locks')
|
||||
borgmatic.borg.break_lock.break_lock(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
logger.info('Breaking repository and cache locks')
|
||||
borgmatic.borg.break_lock.break_lock(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import logging
|
||||
|
||||
import borgmatic.borg.change_passphrase
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -18,20 +17,13 @@ def run_change_passphrase(
|
||||
'''
|
||||
Run the "key change-passphrase" action for the given repository.
|
||||
'''
|
||||
if (
|
||||
change_passphrase_arguments.repository is None
|
||||
or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
change_passphrase_arguments.repository,
|
||||
)
|
||||
):
|
||||
logger.info('Changing repository passphrase')
|
||||
borgmatic.borg.change_passphrase.change_passphrase(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
change_passphrase_arguments,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
logger.info('Changing repository passphrase')
|
||||
borgmatic.borg.change_passphrase.change_passphrase(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
change_passphrase_arguments,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
|
||||
@@ -22,7 +22,6 @@ import borgmatic.borg.pattern
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.borg.state
|
||||
import borgmatic.config.paths
|
||||
import borgmatic.config.validate
|
||||
import borgmatic.execute
|
||||
import borgmatic.hooks.command
|
||||
|
||||
@@ -750,12 +749,6 @@ def run_check(
|
||||
|
||||
Raise ValueError if the Borg repository ID cannot be determined.
|
||||
'''
|
||||
if check_arguments.repository and not borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
check_arguments.repository,
|
||||
):
|
||||
return
|
||||
|
||||
logger.info('Running consistency checks')
|
||||
|
||||
repository_id = borgmatic.borg.check.get_repository_id(
|
||||
|
||||
@@ -2,7 +2,6 @@ import logging
|
||||
|
||||
import borgmatic.borg.compact
|
||||
import borgmatic.borg.feature
|
||||
import borgmatic.config.validate
|
||||
import borgmatic.hooks.command
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -22,12 +21,6 @@ def run_compact(
|
||||
'''
|
||||
Run the "compact" action for the given repository.
|
||||
'''
|
||||
if compact_arguments.repository and not borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
compact_arguments.repository,
|
||||
):
|
||||
return
|
||||
|
||||
if borgmatic.borg.feature.available(borgmatic.borg.feature.Feature.COMPACT, local_borg_version):
|
||||
logger.info(f'Compacting segments{dry_run_label}')
|
||||
borgmatic.borg.compact.compact_segments(
|
||||
|
||||
@@ -5,7 +5,6 @@ import os
|
||||
import borgmatic.borg.extract
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.config.paths
|
||||
import borgmatic.config.validate
|
||||
import borgmatic.hooks.command
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -6,7 +6,6 @@ import borgmatic.borg.feature
|
||||
import borgmatic.borg.rename
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.config.paths
|
||||
import borgmatic.config.validate
|
||||
import borgmatic.hooks.dispatch
|
||||
from borgmatic.actions import pattern
|
||||
|
||||
@@ -30,12 +29,6 @@ def run_create(
|
||||
|
||||
If create_arguments.json is True, yield the JSON output from creating the archive.
|
||||
'''
|
||||
if create_arguments.repository and not borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
create_arguments.repository,
|
||||
):
|
||||
return
|
||||
|
||||
if config.get('list_details') and config.get('progress'):
|
||||
raise ValueError(
|
||||
'With the create action, only one of --list/--files/list_details and --progress/progress can be used.',
|
||||
|
||||
+18
-22
@@ -20,32 +20,28 @@ def run_delete(
|
||||
'''
|
||||
Run the "delete" action for the given repository and archive(s).
|
||||
'''
|
||||
if delete_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
delete_arguments.repository,
|
||||
):
|
||||
logger.answer('Deleting archives')
|
||||
logger.answer('Deleting archives')
|
||||
|
||||
archive_name = (
|
||||
borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
delete_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if delete_arguments.archive
|
||||
else None
|
||||
)
|
||||
|
||||
borgmatic.borg.delete.delete_archives(
|
||||
repository,
|
||||
archive_name = (
|
||||
borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
delete_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
borgmatic.actions.arguments.update_arguments(delete_arguments, archive=archive_name),
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if delete_arguments.archive
|
||||
else None
|
||||
)
|
||||
|
||||
borgmatic.borg.delete.delete_archives(
|
||||
repository,
|
||||
config,
|
||||
local_borg_version,
|
||||
borgmatic.actions.arguments.update_arguments(delete_arguments, archive=archive_name),
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import logging
|
||||
|
||||
import borgmatic.borg.export_key
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -18,17 +17,13 @@ def run_export_key(
|
||||
'''
|
||||
Run the "key export" action for the given repository.
|
||||
'''
|
||||
if export_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
export_arguments.repository,
|
||||
):
|
||||
logger.info('Exporting repository key')
|
||||
borgmatic.borg.export_key.export_key(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
export_arguments,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
logger.info('Exporting repository key')
|
||||
borgmatic.borg.export_key.export_key(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
export_arguments,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
|
||||
@@ -2,7 +2,6 @@ import logging
|
||||
|
||||
import borgmatic.borg.export_tar
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -19,30 +18,26 @@ def run_export_tar(
|
||||
'''
|
||||
Run the "export-tar" action for the given repository.
|
||||
'''
|
||||
if export_tar_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
export_tar_arguments.repository,
|
||||
):
|
||||
logger.info(f'Exporting archive {export_tar_arguments.archive} as tar file')
|
||||
borgmatic.borg.export_tar.export_tar_archive(
|
||||
global_arguments.dry_run,
|
||||
logger.info(f'Exporting archive {export_tar_arguments.archive} as tar file')
|
||||
borgmatic.borg.export_tar.export_tar_archive(
|
||||
global_arguments.dry_run,
|
||||
repository['path'],
|
||||
borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
export_tar_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
),
|
||||
export_tar_arguments.paths,
|
||||
export_tar_arguments.destination,
|
||||
export_tar_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
tar_filter=export_tar_arguments.tar_filter,
|
||||
strip_components=export_tar_arguments.strip_components,
|
||||
)
|
||||
local_path,
|
||||
remote_path,
|
||||
),
|
||||
export_tar_arguments.paths,
|
||||
export_tar_arguments.destination,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
tar_filter=export_tar_arguments.tar_filter,
|
||||
strip_components=export_tar_arguments.strip_components,
|
||||
)
|
||||
|
||||
@@ -2,7 +2,6 @@ import logging
|
||||
|
||||
import borgmatic.borg.extract
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.config.validate
|
||||
import borgmatic.hooks.command
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -21,29 +20,25 @@ def run_extract(
|
||||
'''
|
||||
Run the "extract" action for the given repository.
|
||||
'''
|
||||
if extract_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
extract_arguments.repository,
|
||||
):
|
||||
logger.info(f'Extracting archive {extract_arguments.archive}')
|
||||
borgmatic.borg.extract.extract_archive(
|
||||
global_arguments.dry_run,
|
||||
logger.info(f'Extracting archive {extract_arguments.archive}')
|
||||
borgmatic.borg.extract.extract_archive(
|
||||
global_arguments.dry_run,
|
||||
repository['path'],
|
||||
borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
extract_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
),
|
||||
extract_arguments.paths,
|
||||
extract_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
destination_path=extract_arguments.destination,
|
||||
strip_components=extract_arguments.strip_components,
|
||||
)
|
||||
local_path,
|
||||
remote_path,
|
||||
),
|
||||
extract_arguments.paths,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
destination_path=extract_arguments.destination,
|
||||
strip_components=extract_arguments.strip_components,
|
||||
)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import logging
|
||||
|
||||
import borgmatic.borg.import_key
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -18,17 +17,13 @@ def run_import_key(
|
||||
'''
|
||||
Run the "key import" action for the given repository.
|
||||
'''
|
||||
if import_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
import_arguments.repository,
|
||||
):
|
||||
logger.info('Importing repository key')
|
||||
borgmatic.borg.import_key.import_key(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
import_arguments,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
logger.info('Importing repository key')
|
||||
borgmatic.borg.import_key.import_key(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
import_arguments,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
|
||||
+22
-27
@@ -4,7 +4,6 @@ import borgmatic.actions.arguments
|
||||
import borgmatic.actions.json
|
||||
import borgmatic.borg.info
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -23,30 +22,26 @@ def run_info(
|
||||
|
||||
If info_arguments.json is True, yield the JSON output from the info for the archive.
|
||||
'''
|
||||
if info_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
info_arguments.repository,
|
||||
):
|
||||
if not info_arguments.json:
|
||||
logger.answer('Displaying archive summary information')
|
||||
if not info_arguments.json:
|
||||
logger.answer('Displaying archive summary information')
|
||||
|
||||
archive_name = borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
info_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
json_output = borgmatic.borg.info.display_archives_info(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
borgmatic.actions.arguments.update_arguments(info_arguments, archive=archive_name),
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if json_output:
|
||||
yield borgmatic.actions.json.parse_json(json_output, repository.get('label'))
|
||||
archive_name = borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
info_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
json_output = borgmatic.borg.info.display_archives_info(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
borgmatic.actions.arguments.update_arguments(info_arguments, archive=archive_name),
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if json_output:
|
||||
yield borgmatic.actions.json.parse_json(json_output, repository.get('label'))
|
||||
|
||||
+25
-30
@@ -3,7 +3,6 @@ import logging
|
||||
import borgmatic.actions.arguments
|
||||
import borgmatic.actions.json
|
||||
import borgmatic.borg.list
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -22,33 +21,29 @@ def run_list(
|
||||
|
||||
If list_arguments.json is True, yield the JSON output from listing the archive.
|
||||
'''
|
||||
if list_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
list_arguments.repository,
|
||||
):
|
||||
if not list_arguments.json:
|
||||
if list_arguments.find_paths: # pragma: no cover
|
||||
logger.answer('Searching archives')
|
||||
elif not list_arguments.archive: # pragma: no cover
|
||||
logger.answer('Listing archives')
|
||||
if not list_arguments.json:
|
||||
if list_arguments.find_paths: # pragma: no cover
|
||||
logger.answer('Searching archives')
|
||||
elif not list_arguments.archive: # pragma: no cover
|
||||
logger.answer('Listing archives')
|
||||
|
||||
archive_name = borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
list_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
json_output = borgmatic.borg.list.list_archive(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
borgmatic.actions.arguments.update_arguments(list_arguments, archive=archive_name),
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if json_output:
|
||||
yield borgmatic.actions.json.parse_json(json_output, repository.get('label'))
|
||||
archive_name = borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
list_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
json_output = borgmatic.borg.list.list_archive(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
borgmatic.actions.arguments.update_arguments(list_arguments, archive=archive_name),
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
if json_output:
|
||||
yield borgmatic.actions.json.parse_json(json_output, repository.get('label'))
|
||||
|
||||
+18
-23
@@ -2,7 +2,6 @@ import logging
|
||||
|
||||
import borgmatic.borg.mount
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -19,30 +18,26 @@ def run_mount(
|
||||
'''
|
||||
Run the "mount" action for the given repository.
|
||||
'''
|
||||
if mount_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
mount_arguments.repository,
|
||||
):
|
||||
if mount_arguments.archive:
|
||||
logger.info(f'Mounting archive {mount_arguments.archive}')
|
||||
else: # pragma: nocover
|
||||
logger.info('Mounting repository')
|
||||
if mount_arguments.archive:
|
||||
logger.info(f'Mounting archive {mount_arguments.archive}')
|
||||
else: # pragma: nocover
|
||||
logger.info('Mounting repository')
|
||||
|
||||
borgmatic.borg.mount.mount_archive(
|
||||
borgmatic.borg.mount.mount_archive(
|
||||
repository['path'],
|
||||
borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
mount_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
),
|
||||
mount_arguments,
|
||||
mount_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
local_path,
|
||||
remote_path,
|
||||
),
|
||||
mount_arguments,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import logging
|
||||
|
||||
import borgmatic.borg.prune
|
||||
import borgmatic.config.validate
|
||||
import borgmatic.hooks.command
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -21,12 +20,6 @@ def run_prune(
|
||||
'''
|
||||
Run the "prune" action for the given repository.
|
||||
'''
|
||||
if prune_arguments.repository and not borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
prune_arguments.repository,
|
||||
):
|
||||
return
|
||||
|
||||
logger.info(f'Pruning archives{dry_run_label}')
|
||||
borgmatic.borg.prune.prune_archives(
|
||||
global_arguments.dry_run,
|
||||
|
||||
@@ -4,7 +4,6 @@ import subprocess
|
||||
import borgmatic.borg.info
|
||||
import borgmatic.borg.recreate
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.config.validate
|
||||
from borgmatic.actions.pattern import collect_patterns, process_patterns
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -25,64 +24,60 @@ def run_recreate(
|
||||
'''
|
||||
Run the "recreate" action for the given repository.
|
||||
'''
|
||||
if recreate_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
recreate_arguments.repository,
|
||||
):
|
||||
if recreate_arguments.archive:
|
||||
logger.answer(f'Recreating archive {recreate_arguments.archive}')
|
||||
else:
|
||||
logger.answer('Recreating repository')
|
||||
if recreate_arguments.archive:
|
||||
logger.answer(f'Recreating archive {recreate_arguments.archive}')
|
||||
else:
|
||||
logger.answer('Recreating repository')
|
||||
|
||||
# Collect and process patterns.
|
||||
processed_patterns = process_patterns(
|
||||
collect_patterns(config),
|
||||
config,
|
||||
borgmatic.config.paths.get_working_directory(config),
|
||||
# Collect and process patterns.
|
||||
processed_patterns = process_patterns(
|
||||
collect_patterns(config),
|
||||
config,
|
||||
borgmatic.config.paths.get_working_directory(config),
|
||||
)
|
||||
|
||||
archive = borgmatic.borg.repo_list.resolve_archive_name(
|
||||
repository['path'],
|
||||
recreate_arguments.archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
|
||||
if archive and archive.endswith('.recreate'):
|
||||
if recreate_arguments.archive == 'latest':
|
||||
raise ValueError(
|
||||
f'The latest archive "{archive}" is leftover from a prior recreate. Delete it first or select a different archive.',
|
||||
)
|
||||
|
||||
raise ValueError(
|
||||
f'The archive "{recreate_arguments.archive}" is leftover from a prior recreate. Select a different archive.',
|
||||
)
|
||||
|
||||
archive = borgmatic.borg.repo_list.resolve_archive_name(
|
||||
try:
|
||||
borgmatic.borg.recreate.recreate_archive(
|
||||
repository['path'],
|
||||
recreate_arguments.archive,
|
||||
archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
recreate_arguments,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
patterns=processed_patterns,
|
||||
)
|
||||
|
||||
if archive and archive.endswith('.recreate'):
|
||||
if recreate_arguments.archive == 'latest':
|
||||
except subprocess.CalledProcessError as error:
|
||||
if error.returncode == BORG_EXIT_CODE_ARCHIVE_ALREADY_EXISTS:
|
||||
if recreate_arguments.target:
|
||||
raise ValueError(
|
||||
f'The latest archive "{archive}" is leftover from a prior recreate. Delete it first or select a different archive.',
|
||||
f'The archive "{recreate_arguments.target}" already exists. Delete it first or set a different target archive name.',
|
||||
)
|
||||
|
||||
raise ValueError(
|
||||
f'The archive "{recreate_arguments.archive}" is leftover from a prior recreate. Select a different archive.',
|
||||
)
|
||||
if archive:
|
||||
raise ValueError(
|
||||
f'The archive "{archive}.recreate" is leftover from a prior recreate. Delete it first or select a different archive.',
|
||||
)
|
||||
|
||||
try:
|
||||
borgmatic.borg.recreate.recreate_archive(
|
||||
repository['path'],
|
||||
archive,
|
||||
config,
|
||||
local_borg_version,
|
||||
recreate_arguments,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
patterns=processed_patterns,
|
||||
)
|
||||
except subprocess.CalledProcessError as error:
|
||||
if error.returncode == BORG_EXIT_CODE_ARCHIVE_ALREADY_EXISTS:
|
||||
if recreate_arguments.target:
|
||||
raise ValueError(
|
||||
f'The archive "{recreate_arguments.target}" already exists. Delete it first or set a different target archive name.',
|
||||
)
|
||||
|
||||
if archive:
|
||||
raise ValueError(
|
||||
f'The archive "{archive}.recreate" is leftover from a prior recreate. Delete it first or select a different archive.',
|
||||
)
|
||||
|
||||
raise
|
||||
raise
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import logging
|
||||
|
||||
import borgmatic.borg.repo_create
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -18,12 +17,6 @@ def run_repo_create(
|
||||
'''
|
||||
Run the "repo-create" action for the given repository.
|
||||
'''
|
||||
if repo_create_arguments.repository and not borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
repo_create_arguments.repository,
|
||||
):
|
||||
return
|
||||
|
||||
logger.info('Creating repository')
|
||||
|
||||
encryption_mode = repo_create_arguments.encryption_mode or repository.get('encryption')
|
||||
|
||||
@@ -17,20 +17,16 @@ def run_repo_delete(
|
||||
'''
|
||||
Run the "repo-delete" action for the given repository.
|
||||
'''
|
||||
if repo_delete_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
repo_delete_arguments.repository,
|
||||
):
|
||||
logger.answer(
|
||||
'Deleting repository' + (' cache' if repo_delete_arguments.cache_only else ''),
|
||||
)
|
||||
logger.answer(
|
||||
'Deleting repository' + (' cache' if repo_delete_arguments.cache_only else ''),
|
||||
)
|
||||
|
||||
borgmatic.borg.repo_delete.delete_repository(
|
||||
repository,
|
||||
config,
|
||||
local_borg_version,
|
||||
repo_delete_arguments,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
borgmatic.borg.repo_delete.delete_repository(
|
||||
repository,
|
||||
config,
|
||||
local_borg_version,
|
||||
repo_delete_arguments,
|
||||
global_arguments,
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
|
||||
@@ -2,7 +2,6 @@ import logging
|
||||
|
||||
import borgmatic.actions.json
|
||||
import borgmatic.borg.repo_info
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -21,21 +20,17 @@ def run_repo_info(
|
||||
|
||||
If repo_info_arguments.json is True, yield the JSON output from the info for the repository.
|
||||
'''
|
||||
if repo_info_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
repo_info_arguments.repository,
|
||||
):
|
||||
if not repo_info_arguments.json:
|
||||
logger.answer('Displaying repository summary information')
|
||||
if not repo_info_arguments.json:
|
||||
logger.answer('Displaying repository summary information')
|
||||
|
||||
json_output = borgmatic.borg.repo_info.display_repository_info(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
repo_info_arguments=repo_info_arguments,
|
||||
global_arguments=global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
if json_output:
|
||||
yield borgmatic.actions.json.parse_json(json_output, repository.get('label'))
|
||||
json_output = borgmatic.borg.repo_info.display_repository_info(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
repo_info_arguments=repo_info_arguments,
|
||||
global_arguments=global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
if json_output:
|
||||
yield borgmatic.actions.json.parse_json(json_output, repository.get('label'))
|
||||
|
||||
@@ -2,7 +2,6 @@ import logging
|
||||
|
||||
import borgmatic.actions.json
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.config.validate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -21,21 +20,17 @@ def run_repo_list(
|
||||
|
||||
If repo_list_arguments.json is True, yield the JSON output from listing the repository.
|
||||
'''
|
||||
if repo_list_arguments.repository is None or borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
repo_list_arguments.repository,
|
||||
):
|
||||
if not repo_list_arguments.json:
|
||||
logger.answer('Listing repository')
|
||||
if not repo_list_arguments.json:
|
||||
logger.answer('Listing repository')
|
||||
|
||||
json_output = borgmatic.borg.repo_list.list_repository(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
repo_list_arguments=repo_list_arguments,
|
||||
global_arguments=global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
if json_output:
|
||||
yield borgmatic.actions.json.parse_json(json_output, repository.get('label'))
|
||||
json_output = borgmatic.borg.repo_list.list_repository(
|
||||
repository['path'],
|
||||
config,
|
||||
local_borg_version,
|
||||
repo_list_arguments=repo_list_arguments,
|
||||
global_arguments=global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
if json_output:
|
||||
yield borgmatic.actions.json.parse_json(json_output, repository.get('label'))
|
||||
|
||||
@@ -11,7 +11,6 @@ import borgmatic.borg.list
|
||||
import borgmatic.borg.mount
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.config.paths
|
||||
import borgmatic.config.validate
|
||||
import borgmatic.hooks.data_source.dump
|
||||
import borgmatic.hooks.dispatch
|
||||
|
||||
@@ -524,18 +523,11 @@ def run_restore(
|
||||
remote_path,
|
||||
):
|
||||
'''
|
||||
Run the "restore" action for the given repository, but only if the repository matches the
|
||||
requested repository in restore arguments.
|
||||
Run the "restore" action for the given repository.
|
||||
|
||||
Raise ValueError if a configured data source could not be found to restore or there's no
|
||||
matching dump in the archive.
|
||||
'''
|
||||
if restore_arguments.repository and not borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
restore_arguments.repository,
|
||||
):
|
||||
return
|
||||
|
||||
logger.info(f'Restoring data sources from archive {restore_arguments.archive}')
|
||||
working_directory = borgmatic.config.paths.get_working_directory(config)
|
||||
|
||||
|
||||
@@ -27,7 +27,14 @@ def make_repo_delete_command(
|
||||
arguments to the repo_delete action as an argparse.Namespace, and global arguments, return a command
|
||||
as a tuple to repo_delete the entire repository.
|
||||
'''
|
||||
extra_borg_options = config.get('extra_borg_options', {}).get('repo_delete', '')
|
||||
extra_borg_options = config.get('extra_borg_options', {}).get(
|
||||
'repo_delete'
|
||||
if borgmatic.borg.feature.available(
|
||||
borgmatic.borg.feature.Feature.REPO_DELETE, local_borg_version
|
||||
)
|
||||
else 'delete',
|
||||
'',
|
||||
)
|
||||
|
||||
return (
|
||||
(local_path,)
|
||||
|
||||
@@ -25,7 +25,10 @@ def display_repository_info(
|
||||
'''
|
||||
borgmatic.logger.add_custom_log_levels()
|
||||
lock_wait = config.get('lock_wait', None)
|
||||
extra_borg_options = config.get('extra_borg_options', {}).get('repo_info', '')
|
||||
extra_borg_options = config.get('extra_borg_options', {}).get(
|
||||
'repo_info' if feature.available(feature.Feature.REPO_INFO, local_borg_version) else 'info',
|
||||
'',
|
||||
)
|
||||
|
||||
full_command = (
|
||||
(local_path,)
|
||||
|
||||
@@ -63,7 +63,10 @@ def get_latest_archive(
|
||||
|
||||
Raises ValueError if there are no archives in the repository.
|
||||
'''
|
||||
extra_borg_options = config.get('extra_borg_options', {}).get('repo_list', '')
|
||||
extra_borg_options = config.get('extra_borg_options', {}).get(
|
||||
'repo_list' if feature.available(feature.Feature.REPO_LIST, local_borg_version) else 'list',
|
||||
'',
|
||||
)
|
||||
|
||||
full_command = (
|
||||
local_path,
|
||||
@@ -124,7 +127,10 @@ def make_repo_list_command(
|
||||
arguments to the repo_list action, global arguments as an argparse.Namespace instance, and local and
|
||||
remote Borg paths, return a command as a tuple to list archives with a repository.
|
||||
'''
|
||||
extra_borg_options = config.get('extra_borg_options', {}).get('repo_list', '')
|
||||
extra_borg_options = config.get('extra_borg_options', {}).get(
|
||||
'repo_list' if feature.available(feature.Feature.REPO_LIST, local_borg_version) else 'list',
|
||||
'',
|
||||
)
|
||||
|
||||
return (
|
||||
(
|
||||
|
||||
@@ -340,7 +340,7 @@ def run_actions( # noqa: PLR0912, PLR0915
|
||||
'''
|
||||
Given parsed command-line arguments as an argparse.ArgumentParser instance, the configuration
|
||||
filename, a configuration dict, a sequence of loaded configuration paths, local and remote paths
|
||||
to Borg, a local Borg version string, and a repository name, run all actions from the
|
||||
to Borg, a local Borg version string, and a repository dict, run all actions from the
|
||||
command-line arguments on the given repository.
|
||||
|
||||
Yield JSON output strings from executing any actions that produce JSON.
|
||||
@@ -362,6 +362,22 @@ def run_actions( # noqa: PLR0912, PLR0915
|
||||
'repository': repository_path,
|
||||
}
|
||||
skip_actions = set(get_skip_actions(config, arguments))
|
||||
requested_repository = next(
|
||||
(
|
||||
repository
|
||||
for action_arguments in arguments.values()
|
||||
for repository in (getattr(action_arguments, 'repository', None),)
|
||||
if repository is not None
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
if requested_repository and not borgmatic.config.validate.repositories_match(
|
||||
repository,
|
||||
requested_repository,
|
||||
):
|
||||
logger.debug('Skipping actions because the requested --repository does not match')
|
||||
return
|
||||
|
||||
with borgmatic.hooks.command.Before_after_hooks(
|
||||
command_hooks=config.get('commands'),
|
||||
|
||||
@@ -2,10 +2,19 @@ import contextlib
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
from enum import Enum
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Systemd_directories(Enum):
|
||||
RUNTIME_DIRECTORY = 0
|
||||
STATE_DIRECTORY = 1
|
||||
CACHE_DIRECTORY = 2
|
||||
LOGS_DIRECTORY = 3
|
||||
CONFIGURATION_DIRECTORY = 4
|
||||
|
||||
|
||||
def expand_user_in_path(path):
|
||||
'''
|
||||
Given a directory path, expand any tildes in it.
|
||||
@@ -16,6 +25,17 @@ def expand_user_in_path(path):
|
||||
return None
|
||||
|
||||
|
||||
def resolve_systemd_directory(directory):
|
||||
'''
|
||||
Given a systemd directory environment variable enum, read the value if set and return the first
|
||||
configured directory.
|
||||
'''
|
||||
separator = ':'
|
||||
|
||||
paths = os.environ.get(directory.name)
|
||||
return paths.split(separator)[0] if paths else None
|
||||
|
||||
|
||||
def get_working_directory(config): # pragma: no cover
|
||||
'''
|
||||
Given a configuration dict, get the working directory from it, expanding any tildes.
|
||||
@@ -96,7 +116,9 @@ class Runtime_directory:
|
||||
runtime_directory = (
|
||||
config.get('user_runtime_directory')
|
||||
or os.environ.get('XDG_RUNTIME_DIR') # Set by PAM on Linux.
|
||||
or os.environ.get('RUNTIME_DIRECTORY') # Set by systemd if configured.
|
||||
or resolve_systemd_directory(
|
||||
Systemd_directories.RUNTIME_DIRECTORY
|
||||
) # Set by systemd if configured.
|
||||
)
|
||||
|
||||
if runtime_directory:
|
||||
@@ -174,7 +196,9 @@ def get_borgmatic_state_directory(config):
|
||||
os.path.join(
|
||||
config.get('user_state_directory')
|
||||
or os.environ.get('XDG_STATE_HOME')
|
||||
or os.environ.get('STATE_DIRECTORY') # Set by systemd if configured.
|
||||
or resolve_systemd_directory(
|
||||
Systemd_directories.STATE_DIRECTORY
|
||||
) # Set by systemd if configured.
|
||||
or '~/.local/state',
|
||||
'borgmatic',
|
||||
),
|
||||
|
||||
@@ -173,9 +173,11 @@ properties:
|
||||
type: string
|
||||
description: |
|
||||
Any paths matching these patterns are included/excluded from
|
||||
backups. Globs are expanded. (Tildes are not.) See the output of
|
||||
"borg help patterns" for more details. Quote any value if it
|
||||
contains leading punctuation, so it parses correctly.
|
||||
backups. Recursion root patterns ("R ...") are effectively the same
|
||||
as "source_directories"; they tell Borg which paths to backup
|
||||
(modulo any excludes). Globs are expanded. (Tildes are not.) See
|
||||
the output of "borg help patterns" for more details. Quote any value
|
||||
if it contains leading punctuation, so it parses correctly.
|
||||
example:
|
||||
- 'R /'
|
||||
- '- /home/*/.cache'
|
||||
@@ -259,7 +261,7 @@ properties:
|
||||
Path for storing temporary runtime data like streaming database
|
||||
dumps and bootstrap metadata. borgmatic automatically creates and
|
||||
uses a "borgmatic" subdirectory here. Defaults to $XDG_RUNTIME_DIR
|
||||
or or $TMPDIR or $TEMP or /run/user/$UID.
|
||||
or $TMPDIR or $TEMP or /run/user/$UID.
|
||||
example: /run/user/1001
|
||||
user_state_directory:
|
||||
type: string
|
||||
@@ -607,6 +609,11 @@ properties:
|
||||
description: |
|
||||
Extra command-line options to pass to "borg recreate".
|
||||
example: "--extra-option"
|
||||
rename:
|
||||
type: string
|
||||
description: |
|
||||
Extra command-line options to pass to "borg rename".
|
||||
example: "--extra-option"
|
||||
repo_create:
|
||||
type: string
|
||||
description: |
|
||||
@@ -3015,6 +3022,12 @@ properties:
|
||||
project monitor. Used along with the data source name URL to
|
||||
construct a cron URL.
|
||||
example: mymonitor
|
||||
environment:
|
||||
type: string
|
||||
description: |
|
||||
Sentry monitor environment used in the call to Sentry. If
|
||||
not set, the Sentry default is used.
|
||||
example: production
|
||||
states:
|
||||
type: array
|
||||
items:
|
||||
|
||||
@@ -158,8 +158,8 @@ def log_outputs(processes, exclude_stdouts, output_log_level, borg_local_path, b
|
||||
if not line or not ready_process:
|
||||
break
|
||||
|
||||
# Keep the last few lines of output in case the process errors, and we need the output for
|
||||
# the exception below.
|
||||
# Keep the last few lines of output in case the process errors, and we need the
|
||||
# output for the exception below.
|
||||
append_last_lines(
|
||||
buffer_last_lines[ready_buffer],
|
||||
captured_outputs[ready_process],
|
||||
@@ -199,7 +199,7 @@ def log_outputs(processes, exclude_stdouts, output_log_level, borg_local_path, b
|
||||
last_lines,
|
||||
captured_outputs[process],
|
||||
line,
|
||||
output_log_level=logging.ERROR,
|
||||
output_log_level,
|
||||
)
|
||||
|
||||
if len(last_lines) == ERROR_OUTPUT_MAX_LINE_COUNT:
|
||||
|
||||
@@ -329,9 +329,15 @@ def dump_data_sources(
|
||||
|
||||
snapshot_subvolume(btrfs_command, subvolume.path, snapshot_path)
|
||||
|
||||
last_contained_pattern_index = borgmatic.hooks.data_source.config.get_last_pattern_index(
|
||||
patterns, subvolume.contained_patterns
|
||||
)
|
||||
|
||||
for pattern in subvolume.contained_patterns:
|
||||
snapshot_pattern = make_borg_snapshot_pattern(subvolume.path, pattern)
|
||||
borgmatic.hooks.data_source.config.replace_pattern(patterns, pattern, snapshot_pattern)
|
||||
borgmatic.hooks.data_source.config.replace_pattern(
|
||||
patterns, pattern, snapshot_pattern, last_contained_pattern_index
|
||||
)
|
||||
|
||||
borgmatic.hooks.data_source.config.inject_pattern(
|
||||
patterns, make_snapshot_exclude_pattern(subvolume.path)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import contextlib
|
||||
import json
|
||||
import logging
|
||||
import shutil
|
||||
@@ -131,7 +132,23 @@ def inject_pattern(patterns, data_source_pattern):
|
||||
patterns.insert(0, data_source_pattern)
|
||||
|
||||
|
||||
def replace_pattern(patterns, pattern_to_replace, data_source_pattern):
|
||||
def get_last_pattern_index(patterns, patterns_subset):
|
||||
'''
|
||||
Given a sequence of all patterns and a subset of those patterns, find each subset pattern in the
|
||||
all patterns sequence and return the highest (last) index.
|
||||
'''
|
||||
last_pattern_index = 0
|
||||
|
||||
for pattern in patterns_subset:
|
||||
with contextlib.suppress(ValueError):
|
||||
last_pattern_index = max(patterns.index(pattern), last_pattern_index)
|
||||
|
||||
return last_pattern_index
|
||||
|
||||
|
||||
def replace_pattern(
|
||||
patterns, pattern_to_replace, data_source_pattern, last_contained_pattern_index
|
||||
):
|
||||
'''
|
||||
Given a list of borgmatic.borg.pattern.Pattern instances representing the configured patterns,
|
||||
replace the given pattern with the given data source pattern. The idea is that borgmatic is
|
||||
@@ -139,8 +156,32 @@ def replace_pattern(patterns, pattern_to_replace, data_source_pattern):
|
||||
that the hook's data gets included in the backup.
|
||||
|
||||
As part of this replacement, if the data source pattern is a root pattern, also insert an
|
||||
"include" version of the given root pattern right after the replaced pattern, in an attempt to
|
||||
preempt any of the user's configured exclude patterns that may follow.
|
||||
"include" version of the given root pattern right after the given last contained pattern index
|
||||
in an attempt to preempt any of the user's configured global exclude patterns that may follow.
|
||||
But we don't want to preempt any intentional partial excludes of the data source pattern itself,
|
||||
which is why the include goes after the last contained pattern index.
|
||||
|
||||
For instance, let's say that the patterns are effectively:
|
||||
|
||||
R /foo
|
||||
R /bar
|
||||
- /bar/.cache
|
||||
R /baz
|
||||
- **
|
||||
|
||||
... and "R /bar" is the pattern to replace, data source pattern is "R /bar/snapshot", and the
|
||||
last contained pattern index is 2 (corresponding to "- /bar/.cache"). The resulting patterns
|
||||
after calling this function would be:
|
||||
|
||||
R /foo
|
||||
R /bar/snapshot
|
||||
- /bar/snapshot/.cache
|
||||
+ /bar/snapshot
|
||||
R /baz
|
||||
- **
|
||||
|
||||
Note that the positioning of "+ /bar/snapshot" means that it overrides the "- **" global exclude
|
||||
but not the "- /bar/snapshot/.cache" contained pattern exclude.
|
||||
|
||||
If the pattern to replace can't be found in the given patterns, then just inject the data source
|
||||
pattern at the start of the list.
|
||||
@@ -156,7 +197,7 @@ def replace_pattern(patterns, pattern_to_replace, data_source_pattern):
|
||||
|
||||
if data_source_pattern.type == borgmatic.borg.pattern.Pattern_type.ROOT:
|
||||
patterns.insert(
|
||||
index + 1,
|
||||
last_contained_pattern_index + 1,
|
||||
borgmatic.borg.pattern.Pattern(
|
||||
path=data_source_pattern.path,
|
||||
type=borgmatic.borg.pattern.Pattern_type.INCLUDE,
|
||||
|
||||
@@ -269,6 +269,10 @@ def dump_data_sources(
|
||||
snapshot_mount_path,
|
||||
)
|
||||
|
||||
last_contained_pattern_index = borgmatic.hooks.data_source.config.get_last_pattern_index(
|
||||
patterns, logical_volume.contained_patterns
|
||||
)
|
||||
|
||||
for pattern in logical_volume.contained_patterns:
|
||||
snapshot_pattern = make_borg_snapshot_pattern(
|
||||
pattern,
|
||||
@@ -276,7 +280,9 @@ def dump_data_sources(
|
||||
normalized_runtime_directory,
|
||||
)
|
||||
|
||||
borgmatic.hooks.data_source.config.replace_pattern(patterns, pattern, snapshot_pattern)
|
||||
borgmatic.hooks.data_source.config.replace_pattern(
|
||||
patterns, pattern, snapshot_pattern, last_contained_pattern_index
|
||||
)
|
||||
|
||||
return []
|
||||
|
||||
|
||||
@@ -300,6 +300,10 @@ def dump_data_sources(
|
||||
snapshot_mount_path,
|
||||
)
|
||||
|
||||
last_contained_pattern_index = borgmatic.hooks.data_source.config.get_last_pattern_index(
|
||||
patterns, dataset.contained_patterns
|
||||
)
|
||||
|
||||
for pattern in dataset.contained_patterns:
|
||||
snapshot_pattern = make_borg_snapshot_pattern(
|
||||
pattern,
|
||||
@@ -307,7 +311,9 @@ def dump_data_sources(
|
||||
normalized_runtime_directory,
|
||||
)
|
||||
|
||||
borgmatic.hooks.data_source.config.replace_pattern(patterns, pattern, snapshot_pattern)
|
||||
borgmatic.hooks.data_source.config.replace_pattern(
|
||||
patterns, pattern, snapshot_pattern, last_contained_pattern_index
|
||||
)
|
||||
|
||||
return []
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import logging
|
||||
import re
|
||||
import urllib
|
||||
|
||||
import requests
|
||||
|
||||
@@ -40,6 +41,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
|
||||
dry_run_label = ' (dry run; not actually pinging)' if dry_run else ''
|
||||
|
||||
data_source_name_url = hook_config.get('data_source_name_url')
|
||||
environment = hook_config.get('environment')
|
||||
monitor_slug = hook_config.get('monitor_slug')
|
||||
match = DATA_SOURCE_NAME_URL_PATTERN.match(data_source_name_url)
|
||||
|
||||
@@ -65,10 +67,12 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
|
||||
if dry_run:
|
||||
return
|
||||
|
||||
environment_query = f'&environment={urllib.parse.quote(environment)}' if environment else ''
|
||||
|
||||
logging.getLogger('urllib3').setLevel(logging.ERROR)
|
||||
try:
|
||||
response = requests.post(
|
||||
f'{cron_url}?status={status}',
|
||||
f'{cron_url}?status={status}{environment_query}',
|
||||
timeout=TIMEOUT_SECONDS,
|
||||
headers={'User-Agent': 'borgmatic'},
|
||||
)
|
||||
|
||||
@@ -5,6 +5,8 @@ eleventyNavigation:
|
||||
parent: How-to guides
|
||||
order: 15
|
||||
---
|
||||
<span data-pagefind-weight="0.25">
|
||||
|
||||
To get set up to develop on borgmatic, first [`install
|
||||
uv`](https://docs.astral.sh/uv/) to make managing your borgmatic environment
|
||||
easier without impacting other Python applications on your system.
|
||||
@@ -205,3 +207,5 @@ borgmatic's developer build for documentation optionally supports using
|
||||
Setting up Podman is outside the scope of this documentation. But once you
|
||||
install and configure Podman, then `scripts/dev-docs` should automatically use
|
||||
Podman instead of Docker.
|
||||
|
||||
</span>
|
||||
|
||||
@@ -59,6 +59,20 @@ entry using borgmatic's `--config` flag instead of relying on
|
||||
`/etc/borgmatic.d`.
|
||||
|
||||
|
||||
## Limitations
|
||||
|
||||
borgmatic does not currently support its own parallelism—being run multiple
|
||||
times on the same machine simultaneously. In particular, many of the [data
|
||||
source
|
||||
hooks](https://torsion.org/borgmatic/reference/configuration/data-sources/) rely
|
||||
on global borgmatic runtime files which can't be shared across processes, and
|
||||
therefore multiple borgmatic instances on the same machine would interfere with
|
||||
each other.
|
||||
|
||||
A single borgmatic instance also doesn't currently support running multiple Borg
|
||||
instances in parallel on the same machine.
|
||||
|
||||
|
||||
<a id="archive-naming"></a>
|
||||
<a id="configuration-includes"></a>
|
||||
<a id="configuration-overrides"></a>
|
||||
|
||||
@@ -75,12 +75,16 @@ with `sudo`. If that doesn't work, you may need to update your [sudoers
|
||||
Besides the approaches described above, there are several other options for
|
||||
installing borgmatic:
|
||||
|
||||
* [container image with scheduled backups](https://hub.docker.com/r/b3vis/borgmatic/) (+ Docker Compose files)
|
||||
* [container image with multi-arch and Docker CLI support](https://hub.docker.com/r/modem7/borgmatic-docker/)
|
||||
#### <span data-pagefind-weight="7.0">Docker / Podman</span>
|
||||
|
||||
* [container image with scheduled backups](https://github.com/borgmatic-collective/docker-borgmatic) (+ Docker Compose files)
|
||||
* [container image with multi-arch and Docker CLI support](https://github.com/modem7/docker-borgmatic)
|
||||
|
||||
#### Operating system packages
|
||||
|
||||
* [Debian](https://tracker.debian.org/pkg/borgmatic)
|
||||
* [Ubuntu](https://launchpad.net/ubuntu/+source/borgmatic)
|
||||
* [Fedora official](https://bodhi.fedoraproject.org/updates/?search=borgmatic)
|
||||
* [Fedora unofficial](https://copr.fedorainfracloud.org/coprs/heffer/borgmatic/)
|
||||
* [Fedora](https://bodhi.fedoraproject.org/updates/?search=borgmatic)
|
||||
* [Gentoo](https://packages.gentoo.org/packages/app-backup/borgmatic)
|
||||
* [Arch Linux](https://archlinux.org/packages/extra/any/borgmatic/)
|
||||
* [Alpine Linux](https://pkgs.alpinelinux.org/packages?name=borgmatic)
|
||||
@@ -88,9 +92,11 @@ installing borgmatic:
|
||||
* [openSUSE](https://software.opensuse.org/package/borgmatic)
|
||||
* [macOS (via Homebrew)](https://formulae.brew.sh/formula/borgmatic)
|
||||
* [macOS (via MacPorts)](https://ports.macports.org/port/borgmatic/)
|
||||
* [NixOS](https://search.nixos.org/packages?show=borgmatic&sort=relevance&type=packages&query=borgmatic)
|
||||
* [NixOS](https://search.nixos.org/packages?channel=unstable&show=borgmatic&query=borgmatic)
|
||||
|
||||
#### Etc.
|
||||
|
||||
* [Ansible role](https://github.com/borgbase/ansible-role-borgbackup)
|
||||
* [Unraid](https://unraid.net/community/apps?q=borgmatic#r)
|
||||
* [uv tool install](https://docs.astral.sh/uv/)
|
||||
|
||||
|
||||
@@ -150,6 +156,9 @@ added new options since you originally created your configuration file. Also
|
||||
check out how to [upgrade your
|
||||
configuration](https://torsion.org/borgmatic/how-to/upgrade/#upgrading-your-configuration).
|
||||
|
||||
And see the documentation on [patterns and
|
||||
excludes](https://torsion.org/borgmatic/reference/configuration/patterns-and-excludes/).
|
||||
|
||||
|
||||
### Encryption
|
||||
|
||||
|
||||
@@ -5,11 +5,14 @@ eleventyNavigation:
|
||||
parent: 🔒 Credentials
|
||||
---
|
||||
<span class="minilink minilink-addedin">New in version 1.9.11</span> When
|
||||
running inside a container, borgmatic can read [Docker
|
||||
secrets](https://docs.docker.com/compose/how-tos/use-secrets/) and [Podman
|
||||
running inside a container, borgmatic can read [<span
|
||||
data-pagefind-weight="0.5">Docker</span>
|
||||
secrets](https://docs.docker.com/compose/how-tos/use-secrets/) and [<span
|
||||
data-pagefind-weight="0.5">Podman</span>
|
||||
secrets](https://www.redhat.com/en/blog/new-podman-secrets-command). Creating
|
||||
those secrets and passing them into your borgmatic container is outside the
|
||||
scope of this documentation, but here's a simple example of that with [Docker
|
||||
scope of this documentation, but here's a simple example of that with [<span
|
||||
data-pagefind-weight="0.5">Docker</span>
|
||||
Compose](https://docs.docker.com/compose/):
|
||||
|
||||
```yaml
|
||||
@@ -25,9 +28,9 @@ secrets:
|
||||
```
|
||||
|
||||
This assumes there's a file on the host at `/etc/borgmatic/passphrase.txt`
|
||||
containing your passphrase. Docker or Podman mounts the contents of that file
|
||||
into a secret named `borgmatic_passphrase` in the borgmatic container at
|
||||
`/run/secrets/`.
|
||||
containing your passphrase. <span data-pagefind-weight="0.5">Docker or
|
||||
Podman</span> mounts the contents of that file into a secret named
|
||||
`borgmatic_passphrase` in the borgmatic container at `/run/secrets/`.
|
||||
|
||||
Once your container secret is in place, you can consume it within your borgmatic
|
||||
configuration file:
|
||||
|
||||
@@ -26,6 +26,9 @@ sentry:
|
||||
The `monitor_slug` value comes from the "Monitor Slug" under "Cron Details" on
|
||||
the same Sentry monitor page.
|
||||
|
||||
The `environment` value optionally specifies the environment that is used in
|
||||
Sentry.
|
||||
|
||||
With this configuration, borgmatic pings Sentry whenever borgmatic starts,
|
||||
finishes, or fails, but only when any of the `create`, `prune`, `compact`, or
|
||||
`check` actions are run. You can optionally override the start/finish/fail
|
||||
@@ -36,6 +39,7 @@ Sentry on failure:
|
||||
sentry:
|
||||
data_source_name_url: https://5f80ec@o294220.ingest.us.sentry.io/203069
|
||||
monitor_slug: mymonitor
|
||||
environment: myenvironment
|
||||
states:
|
||||
- fail
|
||||
```
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
---
|
||||
title: Patterns and excludes
|
||||
eleventyNavigation:
|
||||
key: ⛔ Patterns and excludes
|
||||
parent: ⚙️ Configuration
|
||||
---
|
||||
|
||||
borgmatic's configuration has multiple options for specifying the source files
|
||||
to include in your backups. Which of these options you use depends on how
|
||||
complex your file matching needs are.
|
||||
|
||||
## Source directories
|
||||
|
||||
The `source_directories` option is the simplest way to specify the files and
|
||||
directories to include in your backups. Globs (`*`) allow you to match multiple
|
||||
paths at once, and tildes (`~`) get expanded to the current user's home
|
||||
directory. Here's an example:
|
||||
|
||||
```yaml
|
||||
source_directories:
|
||||
- /home
|
||||
- /etc
|
||||
- /var/log/syslog*
|
||||
- /home/user/path with spaces
|
||||
- ~/.config
|
||||
```
|
||||
|
||||
## Excludes
|
||||
|
||||
The `exclude_patterns` options lists particular paths to exclude from your
|
||||
backups, paths that would otherwise get included by `source_directories`. Globs
|
||||
and tildes are also supported here. Use quotes as needed. For example:
|
||||
|
||||
```yaml
|
||||
exclude_patterns:
|
||||
- '*.pyc'
|
||||
- '/home/*/.cache'
|
||||
- '*/.vim*.tmp'
|
||||
- /etc/ssl
|
||||
- /home/user/path with spaces
|
||||
```
|
||||
|
||||
See the [Borg patterns
|
||||
documentation](https://borgbackup.readthedocs.io/en/stable/usage/help.html#borg-patterns)
|
||||
for more details about the specific "fnmatch"-style syntax used by excludes.
|
||||
|
||||
The `exclude_from` option is similar to `exclude_patterns`, but with your patterns
|
||||
listed in an external file instead of directly within borgmatic's configuration.
|
||||
Here's an example:
|
||||
|
||||
```yaml
|
||||
exclude_from:
|
||||
- /etc/borgmatic/excludes
|
||||
```
|
||||
|
||||
Also see the [borgmatic configuration
|
||||
reference](https://torsion.org/borgmatic/reference/configuration/) for
|
||||
additional exclude-related options.
|
||||
|
||||
|
||||
## Patterns
|
||||
|
||||
When you have more complex needs for including and excluding files to backup,
|
||||
the `patterns` option is available. The definitive documentation on patterns is
|
||||
the [Borg patterns
|
||||
documentation](https://borgbackup.readthedocs.io/en/stable/usage/help.html#borg-patterns),
|
||||
but here are the basics.
|
||||
|
||||
First, unless you have `source_directories`, you need root patterns. In fact,
|
||||
root patterns are just another way to specify the same paths as in
|
||||
`source_directories`; they tell Borg the starting point for recursing into
|
||||
directories to find files to backup. Root patterns are prefixed with "`R `". For
|
||||
instance:
|
||||
|
||||
```yaml
|
||||
patterns:
|
||||
- R /home
|
||||
- R /etc
|
||||
```
|
||||
|
||||
You can also add excludes and includes to your patterns. Excludes are prefixed
|
||||
with "`- `". If you're defining these directly in borgmatic's configuration
|
||||
file, use quotes around the pattern. For example:
|
||||
|
||||
```yaml
|
||||
patterns:
|
||||
- R /home
|
||||
- '- /home/user/.cache'
|
||||
- R /etc
|
||||
```
|
||||
|
||||
How this works is that when Borg discovers a particular file path as it's
|
||||
recursing into root directories, it tries to match that path against any
|
||||
excludes and includes in your patterns *in order*, one at a time. If the first
|
||||
match is to an exclude, then Borg excludes the file from the backup. But if the
|
||||
first match is to an include, Borg includes it—even if there's a subsequent
|
||||
exclude.
|
||||
|
||||
The respective order of root patterns vs. exclude and include patterns doesn't
|
||||
matter to Borg, so organize root patterns how you like.
|
||||
|
||||
Here's an example of an include, which is prefixed with "`+ `":
|
||||
|
||||
```yaml
|
||||
patterns:
|
||||
- R /home
|
||||
- '+ /home/user/.cache/keep-me'
|
||||
- '- /home/user/.cache'
|
||||
- R /etc
|
||||
```
|
||||
|
||||
This example excludes all of the `.cache` directory—except for the `keep-me`
|
||||
subdirectory, which gets included since it's listed first.
|
||||
|
||||
There's also a different kind of exclude pattern—a no-recurse exclude. That's
|
||||
prefixed with "`! `" and tells Borg to not only exclude any matching paths but
|
||||
also to ignore any subdirectories, saving file processing time. Here's an
|
||||
example:
|
||||
|
||||
```yaml
|
||||
patterns:
|
||||
- R /home
|
||||
- '! /home/user/.cache'
|
||||
- R /etc
|
||||
```
|
||||
|
||||
The `patterns_from` option is similar to `patterns`, but with your patterns
|
||||
listed in an external file instead of directly within borgmatic's configuration.
|
||||
Here's an example:
|
||||
|
||||
```yaml
|
||||
patterns_from:
|
||||
- /etc/borgmatic/patterns
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
Under the hood, borgmatic actually converts `source_directories`,
|
||||
`exclude_patterns`, and `exclude_from` values to Borg patterns and merges them
|
||||
with any `patterns` and `patterns_from` values you've configured—passing the
|
||||
resulting processed patterns to Borg.
|
||||
|
||||
To see the combined patterns that borgmatic passes to Borg, run borgmatic with
|
||||
[`--verbosity 2`](https://torsion.org/borgmatic/reference/command-line/logging/)
|
||||
(and optionally `--dry-run`) and look for "`Writing patterns to ...`" in the
|
||||
output. For instance:
|
||||
|
||||
```
|
||||
repo: Writing patterns to /tmp/borgmatic-xzwb6s07/borgmatic/tmp61shymp0:
|
||||
R /tmp/borgmatic-xzwb6s07/./borgmatic/sqlite_databases
|
||||
+ /tmp/borgmatic-xzwb6s07/./borgmatic/sqlite_databases
|
||||
R /home
|
||||
R /etc
|
||||
! fm:/home/user/.cache
|
||||
```
|
||||
|
||||
You'll notice that borgmatic prepends your patterns with its own to support
|
||||
use cases like streaming database dumps to Borg, creating filesystem snapshots,
|
||||
saving bootstrap metadata, and so on.
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "borgmatic"
|
||||
version = "2.0.10"
|
||||
version = "2.0.11"
|
||||
authors = [
|
||||
{ name="Dan Helfman", email="witten@torsion.org" },
|
||||
]
|
||||
|
||||
@@ -25,5 +25,5 @@ export PATH="/root/.local/bin:$PATH"
|
||||
uv tool install tox --with tox-uv
|
||||
export COVERAGE_FILE=/tmp/.coverage
|
||||
|
||||
tox --workdir /tmp/.tox -e py39,py313 --sitepackages
|
||||
tox --workdir /tmp/.tox -e py311,py314 --sitepackages
|
||||
tox --workdir /tmp/.tox --sitepackages -e end-to-end
|
||||
|
||||
+19
-18
@@ -1,26 +1,27 @@
|
||||
apprise==1.9.3
|
||||
attrs==25.3.0
|
||||
certifi==2025.7.14
|
||||
charset-normalizer==3.4.2
|
||||
apprise==1.9.5
|
||||
attrs==25.4.0
|
||||
certifi==2025.10.5
|
||||
charset-normalizer==3.4.4
|
||||
click>=8.1.8
|
||||
codespell==2.4.1
|
||||
coverage==7.9.2
|
||||
coverage==7.11.0
|
||||
flexmock==0.12.2
|
||||
idna==3.10
|
||||
iniconfig==2.1.0
|
||||
jsonschema==4.24.1
|
||||
jsonschema-specifications==2025.4.1
|
||||
Markdown==3.8.2
|
||||
idna==3.11
|
||||
iniconfig==2.3.0
|
||||
jsonschema==4.25.1
|
||||
jsonschema-specifications==2025.9.1
|
||||
markdown==3.9
|
||||
oauthlib==3.3.1
|
||||
packaging==25.0
|
||||
pluggy==1.6.0
|
||||
Pygments==2.19.2
|
||||
pytest==8.4.1
|
||||
pytest-cov==6.2.1
|
||||
PyYAML>5.0.0
|
||||
referencing==0.36.2
|
||||
requests==2.32.4
|
||||
pygments==2.19.2
|
||||
pytest==8.4.2
|
||||
pytest-cov==7.0.0
|
||||
pyyaml>5.0.0
|
||||
referencing==0.37.0
|
||||
requests==2.32.5
|
||||
requests-oauthlib==2.0.0
|
||||
rpds-py==0.26.0
|
||||
ruamel.yaml>0.15.0
|
||||
rpds-py==0.28.0
|
||||
ruamel-yaml>0.15.0
|
||||
typing-extensions==4.15.0
|
||||
urllib3==2.5.0
|
||||
|
||||
@@ -5,11 +5,22 @@ from borgmatic.hooks.data_source import btrfs as module
|
||||
|
||||
|
||||
def test_dump_data_sources_snapshots_each_subvolume_and_updates_patterns():
|
||||
patterns = [Pattern('/foo'), Pattern('/mnt/subvol1'), Pattern('/mnt/subvol2')]
|
||||
patterns = [
|
||||
Pattern('/foo'),
|
||||
Pattern('/mnt/subvol1'),
|
||||
Pattern('/mnt/subvol1/.cache', Pattern_type.EXCLUDE),
|
||||
Pattern('/mnt/subvol2'),
|
||||
]
|
||||
config = {'btrfs': {}}
|
||||
flexmock(module).should_receive('get_subvolumes').and_return(
|
||||
(
|
||||
module.Subvolume('/mnt/subvol1', contained_patterns=(Pattern('/mnt/subvol1'),)),
|
||||
module.Subvolume(
|
||||
'/mnt/subvol1',
|
||||
contained_patterns=(
|
||||
Pattern('/mnt/subvol1'),
|
||||
Pattern('/mnt/subvol1/.cache', Pattern_type.EXCLUDE),
|
||||
),
|
||||
),
|
||||
module.Subvolume('/mnt/subvol2', contained_patterns=(Pattern('/mnt/subvol2'),)),
|
||||
),
|
||||
)
|
||||
@@ -50,6 +61,7 @@ def test_dump_data_sources_snapshots_each_subvolume_and_updates_patterns():
|
||||
),
|
||||
Pattern('/foo'),
|
||||
Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1'),
|
||||
Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1/.cache', Pattern_type.EXCLUDE),
|
||||
Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1', Pattern_type.INCLUDE),
|
||||
Pattern('/mnt/subvol2/.borgmatic-snapshot-1234/./mnt/subvol2'),
|
||||
Pattern('/mnt/subvol2/.borgmatic-snapshot-1234/./mnt/subvol2', Pattern_type.INCLUDE),
|
||||
|
||||
@@ -6,13 +6,20 @@ from borgmatic.hooks.data_source import lvm as module
|
||||
|
||||
def test_dump_data_sources_snapshots_and_mounts_and_updates_patterns():
|
||||
config = {'lvm': {}}
|
||||
patterns = [Pattern('/mnt/lvolume1/subdir'), Pattern('/mnt/lvolume2')]
|
||||
patterns = [
|
||||
Pattern('/mnt/lvolume1/subdir'),
|
||||
Pattern('/mnt/lvolume1/subdir/.cache', Pattern_type.EXCLUDE),
|
||||
Pattern('/mnt/lvolume2'),
|
||||
]
|
||||
logical_volumes = (
|
||||
module.Logical_volume(
|
||||
name='lvolume1',
|
||||
device_path='/dev/lvolume1',
|
||||
mount_point='/mnt/lvolume1',
|
||||
contained_patterns=(Pattern('/mnt/lvolume1/subdir'),),
|
||||
contained_patterns=(
|
||||
Pattern('/mnt/lvolume1/subdir'),
|
||||
Pattern('/mnt/lvolume1/subdir/.cache', Pattern_type.EXCLUDE),
|
||||
),
|
||||
),
|
||||
module.Logical_volume(
|
||||
name='lvolume2',
|
||||
@@ -75,6 +82,9 @@ def test_dump_data_sources_snapshots_and_mounts_and_updates_patterns():
|
||||
|
||||
assert patterns == [
|
||||
Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir'),
|
||||
Pattern(
|
||||
'/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir/.cache', Pattern_type.EXCLUDE
|
||||
),
|
||||
Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir', Pattern_type.INCLUDE),
|
||||
Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2'),
|
||||
Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2', Pattern_type.INCLUDE),
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import borg as module
|
||||
|
||||
def test_run_borg_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import break_lock as module
|
||||
|
||||
def test_run_break_lock_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.break_lock).should_receive('break_lock')
|
||||
break_lock_arguments = flexmock(repository=flexmock())
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import change_passphrase as module
|
||||
|
||||
def test_run_change_passphrase_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.change_passphrase).should_receive('change_passphrase')
|
||||
change_passphrase_arguments = flexmock(repository=flexmock())
|
||||
|
||||
|
||||
@@ -1530,7 +1530,6 @@ def test_spot_check_without_any_source_paths_errors():
|
||||
|
||||
def test_run_check_checks_archives_for_configured_repository():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
|
||||
flexmock(module).should_receive('upgrade_check_times')
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
@@ -1566,7 +1565,6 @@ def test_run_check_checks_archives_for_configured_repository():
|
||||
|
||||
def test_run_check_runs_configured_extract_check():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
|
||||
flexmock(module).should_receive('upgrade_check_times')
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
@@ -1600,7 +1598,6 @@ def test_run_check_runs_configured_extract_check():
|
||||
|
||||
def test_run_check_runs_configured_spot_check():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
|
||||
flexmock(module).should_receive('upgrade_check_times')
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
@@ -1637,7 +1634,6 @@ def test_run_check_runs_configured_spot_check():
|
||||
|
||||
def test_run_check_without_checks_runs_nothing_except_hooks():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
|
||||
flexmock(module).should_receive('upgrade_check_times')
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
@@ -1667,68 +1663,3 @@ def test_run_check_without_checks_runs_nothing_except_hooks():
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
)
|
||||
|
||||
|
||||
def test_run_check_checks_archives_in_selected_repository():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'repositories_match',
|
||||
).once().and_return(True)
|
||||
flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
|
||||
flexmock(module).should_receive('upgrade_check_times')
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module.borgmatic.borg.check).should_receive('make_archive_filter_flags').and_return(())
|
||||
flexmock(module).should_receive('make_archives_check_id').and_return(None)
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(
|
||||
{'repository', 'archives'},
|
||||
)
|
||||
flexmock(module.borgmatic.borg.check).should_receive('check_archives').once()
|
||||
flexmock(module).should_receive('make_check_time_path')
|
||||
flexmock(module).should_receive('write_check_time')
|
||||
flexmock(module.borgmatic.borg.extract).should_receive('extract_last_archive_dry_run').never()
|
||||
check_arguments = flexmock(
|
||||
repository=flexmock(),
|
||||
progress=flexmock(),
|
||||
repair=flexmock(),
|
||||
only_checks=flexmock(),
|
||||
force=flexmock(),
|
||||
)
|
||||
global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
|
||||
|
||||
module.run_check(
|
||||
config_filename='test.yaml',
|
||||
repository={'path': 'repo'},
|
||||
config={'repositories': ['repo']},
|
||||
local_borg_version=None,
|
||||
check_arguments=check_arguments,
|
||||
global_arguments=global_arguments,
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
)
|
||||
|
||||
|
||||
def test_run_check_bails_if_repository_does_not_match():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'repositories_match',
|
||||
).once().and_return(False)
|
||||
flexmock(module.borgmatic.borg.check).should_receive('check_archives').never()
|
||||
check_arguments = flexmock(
|
||||
repository=flexmock(),
|
||||
progress=flexmock(),
|
||||
repair=flexmock(),
|
||||
only_checks=flexmock(),
|
||||
force=flexmock(),
|
||||
)
|
||||
global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
|
||||
|
||||
module.run_check(
|
||||
config_filename='test.yaml',
|
||||
repository={'path': 'repo'},
|
||||
config={'repositories': ['repo']},
|
||||
local_borg_version=None,
|
||||
check_arguments=check_arguments,
|
||||
global_arguments=global_arguments,
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
)
|
||||
|
||||
@@ -6,7 +6,6 @@ from borgmatic.actions import compact as module
|
||||
def test_compact_actions_calls_hooks_for_configured_repository():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.borg.compact).should_receive('compact_segments').once()
|
||||
compact_arguments = flexmock(
|
||||
repository=None,
|
||||
@@ -27,59 +26,3 @@ def test_compact_actions_calls_hooks_for_configured_repository():
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
)
|
||||
|
||||
|
||||
def test_compact_runs_with_selected_repository():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'repositories_match',
|
||||
).once().and_return(True)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.compact).should_receive('compact_segments').once()
|
||||
compact_arguments = flexmock(
|
||||
repository=flexmock(),
|
||||
progress=flexmock(),
|
||||
cleanup_commits=flexmock(),
|
||||
compact_threshold=flexmock(),
|
||||
)
|
||||
global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
|
||||
|
||||
module.run_compact(
|
||||
config_filename='test.yaml',
|
||||
repository={'path': 'repo'},
|
||||
config={},
|
||||
local_borg_version=None,
|
||||
compact_arguments=compact_arguments,
|
||||
global_arguments=global_arguments,
|
||||
dry_run_label='',
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
)
|
||||
|
||||
|
||||
def test_compact_bails_if_repository_does_not_match():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'repositories_match',
|
||||
).once().and_return(False)
|
||||
flexmock(module.borgmatic.borg.compact).should_receive('compact_segments').never()
|
||||
compact_arguments = flexmock(
|
||||
repository=flexmock(),
|
||||
progress=flexmock(),
|
||||
cleanup_commits=flexmock(),
|
||||
compact_threshold=flexmock(),
|
||||
)
|
||||
global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
|
||||
|
||||
module.run_compact(
|
||||
config_filename='test.yaml',
|
||||
repository={'path': 'repo'},
|
||||
config={},
|
||||
local_borg_version=None,
|
||||
compact_arguments=compact_arguments,
|
||||
global_arguments=global_arguments,
|
||||
dry_run_label='',
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
)
|
||||
|
||||
@@ -9,7 +9,6 @@ from borgmatic.actions import create as module
|
||||
|
||||
def test_run_create_executes_and_calls_hooks_for_configured_repository():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -48,87 +47,8 @@ def test_run_create_executes_and_calls_hooks_for_configured_repository():
|
||||
)
|
||||
|
||||
|
||||
def test_run_create_runs_with_selected_repository():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'repositories_match',
|
||||
).once().and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
flexmock(module.borgmatic.borg.create).should_receive('create_archive').once()
|
||||
flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return({})
|
||||
flexmock(module.borgmatic.hooks.dispatch).should_receive(
|
||||
'call_hooks_even_if_unconfigured',
|
||||
).and_return({})
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(())
|
||||
flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').and_return([])
|
||||
flexmock(os.path).should_receive('join').and_return('/run/borgmatic/bootstrap')
|
||||
create_arguments = flexmock(
|
||||
repository=flexmock(),
|
||||
progress=flexmock(),
|
||||
statistics=flexmock(),
|
||||
json=False,
|
||||
comment=None,
|
||||
list_details=flexmock(),
|
||||
)
|
||||
global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
|
||||
|
||||
list(
|
||||
module.run_create(
|
||||
config_filename='test.yaml',
|
||||
repository={'path': 'repo'},
|
||||
config={},
|
||||
config_paths=['/tmp/test.yaml'],
|
||||
local_borg_version=None,
|
||||
create_arguments=create_arguments,
|
||||
global_arguments=global_arguments,
|
||||
dry_run_label='',
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_run_create_bails_if_repository_does_not_match():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'repositories_match',
|
||||
).once().and_return(False)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').never()
|
||||
flexmock(module.borgmatic.borg.create).should_receive('create_archive').never()
|
||||
create_arguments = flexmock(
|
||||
repository=flexmock(),
|
||||
progress=flexmock(),
|
||||
statistics=flexmock(),
|
||||
json=False,
|
||||
comment=None,
|
||||
list_details=flexmock(),
|
||||
)
|
||||
global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
|
||||
|
||||
list(
|
||||
module.run_create(
|
||||
config_filename='test.yaml',
|
||||
repository='repo',
|
||||
config={},
|
||||
config_paths=['/tmp/test.yaml'],
|
||||
local_borg_version=None,
|
||||
create_arguments=create_arguments,
|
||||
global_arguments=global_arguments,
|
||||
dry_run_label='',
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_run_create_with_both_list_and_json_errors():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'repositories_match',
|
||||
).once().and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').never()
|
||||
flexmock(module.borgmatic.borg.create).should_receive('create_archive').never()
|
||||
create_arguments = flexmock(
|
||||
@@ -160,9 +80,6 @@ def test_run_create_with_both_list_and_json_errors():
|
||||
|
||||
def test_run_create_with_both_list_and_progress_errors():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'repositories_match',
|
||||
).once().and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').never()
|
||||
flexmock(module.borgmatic.borg.create).should_receive('create_archive').never()
|
||||
create_arguments = flexmock(
|
||||
@@ -194,9 +111,6 @@ def test_run_create_with_both_list_and_progress_errors():
|
||||
|
||||
def test_run_create_produces_json():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'repositories_match',
|
||||
).once().and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -244,7 +158,6 @@ def test_run_create_with_active_dumps_roundtrips_via_checkpoint_archive():
|
||||
mock_dump_process.should_receive('poll').and_return(None).and_return(0)
|
||||
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -325,7 +238,6 @@ def test_run_create_with_active_dumps_json_updates_archive_info():
|
||||
}
|
||||
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import delete as module
|
||||
|
||||
def test_run_delete_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name')
|
||||
flexmock(module.borgmatic.actions.arguments).should_receive('update_arguments').and_return(
|
||||
flexmock(),
|
||||
@@ -25,7 +24,6 @@ def test_run_delete_does_not_raise():
|
||||
|
||||
def test_run_delete_without_archive_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name')
|
||||
flexmock(module.borgmatic.actions.arguments).should_receive('update_arguments').and_return(
|
||||
flexmock(),
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import export_key as module
|
||||
|
||||
def test_run_export_key_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.export_key).should_receive('export_key')
|
||||
export_arguments = flexmock(repository=flexmock())
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import export_tar as module
|
||||
|
||||
def test_run_export_tar_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.export_tar).should_receive('export_tar_archive')
|
||||
export_tar_arguments = flexmock(
|
||||
repository=flexmock(),
|
||||
@@ -31,7 +30,6 @@ def test_run_export_tar_does_not_raise():
|
||||
|
||||
def test_run_export_tar_favors_flags_over_config():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.export_tar).should_receive('export_tar_archive').with_args(
|
||||
object,
|
||||
object,
|
||||
@@ -70,7 +68,6 @@ def test_run_export_tar_favors_flags_over_config():
|
||||
|
||||
def test_run_export_tar_defaults_to_config():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.export_tar).should_receive('export_tar_archive').with_args(
|
||||
object,
|
||||
object,
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import extract as module
|
||||
|
||||
def test_run_extract_calls_hooks():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.extract).should_receive('extract_archive')
|
||||
extract_arguments = flexmock(
|
||||
paths=flexmock(),
|
||||
@@ -31,7 +30,6 @@ def test_run_extract_calls_hooks():
|
||||
|
||||
def test_run_extract_favors_flags_over_config():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').with_args(
|
||||
object,
|
||||
object,
|
||||
@@ -69,7 +67,6 @@ def test_run_extract_favors_flags_over_config():
|
||||
|
||||
def test_run_extract_defaults_to_config():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').with_args(
|
||||
object,
|
||||
object,
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import import_key as module
|
||||
|
||||
def test_run_import_key_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.import_key).should_receive('import_key')
|
||||
import_arguments = flexmock(repository=flexmock())
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import info as module
|
||||
|
||||
def test_run_info_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -30,7 +29,6 @@ def test_run_info_does_not_raise():
|
||||
|
||||
def test_run_info_produces_json():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import list as module
|
||||
|
||||
def test_run_list_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -35,7 +34,6 @@ def test_run_list_does_not_raise():
|
||||
|
||||
def test_run_list_produces_json():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import mount as module
|
||||
|
||||
def test_run_mount_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.mount).should_receive('mount_archive')
|
||||
mount_arguments = flexmock(
|
||||
repository=flexmock(),
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import prune as module
|
||||
|
||||
def test_run_prune_calls_hooks_for_configured_repository():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.borg.prune).should_receive('prune_archives').once()
|
||||
prune_arguments = flexmock(repository=None, statistics=flexmock(), list_details=flexmock())
|
||||
global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
|
||||
@@ -21,55 +20,3 @@ def test_run_prune_calls_hooks_for_configured_repository():
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
)
|
||||
|
||||
|
||||
def test_run_prune_runs_with_selected_repository():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'repositories_match',
|
||||
).once().and_return(True)
|
||||
flexmock(module.borgmatic.borg.prune).should_receive('prune_archives').once()
|
||||
prune_arguments = flexmock(
|
||||
repository=flexmock(),
|
||||
statistics=flexmock(),
|
||||
list_details=flexmock(),
|
||||
)
|
||||
global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
|
||||
|
||||
module.run_prune(
|
||||
config_filename='test.yaml',
|
||||
repository={'path': 'repo'},
|
||||
config={},
|
||||
local_borg_version=None,
|
||||
prune_arguments=prune_arguments,
|
||||
global_arguments=global_arguments,
|
||||
dry_run_label='',
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
)
|
||||
|
||||
|
||||
def test_run_prune_bails_if_repository_does_not_match():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'repositories_match',
|
||||
).once().and_return(False)
|
||||
flexmock(module.borgmatic.borg.prune).should_receive('prune_archives').never()
|
||||
prune_arguments = flexmock(
|
||||
repository=flexmock(),
|
||||
statistics=flexmock(),
|
||||
list_details=flexmock(),
|
||||
)
|
||||
global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
|
||||
|
||||
module.run_prune(
|
||||
config_filename='test.yaml',
|
||||
repository='repo',
|
||||
config={},
|
||||
local_borg_version=None,
|
||||
prune_arguments=prune_arguments,
|
||||
global_arguments=global_arguments,
|
||||
dry_run_label='',
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
)
|
||||
|
||||
@@ -6,7 +6,6 @@ from borgmatic.actions import recreate as module
|
||||
|
||||
def test_run_recreate_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -28,7 +27,6 @@ def test_run_recreate_does_not_raise():
|
||||
|
||||
def test_run_recreate_with_archive_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -50,7 +48,6 @@ def test_run_recreate_with_archive_does_not_raise():
|
||||
|
||||
def test_run_recreate_with_leftover_recreate_archive_raises():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -73,7 +70,6 @@ def test_run_recreate_with_leftover_recreate_archive_raises():
|
||||
|
||||
def test_run_recreate_with_latest_archive_resolving_to_leftover_recreate_archive_raises():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -96,7 +92,6 @@ def test_run_recreate_with_latest_archive_resolving_to_leftover_recreate_archive
|
||||
|
||||
def test_run_recreate_with_archive_already_exists_error_raises():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -124,7 +119,6 @@ def test_run_recreate_with_archive_already_exists_error_raises():
|
||||
|
||||
def test_run_recreate_with_target_and_archive_already_exists_error_raises():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -156,7 +150,6 @@ def test_run_recreate_with_target_and_archive_already_exists_error_raises():
|
||||
|
||||
def test_run_recreate_with_other_called_process_error_passes_it_through():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
|
||||
@@ -6,7 +6,6 @@ from borgmatic.actions import repo_create as module
|
||||
|
||||
def test_run_repo_create_with_encryption_mode_argument_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_create).should_receive('create_repository')
|
||||
arguments = flexmock(
|
||||
encryption_mode=flexmock(),
|
||||
@@ -31,7 +30,6 @@ def test_run_repo_create_with_encryption_mode_argument_does_not_raise():
|
||||
|
||||
def test_run_repo_create_with_encryption_mode_option_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_create).should_receive('create_repository')
|
||||
arguments = flexmock(
|
||||
encryption_mode=None,
|
||||
@@ -56,7 +54,6 @@ def test_run_repo_create_with_encryption_mode_option_does_not_raise():
|
||||
|
||||
def test_run_repo_create_without_encryption_mode_raises():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_create).should_receive('create_repository')
|
||||
arguments = flexmock(
|
||||
encryption_mode=None,
|
||||
@@ -80,36 +77,8 @@ def test_run_repo_create_without_encryption_mode_raises():
|
||||
)
|
||||
|
||||
|
||||
def test_run_repo_create_bails_if_repository_does_not_match():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(
|
||||
False,
|
||||
)
|
||||
flexmock(module.borgmatic.borg.repo_create).should_receive('create_repository').never()
|
||||
arguments = flexmock(
|
||||
encryption_mode=flexmock(),
|
||||
source_repository=flexmock(),
|
||||
repository=flexmock(),
|
||||
copy_crypt_key=flexmock(),
|
||||
append_only=flexmock(),
|
||||
storage_quota=flexmock(),
|
||||
make_parent_directories=flexmock(),
|
||||
)
|
||||
|
||||
module.run_repo_create(
|
||||
repository={'path': 'repo'},
|
||||
config={},
|
||||
local_borg_version=None,
|
||||
repo_create_arguments=arguments,
|
||||
global_arguments=flexmock(dry_run=False),
|
||||
local_path=None,
|
||||
remote_path=None,
|
||||
)
|
||||
|
||||
|
||||
def test_run_repo_create_favors_flags_over_config():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_create).should_receive('create_repository').with_args(
|
||||
object,
|
||||
object,
|
||||
@@ -153,7 +122,6 @@ def test_run_repo_create_favors_flags_over_config():
|
||||
|
||||
def test_run_repo_create_defaults_to_config():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_create).should_receive('create_repository').with_args(
|
||||
object,
|
||||
object,
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import repo_delete as module
|
||||
|
||||
def test_run_repo_delete_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.actions.arguments).should_receive('update_arguments').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -24,7 +23,6 @@ def test_run_repo_delete_does_not_raise():
|
||||
|
||||
def test_run_repo_delete_with_cache_only_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.actions.arguments).should_receive('update_arguments').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import repo_info as module
|
||||
|
||||
def test_run_repo_info_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_info).should_receive('display_repository_info')
|
||||
repo_info_arguments = flexmock(repository=flexmock(), json=False)
|
||||
|
||||
@@ -24,7 +23,6 @@ def test_run_repo_info_does_not_raise():
|
||||
|
||||
def test_run_repo_info_parses_json():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_info).should_receive('display_repository_info').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@ from borgmatic.actions import repo_list as module
|
||||
|
||||
def test_run_repo_list_does_not_raise():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_list).should_receive('list_repository')
|
||||
repo_list_arguments = flexmock(repository=flexmock(), json=False)
|
||||
|
||||
@@ -24,7 +23,6 @@ def test_run_repo_list_does_not_raise():
|
||||
|
||||
def test_run_repo_list_produces_json():
|
||||
flexmock(module.logger).answer = lambda message: None
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.borg.repo_list).should_receive('list_repository').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
|
||||
@@ -1168,7 +1168,6 @@ def test_run_restore_restores_each_data_source():
|
||||
module.Dump(hook_name='postgresql_databases', data_source_name='bar'),
|
||||
}
|
||||
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
borgmatic_runtime_directory = flexmock()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
|
||||
borgmatic_runtime_directory,
|
||||
@@ -1238,41 +1237,11 @@ def test_run_restore_restores_each_data_source():
|
||||
)
|
||||
|
||||
|
||||
def test_run_restore_bails_for_non_matching_repository():
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(
|
||||
False,
|
||||
)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
flexmock(module.borgmatic.config.paths).should_receive(
|
||||
'make_runtime_directory_glob',
|
||||
).replace_with(lambda path: path)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(())
|
||||
flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').and_return([])
|
||||
flexmock(module.borgmatic.hooks.dispatch).should_receive(
|
||||
'call_hooks_even_if_unconfigured',
|
||||
).never()
|
||||
flexmock(module).should_receive('restore_single_dump').never()
|
||||
|
||||
module.run_restore(
|
||||
repository={'path': 'repo'},
|
||||
config=flexmock(),
|
||||
local_borg_version=flexmock(),
|
||||
restore_arguments=flexmock(repository='repo', archive='archive', data_sources=flexmock()),
|
||||
global_arguments=flexmock(dry_run=False),
|
||||
local_path=flexmock(),
|
||||
remote_path=flexmock(),
|
||||
)
|
||||
|
||||
|
||||
def test_run_restore_restores_data_source_by_falling_back_to_all_name():
|
||||
dumps_to_restore = {
|
||||
module.Dump(hook_name='postgresql_databases', data_source_name='foo'),
|
||||
}
|
||||
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
borgmatic_runtime_directory = flexmock()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
|
||||
borgmatic_runtime_directory,
|
||||
@@ -1335,7 +1304,6 @@ def test_run_restore_restores_data_source_configured_with_all_name():
|
||||
module.Dump(hook_name='postgresql_databases', data_source_name='bar'),
|
||||
}
|
||||
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
borgmatic_runtime_directory = flexmock()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
|
||||
borgmatic_runtime_directory,
|
||||
@@ -1420,7 +1388,6 @@ def test_run_restore_skips_missing_data_source():
|
||||
module.Dump(hook_name='postgresql_databases', data_source_name='bar'),
|
||||
}
|
||||
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
borgmatic_runtime_directory = flexmock()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
|
||||
borgmatic_runtime_directory,
|
||||
@@ -1505,7 +1472,6 @@ def test_run_restore_restores_data_sources_from_different_hooks():
|
||||
module.Dump(hook_name='mysql_databases', data_source_name='foo'),
|
||||
}
|
||||
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
borgmatic_runtime_directory = flexmock()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
|
||||
borgmatic_runtime_directory,
|
||||
|
||||
@@ -216,7 +216,28 @@ def test_make_repo_delete_command_includes_lock_wait():
|
||||
assert command == ('borg', 'repo-delete', '--lock-wait', '5', 'repo')
|
||||
|
||||
|
||||
def test_make_repo_delete_command_includes_extra_borg_options():
|
||||
def test_make_repo_delete_command_without_feature_available_includes_delete_extra_borg_options():
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
|
||||
command = module.make_repo_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
config={'extra_borg_options': {'delete': '--extra "value with space"'}},
|
||||
local_borg_version='1.2.3',
|
||||
repo_delete_arguments=flexmock(list_details=False, force=0),
|
||||
global_arguments=flexmock(dry_run=False),
|
||||
local_path='borg',
|
||||
remote_path=None,
|
||||
)
|
||||
|
||||
assert command == ('borg', 'delete', '--extra', 'value with space', 'repo')
|
||||
|
||||
|
||||
def test_make_repo_delete_command_with_feature_available_includes_delete_extra_borg_options():
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
|
||||
@@ -528,7 +528,49 @@ def test_display_repository_info_with_lock_wait_calls_borg_with_lock_wait_flags(
|
||||
)
|
||||
|
||||
|
||||
def test_display_repository_info_calls_borg_with_extra_borg_options():
|
||||
def test_display_repository_info_without_feature_available_calls_borg_with_info_extra_borg_options():
|
||||
flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
|
||||
flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
|
||||
config = {'extra_borg_options': {'info': '--extra "value with space"'}}
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').replace_with(
|
||||
lambda name, value: (f'--{name}', str(value)) if value else (),
|
||||
)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
'--repo',
|
||||
'repo',
|
||||
),
|
||||
)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||
('borg', 'info', '--extra', 'value with space', '--json', '--repo', 'repo'),
|
||||
environment=None,
|
||||
working_directory=None,
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_return('[]')
|
||||
flexmock(module.flags).should_receive('warn_for_aggressive_archive_flags')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', '--extra', 'value with space', '--repo', 'repo'),
|
||||
output_log_level=module.borgmatic.logger.ANSWER,
|
||||
environment=None,
|
||||
working_directory=None,
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
config=config,
|
||||
local_borg_version='2.3.4',
|
||||
repo_info_arguments=flexmock(json=False),
|
||||
global_arguments=flexmock(),
|
||||
)
|
||||
|
||||
|
||||
def test_display_repository_info_with_feature_available_calls_borg_with_repo_info_extra_borg_options():
|
||||
flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
|
||||
flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
|
||||
config = {'extra_borg_options': {'repo_info': '--extra "value with space"'}}
|
||||
|
||||
@@ -412,7 +412,7 @@ def test_get_latest_archive_with_lock_wait_calls_borg_with_lock_wait_flags():
|
||||
)
|
||||
|
||||
|
||||
def test_get_latest_archive_calls_borg_with_extra_borg_options():
|
||||
def test_get_latest_archive_calls_borg_with_list_extra_borg_options():
|
||||
expected_archive = {'name': 'archive-name', 'id': 'd34db33f'}
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
@@ -437,6 +437,42 @@ def test_get_latest_archive_calls_borg_with_extra_borg_options():
|
||||
borg_exit_codes=None,
|
||||
).and_return(json.dumps({'archives': [expected_archive]}))
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
'repo',
|
||||
config={'extra_borg_options': {'list': '--extra "value with space"'}},
|
||||
local_borg_version='1.2.3',
|
||||
global_arguments=flexmock(),
|
||||
)
|
||||
== expected_archive
|
||||
)
|
||||
|
||||
|
||||
def test_get_latest_archive_with_feature_available_calls_borg_with_repo_list_extra_borg_options():
|
||||
expected_archive = {'name': 'archive-name', 'id': 'd34db33f'}
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags').with_args('last', 1).and_return(
|
||||
('--last', '1')
|
||||
)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||
(
|
||||
'borg',
|
||||
'repo-list',
|
||||
*BORG_LIST_LATEST_ARGUMENTS[:-1],
|
||||
'--extra',
|
||||
'value with space',
|
||||
*BORG_LIST_LATEST_ARGUMENTS[-1:],
|
||||
),
|
||||
environment=None,
|
||||
working_directory=None,
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_return(json.dumps({'archives': [expected_archive]}))
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
'repo',
|
||||
@@ -546,6 +582,7 @@ def test_get_latest_archive_calls_borg_with_working_directory():
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_log_info():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
insert_logging_mock(logging.INFO)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
@@ -574,6 +611,7 @@ def test_make_repo_list_command_includes_log_info():
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_json_but_not_info():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
insert_logging_mock(logging.INFO)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
@@ -602,6 +640,7 @@ def test_make_repo_list_command_includes_json_but_not_info():
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_log_debug():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
@@ -630,6 +669,7 @@ def test_make_repo_list_command_includes_log_debug():
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_json_but_not_debug():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
@@ -658,6 +698,7 @@ def test_make_repo_list_command_includes_json_but_not_debug():
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_json():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
None,
|
||||
@@ -685,6 +726,7 @@ def test_make_repo_list_command_includes_json():
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_log_json():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(
|
||||
('--log-json',),
|
||||
).and_return(())
|
||||
@@ -714,6 +756,7 @@ def test_make_repo_list_command_includes_log_json():
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_lock_wait():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(
|
||||
('--lock-wait', '5'),
|
||||
).and_return(())
|
||||
@@ -742,7 +785,36 @@ def test_make_repo_list_command_includes_lock_wait():
|
||||
assert command == ('borg', 'list', '--lock-wait', '5', 'repo')
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_extra_borg_options():
|
||||
def test_make_repo_list_command_includes_list_extra_borg_options():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
None,
|
||||
None,
|
||||
'1.2.3',
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
config={'extra_borg_options': {'list': '--extra "value with space"'}},
|
||||
local_borg_version='1.2.3',
|
||||
repo_list_arguments=flexmock(
|
||||
archive=None,
|
||||
paths=None,
|
||||
json=False,
|
||||
prefix=None,
|
||||
match_archives=None,
|
||||
),
|
||||
global_arguments=flexmock(),
|
||||
)
|
||||
|
||||
assert command == ('borg', 'list', '--extra', 'value with space', 'repo')
|
||||
|
||||
|
||||
def test_make_repo_list_command_with_feature_available_includes_repo_list_extra_borg_options():
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
None,
|
||||
@@ -766,10 +838,11 @@ def test_make_repo_list_command_includes_extra_borg_options():
|
||||
global_arguments=flexmock(),
|
||||
)
|
||||
|
||||
assert command == ('borg', 'list', '--extra', 'value with space', 'repo')
|
||||
assert command == ('borg', 'repo-list', '--extra', 'value with space', 'repo')
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_local_path():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
None,
|
||||
@@ -798,6 +871,7 @@ def test_make_repo_list_command_includes_local_path():
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_remote_path():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').replace_with(
|
||||
lambda name, value: (f'--{name}', value) if value else (),
|
||||
)
|
||||
@@ -828,6 +902,7 @@ def test_make_repo_list_command_includes_remote_path():
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_umask():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').replace_with(
|
||||
lambda name, value: (f'--{name}', value) if value else (),
|
||||
)
|
||||
@@ -857,6 +932,7 @@ def test_make_repo_list_command_includes_umask():
|
||||
|
||||
|
||||
def test_make_repo_list_command_transforms_prefix_into_match_archives():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(()).and_return(
|
||||
('--match-archives', 'sh:foo*'),
|
||||
)
|
||||
@@ -880,6 +956,7 @@ def test_make_repo_list_command_transforms_prefix_into_match_archives():
|
||||
|
||||
|
||||
def test_make_repo_list_command_prefers_prefix_over_archive_name_format():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(()).and_return(
|
||||
('--match-archives', 'sh:foo*'),
|
||||
)
|
||||
@@ -899,6 +976,7 @@ def test_make_repo_list_command_prefers_prefix_over_archive_name_format():
|
||||
|
||||
|
||||
def test_make_repo_list_command_transforms_archive_name_format_into_match_archives():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
None,
|
||||
@@ -926,6 +1004,7 @@ def test_make_repo_list_command_transforms_archive_name_format_into_match_archiv
|
||||
|
||||
|
||||
def test_make_repo_list_command_includes_short():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
None,
|
||||
@@ -966,6 +1045,7 @@ def test_make_repo_list_command_includes_short():
|
||||
),
|
||||
)
|
||||
def test_make_repo_list_command_includes_additional_flags(argument_name):
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
None,
|
||||
@@ -998,6 +1078,7 @@ def test_make_repo_list_command_includes_additional_flags(argument_name):
|
||||
|
||||
|
||||
def test_make_repo_list_command_with_match_archives_calls_borg_with_match_archives_flags():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
None,
|
||||
@@ -1073,6 +1154,7 @@ def test_list_repository_with_json_calls_json_command_only():
|
||||
|
||||
|
||||
def test_make_repo_list_command_with_date_based_matching_calls_borg_with_date_based_flags():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
|
||||
None,
|
||||
|
||||
@@ -939,6 +939,7 @@ def test_run_configuration_with_multiple_repositories_retries_with_timeout():
|
||||
def test_run_actions_runs_repo_create():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -962,9 +963,64 @@ def test_run_actions_runs_repo_create():
|
||||
)
|
||||
|
||||
|
||||
def test_run_actions_with_matching_repository_flag_runs_repo_create():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||
flexmock(borgmatic.actions.repo_create).should_receive('run_repo_create').once()
|
||||
|
||||
tuple(
|
||||
module.run_actions(
|
||||
arguments={
|
||||
'global': flexmock(dry_run=False),
|
||||
'repo-create': flexmock(repository='repo'),
|
||||
},
|
||||
config_filename=flexmock(),
|
||||
config={'repositories': []},
|
||||
config_paths=[],
|
||||
local_path=flexmock(),
|
||||
remote_path=flexmock(),
|
||||
local_borg_version=flexmock(),
|
||||
repository={'path': 'repo'},
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_run_actions_with_non_matching_repository_flag_bails():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(
|
||||
False
|
||||
)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').never()
|
||||
flexmock(module.command).should_receive('Before_after_hooks').never()
|
||||
flexmock(borgmatic.actions.repo_create).should_receive('run_repo_create').never()
|
||||
|
||||
tuple(
|
||||
module.run_actions(
|
||||
arguments={
|
||||
'global': flexmock(dry_run=False),
|
||||
'repo-create': flexmock(repository='other-repo'),
|
||||
},
|
||||
config_filename=flexmock(),
|
||||
config={'repositories': []},
|
||||
config_paths=[],
|
||||
local_path=flexmock(),
|
||||
remote_path=flexmock(),
|
||||
local_borg_version=flexmock(),
|
||||
repository={'path': 'repo'},
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_run_actions_adds_label_file_to_hook_context():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1001,6 +1057,7 @@ def test_run_actions_adds_label_file_to_hook_context():
|
||||
def test_run_actions_adds_log_file_to_hook_context():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1037,6 +1094,7 @@ def test_run_actions_adds_log_file_to_hook_context():
|
||||
def test_run_actions_runs_transfer():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1060,6 +1118,7 @@ def test_run_actions_runs_transfer():
|
||||
def test_run_actions_runs_create():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1085,6 +1144,7 @@ def test_run_actions_runs_create():
|
||||
def test_run_actions_with_skip_actions_does_not_run_action_or_action_command_hooks():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return(['create'])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1121,6 +1181,7 @@ def test_run_actions_with_skip_actions_does_not_run_action_or_action_command_hoo
|
||||
def test_run_actions_runs_recreate():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1145,6 +1206,7 @@ def test_run_actions_runs_recreate():
|
||||
def test_run_actions_runs_prune():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1168,6 +1230,7 @@ def test_run_actions_runs_prune():
|
||||
def test_run_actions_runs_compact():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1191,6 +1254,7 @@ def test_run_actions_runs_compact():
|
||||
def test_run_actions_runs_check_when_repository_enabled_for_checks():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1215,6 +1279,7 @@ def test_run_actions_runs_check_when_repository_enabled_for_checks():
|
||||
def test_run_actions_skips_check_when_repository_not_enabled_for_checks():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1239,6 +1304,7 @@ def test_run_actions_skips_check_when_repository_not_enabled_for_checks():
|
||||
def test_run_actions_runs_extract():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1262,6 +1328,7 @@ def test_run_actions_runs_extract():
|
||||
def test_run_actions_runs_export_tar():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1285,6 +1352,7 @@ def test_run_actions_runs_export_tar():
|
||||
def test_run_actions_runs_mount():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1308,6 +1376,7 @@ def test_run_actions_runs_mount():
|
||||
def test_run_actions_runs_restore():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1331,6 +1400,7 @@ def test_run_actions_runs_restore():
|
||||
def test_run_actions_runs_repo_list():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1356,6 +1426,7 @@ def test_run_actions_runs_repo_list():
|
||||
def test_run_actions_runs_list():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1381,6 +1452,7 @@ def test_run_actions_runs_list():
|
||||
def test_run_actions_runs_repo_info():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1406,6 +1478,7 @@ def test_run_actions_runs_repo_info():
|
||||
def test_run_actions_runs_info():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1431,6 +1504,7 @@ def test_run_actions_runs_info():
|
||||
def test_run_actions_runs_break_lock():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1454,6 +1528,7 @@ def test_run_actions_runs_break_lock():
|
||||
def test_run_actions_runs_export_key():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1477,6 +1552,7 @@ def test_run_actions_runs_export_key():
|
||||
def test_run_actions_runs_import_key():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1500,6 +1576,7 @@ def test_run_actions_runs_import_key():
|
||||
def test_run_actions_runs_change_passphrase():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1526,6 +1603,7 @@ def test_run_actions_runs_change_passphrase():
|
||||
def test_run_actions_runs_delete():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1549,6 +1627,7 @@ def test_run_actions_runs_delete():
|
||||
def test_run_actions_runs_repo_delete():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1575,6 +1654,7 @@ def test_run_actions_runs_repo_delete():
|
||||
def test_run_actions_runs_borg():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1598,6 +1678,7 @@ def test_run_actions_runs_borg():
|
||||
def test_run_actions_runs_multiple_actions_in_argument_order():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
@@ -1626,6 +1707,7 @@ def test_run_actions_runs_multiple_actions_in_argument_order():
|
||||
def test_run_actions_runs_action_hooks_for_one_action_at_a_time():
|
||||
flexmock(module).should_receive('add_custom_log_levels')
|
||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
|
||||
flexmock(),
|
||||
)
|
||||
|
||||
@@ -121,7 +121,9 @@ def test_runtime_directory_with_relative_xdg_runtime_dir_errors():
|
||||
def test_runtime_directory_falls_back_to_runtime_directory():
|
||||
flexmock(module).should_receive('expand_user_in_path').replace_with(lambda path: path)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('XDG_RUNTIME_DIR').and_return(None)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
flexmock(module).should_receive('resolve_systemd_directory').with_args(
|
||||
module.Systemd_directories.RUNTIME_DIRECTORY
|
||||
).and_return(
|
||||
'/run',
|
||||
)
|
||||
flexmock(module.os).should_receive('makedirs')
|
||||
@@ -133,7 +135,9 @@ def test_runtime_directory_falls_back_to_runtime_directory():
|
||||
def test_runtime_directory_falls_back_to_runtime_directory_without_adding_duplicate_borgmatic_subdirectory():
|
||||
flexmock(module).should_receive('expand_user_in_path').replace_with(lambda path: path)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('XDG_RUNTIME_DIR').and_return(None)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
flexmock(module).should_receive('resolve_systemd_directory').with_args(
|
||||
module.Systemd_directories.RUNTIME_DIRECTORY
|
||||
).and_return(
|
||||
'/run/borgmatic',
|
||||
)
|
||||
flexmock(module.os).should_receive('makedirs')
|
||||
@@ -144,7 +148,9 @@ def test_runtime_directory_falls_back_to_runtime_directory_without_adding_duplic
|
||||
|
||||
def test_runtime_directory_with_relative_runtime_directory_errors():
|
||||
flexmock(module.os.environ).should_receive('get').with_args('XDG_RUNTIME_DIR').and_return(None)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
flexmock(module).should_receive('resolve_systemd_directory').with_args(
|
||||
module.Systemd_directories.RUNTIME_DIRECTORY
|
||||
).and_return(
|
||||
'run',
|
||||
)
|
||||
flexmock(module.os).should_receive('makedirs').never()
|
||||
@@ -156,7 +162,9 @@ def test_runtime_directory_with_relative_runtime_directory_errors():
|
||||
def test_runtime_directory_falls_back_to_tmpdir_and_adds_temporary_subdirectory_that_get_cleaned_up():
|
||||
flexmock(module).should_receive('expand_user_in_path').replace_with(lambda path: path)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('XDG_RUNTIME_DIR').and_return(None)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
flexmock(module).should_receive('resolve_systemd_directory').with_args(
|
||||
module.Systemd_directories.RUNTIME_DIRECTORY
|
||||
).and_return(
|
||||
None,
|
||||
)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('TMPDIR').and_return('/run')
|
||||
@@ -174,7 +182,9 @@ def test_runtime_directory_falls_back_to_tmpdir_and_adds_temporary_subdirectory_
|
||||
|
||||
def test_runtime_directory_with_relative_tmpdir_errors():
|
||||
flexmock(module.os.environ).should_receive('get').with_args('XDG_RUNTIME_DIR').and_return(None)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
flexmock(module).should_receive('resolve_systemd_directory').with_args(
|
||||
module.Systemd_directories.RUNTIME_DIRECTORY
|
||||
).and_return(
|
||||
None,
|
||||
)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('TMPDIR').and_return('run')
|
||||
@@ -188,7 +198,9 @@ def test_runtime_directory_with_relative_tmpdir_errors():
|
||||
def test_runtime_directory_falls_back_to_temp_and_adds_temporary_subdirectory_that_get_cleaned_up():
|
||||
flexmock(module).should_receive('expand_user_in_path').replace_with(lambda path: path)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('XDG_RUNTIME_DIR').and_return(None)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
flexmock(module).should_receive('resolve_systemd_directory').with_args(
|
||||
module.Systemd_directories.RUNTIME_DIRECTORY
|
||||
).and_return(
|
||||
None,
|
||||
)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('TMPDIR').and_return(None)
|
||||
@@ -207,7 +219,9 @@ def test_runtime_directory_falls_back_to_temp_and_adds_temporary_subdirectory_th
|
||||
|
||||
def test_runtime_directory_with_relative_temp_errors():
|
||||
flexmock(module.os.environ).should_receive('get').with_args('XDG_RUNTIME_DIR').and_return(None)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
flexmock(module).should_receive('resolve_systemd_directory').with_args(
|
||||
module.Systemd_directories.RUNTIME_DIRECTORY
|
||||
).and_return(
|
||||
None,
|
||||
)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('TMPDIR').and_return(None)
|
||||
@@ -222,7 +236,9 @@ def test_runtime_directory_with_relative_temp_errors():
|
||||
def test_runtime_directory_falls_back_to_hard_coded_tmp_path_and_adds_temporary_subdirectory_that_get_cleaned_up():
|
||||
flexmock(module).should_receive('expand_user_in_path').replace_with(lambda path: path)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('XDG_RUNTIME_DIR').and_return(None)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
flexmock(module).should_receive('resolve_systemd_directory').with_args(
|
||||
module.Systemd_directories.RUNTIME_DIRECTORY
|
||||
).and_return(
|
||||
None,
|
||||
)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('TMPDIR').and_return(None)
|
||||
@@ -242,7 +258,9 @@ def test_runtime_directory_falls_back_to_hard_coded_tmp_path_and_adds_temporary_
|
||||
def test_runtime_directory_with_erroring_cleanup_does_not_raise():
|
||||
flexmock(module).should_receive('expand_user_in_path').replace_with(lambda path: path)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('XDG_RUNTIME_DIR').and_return(None)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
flexmock(module).should_receive('resolve_systemd_directory').with_args(
|
||||
module.Systemd_directories.RUNTIME_DIRECTORY
|
||||
).and_return(
|
||||
None,
|
||||
)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('TMPDIR').and_return(None)
|
||||
@@ -293,7 +311,9 @@ def test_get_borgmatic_state_directory_falls_back_to_xdg_state_home():
|
||||
def test_get_borgmatic_state_directory_falls_back_to_state_directory():
|
||||
flexmock(module).should_receive('expand_user_in_path').replace_with(lambda path: path)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('XDG_STATE_HOME').and_return(None)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('STATE_DIRECTORY').and_return(
|
||||
flexmock(module).should_receive('resolve_systemd_directory').with_args(
|
||||
module.Systemd_directories.STATE_DIRECTORY
|
||||
).and_return(
|
||||
'/tmp',
|
||||
)
|
||||
|
||||
@@ -304,3 +324,52 @@ def test_get_borgmatic_state_directory_defaults_to_hard_coded_path():
|
||||
flexmock(module).should_receive('expand_user_in_path').replace_with(lambda path: path)
|
||||
flexmock(module.os.environ).should_receive('get').and_return(None)
|
||||
assert module.get_borgmatic_state_directory({}) == '~/.local/state/borgmatic'
|
||||
|
||||
|
||||
def test_resolve_systemd_directory_none():
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
None
|
||||
)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('STATE_DIRECTORY').and_return(None)
|
||||
|
||||
assert module.resolve_systemd_directory(module.Systemd_directories.RUNTIME_DIRECTORY) is None
|
||||
assert module.resolve_systemd_directory(module.Systemd_directories.STATE_DIRECTORY) is None
|
||||
|
||||
|
||||
def test_resolve_systemd_directory_single():
|
||||
runtime_dir = '/run/borgmatic'
|
||||
state_dir = '/var/lib/borgmatic'
|
||||
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
runtime_dir
|
||||
)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('STATE_DIRECTORY').and_return(
|
||||
state_dir
|
||||
)
|
||||
|
||||
assert (
|
||||
module.resolve_systemd_directory(module.Systemd_directories.RUNTIME_DIRECTORY)
|
||||
== runtime_dir
|
||||
)
|
||||
assert module.resolve_systemd_directory(module.Systemd_directories.STATE_DIRECTORY) == state_dir
|
||||
|
||||
|
||||
def test_resolve_systemd_directory_multiple():
|
||||
runtime_dirs = '/run/borgmatic:/run/second:/run/third'
|
||||
state_dirs = '/var/lib/borgmatic:/var/lib/second:/var/lib/third'
|
||||
|
||||
flexmock(module.os.environ).should_receive('get').with_args('RUNTIME_DIRECTORY').and_return(
|
||||
runtime_dirs
|
||||
)
|
||||
flexmock(module.os.environ).should_receive('get').with_args('STATE_DIRECTORY').and_return(
|
||||
state_dirs
|
||||
)
|
||||
|
||||
assert (
|
||||
module.resolve_systemd_directory(module.Systemd_directories.RUNTIME_DIRECTORY)
|
||||
== '/run/borgmatic'
|
||||
)
|
||||
assert (
|
||||
module.resolve_systemd_directory(module.Systemd_directories.STATE_DIRECTORY)
|
||||
== '/var/lib/borgmatic'
|
||||
)
|
||||
|
||||
@@ -450,6 +450,9 @@ def test_dump_data_sources_snapshots_each_subvolume_and_replaces_patterns():
|
||||
'/mnt/subvol2',
|
||||
object,
|
||||
).and_return(Pattern('/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2'))
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
Pattern('/mnt/subvol1'),
|
||||
@@ -457,6 +460,7 @@ def test_dump_data_sources_snapshots_each_subvolume_and_replaces_patterns():
|
||||
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
@@ -465,6 +469,7 @@ def test_dump_data_sources_snapshots_each_subvolume_and_replaces_patterns():
|
||||
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').with_args(
|
||||
object,
|
||||
@@ -527,6 +532,9 @@ def test_dump_data_sources_uses_custom_btrfs_command_in_commands():
|
||||
'/mnt/subvol1',
|
||||
object,
|
||||
).and_return(Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1'))
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
Pattern('/mnt/subvol1'),
|
||||
@@ -534,6 +542,7 @@ def test_dump_data_sources_uses_custom_btrfs_command_in_commands():
|
||||
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').with_args(
|
||||
object,
|
||||
@@ -594,6 +603,9 @@ def test_dump_data_sources_with_findmnt_command_warns():
|
||||
'/mnt/subvol1',
|
||||
object,
|
||||
).and_return(Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1'))
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
Pattern('/mnt/subvol1'),
|
||||
@@ -601,6 +613,7 @@ def test_dump_data_sources_with_findmnt_command_warns():
|
||||
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').with_args(
|
||||
object,
|
||||
@@ -641,6 +654,9 @@ def test_dump_data_sources_with_dry_run_skips_snapshot_and_patterns_update():
|
||||
)
|
||||
flexmock(module).should_receive('snapshot_subvolume').never()
|
||||
flexmock(module).should_receive('make_snapshot_exclude_pattern').never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').never()
|
||||
|
||||
@@ -666,6 +682,9 @@ def test_dump_data_sources_without_matching_subvolumes_skips_snapshot_and_patter
|
||||
flexmock(module).should_receive('make_snapshot_path').never()
|
||||
flexmock(module).should_receive('snapshot_subvolume').never()
|
||||
flexmock(module).should_receive('make_snapshot_exclude_pattern').never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').never()
|
||||
|
||||
|
||||
@@ -203,6 +203,52 @@ def test_inject_pattern_with_root_pattern_prepends_it_along_with_corresponding_i
|
||||
]
|
||||
|
||||
|
||||
def test_get_last_pattern_index_with_ordered_subset_patterns_finds_last_one():
|
||||
patterns = [
|
||||
module.borgmatic.borg.pattern.Pattern('/foo'),
|
||||
module.borgmatic.borg.pattern.Pattern('/bar'),
|
||||
module.borgmatic.borg.pattern.Pattern('/baz'),
|
||||
module.borgmatic.borg.pattern.Pattern('/quux'),
|
||||
]
|
||||
patterns_subset = [
|
||||
module.borgmatic.borg.pattern.Pattern('/bar'),
|
||||
module.borgmatic.borg.pattern.Pattern('/baz'),
|
||||
]
|
||||
|
||||
assert module.get_last_pattern_index(patterns, patterns_subset) == 2
|
||||
|
||||
|
||||
def test_get_last_pattern_index_with_unordered_subset_patterns_finds_last_one():
|
||||
patterns = [
|
||||
module.borgmatic.borg.pattern.Pattern('/foo'),
|
||||
module.borgmatic.borg.pattern.Pattern('/bar'),
|
||||
module.borgmatic.borg.pattern.Pattern('/baz'),
|
||||
module.borgmatic.borg.pattern.Pattern('/quux'),
|
||||
]
|
||||
patterns_subset = [
|
||||
module.borgmatic.borg.pattern.Pattern('/baz'),
|
||||
module.borgmatic.borg.pattern.Pattern('/bar'),
|
||||
]
|
||||
|
||||
assert module.get_last_pattern_index(patterns, patterns_subset) == 2
|
||||
|
||||
|
||||
def test_get_last_pattern_index_with_unknown_subset_patterns_skips_it():
|
||||
patterns = [
|
||||
module.borgmatic.borg.pattern.Pattern('/foo'),
|
||||
module.borgmatic.borg.pattern.Pattern('/bar'),
|
||||
module.borgmatic.borg.pattern.Pattern('/baz'),
|
||||
module.borgmatic.borg.pattern.Pattern('/quux'),
|
||||
]
|
||||
patterns_subset = [
|
||||
module.borgmatic.borg.pattern.Pattern('/baz'),
|
||||
module.borgmatic.borg.pattern.Pattern('/unknown'),
|
||||
module.borgmatic.borg.pattern.Pattern('/bar'),
|
||||
]
|
||||
|
||||
assert module.get_last_pattern_index(patterns, patterns_subset) == 2
|
||||
|
||||
|
||||
def test_replace_pattern_swaps_out_pattern_in_place():
|
||||
patterns = [
|
||||
module.borgmatic.borg.pattern.Pattern('/etc'),
|
||||
@@ -217,6 +263,7 @@ def test_replace_pattern_swaps_out_pattern_in_place():
|
||||
'/foo/bar',
|
||||
type=module.borgmatic.borg.pattern.Pattern_type.EXCLUDE,
|
||||
),
|
||||
0,
|
||||
)
|
||||
|
||||
assert patterns == [
|
||||
@@ -243,6 +290,7 @@ def test_replace_pattern_with_unknown_pattern_falls_back_to_injecting():
|
||||
patterns,
|
||||
module.borgmatic.borg.pattern.Pattern('/unknown'),
|
||||
module.borgmatic.borg.pattern.Pattern('/foo/bar'),
|
||||
0,
|
||||
)
|
||||
|
||||
|
||||
@@ -251,20 +299,23 @@ def test_replace_pattern_with_root_pattern_swaps_it_in_along_with_corresponding_
|
||||
module.borgmatic.borg.pattern.Pattern('/etc'),
|
||||
module.borgmatic.borg.pattern.Pattern('/var'),
|
||||
module.borgmatic.borg.pattern.Pattern('/lib'),
|
||||
module.borgmatic.borg.pattern.Pattern('/run'),
|
||||
]
|
||||
|
||||
module.replace_pattern(
|
||||
patterns,
|
||||
module.borgmatic.borg.pattern.Pattern('/var'),
|
||||
module.borgmatic.borg.pattern.Pattern('/foo/bar'),
|
||||
2,
|
||||
)
|
||||
|
||||
assert patterns == [
|
||||
module.borgmatic.borg.pattern.Pattern('/etc'),
|
||||
module.borgmatic.borg.pattern.Pattern('/foo/bar'),
|
||||
module.borgmatic.borg.pattern.Pattern('/lib'),
|
||||
module.borgmatic.borg.pattern.Pattern(
|
||||
'/foo/bar',
|
||||
type=module.borgmatic.borg.pattern.Pattern_type.INCLUDE,
|
||||
),
|
||||
module.borgmatic.borg.pattern.Pattern('/lib'),
|
||||
module.borgmatic.borg.pattern.Pattern('/run'),
|
||||
]
|
||||
|
||||
@@ -360,6 +360,9 @@ def test_dump_data_sources_snapshots_and_mounts_and_replaces_patterns():
|
||||
logical_volumes[1],
|
||||
'/run/borgmatic',
|
||||
).and_return(Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2'))
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
Pattern('/mnt/lvolume1/subdir'),
|
||||
@@ -367,6 +370,7 @@ def test_dump_data_sources_snapshots_and_mounts_and_replaces_patterns():
|
||||
'/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
@@ -375,6 +379,7 @@ def test_dump_data_sources_snapshots_and_mounts_and_replaces_patterns():
|
||||
'/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
|
||||
assert (
|
||||
@@ -396,6 +401,9 @@ def test_dump_data_sources_with_no_logical_volumes_skips_snapshots():
|
||||
flexmock(module).should_receive('get_logical_volumes').and_return(())
|
||||
flexmock(module).should_receive('snapshot_logical_volume').never()
|
||||
flexmock(module).should_receive('mount_snapshot').never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
|
||||
|
||||
assert (
|
||||
@@ -477,6 +485,9 @@ def test_dump_data_sources_uses_snapshot_size_for_snapshot():
|
||||
logical_volumes[1],
|
||||
'/run/borgmatic',
|
||||
).and_return(Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2'))
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
Pattern('/mnt/lvolume1/subdir'),
|
||||
@@ -484,6 +495,7 @@ def test_dump_data_sources_uses_snapshot_size_for_snapshot():
|
||||
'/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
@@ -492,6 +504,7 @@ def test_dump_data_sources_uses_snapshot_size_for_snapshot():
|
||||
'/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
|
||||
assert (
|
||||
@@ -580,6 +593,9 @@ def test_dump_data_sources_uses_custom_commands():
|
||||
logical_volumes[1],
|
||||
'/run/borgmatic',
|
||||
).and_return(Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2'))
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
Pattern('/mnt/lvolume1/subdir'),
|
||||
@@ -587,6 +603,7 @@ def test_dump_data_sources_uses_custom_commands():
|
||||
'/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
@@ -595,6 +612,7 @@ def test_dump_data_sources_uses_custom_commands():
|
||||
'/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
|
||||
assert (
|
||||
@@ -633,6 +651,9 @@ def test_dump_data_sources_with_dry_run_skips_snapshots_and_does_not_touch_patte
|
||||
flexmock(module).should_receive('snapshot_logical_volume').never()
|
||||
flexmock(module).should_receive('get_snapshots').never()
|
||||
flexmock(module).should_receive('mount_snapshot').never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
|
||||
|
||||
assert (
|
||||
@@ -714,6 +735,9 @@ def test_dump_data_sources_ignores_mismatch_between_given_patterns_and_contained
|
||||
logical_volumes[1],
|
||||
'/run/borgmatic',
|
||||
).and_return(Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2'))
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
Pattern('/mnt/lvolume1/subdir'),
|
||||
@@ -721,6 +745,7 @@ def test_dump_data_sources_ignores_mismatch_between_given_patterns_and_contained
|
||||
'/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
@@ -729,6 +754,7 @@ def test_dump_data_sources_ignores_mismatch_between_given_patterns_and_contained
|
||||
'/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
|
||||
assert (
|
||||
@@ -785,6 +811,9 @@ def test_dump_data_sources_with_missing_snapshot_errors():
|
||||
snapshot_name='lvolume2_borgmatic-1234',
|
||||
).never()
|
||||
flexmock(module).should_receive('mount_snapshot').never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
|
||||
@@ -328,6 +328,9 @@ def test_dump_data_sources_snapshots_and_mounts_and_replaces_patterns():
|
||||
'/run/borgmatic',
|
||||
).and_return(Pattern('/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir'))
|
||||
patterns = [Pattern('/mnt/dataset/subdir')]
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
Pattern('/mnt/dataset/subdir'),
|
||||
@@ -335,6 +338,7 @@ def test_dump_data_sources_snapshots_and_mounts_and_replaces_patterns():
|
||||
'/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
|
||||
assert (
|
||||
@@ -355,6 +359,9 @@ def test_dump_data_sources_with_no_datasets_skips_snapshots():
|
||||
flexmock(module.os).should_receive('getpid').and_return(1234)
|
||||
flexmock(module).should_receive('snapshot_dataset').never()
|
||||
flexmock(module).should_receive('mount_snapshot').never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
|
||||
patterns = [Pattern('/mnt/dataset')]
|
||||
|
||||
@@ -400,6 +407,9 @@ def test_dump_data_sources_uses_custom_commands():
|
||||
dataset,
|
||||
'/run/borgmatic',
|
||||
).and_return(Pattern('/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir'))
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
Pattern('/mnt/dataset/subdir'),
|
||||
@@ -407,6 +417,7 @@ def test_dump_data_sources_uses_custom_commands():
|
||||
'/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
patterns = [Pattern('/mnt/dataset/subdir')]
|
||||
hook_config = {
|
||||
@@ -437,6 +448,9 @@ def test_dump_data_sources_with_dry_run_skips_commands_and_does_not_touch_patter
|
||||
flexmock(module.os).should_receive('getpid').and_return(1234)
|
||||
flexmock(module).should_receive('snapshot_dataset').never()
|
||||
flexmock(module).should_receive('mount_snapshot').never()
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
|
||||
patterns = [Pattern('/mnt/dataset')]
|
||||
|
||||
@@ -480,6 +494,9 @@ def test_dump_data_sources_ignores_mismatch_between_given_patterns_and_contained
|
||||
dataset,
|
||||
'/run/borgmatic',
|
||||
).and_return(Pattern('/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir'))
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive(
|
||||
'get_last_pattern_index'
|
||||
).and_return(0)
|
||||
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
|
||||
object,
|
||||
Pattern('/mnt/dataset/subdir'),
|
||||
@@ -487,6 +504,7 @@ def test_dump_data_sources_ignores_mismatch_between_given_patterns_and_contained
|
||||
'/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir',
|
||||
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
|
||||
),
|
||||
0,
|
||||
).once()
|
||||
patterns = [Pattern('/hmm')]
|
||||
|
||||
|
||||
@@ -6,20 +6,23 @@ from borgmatic.hooks.monitoring import sentry as module
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'state,configured_states,expected_status',
|
||||
'state,configured_states,configured_environment,expected_status',
|
||||
(
|
||||
(borgmatic.hooks.monitoring.monitor.State.START, ['start'], 'in_progress'),
|
||||
(borgmatic.hooks.monitoring.monitor.State.START, ['start'], None, 'in_progress'),
|
||||
(
|
||||
borgmatic.hooks.monitoring.monitor.State.START,
|
||||
['start', 'finish', 'fail'],
|
||||
None,
|
||||
'in_progress',
|
||||
),
|
||||
(borgmatic.hooks.monitoring.monitor.State.START, None, 'in_progress'),
|
||||
(borgmatic.hooks.monitoring.monitor.State.FINISH, ['finish'], 'ok'),
|
||||
(borgmatic.hooks.monitoring.monitor.State.FAIL, ['fail'], 'error'),
|
||||
(borgmatic.hooks.monitoring.monitor.State.START, None, 'production', 'in_progress'),
|
||||
(borgmatic.hooks.monitoring.monitor.State.FINISH, ['finish'], 'development', 'ok'),
|
||||
(borgmatic.hooks.monitoring.monitor.State.FAIL, ['fail'], 'another-environment', 'error'),
|
||||
),
|
||||
)
|
||||
def test_ping_monitor_constructs_cron_url_and_pings_it(state, configured_states, expected_status):
|
||||
def test_ping_monitor_constructs_cron_url_and_pings_it(
|
||||
state, configured_states, configured_environment, expected_status
|
||||
):
|
||||
hook_config = {
|
||||
'data_source_name_url': 'https://5f80ec@o294220.ingest.us.sentry.io/203069',
|
||||
'monitor_slug': 'test',
|
||||
@@ -28,8 +31,13 @@ def test_ping_monitor_constructs_cron_url_and_pings_it(state, configured_states,
|
||||
if configured_states:
|
||||
hook_config['states'] = configured_states
|
||||
|
||||
environment_query = ''
|
||||
if configured_environment:
|
||||
hook_config['environment'] = configured_environment
|
||||
environment_query = f'&environment={configured_environment}'
|
||||
|
||||
flexmock(module.requests).should_receive('post').with_args(
|
||||
f'https://o294220.ingest.us.sentry.io/api/203069/cron/test/5f80ec/?status={expected_status}',
|
||||
f'https://o294220.ingest.us.sentry.io/api/203069/cron/test/5f80ec/?status={expected_status}{environment_query}',
|
||||
timeout=int,
|
||||
headers={'User-Agent': 'borgmatic'},
|
||||
).and_return(flexmock(ok=True)).once()
|
||||
|
||||
Reference in New Issue
Block a user