diff options
author | Alyssa Ross <hi@alyssa.is> | 2021-01-10 07:13:44 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2021-01-12 14:07:16 +0000 |
commit | e2698550456abba83c6dcd5d5e5a9990a0b96f8a (patch) | |
tree | 79a56f0df3fa55e470d84b4dff6059fbf487ec18 /nixpkgs/pkgs/pkgs-lib | |
parent | 1cdc42df888dc98c347e03bd942ed9825a55bcb3 (diff) | |
parent | 84d74ae9c9cbed73274b8e4e00be14688ffc93fe (diff) | |
download | nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar.gz nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar.bz2 nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar.lz nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar.xz nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.tar.zst nixlib-e2698550456abba83c6dcd5d5e5a9990a0b96f8a.zip |
Merge commit '84d74ae9c9cbed73274b8e4e00be14688ffc93fe'
Diffstat (limited to 'nixpkgs/pkgs/pkgs-lib')
-rw-r--r-- | nixpkgs/pkgs/pkgs-lib/default.nix | 11 | ||||
-rw-r--r-- | nixpkgs/pkgs/pkgs-lib/formats.nix | 109 | ||||
-rw-r--r-- | nixpkgs/pkgs/pkgs-lib/tests/default.nix | 7 | ||||
-rw-r--r-- | nixpkgs/pkgs/pkgs-lib/tests/formats.nix | 157 |
4 files changed, 284 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/pkgs-lib/default.nix b/nixpkgs/pkgs/pkgs-lib/default.nix new file mode 100644 index 000000000000..113dcebf8c68 --- /dev/null +++ b/nixpkgs/pkgs/pkgs-lib/default.nix @@ -0,0 +1,11 @@ +# pkgs-lib is for functions and values that can't be in lib because +# they depend on some packages. This notably is *not* for supporting package +# building, instead pkgs/build-support is the place for that. +{ lib, pkgs }: { + # setting format types and generators. These do not fit in lib/types.nix, + # because they depend on pkgs for rendering some formats + formats = import ./formats.nix { + inherit lib pkgs; + }; +} + diff --git a/nixpkgs/pkgs/pkgs-lib/formats.nix b/nixpkgs/pkgs/pkgs-lib/formats.nix new file mode 100644 index 000000000000..14589f8ecdc3 --- /dev/null +++ b/nixpkgs/pkgs/pkgs-lib/formats.nix @@ -0,0 +1,109 @@ +{ lib, pkgs }: +rec { + + /* + + Every following entry represents a format for program configuration files + used for `settings`-style options (see https://github.com/NixOS/rfcs/pull/42). + Each entry should look as follows: + + <format> = <parameters>: { + # ^^ Parameters for controlling the format + + # The module system type most suitable for representing such a format + # The description needs to be overwritten for recursive types + type = ...; + + # generate :: Name -> Value -> Path + # A function for generating a file with a value of such a type + generate = ...; + + }); + */ + + + json = {}: { + + type = with lib.types; let + valueType = nullOr (oneOf [ + bool + int + float + str + (attrsOf valueType) + (listOf valueType) + ]) // { + description = "JSON value"; + }; + in valueType; + + generate = name: value: pkgs.runCommandNoCC name { + nativeBuildInputs = [ pkgs.jq ]; + value = builtins.toJSON value; + passAsFile = [ "value" ]; + } '' + jq . "$valuePath"> $out + ''; + + }; + + # YAML has been a strict superset of JSON since 1.2 + yaml = {}: + let jsonSet = json {}; + in jsonSet // { + type = jsonSet.type // { + description = "YAML value"; + }; + }; + + ini = { listsAsDuplicateKeys ? false, ... }@args: { + + type = with lib.types; let + + singleIniAtom = nullOr (oneOf [ + bool + int + float + str + ]) // { + description = "INI atom (null, bool, int, float or string)"; + }; + + iniAtom = + if listsAsDuplicateKeys then + coercedTo singleIniAtom lib.singleton (listOf singleIniAtom) // { + description = singleIniAtom.description + " or a list of them for duplicate keys"; + } + else + singleIniAtom; + + in attrsOf (attrsOf iniAtom); + + generate = name: value: pkgs.writeText name (lib.generators.toINI args value); + + }; + + toml = {}: json {} // { + type = with lib.types; let + valueType = oneOf [ + bool + int + float + str + (attrsOf valueType) + (listOf valueType) + ] // { + description = "TOML value"; + }; + in valueType; + + generate = name: value: pkgs.runCommandNoCC name { + nativeBuildInputs = [ pkgs.remarshal ]; + value = builtins.toJSON value; + passAsFile = [ "value" ]; + } '' + json2toml "$valuePath" "$out" + ''; + + }; +} diff --git a/nixpkgs/pkgs/pkgs-lib/tests/default.nix b/nixpkgs/pkgs/pkgs-lib/tests/default.nix new file mode 100644 index 000000000000..f3549ea9b0f2 --- /dev/null +++ b/nixpkgs/pkgs/pkgs-lib/tests/default.nix @@ -0,0 +1,7 @@ +# Call nix-build on this file to run all tests in this directory +{ pkgs ? import ../../.. {} }: +let + formats = import ./formats.nix { inherit pkgs; }; +in pkgs.linkFarm "nixpkgs-pkgs-lib-tests" [ + { name = "formats"; path = import ./formats.nix { inherit pkgs; }; } +] diff --git a/nixpkgs/pkgs/pkgs-lib/tests/formats.nix b/nixpkgs/pkgs/pkgs-lib/tests/formats.nix new file mode 100644 index 000000000000..bf6be8595e1b --- /dev/null +++ b/nixpkgs/pkgs/pkgs-lib/tests/formats.nix @@ -0,0 +1,157 @@ +{ pkgs }: +let + inherit (pkgs) lib formats; +in +with lib; +let + + evalFormat = format: args: def: + let + formatSet = format args; + config = formatSet.type.merge [] (imap1 (n: def: { + value = def; + file = "def${toString n}"; + }) [ def ]); + in formatSet.generate "test-format-file" config; + + runBuildTest = name: { drv, expected }: pkgs.runCommandNoCC name {} '' + if diff ${drv} ${builtins.toFile "expected" expected}; then + touch $out + else + echo "Got: $(cat ${drv})" + echo "Should be: ${expected}" + exit 1 + fi + ''; + + runBuildTests = tests: pkgs.linkFarm "nixpkgs-pkgs-lib-format-tests" (mapAttrsToList (name: value: { inherit name; path = runBuildTest name value; }) (filterAttrs (name: value: value != null) tests)); + +in runBuildTests { + + testJsonAtoms = { + drv = evalFormat formats.json {} { + null = null; + false = false; + true = true; + int = 10; + float = 3.141; + str = "foo"; + attrs.foo = null; + list = [ null null ]; + }; + expected = '' + { + "attrs": { + "foo": null + }, + "false": false, + "float": 3.141, + "int": 10, + "list": [ + null, + null + ], + "null": null, + "str": "foo", + "true": true + } + ''; + }; + + testYamlAtoms = { + drv = evalFormat formats.yaml {} { + null = null; + false = false; + true = true; + float = 3.141; + str = "foo"; + attrs.foo = null; + list = [ null null ]; + }; + expected = '' + { + "attrs": { + "foo": null + }, + "false": false, + "float": 3.141, + "list": [ + null, + null + ], + "null": null, + "str": "foo", + "true": true + } + ''; + }; + + testIniAtoms = { + drv = evalFormat formats.ini {} { + foo = { + bool = true; + int = 10; + float = 3.141; + str = "string"; + }; + }; + expected = '' + [foo] + bool=true + float=3.141000 + int=10 + str=string + ''; + }; + + testIniDuplicateKeys = { + drv = evalFormat formats.ini { listsAsDuplicateKeys = true; } { + foo = { + bar = [ null true "test" 1.2 10 ]; + baz = false; + qux = "qux"; + }; + }; + expected = '' + [foo] + bar=null + bar=true + bar=test + bar=1.200000 + bar=10 + baz=false + qux=qux + ''; + }; + + testTomlAtoms = { + drv = evalFormat formats.toml {} { + false = false; + true = true; + int = 10; + float = 3.141; + str = "foo"; + attrs.foo = "foo"; + list = [ 1 2 ]; + level1.level2.level3.level4 = "deep"; + }; + expected = '' + false = false + float = 3.141 + int = 10 + list = [1, 2] + str = "foo" + true = true + + [attrs] + foo = "foo" + + [level1] + + [level1.level2] + + [level1.level2.level3] + level4 = "deep" + ''; + }; +} |