From 7daf0c6ef12a0fbeedb53ed683c93478764fe1ab Mon Sep 17 00:00:00 2001
From: regnat <rg@regnat.ovh>
Date: Tue, 29 Jun 2021 14:52:46 +0200
Subject: [PATCH] Forward the experimental features to the nix repl
 subprocesses
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Pass the current experimental features using `NIX_CONFIG` to the various
Nix subprocesses that `nix repl` invokes.

This is quite a hack, but having `nix repl` call Nix with a subprocess
is a hack already, so I guess that’s fine.
---
 src/nix/repl.cc | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index eed79c332..0275feae7 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -104,6 +104,26 @@ NixRepl::~NixRepl()
     write_history(historyFile.c_str());
 }
 
+string runNix(Path program, const Strings & args,
+    const std::optional<std::string> & input = {})
+{
+    auto experimentalFeatures = concatStringsSep(" ", settings.experimentalFeatures.get());
+    auto nixConf = getEnv("NIX_CONFIG").value_or("");
+    nixConf.append("\nexperimental-features = " + experimentalFeatures);
+    auto subprocessEnv = getEnv();
+    subprocessEnv["NIX_CONFIG"] = nixConf;
+    RunOptions opts(settings.nixBinDir+ "/" + program, args);
+    opts.input = input;
+    opts.environment = subprocessEnv;
+
+    auto res = runProgram(opts);
+
+    if (!statusOk(res.first))
+        throw ExecError(res.first, fmt("program '%1%' %2%", program, statusToString(res.first)));
+
+    return res.second;
+}
+
 static NixRepl * curRepl; // ugly
 
 static char * completionCallback(char * s, int *match) {
@@ -463,7 +483,7 @@ bool NixRepl::processLine(string line)
         state->callFunction(f, v, result, Pos());
 
         StorePath drvPath = getDerivationPath(result);
-        runProgram(settings.nixBinDir + "/nix-shell", true, {state->store->printStorePath(drvPath)});
+        runNix("nix-shell", {state->store->printStorePath(drvPath)});
     }
 
     else if (command == ":b" || command == ":i" || command == ":s") {
@@ -477,7 +497,7 @@ bool NixRepl::processLine(string line)
                but doing it in a child makes it easier to recover from
                problems / SIGINT. */
             try {
-                runProgram(settings.nixBinDir + "/nix", true, {"build", "--no-link", drvPathRaw});
+                runNix("nix", {"build", "--no-link", drvPathRaw});
                 auto drv = state->store->readDerivation(drvPath);
                 std::cout << std::endl << "this derivation produced the following outputs:" << std::endl;
                 for (auto & i : drv.outputsAndOptPaths(*state->store))
@@ -485,9 +505,9 @@ bool NixRepl::processLine(string line)
             } catch (ExecError &) {
             }
         } else if (command == ":i") {
-            runProgram(settings.nixBinDir + "/nix-env", true, {"-i", drvPathRaw});
+            runNix("nix-env", {"-i", drvPathRaw});
         } else {
-            runProgram(settings.nixBinDir + "/nix-shell", true, {drvPathRaw});
+            runNix("nix-shell", {drvPathRaw});
         }
     }