Support for several more borgmatic/borg info command-line flags (#193).

This commit is contained in:
Dan Helfman 2019-06-25 10:46:55 -07:00
parent c644270599
commit 86dbc00cbe
6 changed files with 134 additions and 35 deletions

6
NEWS
View File

@ -1,6 +1,8 @@
1.3.11.dev0
* #193: Pass through several "borg list" flags like --short, --format, --sort-by, --first, --last,
etc. via borgmatic list command-line flags.
* #193: Pass through several "borg list" and "borg info" flags like --short, --format, --sort-by,
--first, --last, etc. via borgmatic command-line flags.
* Add borgmatic info --repository and --archive command-line flags to display info for individual
repositories or archives.
1.3.10
* #198: Fix for Borg create error output not showing up at borgmatic verbosity level zero.

View File

@ -1,26 +1,44 @@
import logging
from borgmatic.borg.flags import make_flags, make_flags_from_arguments
from borgmatic.execute import execute_command
logger = logging.getLogger(__name__)
def display_archives_info(
repository, storage_config, local_path='borg', remote_path=None, json=False
repository, storage_config, info_arguments, local_path='borg', remote_path=None
):
'''
Given a local or remote repository path, and a storage config dict, display summary information
for Borg archives in the repository or return JSON summary information.
Given a local or remote repository path, a storage config dict, and the arguments to the info
action, display summary information for Borg archives in the repository or return JSON summary
information.
'''
lock_wait = storage_config.get('lock_wait', None)
full_command = (
(local_path, 'info', repository)
+ (('--remote-path', remote_path) if remote_path else ())
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
+ (('--info',) if logger.getEffectiveLevel() == logging.INFO and not json else ())
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) and not json else ())
+ (('--json',) if json else ())
(
local_path,
'info',
'::'.join((repository, info_arguments.archive))
if info_arguments.archive
else repository,
)
+ (
('--info',)
if logger.getEffectiveLevel() == logging.INFO and not info_arguments.json
else ()
)
+ (
('--debug', '--show-rc')
if logger.isEnabledFor(logging.DEBUG) and not info_arguments.json
else ()
)
+ make_flags('remote-path', remote_path)
+ make_flags('lock-wait', lock_wait)
+ make_flags_from_arguments(info_arguments, excludes=('repository', 'archive'))
)
return execute_command(full_command, output_log_level=None if json else logging.WARNING)
return execute_command(
full_command, output_log_level=None if info_arguments.json else logging.WARNING
)

View File

@ -224,7 +224,7 @@ def parse_arguments(*unparsed_arguments):
extract_group = extract_parser.add_argument_group('extract arguments')
extract_group.add_argument(
'--repository',
help='Path of repository to use, defaults to the configured repository if there is only one',
help='Path of repository to extract, defaults to the configured repository if there is only one',
)
extract_group.add_argument('--archive', help='Name of archive to operate on', required=True)
extract_group.add_argument(
@ -254,9 +254,9 @@ def parse_arguments(*unparsed_arguments):
list_group = list_parser.add_argument_group('list arguments')
list_group.add_argument(
'--repository',
help='Path of repository to use, defaults to the configured repository if there is only one',
help='Path of repository to list, defaults to the configured repository if there is only one',
)
list_group.add_argument('--archive', help='Name of archive to operate on')
list_group.add_argument('--archive', help='Name of archive to list')
list_group.add_argument(
'--short', default=False, action='store_true', help='Output only archive or path names'
)
@ -301,9 +301,34 @@ def parse_arguments(*unparsed_arguments):
add_help=False,
)
info_group = info_parser.add_argument_group('info arguments')
info_group.add_argument(
'--repository',
help='Path of repository to show info for, defaults to the configured repository if there is only one',
)
info_group.add_argument('--archive', help='Name of archive to show info for')
info_group.add_argument(
'--json', dest='json', default=False, action='store_true', help='Output results as JSON'
)
info_group.add_argument(
'-P', '--prefix', help='Only show info for archive names starting with this prefix'
)
info_group.add_argument(
'-a',
'--glob-archives',
metavar='GLOB',
help='Only show info for archive names matching this glob',
)
info_group.add_argument(
'--sort-by', metavar='KEYS', help='Comma-separated list of sorting keys'
)
info_group.add_argument(
'--first',
metavar='N',
help='Show info for first N archives after other filters are applied',
)
info_group.add_argument(
'--last', metavar='N', help='Show info for first N archives after other filters are applied'
)
info_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
arguments = parse_subparser_arguments(unparsed_arguments, top_level_parser, subparsers)

View File

@ -178,16 +178,17 @@ def run_actions(
if json_output:
yield json.loads(json_output)
if 'info' in arguments:
logger.info('{}: Displaying summary info for archives'.format(repository))
json_output = borg_info.display_archives_info(
repository,
storage,
local_path=local_path,
remote_path=remote_path,
json=arguments['info'].json,
)
if json_output:
yield json.loads(json_output)
if arguments['info'].repository is None or repository == arguments['info'].repository:
logger.info('{}: Displaying summary info for archives'.format(repository))
json_output = borg_info.display_archives_info(
repository,
storage,
info_arguments=arguments['info'],
local_path=local_path,
remote_path=remote_path,
)
if json_output:
yield json.loads(json_output)
def load_configurations(config_filenames):

View File

@ -30,7 +30,9 @@ def test_make_flags_from_arguments_flattens_multiple_arguments():
)
arguments = flexmock(foo='bar', baz='quux')
assert module.make_flags_from_arguments(arguments) == ('foo', 'bar', 'baz', 'quux')
assert sorted(module.make_flags_from_arguments(arguments)) == sorted(
('foo', 'bar', 'baz', 'quux')
)
def test_make_flags_from_arguments_excludes_underscored_argument_names():

View File

@ -1,5 +1,6 @@
import logging
import pytest
from flexmock import flexmock
from borgmatic.borg import info as module
@ -14,7 +15,9 @@ def test_display_archives_info_calls_borg_with_parameters():
INFO_COMMAND, output_log_level=logging.WARNING
)
module.display_archives_info(repository='repo', storage_config={})
module.display_archives_info(
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=False)
)
def test_display_archives_info_with_log_info_calls_borg_with_info_parameter():
@ -22,7 +25,9 @@ def test_display_archives_info_with_log_info_calls_borg_with_info_parameter():
INFO_COMMAND + ('--info',), output_log_level=logging.WARNING
)
insert_logging_mock(logging.INFO)
module.display_archives_info(repository='repo', storage_config={})
module.display_archives_info(
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=False)
)
def test_display_archives_info_with_log_info_and_json_suppresses_most_borg_output():
@ -31,7 +36,9 @@ def test_display_archives_info_with_log_info_and_json_suppresses_most_borg_outpu
).and_return('[]')
insert_logging_mock(logging.INFO)
json_output = module.display_archives_info(repository='repo', storage_config={}, json=True)
json_output = module.display_archives_info(
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=True)
)
assert json_output == '[]'
@ -42,7 +49,9 @@ def test_display_archives_info_with_log_debug_calls_borg_with_debug_parameter():
)
insert_logging_mock(logging.DEBUG)
module.display_archives_info(repository='repo', storage_config={})
module.display_archives_info(
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=False)
)
def test_display_archives_info_with_log_debug_and_json_suppresses_most_borg_output():
@ -51,7 +60,9 @@ def test_display_archives_info_with_log_debug_and_json_suppresses_most_borg_outp
).and_return('[]')
insert_logging_mock(logging.DEBUG)
json_output = module.display_archives_info(repository='repo', storage_config={}, json=True)
json_output = module.display_archives_info(
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=True)
)
assert json_output == '[]'
@ -61,17 +72,34 @@ def test_display_archives_info_with_json_calls_borg_with_json_parameter():
INFO_COMMAND + ('--json',), output_log_level=None
).and_return('[]')
json_output = module.display_archives_info(repository='repo', storage_config={}, json=True)
json_output = module.display_archives_info(
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=True)
)
assert json_output == '[]'
def test_display_archives_info_with_archive_calls_borg_with_archive_parameter():
flexmock(module).should_receive('execute_command').with_args(
('borg', 'info', 'repo::archive'), output_log_level=logging.WARNING
)
module.display_archives_info(
repository='repo', storage_config={}, info_arguments=flexmock(archive='archive', json=False)
)
def test_display_archives_info_with_local_path_calls_borg_via_local_path():
flexmock(module).should_receive('execute_command').with_args(
('borg1',) + INFO_COMMAND[1:], output_log_level=logging.WARNING
)
module.display_archives_info(repository='repo', storage_config={}, local_path='borg1')
module.display_archives_info(
repository='repo',
storage_config={},
info_arguments=flexmock(archive=None, json=False),
local_path='borg1',
)
def test_display_archives_info_with_remote_path_calls_borg_with_remote_path_parameters():
@ -79,7 +107,12 @@ def test_display_archives_info_with_remote_path_calls_borg_with_remote_path_para
INFO_COMMAND + ('--remote-path', 'borg1'), output_log_level=logging.WARNING
)
module.display_archives_info(repository='repo', storage_config={}, remote_path='borg1')
module.display_archives_info(
repository='repo',
storage_config={},
info_arguments=flexmock(archive=None, json=False),
remote_path='borg1',
)
def test_display_archives_info_with_lock_wait_calls_borg_with_lock_wait_parameters():
@ -88,4 +121,22 @@ def test_display_archives_info_with_lock_wait_calls_borg_with_lock_wait_paramete
INFO_COMMAND + ('--lock-wait', '5'), output_log_level=logging.WARNING
)
module.display_archives_info(repository='repo', storage_config=storage_config)
module.display_archives_info(
repository='repo',
storage_config=storage_config,
info_arguments=flexmock(archive=None, json=False),
)
@pytest.mark.parametrize('argument_name', ('prefix', 'glob_archives', 'sort_by', 'first', 'last'))
def test_display_archives_info_passes_through_arguments_to_borg(argument_name):
flexmock(module).should_receive('execute_command').with_args(
INFO_COMMAND + ('--' + argument_name.replace('_', '-'), 'value'),
output_log_level=logging.WARNING,
)
module.display_archives_info(
repository='repo',
storage_config={},
info_arguments=flexmock(archive=None, json=False, **{argument_name: 'value'}),
)