summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Flament <alex@al-f.net>2024-01-06 17:56:52 +0000
committerMarkus Heiser <markus.heiser@darmarIT.de>2024-01-09 16:31:19 +0100
commit60bc5baea31c24a72cfb4f45322e326cc62caf23 (patch)
tree94bad142d230656767fde1223ebaf81fa797b6fd
parent3dea7e609bac72d4a129979ba15315b966ff020f (diff)
[mod] ./utils/get_setting.py tiny YAML parser for settings.yml
This allow to read settings on the fly even without virtualenv. The ultimate goal of the commit is to remove utils/brand.env from the git repository. The code includes a tiny yaml parser that **should** be good enough. The code read searx/settings.yml directly (and ignore the environment variables). yq [1] is a more reliable alternative but this require to download a binary from github which is not great. [1] https://github.com/mikefarah/yq/#install
-rw-r--r--utils/get_setting.py134
1 files changed, 134 insertions, 0 deletions
diff --git a/utils/get_setting.py b/utils/get_setting.py
new file mode 100644
index 00000000..fa8d9cf8
--- /dev/null
+++ b/utils/get_setting.py
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: AGPL-3.0-or-later
+"""build environment used by shell scripts
+"""
+
+# set path
+import sys
+import importlib.util
+import re
+
+from pathlib import Path
+
+repo_root = Path(__file__).resolve().parent.parent
+
+
+# If you add or remove variables here, do not forget to update:
+# - ./docs/admin/engines/settings.rst
+# - ./docs/dev/makefile.rst (section make buildenv)
+
+name_val = [
+ ("SEARXNG_URL", "server.base_url"),
+ ("SEARXNG_PORT", "server.port"),
+ ("SEARXNG_BIND_ADDRESS", "server.bind_address"),
+]
+
+
+def main(setting_name):
+
+ settings_path = repo_root / "searx" / "settings.yml"
+ with open(settings_path) as f:
+ settings = parse_yaml(f.read())
+ print(get_setting_value(settings, setting_name))
+
+
+def get_setting_value(settings, name):
+ value = settings
+ for a in name.split("."):
+ value = value[a]
+ if value is True:
+ value = "1"
+ elif value is False:
+ value = ""
+ return value
+
+
+def parse_yaml(yaml_str):
+ """A simple YAML parser that converts a YAML string to a Python dictionary.
+ This parser can handle nested dictionaries, but does not handle list or JSON
+ like structures.
+
+ Good enough parser to get the values of server.base_url, server.port and
+ server.bind_address
+
+ """
+
+ def get_type_and_value_without_comment(line):
+ """Extract value without comment and quote
+
+ Returns a tuple:
+
+ 1. str or None: str when the value is written inside quote, None otherwise
+ 2. the value without quote if any
+ """
+ match = re.search(r"\"(.*)\"(\s+#)?|\'(.*)\'(\s+#)?|([^#]*)(\s+#)?", line)
+ if match:
+ g = match.groups()
+ if g[0] is not None:
+ return str, g[0]
+ elif g[2] is not None:
+ return str, g[2]
+ elif g[4] is not None:
+ return None, g[4].strip()
+ return None, line.strip()
+
+ # fmt: off
+ true_values = ("y", "Y", "yes", "Yes", "YES", "true", "True", "TRUE", "on", "On", "ON",)
+ false_values = ("n", "N", "no", "No", "NO", "false", "False", "FALSE", "off", "Off", "OFF",)
+ # fmt: on
+
+ def process_line(line):
+ """Extract key and value from a line, considering its indentation."""
+ if ": " in line:
+ key, value = line.split(": ", 1)
+ key = key.strip()
+ value_type, value = get_type_and_value_without_comment(value)
+ if value in true_values and value_type is None:
+ value = True
+ elif value in false_values and value_type is None:
+ value = False
+ elif value.replace(".", "").isdigit() and value_type is None:
+ for t in (int, float):
+ try:
+ value = t(value)
+ break
+ except ValueError:
+ continue
+ return key, value
+ return None, None
+
+ def get_indentation_level(line):
+ """Determine the indentation level of a line."""
+ return len(line) - len(line.lstrip())
+
+ yaml_dict = {}
+ lines = yaml_str.split("\n")
+ stack = [yaml_dict]
+
+ for line in lines:
+ if not line.strip():
+ continue # Skip empty lines
+
+ indentation_level = get_indentation_level(line)
+ # Assuming 2 spaces per indentation level
+ # see .yamllint.yml
+ current_level = indentation_level // 2
+
+ # Adjust the stack based on the current indentation level
+ while len(stack) > current_level + 1:
+ stack.pop()
+
+ if line.endswith(":"):
+ key = line[0:-1].strip()
+ new_dict = {}
+ stack[-1][key] = new_dict
+ stack.append(new_dict)
+ else:
+ key, value = process_line(line)
+ if key is not None:
+ stack[-1][key] = value
+
+ return yaml_dict
+
+
+if __name__ == "__main__":
+ main(sys.argv[1])