Add info command
This commit is contained in:
46
src/locutus/info.py
Normal file
46
src/locutus/info.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from locutus.config import LocutusConfig
|
||||
|
||||
|
||||
def run_info(args: argparse.Namespace) -> int:
|
||||
"""Show current config/profile summary and repository info."""
|
||||
cfg = LocutusConfig(args.config, args.profile)
|
||||
print(f'Config: {cfg.toml_path}')
|
||||
print(f'Profile: {cfg.rc_path}')
|
||||
|
||||
repo = cfg.get_repo()
|
||||
if repo:
|
||||
print(f'Repo: {repo}')
|
||||
else:
|
||||
print('Repo: (not set)')
|
||||
passphrase = cfg.get_passphrase()
|
||||
if passphrase:
|
||||
print('Passphrase: set')
|
||||
else:
|
||||
print('Passphrase: (not set)')
|
||||
|
||||
print('\nIncludes:')
|
||||
for inc in cfg.includes:
|
||||
print(f' {inc}')
|
||||
|
||||
print('\nExcludes:')
|
||||
for exc in cfg.excludes:
|
||||
print(f' {exc}')
|
||||
|
||||
if cfg.prune:
|
||||
prune_str = ', '.join(f'{k}={v}' for k, v in cfg.prune.items())
|
||||
print(f'\nPrune: {prune_str}')
|
||||
|
||||
print('\n[borg info output below]\n')
|
||||
if repo:
|
||||
env = {**os.environ, **cfg.env}
|
||||
try:
|
||||
subprocess.run(['borg', 'info', repo], env=env, check=True)
|
||||
except Exception as e:
|
||||
print(f'borg info failed: {e}', file=sys.stderr)
|
||||
|
||||
return 0
|
||||
@@ -73,6 +73,11 @@ def parse_args() -> tuple[argparse.Namespace, argparse.ArgumentParser]:
|
||||
)
|
||||
restore_parser.add_argument('targetdir', help='Directory to restore into')
|
||||
|
||||
# info
|
||||
_info_parser = subparsers.add_parser(
|
||||
'info', help='Show current config and repository info'
|
||||
)
|
||||
|
||||
return parser.parse_args(), parser
|
||||
|
||||
|
||||
@@ -104,6 +109,10 @@ def main() -> int:
|
||||
from .restore import run_restore
|
||||
|
||||
return run_restore(args)
|
||||
case 'info':
|
||||
from .info import run_info
|
||||
|
||||
return run_info(args)
|
||||
case _:
|
||||
parser.print_help()
|
||||
return 1
|
||||
|
||||
100
test/test_info.py
Normal file
100
test/test_info.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import argparse
|
||||
from unittest import mock
|
||||
import subprocess
|
||||
import pytest
|
||||
|
||||
from locutus.info import run_info
|
||||
|
||||
|
||||
def make_args(config, profile):
|
||||
args = argparse.Namespace()
|
||||
args.config = config
|
||||
args.profile = profile
|
||||
return args
|
||||
|
||||
|
||||
@mock.patch('locutus.info.LocutusConfig')
|
||||
@mock.patch('subprocess.run')
|
||||
def test_info_basic_output(mock_run, mock_config, capsys):
|
||||
mock_config.return_value.toml_path = '/tmp/test.toml'
|
||||
mock_config.return_value.rc_path = '/tmp/test.rc'
|
||||
mock_config.return_value.get_repo.return_value = '/repo'
|
||||
mock_config.return_value.get_passphrase.return_value = 'hunter2'
|
||||
mock_config.return_value.includes = ['/etc', '/home']
|
||||
mock_config.return_value.excludes = ['*.cache']
|
||||
mock_config.return_value.prune = {'keep_last': 3, 'keep_daily': 1}
|
||||
|
||||
args = make_args('/tmp/test.toml', '/tmp/test.rc')
|
||||
mock_run.return_value.returncode = 0
|
||||
|
||||
run_info(args)
|
||||
out = capsys.readouterr().out
|
||||
|
||||
assert 'Config: /tmp/test.toml' in out
|
||||
assert 'Profile: /tmp/test.rc' in out
|
||||
assert 'Repo: /repo' in out
|
||||
assert 'Passphrase: set' in out
|
||||
assert 'Includes:' in out and '/etc' in out and '/home' in out
|
||||
assert 'Excludes:' in out and '*.cache' in out
|
||||
assert 'Prune: keep_last=3, keep_daily=1' in out
|
||||
assert '[borg info output below]' in out
|
||||
mock_run.assert_called_with(
|
||||
['borg', 'info', '/repo'], env=mock.ANY, check=True
|
||||
)
|
||||
|
||||
|
||||
@mock.patch('locutus.info.LocutusConfig')
|
||||
@mock.patch('subprocess.run')
|
||||
def test_info_no_repo(mock_run, mock_config, capsys):
|
||||
mock_config.return_value.toml_path = '/tmp/test.toml'
|
||||
mock_config.return_value.rc_path = '/tmp/test.rc'
|
||||
mock_config.return_value.get_repo.return_value = None
|
||||
mock_config.return_value.get_passphrase.return_value = None
|
||||
mock_config.return_value.includes = []
|
||||
mock_config.return_value.excludes = []
|
||||
mock_config.return_value.prune = {}
|
||||
|
||||
args = make_args('/tmp/test.toml', '/tmp/test.rc')
|
||||
run_info(args)
|
||||
out = capsys.readouterr().out
|
||||
assert 'Repo: (not set)' in out
|
||||
assert 'Passphrase: (not set)' in out
|
||||
assert '[borg info output below]' in out
|
||||
mock_run.assert_not_called()
|
||||
|
||||
|
||||
@mock.patch('locutus.info.LocutusConfig')
|
||||
@mock.patch(
|
||||
'subprocess.run',
|
||||
side_effect=subprocess.CalledProcessError(1, ['borg', 'info']),
|
||||
)
|
||||
def test_info_borg_info_fails(mock_run, mock_config, capsys):
|
||||
mock_config.return_value.toml_path = '/tmp/test.toml'
|
||||
mock_config.return_value.rc_path = '/tmp/test.rc'
|
||||
mock_config.return_value.get_repo.return_value = '/repo'
|
||||
mock_config.return_value.get_passphrase.return_value = 'hunter2'
|
||||
mock_config.return_value.includes = []
|
||||
mock_config.return_value.excludes = []
|
||||
mock_config.return_value.prune = {}
|
||||
|
||||
args = make_args('/tmp/test.toml', '/tmp/test.rc')
|
||||
run_info(args)
|
||||
err = capsys.readouterr().err
|
||||
assert 'borg info failed:' in err
|
||||
|
||||
|
||||
@mock.patch('locutus.info.LocutusConfig')
|
||||
@mock.patch('subprocess.run', side_effect=Exception('fail'))
|
||||
def test_info_borg_info_generic_exception(mock_run, mock_config, capsys):
|
||||
mock_config.return_value.toml_path = '/tmp/test.toml'
|
||||
mock_config.return_value.rc_path = '/tmp/test.rc'
|
||||
mock_config.return_value.get_repo.return_value = '/repo'
|
||||
mock_config.return_value.get_passphrase.return_value = 'hunter2'
|
||||
mock_config.return_value.includes = []
|
||||
mock_config.return_value.excludes = []
|
||||
mock_config.return_value.prune = {}
|
||||
|
||||
args = make_args('/tmp/test.toml', '/tmp/test.rc')
|
||||
run_info(args)
|
||||
err = capsys.readouterr().err
|
||||
assert 'borg info failed: fail' in err
|
||||
Reference in New Issue
Block a user