From 0f6231702fc1ccde0130bcbf297ff415d17b06d8 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Fri, 4 Sep 2020 17:19:55 +0200 Subject: lib/generators.toPretty: Only quote attribute names if necessary --- lib/generators.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/generators.nix') diff --git a/lib/generators.nix b/lib/generators.nix index abd237eb7d3..800ef5be4fc 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -227,7 +227,7 @@ rec { else "{ " + libStr.concatStringsSep " " (libAttr.mapAttrsToList (name: value: - "${toPretty args name} = ${toPretty args value};") v) + "${libStr.escapeNixIdentifier name} = ${toPretty args value};") v) + " }" else if isFunction v then let fna = lib.functionArgs v; -- cgit 1.4.1 From 4811f54e94756d8a83ee9fb439e56675033923ae Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Fri, 4 Sep 2020 17:23:28 +0200 Subject: lib/generators.toPretty: Wrap in a go function As a preparation to the following commit --- lib/generators.nix | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'lib/generators.nix') diff --git a/lib/generators.nix b/lib/generators.nix index 800ef5be4fc..e6b9b6b66c8 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -204,7 +204,7 @@ rec { will use fn to convert val to a pretty printed representation. (This means fn is type Val -> String.) */ allowPrettyValues ? false - }@args: v: with builtins; + }@args: let go = v: with builtins; let isPath = v: typeOf v == "path"; in if isInt v then toString v else if isFloat v then "~${toString v}" @@ -214,7 +214,7 @@ rec { else if null == v then "null" else if isPath v then toString v else if isList v then "[ " - + libStr.concatMapStringsSep " " (toPretty args) v + + libStr.concatMapStringsSep " " go v + " ]" else if isAttrs v then # apply pretty values if allowed @@ -227,7 +227,7 @@ rec { else "{ " + libStr.concatStringsSep " " (libAttr.mapAttrsToList (name: value: - "${libStr.escapeNixIdentifier name} = ${toPretty args value};") v) + "${libStr.escapeNixIdentifier name} = ${go value};") v) + " }" else if isFunction v then let fna = lib.functionArgs v; @@ -237,6 +237,7 @@ rec { in if fna == {} then "<λ>" else "<λ:{${showFnas}}>" else abort "generators.toPretty: should never happen (v = ${v})"; + in go; # PLIST handling toPlist = {}: v: let -- cgit 1.4.1 From 47f2eb89c16a74881c6e1a3b18290bf3d0f94a60 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Fri, 4 Sep 2020 17:46:12 +0200 Subject: lib/generators.toPretty: Implement multiline printing --- lib/generators.nix | 25 +++++++++++++++---------- lib/tests/misc.nix | 26 +++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 11 deletions(-) (limited to 'lib/generators.nix') diff --git a/lib/generators.nix b/lib/generators.nix index e6b9b6b66c8..23a74c757f8 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -203,9 +203,14 @@ rec { /* If this option is true, attrsets like { __pretty = fn; val = …; } will use fn to convert val to a pretty printed representation. (This means fn is type Val -> String.) */ - allowPrettyValues ? false - }@args: let go = v: with builtins; + allowPrettyValues ? false, + /* If this option is true, the output is indented with newlines for attribute sets and lists */ + multiline ? true + }@args: let + go = indent: v: with builtins; let isPath = v: typeOf v == "path"; + introSpace = if multiline then "\n${indent} " else " "; + outroSpace = if multiline then "\n${indent}" else " "; in if isInt v then toString v else if isFloat v then "~${toString v}" else if isString v then ''"${libStr.escape [''"''] v}"'' @@ -213,9 +218,9 @@ rec { else if false == v then "false" else if null == v then "null" else if isPath v then toString v - else if isList v then "[ " - + libStr.concatMapStringsSep " " go v - + " ]" + else if isList v then "[" + introSpace + + libStr.concatMapStringsSep introSpace (go (indent + " ")) v + + outroSpace + "]" else if isAttrs v then # apply pretty values if allowed if attrNames v == [ "__pretty" "val" ] && allowPrettyValues @@ -224,11 +229,11 @@ rec { else if v ? type && v.type == "derivation" then "<δ:${v.name}>" # "<δ:${concatStringsSep "," (builtins.attrNames v)}>" - else "{ " - + libStr.concatStringsSep " " (libAttr.mapAttrsToList + else "{" + introSpace + + libStr.concatStringsSep introSpace (libAttr.mapAttrsToList (name: value: - "${libStr.escapeNixIdentifier name} = ${go value};") v) - + " }" + "${libStr.escapeNixIdentifier name} = ${go (indent + " ") value};") v) + + outroSpace + "}" else if isFunction v then let fna = lib.functionArgs v; showFnas = concatStringsSep "," (libAttr.mapAttrsToList @@ -237,7 +242,7 @@ rec { in if fna == {} then "<λ>" else "<λ:{${showFnas}}>" else abort "generators.toPretty: should never happen (v = ${v})"; - in go; + in go ""; # PLIST handling toPlist = {}: v: let diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 7d7380e8b74..4fed8ef01c9 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -446,7 +446,7 @@ runTests { }; testToPretty = { - expr = mapAttrs (const (generators.toPretty {})) rec { + expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec { int = 42; float = 0.1337; bool = true; @@ -474,6 +474,30 @@ runTests { }; }; + testToPrettyMultiline = { + expr = mapAttrs (const (generators.toPretty { })) rec { + list = [ 3 4 [ false ] ]; + attrs = { foo = null; bar.foo = "baz"; }; + }; + expected = rec { + list = '' + [ + 3 + 4 + [ + false + ] + ]''; + attrs = '' + { + bar = { + foo = "baz"; + }; + foo = null; + }''; + }; + }; + testToPrettyAllowPrettyValues = { expr = generators.toPretty { allowPrettyValues = true; } { __pretty = v: "«" + v + "»"; val = "foo"; }; -- cgit 1.4.1 From 073e9b2aed0f855ce26bd3a26dab044c0c17c817 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Thu, 17 Sep 2020 17:58:04 +0200 Subject: lib/generators.toPretty: Improved string printing, handling newlines --- lib/generators.nix | 14 +++++++++++++- lib/tests/misc.nix | 27 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) (limited to 'lib/generators.nix') diff --git a/lib/generators.nix b/lib/generators.nix index 23a74c757f8..81bedd13d80 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -213,7 +213,19 @@ rec { outroSpace = if multiline then "\n${indent}" else " "; in if isInt v then toString v else if isFloat v then "~${toString v}" - else if isString v then ''"${libStr.escape [''"''] v}"'' + else if isString v then + let + # Separate a string into its lines + newlineSplits = filter (v: ! isList v) (builtins.split "\n" v); + # For a '' string terminated by a \n, which happens when the closing '' is on a new line + multilineResult = "''" + introSpace + concatStringsSep introSpace (lib.init newlineSplits) + outroSpace + "''"; + # For a '' string not terminated by a \n, which happens when the closing '' is not on a new line + multilineResult' = "''" + introSpace + concatStringsSep introSpace newlineSplits + "''"; + # For single lines, replace all newlines with their escaped representation + singlelineResult = "\"" + libStr.escape [ "\"" ] (concatStringsSep "\\n" newlineSplits) + "\""; + in if multiline && length newlineSplits > 1 then + if lib.last newlineSplits == "" then multilineResult else multilineResult' + else singlelineResult else if true == v then "true" else if false == v then "false" else if null == v then "null" diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 4fed8ef01c9..813a8e7f815 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -450,7 +450,9 @@ runTests { int = 42; float = 0.1337; bool = true; + emptystring = ""; string = ''fno"rd''; + newlinestring = "\n"; path = /. + "/foo"; null_ = null; function = x: x; @@ -463,7 +465,9 @@ runTests { int = "42"; float = "~0.133700"; bool = "true"; + emptystring = ''""''; string = ''"fno\"rd"''; + newlinestring = "\"\\n\""; path = "/foo"; null_ = "null"; function = "<λ>"; @@ -478,6 +482,16 @@ runTests { expr = mapAttrs (const (generators.toPretty { })) rec { list = [ 3 4 [ false ] ]; attrs = { foo = null; bar.foo = "baz"; }; + newlinestring = "\n"; + multilinestring = '' + hello + there + test + ''; + multilinestring' = '' + hello + there + test''; }; expected = rec { list = '' @@ -495,6 +509,19 @@ runTests { }; foo = null; }''; + newlinestring = "''\n \n''"; + multilinestring = '' + ''' + hello + there + test + '''''; + multilinestring' = '' + ''' + hello + there + test'''''; + }; }; -- cgit 1.4.1 From d0be9e98109428e67e4b7fab3e49728cc6633073 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Thu, 17 Sep 2020 18:08:44 +0200 Subject: lib/generators.toPretty: Switch away from δ and λ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - These symbols can be confusing for those not familiar with them - There's no harm in making these more obvious - Terminals may not print them correctly either Also changes the function argument printing slightly to be more obvious --- lib/generators.nix | 12 +++++------- lib/tests/misc.nix | 13 ++++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'lib/generators.nix') diff --git a/lib/generators.nix b/lib/generators.nix index 81bedd13d80..205092a2681 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -237,10 +237,8 @@ rec { # apply pretty values if allowed if attrNames v == [ "__pretty" "val" ] && allowPrettyValues then v.__pretty v.val - # TODO: there is probably a better representation? else if v ? type && v.type == "derivation" then - "<δ:${v.name}>" - # "<δ:${concatStringsSep "," (builtins.attrNames v)}>" + "" else "{" + introSpace + libStr.concatStringsSep introSpace (libAttr.mapAttrsToList (name: value: @@ -248,11 +246,11 @@ rec { + outroSpace + "}" else if isFunction v then let fna = lib.functionArgs v; - showFnas = concatStringsSep "," (libAttr.mapAttrsToList - (name: hasDefVal: if hasDefVal then "(${name})" else name) + showFnas = concatStringsSep ", " (libAttr.mapAttrsToList + (name: hasDefVal: if hasDefVal then name + "?" else name) fna); - in if fna == {} then "<λ>" - else "<λ:{${showFnas}}>" + in if fna == {} then "" + else "" else abort "generators.toPretty: should never happen (v = ${v})"; in go ""; diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 813a8e7f815..2456b52c099 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -445,7 +445,10 @@ runTests { expected = builtins.toJSON val; }; - testToPretty = { + testToPretty = + let + deriv = derivation { name = "test"; builder = "/bin/sh"; system = builtins.currentSystem; }; + in { expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec { int = 42; float = 0.1337; @@ -459,7 +462,7 @@ runTests { functionArgs = { arg ? 4, foo }: arg; list = [ 3 4 function [ false ] ]; attrs = { foo = null; "foo bar" = "baz"; }; - drv = derivation { name = "test"; system = builtins.currentSystem; }; + drv = deriv; }; expected = rec { int = "42"; @@ -470,11 +473,11 @@ runTests { newlinestring = "\"\\n\""; path = "/foo"; null_ = "null"; - function = "<λ>"; - functionArgs = "<λ:{(arg),foo}>"; + function = ""; + functionArgs = ""; list = "[ 3 4 ${function} [ false ] ]"; attrs = "{ foo = null; \"foo bar\" = \"baz\"; }"; - drv = "<δ:test>"; + drv = ""; }; }; -- cgit 1.4.1 From 05e4d371ef5c3819b969d34eb76ed7e4b3c99027 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Thu, 17 Sep 2020 18:14:18 +0200 Subject: lib/generators.toPretty: Print [] and {} compactly --- lib/generators.nix | 7 +++++-- lib/tests/misc.nix | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'lib/generators.nix') diff --git a/lib/generators.nix b/lib/generators.nix index 205092a2681..716ae77973f 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -230,13 +230,16 @@ rec { else if false == v then "false" else if null == v then "null" else if isPath v then toString v - else if isList v then "[" + introSpace + else if isList v then + if v == [] then "[ ]" + else "[" + introSpace + libStr.concatMapStringsSep introSpace (go (indent + " ")) v - + outroSpace + "]" + + outroSpace + "]" else if isAttrs v then # apply pretty values if allowed if attrNames v == [ "__pretty" "val" ] && allowPrettyValues then v.__pretty v.val + else if v == {} then "{ }" else if v ? type && v.type == "derivation" then "" else "{" + introSpace diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 2456b52c099..f60e6ad1787 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -461,7 +461,9 @@ runTests { function = x: x; functionArgs = { arg ? 4, foo }: arg; list = [ 3 4 function [ false ] ]; + emptylist = []; attrs = { foo = null; "foo bar" = "baz"; }; + emptyattrs = {}; drv = deriv; }; expected = rec { @@ -476,7 +478,9 @@ runTests { function = ""; functionArgs = ""; list = "[ 3 4 ${function} [ false ] ]"; + emptylist = "[ ]"; attrs = "{ foo = null; \"foo bar\" = \"baz\"; }"; + emptyattrs = "{ }"; drv = ""; }; }; -- cgit 1.4.1 From 15c5ba9d28dbdcebd3320864b62fdc7f2b37defd Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Thu, 17 Sep 2020 18:18:50 +0200 Subject: lib/generators.toPretty: functors should print as functions Not attribute sets. So move the function case forward --- lib/generators.nix | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'lib/generators.nix') diff --git a/lib/generators.nix b/lib/generators.nix index 716ae77973f..501a23599f4 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -235,6 +235,13 @@ rec { else "[" + introSpace + libStr.concatMapStringsSep introSpace (go (indent + " ")) v + outroSpace + "]" + else if isFunction v then + let fna = lib.functionArgs v; + showFnas = concatStringsSep ", " (libAttr.mapAttrsToList + (name: hasDefVal: if hasDefVal then name + "?" else name) + fna); + in if fna == {} then "" + else "" else if isAttrs v then # apply pretty values if allowed if attrNames v == [ "__pretty" "val" ] && allowPrettyValues @@ -247,13 +254,6 @@ rec { (name: value: "${libStr.escapeNixIdentifier name} = ${go (indent + " ") value};") v) + outroSpace + "}" - else if isFunction v then - let fna = lib.functionArgs v; - showFnas = concatStringsSep ", " (libAttr.mapAttrsToList - (name: hasDefVal: if hasDefVal then name + "?" else name) - fna); - in if fna == {} then "" - else "" else abort "generators.toPretty: should never happen (v = ${v})"; in go ""; -- cgit 1.4.1 From d9a7d03da8c58aa863911506ae3153729f8931da Mon Sep 17 00:00:00 2001 From: sternenseemann <0rpkxez4ksa01gb3typccl0i@systemli.org> Date: Sun, 31 Jan 2021 14:25:07 +0100 Subject: lib/generators: fix toPretty throwing on (partially applied) builtins An high level example case of this problem occuring can be found below: nix-repl> lib.generators.toPretty {} (lib.concatStringsSep "\n") error: 'functionArgs' requires a function, at /home/lukas/src/nix/nixpkgs/lib/trivial.nix:334:42 However this does not happen on other partially applied functions: nix-repl> lib.generators.toPretty {} (lib.concatMapStringsSep "\n") "" The issue, as it turns out is that while builtins are functions, builtins.functionArgs throws if is passed a builtin or a partially applied builtin: nix-repl> lib.generators.toPretty {} builtins.toString error: 'functionArgs' requires a function, at /home/lukas/src/nix/nixpkgs/lib/trivial.nix:334:42 nix-repl> lib.generators.toPretty {} (builtins.foldl' (a: b: a + b)) error: 'functionArgs' requires a function, at /home/lukas/src/nix/nixpkgs/lib/trivial.nix:334:42 I'm pretty sure this qualifies as a nix bug and should be filed accordingly, but we can work around it in lib.generators.toPretty by using tryEval and falling back to {} which functionArgs _should_ return for builtins. The nix behavior is inconsistent to say the least: nix-repl> builtins.functionArgs builtins.functionArgs error: 'functionArgs' requires a function, at (string):1:1 nix-repl> builtins.typeOf builtins.functionArgs "lambda" builtins.functionArgs (a: 1 + a) { } nix-repl> builtins.typeOf (a: 1 + a) "lambda" --- lib/generators.nix | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'lib/generators.nix') diff --git a/lib/generators.nix b/lib/generators.nix index 501a23599f4..9546f5b5b0a 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -236,12 +236,17 @@ rec { + libStr.concatMapStringsSep introSpace (go (indent + " ")) v + outroSpace + "]" else if isFunction v then - let fna = lib.functionArgs v; + # functionArgs throws in case of (partially applied) builtins + # on nix before commit b2748c6e99239ff6803ba0da76c362790c8be192 + # which includes current nix stable + # TODO remove tryEval workaround when the issue is resolved on nix stable + let fna = builtins.tryEval (lib.functionArgs v); showFnas = concatStringsSep ", " (libAttr.mapAttrsToList (name: hasDefVal: if hasDefVal then name + "?" else name) - fna); - in if fna == {} then "" - else "" + fna.value); + in if !fna.success || fna.value == {} + then "" + else "" else if isAttrs v then # apply pretty values if allowed if attrNames v == [ "__pretty" "val" ] && allowPrettyValues -- cgit 1.4.1 From 06d3b2898717877bb23ae32467dbebba9f307ac4 Mon Sep 17 00:00:00 2001 From: sternenseemann <0rpkxez4ksa01gb3typccl0i@systemli.org> Date: Mon, 1 Feb 2021 16:27:38 +0100 Subject: Revert "lib/generators: fix toPretty throwing on (partially applied) builtins" This reverts commit d9a7d03da8c58aa863911506ae3153729f8931da. Reason for this is that it actually doesn't migitate the issue on nix stable for another reason: builtins.tryEval doesn't prevent the error generated by builtins.functionArgs from halting evaluation: > builtins.tryEval (builtins.functionArgs builtins.functionArgs) error: 'functionArgs' requires a function, at (string):1:19 Thus it seems that there is no workaround to make lib.generators.toPretty work with nix stable and primops since there is no way to distinguish between primops and lambdas in nix. --- lib/generators.nix | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'lib/generators.nix') diff --git a/lib/generators.nix b/lib/generators.nix index 9546f5b5b0a..501a23599f4 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -236,17 +236,12 @@ rec { + libStr.concatMapStringsSep introSpace (go (indent + " ")) v + outroSpace + "]" else if isFunction v then - # functionArgs throws in case of (partially applied) builtins - # on nix before commit b2748c6e99239ff6803ba0da76c362790c8be192 - # which includes current nix stable - # TODO remove tryEval workaround when the issue is resolved on nix stable - let fna = builtins.tryEval (lib.functionArgs v); + let fna = lib.functionArgs v; showFnas = concatStringsSep ", " (libAttr.mapAttrsToList (name: hasDefVal: if hasDefVal then name + "?" else name) - fna.value); - in if !fna.success || fna.value == {} - then "" - else "" + fna); + in if fna == {} then "" + else "" else if isAttrs v then # apply pretty values if allowed if attrNames v == [ "__pretty" "val" ] && allowPrettyValues -- cgit 1.4.1 From 1cd48efa96bc677bfbf7111bd116d092521c3914 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Wed, 24 Mar 2021 11:20:36 +0100 Subject: lib/generators: add toDhall --- lib/generators.nix | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'lib/generators.nix') diff --git a/lib/generators.nix b/lib/generators.nix index 501a23599f4..c8144db50ac 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -307,4 +307,28 @@ rec { ${expr "" v} ''; + /* Translate a simple Nix expression to Dhall notation. + * Note that integers are translated to Integer and never + * the Natural type. + */ + toDhall = { }@args: v: + with builtins; + let concatItems = lib.strings.concatStringsSep ", "; + in if isAttrs v then + "{ ${ + concatItems (lib.attrsets.mapAttrsToList + (key: value: "${key} = ${toDhall args value}") v) + } }" + else if isList v then + "[ ${concatItems (map (toDhall args) v)} ]" + else if isInt v then + "${if v < 0 then "" else "+"}${toString v}" + else if isBool v then + (if v then "True" else "False") + else if isFunction v then + abort "generators.toDhall: cannot convert a function to Dhall" + else if isNull v then + abort "generators.toDhall: cannot convert a null to Dhall" + else + builtins.toJSON v; } -- cgit 1.4.1