diff options
author | Alexandre Flament <alex@al-f.net> | 2024-01-06 17:56:52 +0000 |
---|---|---|
committer | Markus Heiser <markus.heiser@darmarIT.de> | 2024-01-09 16:31:19 +0100 |
commit | 60bc5baea31c24a72cfb4f45322e326cc62caf23 (patch) | |
tree | 94bad142d230656767fde1223ebaf81fa797b6fd /utils | |
parent | 3dea7e609bac72d4a129979ba15315b966ff020f (diff) | |
download | searxng-60bc5baea31c24a72cfb4f45322e326cc62caf23.tar.gz searxng-60bc5baea31c24a72cfb4f45322e326cc62caf23.zip |
[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
Diffstat (limited to 'utils')
-rw-r--r-- | utils/get_setting.py | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/utils/get_setting.py b/utils/get_setting.py new file mode 100644 index 000000000..fa8d9cf8f --- /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]) |