#!/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()