Support backend specific options and HTTP headers via command-line

This commit is contained in:
Unrud 2021-11-14 23:30:59 +01:00
parent b23aa4629c
commit 08e789d993
2 changed files with 46 additions and 6 deletions

View File

@ -75,7 +75,14 @@ def run() -> None:
continue continue
assert ":" not in section # check field separator assert ":" not in section # check field separator
assert "-" not in section and "_" not in section # not implemented assert "-" not in section and "_" not in section # not implemented
group = parser.add_argument_group(section) group_description = None
if section_data.get("_allow_extra"):
group_description = "additional options allowed"
if section == "headers":
group_description += " (e.g. --headers-Pragma=no-cache)"
elif "type" in section_data:
group_description = "backend specific options omitted"
group = parser.add_argument_group(section, group_description)
for option, data in section_data.items(): for option, data in section_data.items():
if option.startswith("_"): if option.startswith("_"):
continue continue
@ -106,7 +113,32 @@ def run() -> None:
del kwargs["type"] del kwargs["type"]
group.add_argument(*args, **kwargs) group.add_argument(*args, **kwargs)
args_ns = parser.parse_args() args_ns, remaining_args = parser.parse_known_args()
unrecognized_args = []
while remaining_args:
arg = remaining_args.pop(0)
for section, data in config.DEFAULT_CONFIG_SCHEMA.items():
if "type" not in data and not data.get("_allow_extra"):
continue
prefix = "--%s-" % section
if arg.startswith(prefix):
arg = arg[len(prefix):]
break
else:
unrecognized_args.append(arg)
continue
value = ""
if "=" in arg:
arg, value = arg.split("=", maxsplit=1)
elif remaining_args and not remaining_args[0].startswith("-"):
value = remaining_args.pop(0)
option = arg
if not data.get("_allow_extra"): # preserve dash in HTTP header names
option = option.replace("-", "_")
vars(args_ns)["c:%s:%s" % (section, option)] = value
if unrecognized_args:
parser.error("unrecognized arguments: %s" %
" ".join(unrecognized_args))
# Preliminary configure logging # Preliminary configure logging
with contextlib.suppress(ValueError): with contextlib.suppress(ValueError):

View File

@ -188,15 +188,17 @@ class TestBaseServerRequests(BaseTest):
self.get("/", check=302) self.get("/", check=302)
def test_command_line_interface(self) -> None: def test_command_line_interface(self) -> None:
self.configuration.update({"headers": {"Test-Server": "test"}})
config_args = [] config_args = []
for section, values in config.DEFAULT_CONFIG_SCHEMA.items(): for section in self.configuration.sections():
if section.startswith("_"): if section.startswith("_"):
continue continue
for option, data in values.items(): for option in self.configuration.options(section):
if option.startswith("_"): if option.startswith("_"):
continue continue
long_name = "--%s-%s" % (section, option.replace("_", "-")) long_name = "--%s-%s" % (section, option.replace("_", "-"))
if data["type"] == bool: if config.DEFAULT_CONFIG_SCHEMA.get(
section, {}).get(option, {}).get("type") == bool:
if not cast(bool, self.configuration.get(section, option)): if not cast(bool, self.configuration.get(section, option)):
long_name = "--no%s" % long_name[1:] long_name = "--no%s" % long_name[1:]
config_args.append(long_name) config_args.append(long_name)
@ -205,11 +207,17 @@ class TestBaseServerRequests(BaseTest):
raw_value = self.configuration.get_raw(section, option) raw_value = self.configuration.get_raw(section, option)
assert isinstance(raw_value, str) assert isinstance(raw_value, str)
config_args.append(raw_value) config_args.append(raw_value)
config_args.append("--headers-Test-Header=test")
p = subprocess.Popen( p = subprocess.Popen(
[sys.executable, "-m", "radicale"] + config_args, [sys.executable, "-m", "radicale"] + config_args,
env={**os.environ, "PYTHONPATH": os.pathsep.join(sys.path)}) env={**os.environ, "PYTHONPATH": os.pathsep.join(sys.path)})
try: try:
self.get("/", is_alive_fn=lambda: p.poll() is None, check=302) status, headers, _ = self.request(
"GET", "/", is_alive_fn=lambda: p.poll() is None)
self._check_status(status, 302)
for key in self.configuration.options("headers"):
assert headers.get(key) == self.configuration.get(
"headers", key)
finally: finally:
p.terminate() p.terminate()
p.wait() p.wait()