From 7f4851a1f5be10704dc6e54561166c79edccdfcb Mon Sep 17 00:00:00 2001 From: Dmitriy Kholkin Date: Tue, 23 Apr 2024 21:38:25 +0300 Subject: [PATCH] add json2nix script --- scripts/json2nix.py | 84 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 scripts/json2nix.py diff --git a/scripts/json2nix.py b/scripts/json2nix.py new file mode 100644 index 0000000..676d1c7 --- /dev/null +++ b/scripts/json2nix.py @@ -0,0 +1,84 @@ +"""Converts JSON objects into nix (hackishly).""" + +import sys +import json + + +INDENT = " " * 2 + + +def strip_comments(t): + # fixme: doesn't work if JSON strings contain // + return "\n".join(l.partition("//")[0] for l in t.split("\n")) + + +def indent(s): + return "\n".join(INDENT + i for i in s.split("\n")) + + +def nix_stringify(s): + # fixme: this doesn't handle string interpolation and possibly has more bugs + return json.dumps(s) + + +def sanitize_key(s): + if s and s.isalnum() and not s[0].isdigit(): + return s + return nix_stringify(s) + + +def flatten_obj_item(k, v): + keys = [k] + val = v + while isinstance(val, dict) and len(val) == 1: + k = next(iter(val.keys())) + keys.append(k) + val = val[k] + return keys, val + + +def fmt_object(obj, flatten): + fields = [] + for k, v in obj.items(): + if flatten: + keys, val = flatten_obj_item(k, v) + formatted_key = ".".join(sanitize_key(i) for i in keys) + else: + formatted_key = sanitize_key(k) + val = v + fields.append(f"{formatted_key} = {fmt_any(val, flatten)};") + + return "{\n" + indent("\n".join(fields)) + "\n}" + + +def fmt_array(o, flatten): + body = indent("\n".join(fmt_any(i, flatten) for i in o)) + return f"[\n{body}\n]" + + +def fmt_any(o, flatten): + if isinstance(o, str) or isinstance(o, bool) or isinstance(o, int): + return json.dumps(o) + if isinstance(o, list): + return fmt_array(o, flatten) + if isinstance(o, dict): + return fmt_object(o, flatten) + raise TypeError(f"Unknown type {type(o)!r}") + + +def main(): + flatten = "--flatten" in sys.argv + args = [a for a in sys.argv[1:] if not a.startswith("--")] + + if len(args) < 1: + print(f"Usage: {sys.argv[0]} [--flatten] ", file=sys.stderr) + sys.exit(1) + + with open(args[0], "r") as f: + data = json.loads(strip_comments(f.read())) + + print(fmt_any(data, flatten=flatten)) + + +if __name__ == "__main__": + main()