Add rinfo action for Borg 2 support (#557).

This commit is contained in:
Dan Helfman 2022-08-12 23:06:56 -07:00
parent 647ecdac29
commit c7176bd00a
4 changed files with 83 additions and 9 deletions

View file

@ -15,6 +15,7 @@ SUBPARSER_ALIASES = {
'umount': ['--umount', '-u'], 'umount': ['--umount', '-u'],
'restore': ['--restore', '-r'], 'restore': ['--restore', '-r'],
'list': ['--list', '-l'], 'list': ['--list', '-l'],
'rinfo': [],
'info': ['--info', '-i'], 'info': ['--info', '-i'],
'borg': [], 'borg': [],
} }
@ -613,17 +614,34 @@ def make_parsers():
) )
list_group.add_argument('-h', '--help', action='help', help='Show this help message and exit') list_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
rinfo_parser = subparsers.add_parser(
'rinfo',
aliases=SUBPARSER_ALIASES['rinfo'],
help='Show repository summary information such as disk space used',
description='Show repository summary information such as disk space used',
add_help=False,
)
rinfo_group = rinfo_parser.add_argument_group('rinfo arguments')
rinfo_group.add_argument(
'--repository',
help='Path of repository to show info for, defaults to the configured repository if there is only one',
)
rinfo_group.add_argument(
'--json', dest='json', default=False, action='store_true', help='Output results as JSON'
)
rinfo_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
info_parser = subparsers.add_parser( info_parser = subparsers.add_parser(
'info', 'info',
aliases=SUBPARSER_ALIASES['info'], aliases=SUBPARSER_ALIASES['info'],
help='Display summary information on archives', help='Show archive summary information such as disk space used',
description='Display summary information on archives', description='Show archive summary information such as disk space used',
add_help=False, add_help=False,
) )
info_group = info_parser.add_argument_group('info arguments') info_group = info_parser.add_argument_group('info arguments')
info_group.add_argument( info_group.add_argument(
'--repository', '--repository',
help='Path of repository to show info for, defaults to the configured repository if there is only one', help='Path of repository containing archive 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 (or "latest")') info_group.add_argument('--archive', help='Name of archive to show info for (or "latest")')
info_group.add_argument( info_group.add_argument(
@ -697,12 +715,11 @@ def parse_arguments(*unparsed_arguments):
raise ValueError('The rcreate/init action cannot be used with the --dry-run flag') raise ValueError('The rcreate/init action cannot be used with the --dry-run flag')
if ( if (
'list' in arguments ('list' in arguments and 'rinfo' in arguments and arguments['list'].json)
and 'info' in arguments or ('list' in arguments and 'info' in arguments and arguments['list'].json)
and arguments['list'].json or ('rinfo' in arguments and 'info' in arguments and arguments['rinfo'].json)
and arguments['info'].json
): ):
raise ValueError('With the --json flag, list and info actions cannot be used together') raise ValueError('With the --json flag, multiple actions cannot be used together')
if 'info' in arguments and arguments['info'].archive and arguments['info'].glob_archives: if 'info' in arguments and arguments['info'].archive and arguments['info'].glob_archives:
raise ValueError( raise ValueError(

View file

@ -24,6 +24,7 @@ from borgmatic.borg import list as borg_list
from borgmatic.borg import mount as borg_mount from borgmatic.borg import mount as borg_mount
from borgmatic.borg import prune as borg_prune from borgmatic.borg import prune as borg_prune
from borgmatic.borg import rcreate as borg_rcreate from borgmatic.borg import rcreate as borg_rcreate
from borgmatic.borg import rinfo as borg_rinfo
from borgmatic.borg import umount as borg_umount from borgmatic.borg import umount as borg_umount
from borgmatic.borg import version as borg_version from borgmatic.borg import version as borg_version
from borgmatic.commands.arguments import parse_arguments from borgmatic.commands.arguments import parse_arguments
@ -613,13 +614,30 @@ def run_actions(
) )
if json_output: # pragma: nocover if json_output: # pragma: nocover
yield json.loads(json_output) yield json.loads(json_output)
if 'rinfo' in arguments:
if arguments['rinfo'].repository is None or validate.repositories_match(
repository, arguments['rinfo'].repository
):
rinfo_arguments = copy.copy(arguments['rinfo'])
if not rinfo_arguments.json: # pragma: nocover
logger.warning('{}: Displaying repository summary information'.format(repository))
json_output = borg_rinfo.display_repository_info(
repository,
storage,
local_borg_version,
rinfo_arguments=rinfo_arguments,
local_path=local_path,
remote_path=remote_path,
)
if json_output: # pragma: nocover
yield json.loads(json_output)
if 'info' in arguments: if 'info' in arguments:
if arguments['info'].repository is None or validate.repositories_match( if arguments['info'].repository is None or validate.repositories_match(
repository, arguments['info'].repository repository, arguments['info'].repository
): ):
info_arguments = copy.copy(arguments['info']) info_arguments = copy.copy(arguments['info'])
if not info_arguments.json: # pragma: nocover if not info_arguments.json: # pragma: nocover
logger.warning('{}: Displaying summary info for archives'.format(repository)) logger.warning('{}: Displaying archive summary information'.format(repository))
info_arguments.archive = borg_list.resolve_archive_name( info_arguments.archive = borg_list.resolve_archive_name(
repository, info_arguments.archive, storage, local_path, remote_path repository, info_arguments.archive, storage, local_path, remote_path
) )

View file

@ -496,6 +496,20 @@ def test_parse_arguments_disallows_json_with_both_list_and_info():
module.parse_arguments('list', 'info', '--json') module.parse_arguments('list', 'info', '--json')
def test_parse_arguments_disallows_json_with_both_list_and_rinfo():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
with pytest.raises(ValueError):
module.parse_arguments('list', 'rinfo', '--json')
def test_parse_arguments_disallows_json_with_both_rinfo_and_info():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
with pytest.raises(ValueError):
module.parse_arguments('rinfo', 'info', '--json')
def test_parse_arguments_disallows_info_with_both_archive_and_glob_archives(): def test_parse_arguments_disallows_info_with_both_archive_and_glob_archives():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default']) flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

View file

@ -597,6 +597,31 @@ def test_run_actions_does_not_raise_for_list_action():
) )
def test_run_actions_does_not_raise_for_rinfo_action():
flexmock(module.validate).should_receive('repositories_match').and_return(True)
flexmock(module.borg_rinfo).should_receive('display_repository_info')
arguments = {
'global': flexmock(monitoring_verbosity=1, dry_run=False),
'rinfo': flexmock(repository=flexmock(), json=flexmock()),
}
list(
module.run_actions(
arguments=arguments,
config_filename='test.yaml',
location={'repositories': ['repo']},
storage={},
retention={},
consistency={},
hooks={},
local_path=None,
remote_path=None,
local_borg_version=None,
repository_path='repo',
)
)
def test_run_actions_does_not_raise_for_info_action(): def test_run_actions_does_not_raise_for_info_action():
flexmock(module.validate).should_receive('repositories_match').and_return(True) flexmock(module.validate).should_receive('repositories_match').and_return(True)
flexmock(module.borg_list).should_receive('resolve_archive_name').and_return(flexmock()) flexmock(module.borg_list).should_receive('resolve_archive_name').and_return(flexmock())