mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
Merge branch 'pu-config' into pu
This commit is contained in:
commit
a87973e0c7
4 changed files with 199 additions and 0 deletions
|
@ -1,6 +1,8 @@
|
||||||
import configparser
|
import configparser
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
# Publicly visible version of aurweb. This is used to display
|
# Publicly visible version of aurweb. This is used to display
|
||||||
# aurweb versioning in the footer and must be maintained.
|
# aurweb versioning in the footer and must be maintained.
|
||||||
# Todo: Make this dynamic/automated.
|
# Todo: Make this dynamic/automated.
|
||||||
|
@ -52,3 +54,13 @@ def getint(section, option, fallback=None):
|
||||||
def get_section(section):
|
def get_section(section):
|
||||||
if section in _get_parser().sections():
|
if section in _get_parser().sections():
|
||||||
return _get_parser()[section]
|
return _get_parser()[section]
|
||||||
|
|
||||||
|
|
||||||
|
def replace_key(section: str, option: str, value: Any) -> Any:
|
||||||
|
_get_parser().set(section, option, value)
|
||||||
|
|
||||||
|
|
||||||
|
def save() -> None:
|
||||||
|
aur_config = os.environ.get("AUR_CONFIG", "/etc/aurweb/config")
|
||||||
|
with open(aur_config, "w") as fp:
|
||||||
|
_get_parser().write(fp)
|
||||||
|
|
61
aurweb/scripts/config.py
Normal file
61
aurweb/scripts/config.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
"""
|
||||||
|
Perform an action on the aurweb config.
|
||||||
|
|
||||||
|
When AUR_CONFIG_IMMUTABLE is set, the `set` action is noop.
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import configparser
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import aurweb.config
|
||||||
|
|
||||||
|
|
||||||
|
def action_set(args):
|
||||||
|
# If AUR_CONFIG_IMMUTABLE is defined, skip out on config setting.
|
||||||
|
if os.environ.get("AUR_CONFIG_IMMUTABLE", 0):
|
||||||
|
return
|
||||||
|
|
||||||
|
if not args.value:
|
||||||
|
print("error: no value provided", file=sys.stderr)
|
||||||
|
return
|
||||||
|
|
||||||
|
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_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)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
fmt_cls = argparse.RawDescriptionHelpFormatter
|
||||||
|
actions = ["get", "set"]
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="aurweb configuration tool",
|
||||||
|
formatter_class=lambda prog: fmt_cls(prog=prog, max_help_position=80))
|
||||||
|
parser.add_argument("action", choices=actions, help="script action")
|
||||||
|
parser.add_argument("section", help="config section")
|
||||||
|
parser.add_argument("option", help="config option")
|
||||||
|
parser.add_argument("value", nargs="?", default=0,
|
||||||
|
help="config option value")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parse_args()
|
||||||
|
action = getattr(sys.modules[__name__], f"action_{args.action}")
|
||||||
|
return action(args)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -108,3 +108,4 @@ aurweb-popupdate = "aurweb.scripts.popupdate:main"
|
||||||
aurweb-rendercomment = "aurweb.scripts.rendercomment:main"
|
aurweb-rendercomment = "aurweb.scripts.rendercomment:main"
|
||||||
aurweb-tuvotereminder = "aurweb.scripts.tuvotereminder:main"
|
aurweb-tuvotereminder = "aurweb.scripts.tuvotereminder:main"
|
||||||
aurweb-usermaint = "aurweb.scripts.usermaint:main"
|
aurweb-usermaint = "aurweb.scripts.usermaint:main"
|
||||||
|
aurweb-config = "aurweb.scripts.config:main"
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
|
import configparser
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from aurweb import config
|
from aurweb import config
|
||||||
|
from aurweb.scripts.config import main
|
||||||
|
|
||||||
|
|
||||||
|
def noop(*args, **kwargs) -> None:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
def test_get():
|
def test_get():
|
||||||
|
@ -11,3 +23,116 @@ def test_getboolean():
|
||||||
|
|
||||||
def test_getint():
|
def test_getint():
|
||||||
assert config.getint("options", "disable_http_login") == 0
|
assert config.getint("options", "disable_http_login") == 0
|
||||||
|
|
||||||
|
|
||||||
|
def mock_config_get():
|
||||||
|
config_get = config.get
|
||||||
|
|
||||||
|
def _mock_config_get(section: str, option: str):
|
||||||
|
if section == "options":
|
||||||
|
if option == "salt_rounds":
|
||||||
|
return "666"
|
||||||
|
return config_get(section, option)
|
||||||
|
return _mock_config_get
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch("aurweb.config.get", side_effect=mock_config_get())
|
||||||
|
def test_config_main_get(get: str):
|
||||||
|
stdout = io.StringIO()
|
||||||
|
args = ["aurweb-config", "get", "options", "salt_rounds"]
|
||||||
|
with mock.patch("sys.argv", args):
|
||||||
|
with mock.patch("sys.stdout", stdout):
|
||||||
|
main()
|
||||||
|
|
||||||
|
expected = "666"
|
||||||
|
assert stdout.getvalue().strip() == expected
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch("aurweb.config.get", side_effect=mock_config_get())
|
||||||
|
def test_config_main_get_unknown_section(get: str):
|
||||||
|
stderr = io.StringIO()
|
||||||
|
args = ["aurweb-config", "get", "fakeblahblah", "salt_rounds"]
|
||||||
|
with mock.patch("sys.argv", args):
|
||||||
|
with mock.patch("sys.stderr", stderr):
|
||||||
|
main()
|
||||||
|
|
||||||
|
# With an invalid section, we should get a usage error.
|
||||||
|
expected = r'^error: no section found$'
|
||||||
|
assert re.match(expected, stderr.getvalue().strip())
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch("aurweb.config.get", side_effect=mock_config_get())
|
||||||
|
def test_config_main_get_unknown_option(get: str):
|
||||||
|
stderr = io.StringIO()
|
||||||
|
args = ["aurweb-config", "get", "options", "fakeblahblah"]
|
||||||
|
with mock.patch("sys.argv", args):
|
||||||
|
with mock.patch("sys.stderr", stderr):
|
||||||
|
main()
|
||||||
|
|
||||||
|
expected = "error: no option found"
|
||||||
|
assert stderr.getvalue().strip() == expected
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch("aurweb.config.save", side_effect=noop)
|
||||||
|
def test_config_main_set(save: None):
|
||||||
|
data = None
|
||||||
|
|
||||||
|
def mock_replace_key(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):
|
||||||
|
main()
|
||||||
|
|
||||||
|
expected = "666"
|
||||||
|
assert data == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_config_main_set_immutable():
|
||||||
|
data = None
|
||||||
|
|
||||||
|
def mock_replace_key(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):
|
||||||
|
main()
|
||||||
|
|
||||||
|
expected = None
|
||||||
|
assert data == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_config_main_set_invalid_value():
|
||||||
|
stderr = io.StringIO()
|
||||||
|
|
||||||
|
args = ["aurweb-config", "set", "options", "salt_rounds"]
|
||||||
|
with mock.patch("sys.argv", args):
|
||||||
|
with mock.patch("sys.stderr", stderr):
|
||||||
|
main()
|
||||||
|
|
||||||
|
expected = "error: no value provided"
|
||||||
|
assert stderr.getvalue().strip() == expected
|
||||||
|
|
||||||
|
|
||||||
|
@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:
|
||||||
|
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):
|
||||||
|
main()
|
||||||
|
|
||||||
|
assert stderr.getvalue().strip() == "error: no section found"
|
||||||
|
|
Loading…
Add table
Reference in a new issue