Refactor command line argument parser

This commit is contained in:
Unrud 2021-11-14 23:30:58 +01:00
parent dba6338968
commit b23aa4629c

View File

@ -30,9 +30,9 @@ import signal
import socket import socket
import sys import sys
from types import FrameType from types import FrameType
from typing import Dict, List, cast from typing import List, cast
from radicale import VERSION, config, log, server, storage from radicale import VERSION, config, log, server, storage, types
from radicale.log import logger from radicale.log import logger
@ -57,6 +57,7 @@ def run() -> None:
log.setup() log.setup()
# Get command-line arguments # Get command-line arguments
# Configuration options are stored in dest with format "c:SECTION:OPTION"
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
prog="radicale", usage="%(prog)s [OPTIONS]", allow_abbrev=False) prog="radicale", usage="%(prog)s [OPTIONS]", allow_abbrev=False)
@ -65,36 +66,38 @@ def run() -> None:
help="check the storage for errors and exit") help="check the storage for errors and exit")
parser.add_argument("-C", "--config", parser.add_argument("-C", "--config",
help="use specific configuration files", nargs="*") help="use specific configuration files", nargs="*")
parser.add_argument("-D", "--debug", action="store_true", parser.add_argument("-D", "--debug", action="store_const", const="debug",
dest="c:logging:level", default=argparse.SUPPRESS,
help="print debug information") help="print debug information")
groups: Dict["argparse._ArgumentGroup", List[str]] = {} for section, section_data in config.DEFAULT_CONFIG_SCHEMA.items():
for section, values in config.DEFAULT_CONFIG_SCHEMA.items():
if section.startswith("_"): if section.startswith("_"):
continue continue
assert ":" not in section # check field separator
assert "-" not in section and "_" not in section # not implemented
group = parser.add_argument_group(section) group = parser.add_argument_group(section)
groups[group] = [] for option, data in section_data.items():
for option, data in values.items():
if option.startswith("_"): if option.startswith("_"):
continue continue
kwargs = data.copy() kwargs = data.copy()
long_name = "--%s-%s" % (section, option.replace("_", "-")) long_name = "--%s-%s" % (section, option.replace("_", "-"))
args: List[str] = list(kwargs.pop("aliases", ())) args: List[str] = list(kwargs.pop("aliases", ()))
args.append(long_name) args.append(long_name)
kwargs["dest"] = "%s_%s" % (section, option) kwargs["dest"] = "c:%s:%s" % (section, option)
groups[group].append(kwargs["dest"]) kwargs["metavar"] = "VALUE"
kwargs["default"] = argparse.SUPPRESS
del kwargs["value"] del kwargs["value"]
with contextlib.suppress(KeyError): with contextlib.suppress(KeyError):
del kwargs["internal"] del kwargs["internal"]
if kwargs["type"] == bool: if kwargs["type"] == bool:
del kwargs["type"] del kwargs["type"]
kwargs["action"] = "store_const"
kwargs["const"] = "True"
opposite_args = list(kwargs.pop("opposite_aliases", ())) opposite_args = list(kwargs.pop("opposite_aliases", ()))
opposite_args.append("--no%s" % long_name[1:]) opposite_args.append("--no%s" % long_name[1:])
kwargs["action"] = "store_const"
kwargs["const"] = "True"
group.add_argument(*args, **kwargs) group.add_argument(*args, **kwargs)
# Opposite argument
kwargs["const"] = "False" kwargs["const"] = "False"
kwargs["help"] = "do not %s (opposite of %s)" % ( kwargs["help"] = "do not %s (opposite of %s)" % (
kwargs["help"], long_name) kwargs["help"], long_name)
@ -106,23 +109,17 @@ def run() -> None:
args_ns = parser.parse_args() args_ns = parser.parse_args()
# Preliminary configure logging # Preliminary configure logging
if args_ns.debug:
args_ns.logging_level = "debug"
with contextlib.suppress(ValueError): with contextlib.suppress(ValueError):
log.set_level(config.DEFAULT_CONFIG_SCHEMA["logging"]["level"]["type"]( log.set_level(config.DEFAULT_CONFIG_SCHEMA["logging"]["level"]["type"](
args_ns.logging_level)) vars(args_ns).get("c:logging:level", "")))
# Update Radicale configuration according to arguments # Update Radicale configuration according to arguments
arguments_config = {} arguments_config: types.MUTABLE_CONFIG = {}
for group, actions in groups.items(): for key, value in vars(args_ns).items():
section = group.title or "" if key.startswith("c:"):
section_config = {} _, section, option = key.split(":", maxsplit=2)
for action in actions: arguments_config[section] = arguments_config.get(section, {})
value = getattr(args_ns, action) arguments_config[section][option] = value
if value is not None:
section_config[action.split('_', 1)[1]] = value
if section_config:
arguments_config[section] = section_config
try: try:
configuration = config.load(config.parse_compound_paths( configuration = config.load(config.parse_compound_paths(