about summary refs log tree commit diff
path: root/nixpkgs/lib/generators.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/lib/generators.nix')
-rw-r--r--nixpkgs/lib/generators.nix209
1 files changed, 133 insertions, 76 deletions
diff --git a/nixpkgs/lib/generators.nix b/nixpkgs/lib/generators.nix
index ed59654cc07e..5f42a98de709 100644
--- a/nixpkgs/lib/generators.nix
+++ b/nixpkgs/lib/generators.nix
@@ -14,15 +14,58 @@
  * Documentation in the manual, #sec-generators
  */
 { lib }:
-with (lib).trivial;
-let
-  libStr = lib.strings;
-  libAttr = lib.attrsets;
-
-  inherit (lib) isFunction;
-in
 
-rec {
+let
+  inherit (lib)
+    addErrorContext
+    assertMsg
+    attrNames
+    concatLists
+    concatMapStringsSep
+    concatStrings
+    concatStringsSep
+    const
+    elem
+    escape
+    filter
+    flatten
+    foldl
+    functionArgs  # Note: not the builtin; considers `__functor` in attrsets.
+    gvariant
+    hasInfix
+    head
+    id
+    init
+    isAttrs
+    isBool
+    isDerivation
+    isFloat
+    isFunction    # Note: not the builtin; considers `__functor` in attrsets.
+    isInt
+    isList
+    isPath
+    isString
+    last
+    length
+    mapAttrs
+    mapAttrsToList
+    optionals
+    recursiveUpdate
+    replaceStrings
+    reverseList
+    splitString
+    tail
+    toList
+    ;
+
+  inherit (lib.strings)
+    escapeNixIdentifier
+    floatToString
+    match
+    split
+    toJSON
+    typeOf
+    ;
 
   ## -- HELPER FUNCTIONS & DEFAULTS --
 
@@ -30,13 +73,13 @@ rec {
    * The builtin `toString` function has some strange defaults,
    * suitable for bash scripts but not much else.
    */
-  mkValueStringDefault = {}: v: with builtins;
+  mkValueStringDefault = {}: v:
     let err = t: v: abort
           ("generators.mkValueStringDefault: " +
            "${t} not supported: ${toPretty {} v}");
     in   if isInt      v then toString v
     # convert derivations to store paths
-    else if lib.isDerivation v then toString v
+    else if isDerivation v then toString v
     # we default to not quoting strings
     else if isString   v then v
     # isString returns "1", which is not a good default
@@ -53,7 +96,7 @@ rec {
     # Floats currently can't be converted to precise strings,
     # condition warning on nix version once this isn't a problem anymore
     # See https://github.com/NixOS/nix/pull/3480
-    else if isFloat    v then libStr.floatToString v
+    else if isFloat    v then floatToString v
     else err "this value is" (toString v);
 
 
@@ -69,7 +112,7 @@ rec {
   mkKeyValueDefault = {
     mkValueString ? mkValueStringDefault {}
   }: sep: k: v:
-    "${libStr.escape [sep] k}${sep}${mkValueString v}";
+    "${escape [sep] k}${sep}${mkValueString v}";
 
 
   ## -- FILE FORMAT GENERATORS --
@@ -86,9 +129,9 @@ rec {
   }:
   let mkLine = k: v: indent + mkKeyValue k v + "\n";
       mkLines = if listsAsDuplicateKeys
-        then k: v: map (mkLine k) (if lib.isList v then v else [v])
+        then k: v: map (mkLine k) (if isList v then v else [v])
         else k: v: [ (mkLine k v) ];
-  in attrs: libStr.concatStrings (lib.concatLists (libAttr.mapAttrsToList mkLines attrs));
+  in attrs: concatStrings (concatLists (mapAttrsToList mkLines attrs));
 
 
   /* Generate an INI-style config file from an
@@ -113,7 +156,7 @@ rec {
    */
   toINI = {
     # apply transformations (e.g. escapes) to section names
-    mkSectionName ? (name: libStr.escape [ "[" "]" ] name),
+    mkSectionName ? (name: escape [ "[" "]" ] name),
     # format a setting line from key and value
     mkKeyValue    ? mkKeyValueDefault {} "=",
     # allow lists as values for duplicate keys
@@ -122,8 +165,8 @@ rec {
     let
         # map function to string for each key val
         mapAttrsToStringsSep = sep: mapFn: attrs:
-          libStr.concatStringsSep sep
-            (libAttr.mapAttrsToList mapFn attrs);
+          concatStringsSep sep
+            (mapAttrsToList mapFn attrs);
         mkSection = sectName: sectValues: ''
           [${mkSectionName sectName}]
         '' + toKeyValue { inherit mkKeyValue listsAsDuplicateKeys; } sectValues;
@@ -164,7 +207,7 @@ rec {
    */
   toINIWithGlobalSection = {
     # apply transformations (e.g. escapes) to section names
-    mkSectionName ? (name: libStr.escape [ "[" "]" ] name),
+    mkSectionName ? (name: escape [ "[" "]" ] name),
     # format a setting line from key and value
     mkKeyValue    ? mkKeyValueDefault {} "=",
     # allow lists as values for duplicate keys
@@ -195,12 +238,11 @@ rec {
    *>   name = "edolstra"
    */
   toGitINI = attrs:
-    with builtins;
     let
       mkSectionName = name:
         let
-          containsQuote = libStr.hasInfix ''"'' name;
-          sections = libStr.splitString "." name;
+          containsQuote = hasInfix ''"'' name;
+          sections = splitString "." name;
           section = head sections;
           subsections = tail sections;
           subsection = concatStringsSep "." subsections;
@@ -220,19 +262,19 @@ rec {
       # generation for multiple ini values
       mkKeyValue = k: v:
         let mkKeyValue = mkKeyValueDefault { inherit mkValueString; } " = " k;
-        in concatStringsSep "\n" (map (kv: "\t" + mkKeyValue kv) (lib.toList v));
+        in concatStringsSep "\n" (map (kv: "\t" + mkKeyValue kv) (toList v));
 
       # converts { a.b.c = 5; } to { "a.b".c = 5; } for toINI
       gitFlattenAttrs = let
         recurse = path: value:
-          if isAttrs value && !lib.isDerivation value then
-            lib.mapAttrsToList (name: value: recurse ([ name ] ++ path) value) value
+          if isAttrs value && !isDerivation value then
+            mapAttrsToList (name: value: recurse ([ name ] ++ path) value) value
           else if length path > 1 then {
-            ${concatStringsSep "." (lib.reverseList (tail path))}.${head path} = value;
+            ${concatStringsSep "." (reverseList (tail path))}.${head path} = value;
           } else {
             ${head path} = value;
           };
-      in attrs: lib.foldl lib.recursiveUpdate { } (lib.flatten (recurse [ ] attrs));
+      in attrs: foldl recursiveUpdate { } (flatten (recurse [ ] attrs));
 
       toINI_ = toINI { inherit mkKeyValue mkSectionName; };
     in
@@ -240,25 +282,12 @@ rec {
 
   # mkKeyValueDefault wrapper that handles dconf INI quirks.
   # The main differences of the format is that it requires strings to be quoted.
-  mkDconfKeyValue = mkKeyValueDefault { mkValueString = v: toString (lib.gvariant.mkValue v); } "=";
+  mkDconfKeyValue = mkKeyValueDefault { mkValueString = v: toString (gvariant.mkValue v); } "=";
 
   # Generates INI in dconf keyfile style. See https://help.gnome.org/admin/system-admin-guide/stable/dconf-keyfiles.html.en
   # for details.
   toDconfINI = toINI { mkKeyValue = mkDconfKeyValue; };
 
-  /* Generates JSON from an arbitrary (non-function) value.
-    * For more information see the documentation of the builtin.
-    */
-  toJSON = {}: builtins.toJSON;
-
-
-  /* YAML has been a strict superset of JSON since 1.2, so we
-    * use toJSON. Before it only had a few differences referring
-    * to implicit typing rules, so it should work with older
-    * parsers as well.
-    */
-  toYAML = toJSON;
-
   withRecursion =
     {
       /* If this option is not null, the given value will stop evaluating at a certain depth */
@@ -266,7 +295,7 @@ rec {
       /* If this option is true, an error will be thrown, if a certain given depth is exceeded */
     , throwOnDepthLimit ? true
     }:
-      assert builtins.isInt depthLimit;
+      assert isInt depthLimit;
       let
         specialAttrs = [
           "__functor"
@@ -275,7 +304,7 @@ rec {
           "__pretty"
         ];
         stepIntoAttr = evalNext: name:
-          if builtins.elem name specialAttrs
+          if elem name specialAttrs
             then id
             else evalNext;
         transform = depth:
@@ -284,7 +313,7 @@ rec {
               then throw "Exceeded maximum eval-depth limit of ${toString depthLimit} while trying to evaluate with `generators.withRecursion'!"
               else const "<unevaluated>"
           else id;
-        mapAny = with builtins; depth: v:
+        mapAny = depth: v:
           let
             evalNext = x: mapAny (depth + 1) (transform (depth + 1) x);
           in
@@ -311,9 +340,8 @@ rec {
     indent ? ""
   }:
     let
-    go = indent: v: with builtins;
-    let     isPath   = v: typeOf v == "path";
-            introSpace = if multiline then "\n${indent}  " else " ";
+    go = indent: v:
+    let     introSpace = if multiline then "\n${indent}  " else " ";
             outroSpace = if multiline then "\n${indent}" else " ";
     in if   isInt      v then toString v
     # toString loses precision on floats, so we use toJSON instead. This isn't perfect
@@ -322,16 +350,16 @@ rec {
     else if isFloat    v then builtins.toJSON v
     else if isString   v then
       let
-        lines = filter (v: ! isList v) (builtins.split "\n" v);
-        escapeSingleline = libStr.escape [ "\\" "\"" "\${" ];
-        escapeMultiline = libStr.replaceStrings [ "\${" "''" ] [ "''\${" "'''" ];
+        lines = filter (v: ! isList v) (split "\n" v);
+        escapeSingleline = escape [ "\\" "\"" "\${" ];
+        escapeMultiline = replaceStrings [ "\${" "''" ] [ "''\${" "'''" ];
         singlelineResult = "\"" + concatStringsSep "\\n" (map escapeSingleline lines) + "\"";
         multilineResult = let
           escapedLines = map escapeMultiline lines;
           # The last line gets a special treatment: if it's empty, '' is on its own line at the "outer"
           # indentation level. Otherwise, '' is appended to the last line.
-          lastLine = lib.last escapedLines;
-        in "''" + introSpace + concatStringsSep introSpace (lib.init escapedLines)
+          lastLine = last escapedLines;
+        in "''" + introSpace + concatStringsSep introSpace (init escapedLines)
                 + (if lastLine == "" then outroSpace else introSpace + lastLine) + "''";
       in
         if multiline && length lines > 1 then multilineResult else singlelineResult
@@ -342,11 +370,11 @@ rec {
     else if isList     v then
       if v == [] then "[ ]"
       else "[" + introSpace
-        + libStr.concatMapStringsSep introSpace (go (indent + "  ")) v
+        + concatMapStringsSep introSpace (go (indent + "  ")) v
         + outroSpace + "]"
     else if isFunction v then
-      let fna = lib.functionArgs v;
-          showFnas = concatStringsSep ", " (libAttr.mapAttrsToList
+      let fna = functionArgs v;
+          showFnas = concatStringsSep ", " (mapAttrsToList
                        (name: hasDefVal: if hasDefVal then name + "?" else name)
                        fna);
       in if fna == {}    then "<function>"
@@ -359,10 +387,10 @@ rec {
       else if v ? type && v.type == "derivation" then
         "<derivation ${v.name or "???"}>"
       else "{" + introSpace
-          + libStr.concatStringsSep introSpace (libAttr.mapAttrsToList
+          + concatStringsSep introSpace (mapAttrsToList
               (name: value:
-                "${libStr.escapeNixIdentifier name} = ${
-                  builtins.addErrorContext "while evaluating an attribute `${name}`"
+                "${escapeNixIdentifier name} = ${
+                  addErrorContext "while evaluating an attribute `${name}`"
                     (go (indent + "  ") value)
                 };") v)
         + outroSpace + "}"
@@ -371,9 +399,7 @@ rec {
 
   # PLIST handling
   toPlist = {}: v: let
-    isFloat = builtins.isFloat or (x: false);
-    isPath = x: builtins.typeOf x == "path";
-    expr = ind: x:  with builtins;
+    expr = ind: x:
       if x == null  then "" else
       if isBool x   then bool ind x else
       if isInt x    then int ind x else
@@ -394,23 +420,23 @@ rec {
 
     indent = ind: expr "\t${ind}";
 
-    item = ind: libStr.concatMapStringsSep "\n" (indent ind);
+    item = ind: concatMapStringsSep "\n" (indent ind);
 
-    list = ind: x: libStr.concatStringsSep "\n" [
+    list = ind: x: concatStringsSep "\n" [
       (literal ind "<array>")
       (item ind x)
       (literal ind "</array>")
     ];
 
-    attrs = ind: x: libStr.concatStringsSep "\n" [
+    attrs = ind: x: concatStringsSep "\n" [
       (literal ind "<dict>")
       (attr ind x)
       (literal ind "</dict>")
     ];
 
     attr = let attrFilter = name: value: name != "_module" && value != null;
-    in ind: x: libStr.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList
-      (name: value: lib.optionals (attrFilter name value) [
+    in ind: x: concatStringsSep "\n" (flatten (mapAttrsToList
+      (name: value: optionals (attrFilter name value) [
       (key "\t${ind}" name)
       (expr "\t${ind}" value)
     ]) x));
@@ -426,11 +452,10 @@ ${expr "" v}
    * the Natural type.
   */
   toDhall = { }@args: v:
-    with builtins;
-    let concatItems = lib.strings.concatStringsSep ", ";
+    let concatItems = concatStringsSep ", ";
     in if isAttrs v then
       "{ ${
-        concatItems (lib.attrsets.mapAttrsToList
+        concatItems (mapAttrsToList
           (key: value: "${key} = ${toDhall args value}") v)
       } }"
     else if isList v then
@@ -444,7 +469,7 @@ ${expr "" v}
     else if v == null then
       abort "generators.toDhall: cannot convert a null to Dhall"
     else
-      builtins.toJSON v;
+      toJSON v;
 
   /*
    Translate a simple Nix expression to Lua representation with occasional
@@ -488,7 +513,6 @@ ${expr "" v}
     /* Interpret as variable bindings */
     asBindings ? false,
   }@args: v:
-    with builtins;
     let
       innerIndent = "${indent}  ";
       introSpace = if multiline then "\n${innerIndent}" else " ";
@@ -501,9 +525,9 @@ ${expr "" v}
       isLuaInline = { _type ? null, ... }: _type == "lua-inline";
 
       generatedBindings =
-          assert lib.assertMsg (badVarNames == []) "Bad Lua var names: ${toPretty {} badVarNames}";
-          libStr.concatStrings (
-            lib.attrsets.mapAttrsToList (key: value: "${indent}${key} = ${toLua innerArgs value}\n") v
+          assert assertMsg (badVarNames == []) "Bad Lua var names: ${toPretty {} badVarNames}";
+          concatStrings (
+            mapAttrsToList (key: value: "${indent}${key} = ${toLua innerArgs value}\n") v
             );
 
       # https://en.wikibooks.org/wiki/Lua_Programming/variable#Variable_names
@@ -515,7 +539,7 @@ ${expr "" v}
     else if v == null then
       "nil"
     else if isInt v || isFloat v || isString v || isBool v then
-      builtins.toJSON v
+      toJSON v
     else if isList v then
       (if v == [ ] then "{}" else
       "{${introSpace}${concatItems (map (value: "${toLua innerArgs value}") v)}${outroSpace}}")
@@ -525,11 +549,11 @@ ${expr "" v}
           "(${v.expr})"
         else if v == { } then
           "{}"
-        else if libAttr.isDerivation v then
+        else if isDerivation v then
           ''"${toString v}"''
         else
           "{${introSpace}${concatItems (
-            lib.attrsets.mapAttrsToList (key: value: "[${builtins.toJSON key}] = ${toLua innerArgs value}") v
+            mapAttrsToList (key: value: "[${toJSON key}] = ${toLua innerArgs value}") v
             )}${outroSpace}}"
       )
     else
@@ -542,4 +566,37 @@ ${expr "" v}
      mkLuaInline :: String -> AttrSet
   */
   mkLuaInline = expr: { _type = "lua-inline"; inherit expr; };
+
+in
+
+# Everything in this attrset is the public interface of the file.
+{
+  inherit
+    mkDconfKeyValue
+    mkKeyValueDefault
+    mkLuaInline
+    mkValueStringDefault
+    toDconfINI
+    toDhall
+    toGitINI
+    toINI
+    toINIWithGlobalSection
+    toKeyValue
+    toLua
+    toPlist
+    toPretty
+    withRecursion
+    ;
+
+  /* Generates JSON from an arbitrary (non-function) value.
+    * For more information see the documentation of the builtin.
+    */
+  toJSON = {}: toJSON;
+
+  /* YAML has been a strict superset of JSON since 1.2, so we
+    * use toJSON. Before it only had a few differences referring
+    * to implicit typing rules, so it should work with older
+    * parsers as well.
+    */
+  toYAML = {}: toJSON;
 }