diff --git a/overlay.nix b/overlay.nix index 41be66d..ec1dd8f 100644 --- a/overlay.nix +++ b/overlay.nix @@ -1,3 +1,4 @@ -final: prev: with prev.lib; { +final: prev: { + formats.xml = import ./xml.nix { pkgs = final; }; pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [ (import ./python_overlay.nix) ]; } diff --git a/xml.nix b/xml.nix new file mode 100644 index 0000000..1a4fae5 --- /dev/null +++ b/xml.nix @@ -0,0 +1,93 @@ +{ pkgs }: +let + inherit (pkgs) lib; + inherit (lib) + escapeShellArg + filterAttrs + hasPrefix + attrNames + ; + inherit (lib.types) + nullOr + oneOf + listOf + attrsOf + bool + int + float + str + path + attrs + ; +in +{ + attribute-prefix ? "@", + content-name ? "#text", +}: +{ + type = + let + attrsType = + let + contentType = attrsOf valueType; + attributesType = attrsOf (oneOf [ + str + path + bool + int + float + ]); + addCheck = + val: + let + attributes = filterAttrs (name: _: hasPrefix attribute-prefix name) val; + contents = filterAttrs (name: _: !hasPrefix attribute-prefix name) val; + in + attributesType.check attributes + && ( + if contents ? ${content-name} then + attrNames contents == [ content-name ] && str.check contents.${content-name} + else + contentType.check contents + ); + in + attrs + // { + check = val: attrs.check val && addCheck val; + description = "XML values"; + }; + valueType = + nullOr (oneOf [ + bool + int + float + str + path + attrsType + (listOf valueType) + ]) + // { + description = "XML value"; + }; + in + valueType; + generate = + name: value: + pkgs.callPackage ( + { runCommand, yq-go }: + runCommand name + { + nativeBuildInputs = [ yq-go ]; + value = builtins.toJSON value; + passAsFile = [ "value" ]; + preferLocalBuild = true; + } + '' + yq \ + --xml-attribute-prefix ${escapeShellArg attribute-prefix} \ + --xml-content-name ${escapeShellArg content-name} \ + --output-format xml \ + "$valuePath" > "$out" + '' + ) { }; +}