From a468405d67ff1e5598947f52ea9b6820ec32f464 Mon Sep 17 00:00:00 2001 From: Felix Buehler Date: Tue, 17 Sep 2024 22:41:36 +0200 Subject: [PATCH] pkgs-lib.formats.xml: init --- .../development/settings-options.section.md | 15 +++++ pkgs/pkgs-lib/formats.nix | 60 +++++++++++++++++++ pkgs/pkgs-lib/tests/formats.nix | 27 +++++++++ 3 files changed, 102 insertions(+) diff --git a/nixos/doc/manual/development/settings-options.section.md b/nixos/doc/manual/development/settings-options.section.md index aa136ba8e9cbf..bae2fb72fdf39 100644 --- a/nixos/doc/manual/development/settings-options.section.md +++ b/nixos/doc/manual/development/settings-options.section.md @@ -343,6 +343,21 @@ have a predefined type and string generator already declared under and returning a set with TOML-specific attributes `type` and `generate` as specified [below](#pkgs-formats-result). +`pkgs.formats.xml` { format ? "badgerfish", withHeader ? true} + +: A function taking an attribute set with values + and returning a set with XML-specific attributes `type` and + `generate` as specified [below](#pkgs-formats-result). + + `format` + + : Input format. Because XML can not be translated one-to-one, we have to use intermediate formats. Possible values: + - `"badgerfish"`: Uses [badgerfish](http://www.sklar.com/badgerfish/) conversion. + + `withHeader` + + : Outputs the xml with header. + `pkgs.formats.cdn` { } : A function taking an empty attribute set (for future extensibility) diff --git a/pkgs/pkgs-lib/formats.nix b/pkgs/pkgs-lib/formats.nix index e02a5803ae0ee..f01ea4fe44fa2 100644 --- a/pkgs/pkgs-lib/formats.nix +++ b/pkgs/pkgs-lib/formats.nix @@ -577,4 +577,64 @@ rec { '') {}; }; + xml = + { + format ? "badgerfish", + withHeader ? true, + }: + if format == "badgerfish" then + { + type = let + valueType = nullOr (oneOf [ + bool + int + float + str + path + (attrsOf valueType) + (listOf valueType) + ]) // { + description = "XML value"; + }; + in valueType; + + generate = + name: value: + pkgs.callPackage ( + { + runCommand, + python3, + libxml2Python, + }: + runCommand name + { + nativeBuildInputs = [ + python3 + python3.pkgs.xmltodict + libxml2Python + ]; + value = builtins.toJSON value; + pythonGen = '' + import json + import os + import xmltodict + + with open(os.environ["valuePath"], "r") as f: + print(xmltodict.unparse(json.load(f), full_document=${toString withHeader}, pretty=True, indent=" " * 2)) + ''; + passAsFile = [ + "value" + "pythonGen" + ]; + preferLocalBuild = true; + } + '' + python3 "$pythonGenPath" > $out + xmllint $out > /dev/null + '' + ) { }; + } + else + throw "pkgs.formats.xml: Unknown format: ${format}"; + } diff --git a/pkgs/pkgs-lib/tests/formats.nix b/pkgs/pkgs-lib/tests/formats.nix index 2576c11b66874..523e19b2d01bf 100644 --- a/pkgs/pkgs-lib/tests/formats.nix +++ b/pkgs/pkgs-lib/tests/formats.nix @@ -644,4 +644,31 @@ in runBuildTests { ''; }; + badgerfishToXmlGenerate = shouldPass { + format = formats.xml { }; + input = { + root = { + "@id" = "123"; + "@class" = "example"; + child1 = { + "@name" = "child1Name"; + "#text" = "text node"; + }; + child2 = { + grandchild = "This is a grandchild text node."; + }; + nulltest = null; + }; + }; + expected = '' + + + text node + + This is a grandchild text node. + + + + ''; + }; }