clan-config: allow passing schema or module file

This commit is contained in:
DavHau
2023-08-02 21:10:41 +02:00
parent 70ec58f68b
commit 7299a63a13
2 changed files with 53 additions and 9 deletions

View File

@@ -1,6 +1,8 @@
# !/usr/bin/env python3 # !/usr/bin/env python3
import argparse import argparse
import json import json
import subprocess
import sys
from pathlib import Path from pathlib import Path
from typing import Any, Optional, Union from typing import Any, Optional, Union
@@ -15,21 +17,41 @@ class Kwargs:
self.choices: Optional[list] = None self.choices: Optional[list] = None
def schema_from_module_file(
file: Union[str, Path] = "./tests/config/example-interface.nix",
) -> dict:
absolute_path = Path(file).absolute()
# define a nix expression that loads the given module file using lib.evalModules
nix_expr = f"""
let
lib = import <nixpkgs/lib>;
slib = import {__file__}/../schema-lib.nix {{inherit lib;}};
in
slib.parseModule {absolute_path}
"""
# run the nix expression and parse the output as json
return json.loads(
subprocess.check_output(
["nix", "eval", "--impure", "--json", "--expr", nix_expr]
)
)
# takes a (sub)parser and configures it # takes a (sub)parser and configures it
def register_parser( def register_parser(
parser: Optional[argparse.ArgumentParser] = None, parser: Optional[argparse.ArgumentParser] = None,
schema: Union[dict, str, Path] = "./tests/config/example-schema.json", schema: Union[dict, str, Path] = "./tests/config/example-interface.nix",
) -> dict: ) -> dict:
if not isinstance(schema, dict): # check if schema is a .nix file and load it in that case
if isinstance(schema, str) and schema.endswith(".nix"):
schema = schema_from_module_file(schema)
elif not isinstance(schema, dict):
with open(str(schema)) as f: with open(str(schema)) as f:
schema: dict = json.load(f) schema: dict = json.load(f)
assert "type" in schema and schema["type"] == "object" assert "type" in schema and schema["type"] == "object"
required_set = set(schema.get("required", [])) required_set = set(schema.get("required", []))
if parser is None:
parser = argparse.ArgumentParser(description=schema.get("description"))
type_map = { type_map = {
"array": list, "array": list,
"boolean": bool, "boolean": bool,
@@ -38,6 +60,9 @@ def register_parser(
"string": str, "string": str,
} }
if parser is None:
parser = argparse.ArgumentParser(description=schema.get("description"))
subparsers = parser.add_subparsers( subparsers = parser.add_subparsers(
title="more options", title="more options",
description="Other options to configure", description="Other options to configure",
@@ -92,8 +117,18 @@ def register_parser(
parser.add_argument(name, **vars(kwargs)) parser.add_argument(name, **vars(kwargs))
if __name__ == "__main__": def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
register_parser(parser) parser.add_argument(
args = parser.parse_args() "schema",
print(args) help="The schema to use for the configuration",
type=str,
)
args = parser.parse_args(sys.argv[1:2])
schema = args.schema
register_parser(schema=schema, parser=parser)
parser.parse_args(sys.argv[2:])
if __name__ == "__main__":
main()

View File

@@ -19,6 +19,15 @@ let
in in
rec { rec {
# parses a nixos module to a jsonschema
parseModule = module:
let
evaled = lib.evalModules {
modules = [ module ];
};
in
parseOptions evaled.options;
# parses a set of evaluated nixos options to a jsonschema # parses a set of evaluated nixos options to a jsonschema
parseOptions = options': parseOptions = options':
let let