about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2015-02-17T13·42+0100
committerEelco Dolstra <eelco.dolstra@logicblox.com>2015-02-17T13·42+0100
commita70d275f3d25f6e1eb1b6d528ee07ecd7265ada5 (patch)
treea103bd4348be410ec66dbde0551ec3ad5d442a74
parent29e1ff675b6b8f1ba2cdcde599888ec3eebce9af (diff)
Allow passing attributes via files instead of environment variables
Closes #473.
-rw-r--r--doc/manual/expressions/advanced-attributes.xml21
-rw-r--r--src/libstore/build.cc20
-rw-r--r--tests/local.mk2
-rw-r--r--tests/pass-as-file.sh17
4 files changed, 55 insertions, 5 deletions
diff --git a/doc/manual/expressions/advanced-attributes.xml b/doc/manual/expressions/advanced-attributes.xml
index 274e36f5c1d0..fee35f0bef48 100644
--- a/doc/manual/expressions/advanced-attributes.xml
+++ b/doc/manual/expressions/advanced-attributes.xml
@@ -242,6 +242,27 @@ stdenv.mkDerivation {
   </varlistentry>
 
 
+  <varlistentry><term><varname>passAsFile</varname></term>
+
+    <listitem><para>A list of names of attributes that should be
+    passed via files rather than environment variables.  For example,
+    if you have
+
+    <programlisting>
+passAsFile = ["big"];
+big = "a very long string";
+    </programlisting>
+
+    then when the builder runs, the environment variable
+    <envar>big</envar> will contain the absolute path to a temporary
+    file containing <literal>a very long string</literal>. This is
+    useful when you need to pass large strings to a builder, since
+    most operating systems impose a limit on the size of the
+    environment (typically, a few hundred kilobyte).</para></listitem>
+
+  </varlistentry>
+
+
   <varlistentry><term><varname>preferLocalBuild</varname></term>
 
     <listitem><para>If this attribute is set to
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 4841c9373ede..0b1985828b52 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -1646,14 +1646,26 @@ void DerivationGoal::startBuilder()
     /* The maximum number of cores to utilize for parallel building. */
     env["NIX_BUILD_CORES"] = (format("%d") % settings.buildCores).str();
 
-    /* Add all bindings specified in the derivation. */
-    foreach (StringPairs::iterator, i, drv.env)
-        env[i->first] = i->second;
-
     /* Create a temporary directory where the build will take
        place. */
     tmpDir = createTempDir("", "nix-build-" + storePathToName(drvPath), false, false, 0700);
 
+    /* Add all bindings specified in the derivation via the
+       environments, except those listed in the passAsFile
+       attribute. Those are passed as file names pointing to
+       temporary files containing the contents. */
+    StringSet passAsFile = tokenizeString<StringSet>(get(drv.env, "passAsFile"));
+    int fileNr = 0;
+    for (auto & i : drv.env) {
+        if (passAsFile.find(i.first) == passAsFile.end()) {
+            env[i.first] = i.second;
+        } else {
+            Path p = tmpDir + "/.attr-" + int2String(fileNr++);
+            writeFile(p, i.second);
+            env[i.first] = p;
+        }
+    }
+
     /* For convenience, set an environment pointing to the top build
        directory. */
     env["NIX_BUILD_TOP"] = tmpDir;
diff --git a/tests/local.mk b/tests/local.mk
index 69a227495d94..7a24fadcb8b9 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -11,7 +11,7 @@ nix_tests = \
   binary-patching.sh timeout.sh secure-drv-outputs.sh nix-channel.sh \
   multiple-outputs.sh import-derivation.sh fetchurl.sh optimise-store.sh \
   binary-cache.sh nix-profile.sh repair.sh dump-db.sh case-hack.sh \
-  check-reqs.sh
+  check-reqs.sh pass-as-file.sh
   # parallel.sh
 
 install-tests += $(foreach x, $(nix_tests), tests/$(x))
diff --git a/tests/pass-as-file.sh b/tests/pass-as-file.sh
new file mode 100644
index 000000000000..b61576e05799
--- /dev/null
+++ b/tests/pass-as-file.sh
@@ -0,0 +1,17 @@
+source common.sh
+
+clearStore
+
+outPath=$(nix-build --no-out-link -E "
+with import ./config.nix;
+
+mkDerivation {
+  name = \"pass-as-file\";
+  passAsFile = [ \"foo\" ];
+  foo = [ \"xyzzy\" ];
+  builder = builtins.toFile \"builder.sh\" ''
+    [ \"\$(cat \$foo)\" = xyzzy ]
+    touch \$out
+  '';
+}
+")