From 0e938209afbf25748cf95bd27b32ad2814f8d77b Mon Sep 17 00:00:00 2001 From: Kevin Morris Date: Sat, 27 Nov 2021 22:34:15 -0800 Subject: [PATCH] feat(aurweb-config): add unset action and simplify Signed-off-by: Kevin Morris --- aurweb/config.py | 7 ++++- aurweb/scripts/config.py | 38 ++++++++++++++++---------- test/test_config.py | 59 +++++++++++++++++++++++++++++++++------- 3 files changed, 78 insertions(+), 26 deletions(-) diff --git a/aurweb/config.py b/aurweb/config.py index 0d0cf676..86f8ddf7 100644 --- a/aurweb/config.py +++ b/aurweb/config.py @@ -56,8 +56,13 @@ def get_section(section): return _get_parser()[section] -def replace_key(section: str, option: str, value: Any) -> Any: +def unset_option(section: str, option: str) -> None: + _get_parser().remove_option(section, option) + + +def set_option(section: str, option: str, value: Any) -> None: _get_parser().set(section, option, value) + return value def save() -> None: diff --git a/aurweb/scripts/config.py b/aurweb/scripts/config.py index dd7bcf5f..e7c91dd1 100644 --- a/aurweb/scripts/config.py +++ b/aurweb/scripts/config.py @@ -11,35 +11,43 @@ import sys import aurweb.config -def action_set(args): +def do_action(func, *args, save: bool = True): # If AUR_CONFIG_IMMUTABLE is defined, skip out on config setting. - if os.environ.get("AUR_CONFIG_IMMUTABLE", 0): + if int(os.environ.get("AUR_CONFIG_IMMUTABLE", 0)): return + value = None + try: + value = func(*args) + if save: + aurweb.config.save() + except configparser.NoSectionError: + print("error: no section found", file=sys.stderr) + except configparser.NoOptionError: + print("error: no option found", file=sys.stderr) + + return value + + +def action_set(args): if not args.value: print("error: no value provided", file=sys.stderr) return + do_action(aurweb.config.set_option, args.section, args.option, args.value) - try: - aurweb.config.replace_key(args.section, args.option, args.value) - aurweb.config.save() - except configparser.NoSectionError: - print("error: no section found", file=sys.stderr) + +def action_unset(args): + do_action(aurweb.config.unset_option, args.section, args.option) def action_get(args): - try: - value = aurweb.config.get(args.section, args.option) - print(value) - except (configparser.NoSectionError): - print("error: no section found", file=sys.stderr) - except (configparser.NoOptionError): - print("error: no option found", file=sys.stderr) + val = do_action(aurweb.config.get, args.section, args.option, save=False) + print(val) def parse_args(): fmt_cls = argparse.RawDescriptionHelpFormatter - actions = ["get", "set"] + actions = ["get", "set", "unset"] parser = argparse.ArgumentParser( description="aurweb configuration tool", formatter_class=lambda prog: fmt_cls(prog=prog, max_help_position=80)) diff --git a/test/test_config.py b/test/test_config.py index 7e9d24b5..b78f477c 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -5,6 +5,8 @@ import re from unittest import mock +import py + from aurweb import config from aurweb.scripts.config import main @@ -77,32 +79,69 @@ def test_config_main_get_unknown_option(get: str): def test_config_main_set(save: None): data = None - def mock_replace_key(section: str, option: str, value: str) -> None: + def set_option(section: str, option: str, value: str) -> None: nonlocal data data = value args = ["aurweb-config", "set", "options", "salt_rounds", "666"] with mock.patch("sys.argv", args): - with mock.patch("aurweb.config.replace_key", - side_effect=mock_replace_key): + with mock.patch("aurweb.config.set_option", side_effect=set_option): main() expected = "666" assert data == expected +def test_config_main_set_real(tmpdir: py.path.local): + """ + Test a real set_option path. + """ + + # Copy AUR_CONFIG to {tmpdir}/aur.config. + aur_config = os.environ.get("AUR_CONFIG") + tmp_aur_config = os.path.join(str(tmpdir), "aur.config") + with open(aur_config) as f: + with open(tmp_aur_config, "w") as o: + o.write(f.read()) + + # Force reset the parser. This should NOT be done publicly. + config._parser = None + + value = 666 + args = ["aurweb-config", "set", "options", "fake-key", str(value)] + with mock.patch.dict("os.environ", {"AUR_CONFIG": tmp_aur_config}): + with mock.patch("sys.argv", args): + # Run aurweb.config.main(). + main() + + # Update the config; fake-key should be set. + config.rehash() + assert config.getint("options", "fake-key") == 666 + + # Restore config back to normal. + args = ["aurweb-config", "unset", "options", "fake-key"] + with mock.patch("sys.argv", args): + main() + + # Return the config back to normal. + config.rehash() + + # fake-key should no longer exist. + assert config.getint("options", "fake-key") is None + + def test_config_main_set_immutable(): data = None - def mock_replace_key(section: str, option: str, value: str) -> None: + def mock_set_option(section: str, option: str, value: str) -> None: nonlocal data data = value args = ["aurweb-config", "set", "options", "salt_rounds", "666"] with mock.patch.dict(os.environ, {"AUR_CONFIG_IMMUTABLE": "1"}): with mock.patch("sys.argv", args): - with mock.patch("aurweb.config.replace_key", - side_effect=mock_replace_key): + with mock.patch("aurweb.config.set_option", + side_effect=mock_set_option): main() expected = None @@ -121,18 +160,18 @@ def test_config_main_set_invalid_value(): assert stderr.getvalue().strip() == expected -@mock.patch("aurweb.config.save", side_effect=noop) +@ mock.patch("aurweb.config.save", side_effect=noop) def test_config_main_set_unknown_section(save: None): stderr = io.StringIO() - def mock_replace_key(section: str, option: str, value: str) -> None: + def mock_set_option(section: str, option: str, value: str) -> None: raise configparser.NoSectionError(section=section) args = ["aurweb-config", "set", "options", "salt_rounds", "666"] with mock.patch("sys.argv", args): with mock.patch("sys.stderr", stderr): - with mock.patch("aurweb.config.replace_key", - side_effect=mock_replace_key): + with mock.patch("aurweb.config.set_option", + side_effect=mock_set_option): main() assert stderr.getvalue().strip() == "error: no section found"