diff --git a/src/libexpr/meson.build b/src/libexpr/meson.build index 622c4c625..73b2fb302 100644 --- a/src/libexpr/meson.build +++ b/src/libexpr/meson.build @@ -103,6 +103,7 @@ libexpr_sources = files( 'primops/path.cc', 'primops/string.cc', 'primops/system.cc', + 'primops/toXML.cc', 'primops/types.cc', 'value/context.cc', ) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ff0842299..d41867a62 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -186,110 +186,6 @@ static void derivationStrictInternal(EvalState & state, const std::string & name /* Convert the argument (which can be any Nix expression) to an XML representation returned in a string. Not all Nix expressions can be sensibly or completely represented (e.g., functions). */ -static void prim_toXML(EvalState & state, const PosIdx pos, Value * * args, Value & v) -{ - std::ostringstream out; - NixStringContext context; - printValueAsXML(state, true, false, *args[0], out, context, pos); - v.mkString(out.str(), context); -} - -static RegisterPrimOp primop_toXML({ - .name = "__toXML", - .args = {"e"}, - .doc = R"( - Return a string containing an XML representation of *e*. The main - application for `toXML` is to communicate information with the - builder in a more structured format than plain environment - variables. - - Here is an example where this is the case: - - ```nix - { stdenv, fetchurl, libxslt, jira, uberwiki }: - - stdenv.mkDerivation (rec { - name = "web-server"; - - buildInputs = [ libxslt ]; - - builder = builtins.toFile "builder.sh" " - source $stdenv/setup - mkdir $out - echo "$servlets" | xsltproc ${stylesheet} - > $out/server-conf.xml ① - "; - - stylesheet = builtins.toFile "stylesheet.xsl" ② - " - - - - - - - - - - - - - "; - - servlets = builtins.toXML [ ③ - { path = "/bugtracker"; war = jira + "/lib/atlassian-jira.war"; } - { path = "/wiki"; war = uberwiki + "/uberwiki.war"; } - ]; - }) - ``` - - The builder is supposed to generate the configuration file for a - [Jetty servlet container](http://jetty.mortbay.org/). A servlet - container contains a number of servlets (`*.war` files) each - exported under a specific URI prefix. So the servlet configuration - is a list of sets containing the `path` and `war` of the servlet - (①). This kind of information is difficult to communicate with the - normal method of passing information through an environment - variable, which just concatenates everything together into a - string (which might just work in this case, but wouldn’t work if - fields are optional or contain lists themselves). Instead the Nix - expression is converted to an XML representation with `toXML`, - which is unambiguous and can easily be processed with the - appropriate tools. For instance, in the example an XSLT stylesheet - (at point ②) is applied to it (at point ①) to generate the XML - configuration file for the Jetty server. The XML representation - produced at point ③ by `toXML` is as follows: - - ```xml - - - - - - - - - - - - - - - - - - - - - - ``` - - Note that we used the `toFile` built-in to write the builder and - the stylesheet “inline” in the Nix expression. The path of the - stylesheet is spliced into the builder using the syntax `xsltproc - ${stylesheet}`. - )", - .fun = prim_toXML, -}); /* Store a string in the Nix store as a source file that can be used diff --git a/src/libexpr/primops/toXML.cc b/src/libexpr/primops/toXML.cc new file mode 100644 index 000000000..6965c8254 --- /dev/null +++ b/src/libexpr/primops/toXML.cc @@ -0,0 +1,115 @@ +#include "primops.hh" +#include "value-to-xml.hh" + +namespace nix { + +/** + * builtins.toXML + */ + +static void prim_toXML(EvalState & state, const PosIdx pos, Value ** args, Value & v) +{ + std::ostringstream out; + NixStringContext context; + printValueAsXML(state, true, false, *args[0], out, context, pos); + v.mkString(out.str(), context); +} + +static RegisterPrimOp primop_toXML({ + .name = "__toXML", + .args = {"e"}, + .doc = R"( + Return a string containing an XML representation of *e*. The main + application for `toXML` is to communicate information with the + builder in a more structured format than plain environment + variables. + + Here is an example where this is the case: + + ```nix + { stdenv, fetchurl, libxslt, jira, uberwiki }: + + stdenv.mkDerivation (rec { + name = "web-server"; + + buildInputs = [ libxslt ]; + + builder = builtins.toFile "builder.sh" " + source $stdenv/setup + mkdir $out + echo "$servlets" | xsltproc ${stylesheet} - > $out/server-conf.xml ① + "; + + stylesheet = builtins.toFile "stylesheet.xsl" ② + " + + + + + + + + + + + + + "; + + servlets = builtins.toXML [ ③ + { path = "/bugtracker"; war = jira + "/lib/atlassian-jira.war"; } + { path = "/wiki"; war = uberwiki + "/uberwiki.war"; } + ]; + }) + ``` + + The builder is supposed to generate the configuration file for a + [Jetty servlet container](http://jetty.mortbay.org/). A servlet + container contains a number of servlets (`*.war` files) each + exported under a specific URI prefix. So the servlet configuration + is a list of sets containing the `path` and `war` of the servlet + (①). This kind of information is difficult to communicate with the + normal method of passing information through an environment + variable, which just concatenates everything together into a + string (which might just work in this case, but wouldn’t work if + fields are optional or contain lists themselves). Instead the Nix + expression is converted to an XML representation with `toXML`, + which is unambiguous and can easily be processed with the + appropriate tools. For instance, in the example an XSLT stylesheet + (at point ②) is applied to it (at point ①) to generate the XML + configuration file for the Jetty server. The XML representation + produced at point ③ by `toXML` is as follows: + + ```xml + + + + + + + + + + + + + + + + + + + + + + ``` + + Note that we used the `toFile` built-in to write the builder and + the stylesheet “inline” in the Nix expression. The path of the + stylesheet is spliced into the builder using the syntax `xsltproc + ${stylesheet}`. + )", + .fun = prim_toXML, +}); + +}