From 283b8d98635a6427cbeecdb175e2f7a47293c968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Thu, 9 Oct 2025 01:36:32 +0200 Subject: [PATCH] [add] tool:cfg-man --- tools/cfg-man | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100755 tools/cfg-man diff --git a/tools/cfg-man b/tools/cfg-man new file mode 100755 index 0000000..6aa543b --- /dev/null +++ b/tools/cfg-man @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 + +import os as _os +import sys as _sys +import json as _json +import argparse as _argparse + + +def convey( + x, + fs +): + y = x + for f in fs: + y = f(y) + return y + + +def file_read( + path +): + handle = open(path, "r") + content = handle.read() + handle.close() + return content + + +class interface_option(object): + def is_filled(self): + raise NotImplementedError() + def cull(self): + raise NotImplementedError() + def propagate(self, function): + raise NotImplementedError() + + +class class_option_empty(interface_option): + def __init__(self): + pass + def is_filled(self): + return False + def cull(self): + raise ValueError("cull from empty") + def propagate(self, function): + return class_option_empty() + + +class class_option_filled(interface_option): + def __init__(self, value): + self.value = value + def is_filled(self): + return True + def cull(self): + return self.value + def propagate(self, function): + return function(self.value) + + +def generate_defaults( + schema_node +): + if ("anyOf" in schema_node): + ## todo: o'rly? + return generate_defaults(schema_node["anyOf"][0]) + else: + if (not ("type" in schema_node)): + raise ValueError(":?") + else: + if (not (schema_node["type"] == "object")): + if (not ("default" in schema_node)): + return class_option_empty() + else: + return class_option_filled(schema_node["default"]) + else: + result = {} + for (key, value, ) in schema_node["properties"].items(): + sub_result = generate_defaults(value) + if (not sub_result.is_filled()): + pass + else: + result[key] = sub_result.cull() + return class_option_filled(result) + + +def generate_overrides( + schema_node +): + if ("anyOf" in schema_node): + ## todo: o'rly? + return generate_overrides(schema_node["anyOf"][0]) + else: + if (not ("type" in schema_node)): + raise ValueError(":?") + else: + if (not (schema_node["type"] == "object")): + if ("default" in schema_node): + return class_option_empty() + else: + if ("enum" in schema_node): + return class_option_filled(schema_node["enum"][0]) + else: + if (schema_node.get("nullable", False)): + return class_option_filled(None) + else: + if (schema_node["type"] == "boolean"): + return class_option_filled(False) + elif (schema_node["type"] == "integer"): + return class_option_filled(0) + elif (schema_node["type"] == "number"): + return class_option_filled(0) + elif (schema_node["type"] == "string"): + return class_option_filled("") + else: + raise ValueError("unhandled type: %s" % schema_node["type"]) + else: + result = {} + for (key, value, ) in schema_node["properties"].items(): + sub_result = generate_overrides(value) + if (not sub_result.is_filled()): + pass + else: + result[key] = sub_result.cull() + return ( + class_option_empty() + if (len(result) <= 0) else + class_option_filled(result) + ) + + +def role_name_derive( + role_name +): + return role_name.replace("-", "_") + + +def main( +): + ## args + argument_parser = _argparse.ArgumentParser() + argument_parser.add_argument( + "action", + type = str, + choices = [ + "defaults", + "overrides", + ], + metavar = "", + ) + argument_parser.add_argument( + "role", + type = str, + metavar = "", + ) + args = argument_parser.parse_args() + + ## exec + cfg_schema = convey( + args.role, + [ + lambda x: _os.path.join("roles", x, "cfg.schema.json"), + file_read, + _json.loads, + ] + ) + if args.action == "defaults": + raw = generate_defaults(cfg_schema) + key = ("cfg_%s_defaults" % (role_name_derive(args.role))) + result = {key: (raw.cull() if raw.is_filled() else {})} + _sys.stdout.write(_json.dumps(result, indent = "\t") + "\n") + elif args.action == "overrides": + raw = generate_overrides(cfg_schema) + key = ("cfg_%s_overrides" % (role_name_derive(args.role))) + result = {key: (raw.cull() if raw.is_filled() else {})} + _sys.stdout.write(_json.dumps(result, indent = "\t") + "\n") + else: + raise ValueError("invalid action: %s" % args.action) + + +main()