diff --git a/pkgs/pkgs-lib/formats.nix b/pkgs/pkgs-lib/formats.nix index cdcbd3663422..13aada3681f7 100644 --- a/pkgs/pkgs-lib/formats.nix +++ b/pkgs/pkgs-lib/formats.nix @@ -135,6 +135,55 @@ rec { }; + keyValue = { + # Represents lists as duplicate keys + listsAsDuplicateKeys ? false, + # Alternative to listsAsDuplicateKeys, converts list to non-list + # listToValue :: [Atom] -> Atom + listToValue ? null, + ... + }@args: + assert !listsAsDuplicateKeys || listToValue == null; + { + + type = with lib.types; let + + singleAtom = nullOr (oneOf [ + bool + int + float + str + ]) // { + description = "atom (null, bool, int, float or string)"; + }; + + atom = + if listsAsDuplicateKeys then + coercedTo singleAtom lib.singleton (listOf singleAtom) // { + description = singleAtom.description + " or a list of them for duplicate keys"; + } + else if listToValue != null then + coercedTo singleAtom lib.singleton (nonEmptyListOf singleAtom) // { + description = singleAtom.description + " or a non-empty list of them"; + } + else + singleAtom; + + in attrsOf atom; + + generate = name: value: + let + transformedValue = + if listToValue != null + then + lib.mapAttrs (key: val: + if lib.isList val then listToValue val else val + ) value + else value; + in pkgs.writeText name (lib.generators.toKeyValue (removeAttrs args ["listToValue"]) transformedValue); + + }; + gitIni = { listsAsDuplicateKeys ? false, ... }@args: { type = with lib.types; let diff --git a/pkgs/pkgs-lib/tests/formats.nix b/pkgs/pkgs-lib/tests/formats.nix index dba7f981cbd9..80df247f7b6a 100644 --- a/pkgs/pkgs-lib/tests/formats.nix +++ b/pkgs/pkgs-lib/tests/formats.nix @@ -147,6 +147,51 @@ in runBuildTests { ''; }; + testKeyValueAtoms = { + drv = evalFormat formats.keyValue {} { + bool = true; + int = 10; + float = 3.141; + str = "string"; + }; + expected = '' + bool=true + float=3.141000 + int=10 + str=string + ''; + }; + + testKeyValueDuplicateKeys = { + drv = evalFormat formats.keyValue { listsAsDuplicateKeys = true; } { + bar = [ null true "test" 1.2 10 ]; + baz = false; + qux = "qux"; + }; + expected = '' + bar=null + bar=true + bar=test + bar=1.200000 + bar=10 + baz=false + qux=qux + ''; + }; + + testKeyValueListToValue = { + drv = evalFormat formats.keyValue { listToValue = concatMapStringsSep ", " (generators.mkValueStringDefault {}); } { + bar = [ null true "test" 1.2 10 ]; + baz = false; + qux = "qux"; + }; + expected = '' + bar=null, true, test, 1.200000, 10 + baz=false + qux=qux + ''; + }; + testTomlAtoms = { drv = evalFormat formats.toml {} { false = false;