about summary refs log tree commit diff
path: root/pkgs/pkgs-lib/formats.nix
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/pkgs-lib/formats.nix')
-rw-r--r--pkgs/pkgs-lib/formats.nix121
1 files changed, 76 insertions, 45 deletions
diff --git a/pkgs/pkgs-lib/formats.nix b/pkgs/pkgs-lib/formats.nix
index c78bd82e01ef..1b72270b43ca 100644
--- a/pkgs/pkgs-lib/formats.nix
+++ b/pkgs/pkgs-lib/formats.nix
@@ -95,29 +95,13 @@ rec {
 
   };
 
-  ini = {
-    # Represents lists as duplicate keys
-    listsAsDuplicateKeys ? false,
-    # Alternative to listsAsDuplicateKeys, converts list to non-list
-    # listToValue :: [IniAtom] -> IniAtom
-    listToValue ? null,
-    ...
-    }@args:
-    assert !listsAsDuplicateKeys || listToValue == null;
-    {
-
-    type = with lib.types; let
-
-      singleIniAtom = nullOr (oneOf [
-        bool
-        int
-        float
-        str
-      ]) // {
+  # the ini formats share a lot of code
+  inherit (
+    let
+      singleIniAtom = with lib.types; nullOr (oneOf [ bool int float str ]) // {
         description = "INI atom (null, bool, int, float or string)";
       };
-
-      iniAtom =
+      iniAtom = with lib.types; { listsAsDuplicateKeys, listToValue }:
         if listsAsDuplicateKeys then
           coercedTo singleIniAtom lib.singleton (listOf singleIniAtom) // {
             description = singleIniAtom.description + " or a list of them for duplicate keys";
@@ -128,21 +112,79 @@ rec {
           }
         else
           singleIniAtom;
+      iniSection = with lib.types; { listsAsDuplicateKeys, listToValue }@args:
+        attrsOf (iniAtom args) // {
+          description = "section of an INI file (attrs of " + (iniAtom args).description + ")";
+        };
 
-    in attrsOf (attrsOf iniAtom);
+      maybeToList = listToValue: if listToValue != null then lib.mapAttrs (key: val: if lib.isList val then listToValue val else val) else lib.id;
+    in {
+      ini = {
+        # Represents lists as duplicate keys
+        listsAsDuplicateKeys ? false,
+        # Alternative to listsAsDuplicateKeys, converts list to non-list
+        # listToValue :: [IniAtom] -> IniAtom
+        listToValue ? null,
+        ...
+        }@args:
+        assert listsAsDuplicateKeys -> listToValue == null;
+        {
 
-    generate = name: value:
-      let
-        transformedValue =
-          if listToValue != null
-          then
-            lib.mapAttrs (section: lib.mapAttrs (key: val:
-              if lib.isList val then listToValue val else val
-            )) value
-          else value;
-      in pkgs.writeText name (lib.generators.toINI (removeAttrs args ["listToValue"]) transformedValue);
+        type = lib.types.attrsOf (iniSection { listsAsDuplicateKeys = listsAsDuplicateKeys; listToValue = listToValue; });
 
-  };
+        generate = name: value:
+          lib.pipe value
+          [
+            (lib.mapAttrs (_: maybeToList listToValue))
+            (lib.generators.toINI (removeAttrs args ["listToValue"]))
+            (pkgs.writeText name)
+          ];
+      };
+
+      iniWithGlobalSection = {
+        # Represents lists as duplicate keys
+        listsAsDuplicateKeys ? false,
+        # Alternative to listsAsDuplicateKeys, converts list to non-list
+        # listToValue :: [IniAtom] -> IniAtom
+        listToValue ? null,
+        ...
+        }@args:
+        assert listsAsDuplicateKeys -> listToValue == null;
+        {
+          type = lib.types.submodule {
+            options = {
+              sections = lib.mkOption rec {
+                type = lib.types.attrsOf (iniSection { listsAsDuplicateKeys = listsAsDuplicateKeys; listToValue = listToValue; });
+                default = {};
+                description = type.description;
+              };
+              globalSection = lib.mkOption rec {
+                type = iniSection { listsAsDuplicateKeys = listsAsDuplicateKeys; listToValue = listToValue; };
+                default = {};
+                description = "global " + type.description;
+              };
+            };
+          };
+          generate = name: { sections ? {}, globalSection ? {}, ... }:
+            pkgs.writeText name (lib.generators.toINIWithGlobalSection (removeAttrs args ["listToValue"])
+            {
+              globalSection = maybeToList listToValue globalSection;
+              sections = lib.mapAttrs (_: maybeToList listToValue) sections;
+            });
+        };
+
+      gitIni = { listsAsDuplicateKeys ? false, ... }@args: {
+        type = let
+          atom = iniAtom {
+            listsAsDuplicateKeys = listsAsDuplicateKeys;
+            listToValue = null;
+          };
+        in with lib.types; attrsOf (attrsOf (either atom (attrsOf atom)));
+
+        generate = name: value: pkgs.writeText name (lib.generators.toGitINI value);
+      };
+
+    }) ini iniWithGlobalSection gitIni;
 
   # As defined by systemd.syntax(7)
   #
@@ -166,7 +208,7 @@ rec {
     listToValue ? null,
     ...
     }@args:
-    assert !listsAsDuplicateKeys || listToValue == null;
+    assert listsAsDuplicateKeys -> listToValue == null;
     {
 
     type = with lib.types; let
@@ -207,17 +249,6 @@ rec {
 
   };
 
-  gitIni = { listsAsDuplicateKeys ? false, ... }@args: {
-
-    type = with lib.types; let
-
-      iniAtom = (ini args).type/*attrsOf*/.functor.wrapped/*attrsOf*/.functor.wrapped;
-
-    in attrsOf (attrsOf (either iniAtom (attrsOf iniAtom)));
-
-    generate = name: value: pkgs.writeText name (lib.generators.toGitINI value);
-  };
-
   toml = {}: json {} // {
     type = with lib.types; let
       valueType = oneOf [