about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--lib/generators.nix49
-rw-r--r--lib/tests/misc.nix60
2 files changed, 107 insertions, 2 deletions
diff --git a/lib/generators.nix b/lib/generators.nix
index 79ae9055ce3d9..3bc0fee332aea 100644
--- a/lib/generators.nix
+++ b/lib/generators.nix
@@ -10,7 +10,7 @@
  * are mostly generators themselves, called with
  * their respective default values; they can be reused.
  *
- * Tests can be found in ./tests.nix
+ * Tests can be found in ./tests/misc.nix
  * Documentation in the manual, #sec-generators
  */
 { lib }:
@@ -108,7 +108,7 @@ rec {
    * 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.
+   * For more examples see the test cases in ./tests/misc.nix.
    */
   toINI = {
     # apply transformations (e.g. escapes) to section names
@@ -130,6 +130,51 @@ rec {
       # map input to ini sections
       mapAttrsToStringsSep "\n" mkSection attrsOfAttrs;
 
+  /* Generate an INI-style config file from an attrset
+   * specifying the global section (no header), and an
+   * attrset of sections to an attrset of key-value pairs.
+   *
+   * generators.toINIWithGlobalSection {} {
+   *   globalSection = {
+   *     someGlobalKey = "hi";
+   *   };
+   *   sections = {
+   *     foo = { hi = "${pkgs.hello}"; ciao = "bar"; };
+   *     baz = { "also, integers" = 42; };
+   * }
+   *
+   *> someGlobalKey=hi
+   *>
+   *> [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/misc.nix.
+   *
+   * If you don’t need a global section, you can also use
+   * `generators.toINI` directly, which only takes
+   * the part in `sections`.
+   */
+  toINIWithGlobalSection = {
+    # apply transformations (e.g. escapes) to section names
+    mkSectionName ? (name: libStr.escape [ "[" "]" ] name),
+    # format a setting line from key and value
+    mkKeyValue    ? mkKeyValueDefault {} "=",
+    # allow lists as values for duplicate keys
+    listsAsDuplicateKeys ? false
+  }: { globalSection, sections }:
+    ( if globalSection == {}
+      then ""
+      else (toKeyValue { inherit mkKeyValue listsAsDuplicateKeys; } globalSection)
+           + "\n")
+    + (toINI { inherit mkSectionName mkKeyValue listsAsDuplicateKeys; } sections);
+
   /* Generate a git-config file from an attrset.
    *
    * It has two major differences from the regular INI format:
diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix
index 9012bba2b5675..fcccf89cc888c 100644
--- a/lib/tests/misc.nix
+++ b/lib/tests/misc.nix
@@ -471,6 +471,66 @@ runTests {
     '';
   };
 
+  testToINIWithGlobalSectionEmpty = {
+    expr = generators.toINIWithGlobalSection {} {
+      globalSection = {
+      };
+      sections = {
+      };
+    };
+    expected = ''
+    '';
+  };
+
+  testToINIWithGlobalSectionGlobalEmptyIsTheSameAsToINI =
+    let
+      sections = {
+        "section 1" = {
+          attribute1 = 5;
+          x = "Me-se JarJar Binx";
+        };
+        "foo" = {
+          "he\\h=he" = "this is okay";
+        };
+      };
+    in {
+      expr =
+        generators.toINIWithGlobalSection {} {
+            globalSection = {};
+            sections = sections;
+        };
+      expected = generators.toINI {} sections;
+  };
+
+  testToINIWithGlobalSectionFull = {
+    expr = generators.toINIWithGlobalSection {} {
+      globalSection = {
+        foo = "bar";
+        test = false;
+      };
+      sections = {
+        "section 1" = {
+          attribute1 = 5;
+          x = "Me-se JarJar Binx";
+        };
+        "foo" = {
+          "he\\h=he" = "this is okay";
+        };
+      };
+    };
+    expected = ''
+      foo=bar
+      test=false
+
+      [foo]
+      he\h\=he=this is okay
+
+      [section 1]
+      attribute1=5
+      x=Me-se JarJar Binx
+    '';
+  };
+
   /* right now only invocation check */
   testToJSONSimple =
     let val = {