diff --git a/lib/default.nix b/lib/default.nix index cb9a9b0bd4d0..c0d7899b882a 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -27,6 +27,7 @@ let # misc debug = import ./debug.nix; + generators = import ./generators.nix; misc = import ./deprecated.nix; # domain-specific @@ -39,7 +40,7 @@ in customisation maintainers meta sources modules options types licenses platforms systems - debug misc + debug generators misc sandbox fetchers; } # !!! don't include everything at top-level; perhaps only the most diff --git a/lib/generators.nix b/lib/generators.nix new file mode 100644 index 000000000000..90dd33714544 --- /dev/null +++ b/lib/generators.nix @@ -0,0 +1,53 @@ +/* Functions that generate widespread config file + * formats from nix data structures. + * Tests can be found in ./tests.nix + */ +with import ./trivial.nix; +let + libStr = import ./strings.nix; + libAttr = import ./attrsets.nix; + + flipMapAttrs = flip libAttr.mapAttrs; +in + +{ + + /* Generates an INI-style config file from an + * attrset of sections to an attrset of key-value pairs. + * + * generators.toINI {} { + * foo = { hi = "${pkgs.hello}"; ciao = "bar"; }; + * baz = { "also, integers" = 42; }; + * } + * + *> [baz] + *> also, integers=42 + *> + *> [foo] + *> ciao=bar + *> hi=/nix/store/y93qql1p5ggfnaqjjqhxcw0vqw95rlz0-hello-2.10 + * + * The mk* configuration attributes can generically change + * the way sections and key-value strings are generated. + * + * For more examples see the test cases in ./tests.nix. + */ + toINI = { + # apply transformations (e.g. escapes) to section names + mkSectionName ? (name: libStr.escape [ "[" "]" ] name), + # format a setting line from key and value + mkKeyValue ? (k: v: "${libStr.escape ["="] k}=${toString v}") + }: attrsOfAttrs: + let + # map function to string for each key val + mapAttrsToStringsSep = sep: mapFn: attrs: + libStr.concatStringsSep sep + (libAttr.mapAttrsToList mapFn attrs); + mkLine = k: v: mkKeyValue k v + "\n"; + mkSection = sectName: sectValues: '' + [${mkSectionName sectName}] + '' + libStr.concatStrings (libAttr.mapAttrsToList mkLine sectValues); + in + # map input to ini sections + mapAttrsToStringsSep "\n" mkSection attrsOfAttrs; +} diff --git a/lib/tests.nix b/lib/tests.nix index c3b8839fda95..b5513dcb5ff4 100644 --- a/lib/tests.nix +++ b/lib/tests.nix @@ -130,4 +130,55 @@ runTests { expected = false; }; + + /* Generator tests */ + # these tests assume attributes are converted to lists + # in alphabetical order + + testToINIEmpty = { + expr = generators.toINI {} {}; + expected = ""; + }; + + testToINIEmptySection = { + expr = generators.toINI {} { foo = {}; bar = {}; }; + expected = '' + [bar] + + [foo] + ''; + }; + + testToINIDefaultEscapes = { + expr = generators.toINI {} { + "no [ and ] allowed unescaped" = { + "and also no = in keys" = 42; + }; + }; + expected = '' + [no \[ and \] allowed unescaped] + and also no \= in keys=42 + ''; + }; + + testToINIDefaultFull = { + expr = generators.toINI {} { + "section 1" = { + attribute1 = 5; + x = "Me-se JarJar Binx"; + }; + "foo[]" = { + "he\\h=he" = "this is okay"; + }; + }; + expected = '' + [foo\[\]] + he\h\=he=this is okay + + [section 1] + attribute1=5 + x=Me-se JarJar Binx + ''; + }; + }