Просмотр исходного кода

Support backend specific options and HTTP headers via command-line

Unrud 4 лет назад
Родитель
Сommit
08e789d993
2 измененных файлов с 46 добавлено и 6 удалено
  1. 34 2
      radicale/__main__.py
  2. 12 4
      radicale/tests/test_server.py

+ 34 - 2
radicale/__main__.py

@@ -75,7 +75,14 @@ def run() -> None:
             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_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():
             if option.startswith("_"):
                 continue
@@ -106,7 +113,32 @@ def run() -> None:
                 del kwargs["type"]
                 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
     with contextlib.suppress(ValueError):

+ 12 - 4
radicale/tests/test_server.py

@@ -188,15 +188,17 @@ class TestBaseServerRequests(BaseTest):
         self.get("/", check=302)
 
     def test_command_line_interface(self) -> None:
+        self.configuration.update({"headers": {"Test-Server": "test"}})
         config_args = []
-        for section, values in config.DEFAULT_CONFIG_SCHEMA.items():
+        for section in self.configuration.sections():
             if section.startswith("_"):
                 continue
-            for option, data in values.items():
+            for option in self.configuration.options(section):
                 if option.startswith("_"):
                     continue
                 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)):
                         long_name = "--no%s" % long_name[1:]
                     config_args.append(long_name)
@@ -205,11 +207,17 @@ class TestBaseServerRequests(BaseTest):
                     raw_value = self.configuration.get_raw(section, option)
                     assert isinstance(raw_value, str)
                     config_args.append(raw_value)
+        config_args.append("--headers-Test-Header=test")
         p = subprocess.Popen(
             [sys.executable, "-m", "radicale"] + config_args,
             env={**os.environ, "PYTHONPATH": os.pathsep.join(sys.path)})
         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:
             p.terminate()
             p.wait()