Compare commits

...
3 Commits
7 changed files with 88 additions and 15 deletions
+4
View File
@@ -1,3 +1,7 @@
1.1.14
* #49: Fix for typo in --patterns-from option.
* #47: Support for Borg --dry-run option via borgmatic command-line.
1.1.13
* #54: Fix for incorrect consistency check flags passed to Borg when all three checks ("repository",
"archives", and "extract") are specified in borgmatic configuration.
+6 -5
View File
@@ -57,7 +57,7 @@ def _make_pattern_flags(location_config, pattern_filename=None):
return tuple(
itertools.chain.from_iterable(
('--pattern-from', pattern_filename)
('--patterns-from', pattern_filename)
for pattern_filename in pattern_filenames
)
)
@@ -85,11 +85,11 @@ def _make_exclude_flags(location_config, exclude_filename=None):
def create_archive(
verbosity, repository, location_config, storage_config, local_path='borg', remote_path=None,
verbosity, dry_run, repository, location_config, storage_config, local_path='borg', remote_path=None,
):
'''
Given a vebosity flag, a local or remote repository path, a location config dict, and a storage
config dict, create a Borg archive.
Given vebosity/dry-run flags, a local or remote repository path, a location config dict, and a
storage config dict, create a Borg archive.
'''
sources = tuple(
itertools.chain.from_iterable(
@@ -122,6 +122,7 @@ def create_archive(
VERBOSITY_SOME: ('--info', '--stats',),
VERBOSITY_LOTS: ('--debug', '--list', '--stats'),
}.get(verbosity, ())
dry_run_flags = ('--dry-run',) if dry_run else ()
default_archive_name_format = '{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}'
archive_name_format = storage_config.get('archive_name_format', default_archive_name_format)
@@ -133,7 +134,7 @@ def create_archive(
),
) + sources + pattern_flags + exclude_flags + compression_flags + remote_rate_limit_flags + \
one_file_system_flags + files_cache_flags + remote_path_flags + umask_flags + \
verbosity_flags
verbosity_flags + dry_run_flags
logger.debug(' '.join(full_command))
subprocess.check_call(full_command)
+5 -4
View File
@@ -32,16 +32,17 @@ def _make_prune_flags(retention_config):
)
def prune_archives(verbosity, repository, retention_config, local_path='borg', remote_path=None):
def prune_archives(verbosity, dry_run, repository, retention_config, local_path='borg', remote_path=None):
'''
Given a verbosity flag, a local or remote repository path, a retention config dict, prune Borg
archives according the the retention policy specified in that configuration.
Given verbosity/dry-run flags, a local or remote repository path, a retention config dict, prune
Borg archives according the the retention policy specified in that configuration.
'''
remote_path_flags = ('--remote-path', remote_path) if remote_path else ()
verbosity_flags = {
VERBOSITY_SOME: ('--info', '--stats',),
VERBOSITY_LOTS: ('--debug', '--stats', '--list'),
}.get(verbosity, ())
dry_run_flags = ('--dry-run',) if dry_run else ()
full_command = (
local_path, 'prune',
@@ -50,7 +51,7 @@ def prune_archives(verbosity, repository, retention_config, local_path='borg', r
element
for pair in _make_prune_flags(retention_config)
for element in pair
) + remote_path_flags + verbosity_flags
) + remote_path_flags + verbosity_flags + dry_run_flags
logger.debug(' '.join(full_command))
subprocess.check_call(full_command)
+11 -2
View File
@@ -61,6 +61,12 @@ def parse_arguments(*arguments):
action='store_true',
help='Check archives for consistency',
)
parser.add_argument(
'-n', '--dry-run',
dest='dry_run',
action='store_true',
help='Go through the motions, but do not actually write any changes to the repository',
)
parser.add_argument(
'-v', '--verbosity',
type=int,
@@ -100,19 +106,22 @@ def run_configuration(config_filename, args): # pragma: no cover
for unexpanded_repository in location['repositories']:
repository = os.path.expanduser(unexpanded_repository)
dry_run_label = ' (dry run; not making any changes)' if args.dry_run else ''
if args.prune:
logger.info('{}: Pruning archives'.format(repository))
logger.info('{}: Pruning archives{}'.format(repository, dry_run_label))
prune.prune_archives(
args.verbosity,
args.dry_run,
repository,
retention,
local_path=local_path,
remote_path=remote_path,
)
if args.create:
logger.info('{}: Creating archive'.format(repository))
logger.info('{}: Creating archive{}'.format(repository, dry_run_label))
create.create_archive(
args.verbosity,
args.dry_run,
repository,
location,
storage,
+41 -3
View File
@@ -84,7 +84,7 @@ def test_make_pattern_flags_includes_pattern_filename_when_given():
pattern_filename='/tmp/patterns',
)
assert pattern_flags == ('--pattern-from', '/tmp/patterns')
assert pattern_flags == ('--patterns-from', '/tmp/patterns')
def test_make_pattern_flags_includes_patterns_from_filenames_when_in_config():
@@ -92,7 +92,7 @@ def test_make_pattern_flags_includes_patterns_from_filenames_when_in_config():
location_config={'patterns_from': ['patterns', 'other']},
)
assert pattern_flags == ('--pattern-from', 'patterns', '--pattern-from', 'other')
assert pattern_flags == ('--patterns-from', 'patterns', '--patterns-from', 'other')
def test_make_pattern_flags_includes_both_filenames_when_patterns_given_and_patterns_from_in_config():
@@ -101,7 +101,7 @@ def test_make_pattern_flags_includes_both_filenames_when_patterns_given_and_patt
pattern_filename='/tmp/patterns',
)
assert pattern_flags == ('--pattern-from', 'patterns', '--pattern-from', '/tmp/patterns')
assert pattern_flags == ('--patterns-from', 'patterns', '--patterns-from', '/tmp/patterns')
def test_make_pattern_flags_considers_none_patterns_from_filenames_as_empty():
@@ -190,6 +190,7 @@ def test_create_archive_calls_borg_with_parameters():
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -210,6 +211,7 @@ def test_create_archive_with_patterns_calls_borg_with_patterns():
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -230,6 +232,7 @@ def test_create_archive_with_exclude_patterns_calls_borg_with_excludes():
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -250,6 +253,7 @@ def test_create_archive_with_verbosity_some_calls_borg_with_info_parameter():
module.create_archive(
verbosity=VERBOSITY_SOME,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -269,6 +273,28 @@ def test_create_archive_with_verbosity_lots_calls_borg_with_debug_parameter():
module.create_archive(
verbosity=VERBOSITY_LOTS,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
'repositories': ['repo'],
'exclude_patterns': None,
},
storage_config={},
)
def test_create_archive_with_dry_run_calls_borg_with_dry_run_parameter():
flexmock(module).should_receive('_expand_directory').and_return(['foo']).and_return(['bar'])
flexmock(module).should_receive('_write_pattern_file').and_return(None)
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_exclude_flags').and_return(())
insert_subprocess_mock(CREATE_COMMAND + ('--dry-run',))
module.create_archive(
verbosity=None,
dry_run=True,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -288,6 +314,7 @@ def test_create_archive_with_compression_calls_borg_with_compression_parameters(
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -307,6 +334,7 @@ def test_create_archive_with_remote_rate_limit_calls_borg_with_remote_ratelimit_
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -326,6 +354,7 @@ def test_create_archive_with_one_file_system_calls_borg_with_one_file_system_par
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -346,6 +375,7 @@ def test_create_archive_with_files_cache_calls_borg_with_files_cache_parameters(
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -366,6 +396,7 @@ def test_create_archive_with_local_path_calls_borg_via_local_path():
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -386,6 +417,7 @@ def test_create_archive_with_remote_path_calls_borg_with_remote_path_parameters(
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -406,6 +438,7 @@ def test_create_archive_with_umask_calls_borg_with_umask_parameters():
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -426,6 +459,7 @@ def test_create_archive_with_source_directories_glob_expands():
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo*'],
@@ -446,6 +480,7 @@ def test_create_archive_with_non_matching_source_directories_glob_passes_through
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo*'],
@@ -465,6 +500,7 @@ def test_create_archive_with_glob_calls_borg_with_expanded_directories():
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo*'],
@@ -484,6 +520,7 @@ def test_create_archive_with_archive_name_format_calls_borg_with_archive_name():
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
@@ -505,6 +542,7 @@ def test_create_archive_with_archive_name_format_accepts_borg_placeholders():
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
+20
View File
@@ -64,6 +64,7 @@ def test_prune_archives_calls_borg_with_parameters():
module.prune_archives(
verbosity=None,
dry_run=False,
repository='repo',
retention_config=retention_config,
)
@@ -79,6 +80,7 @@ def test_prune_archives_with_verbosity_some_calls_borg_with_info_parameter():
module.prune_archives(
repository='repo',
verbosity=VERBOSITY_SOME,
dry_run=False,
retention_config=retention_config,
)
@@ -93,6 +95,22 @@ def test_prune_archives_with_verbosity_lots_calls_borg_with_debug_parameter():
module.prune_archives(
repository='repo',
verbosity=VERBOSITY_LOTS,
dry_run=False,
retention_config=retention_config,
)
def test_prune_archives_with_dry_run_calls_borg_with_dry_run_parameter():
retention_config = flexmock()
flexmock(module).should_receive('_make_prune_flags').with_args(retention_config).and_return(
BASE_PRUNE_FLAGS,
)
insert_subprocess_mock(PRUNE_COMMAND + ('--dry-run',))
module.prune_archives(
repository='repo',
verbosity=None,
dry_run=True,
retention_config=retention_config,
)
@@ -106,6 +124,7 @@ def test_prune_archives_with_local_path_calls_borg_via_local_path():
module.prune_archives(
verbosity=None,
dry_run=False,
repository='repo',
retention_config=retention_config,
local_path='borg1',
@@ -121,6 +140,7 @@ def test_prune_archives_with_remote_path_calls_borg_with_remote_path_parameters(
module.prune_archives(
verbosity=None,
dry_run=False,
repository='repo',
retention_config=retention_config,
remote_path='borg1',
+1 -1
View File
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages
VERSION = '1.1.13'
VERSION = '1.1.14'
setup(