aboutsummaryrefslogtreecommitdiff
path: root/src/nix
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix')
-rw-r--r--src/nix/develop.cc139
-rw-r--r--src/nix/get-env.sh17
-rw-r--r--src/nix/repl.cc32
3 files changed, 135 insertions, 53 deletions
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index 9aaa80822..a2ce9c8c1 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -15,7 +15,7 @@ struct Var
{
bool exported = true;
bool associative = false;
- std::string value; // quoted string or array
+ std::string quoted; // quoted string or array
};
struct BuildEnvironment
@@ -75,12 +75,12 @@ BuildEnvironment readEnvironment(const Path & path)
else if (std::regex_search(pos, file.cend(), match, varRegex, std::regex_constants::match_continuous)) {
pos = match[0].second;
- res.env.insert({match[1], Var { .exported = exported.count(match[1]) > 0, .value = match[2] }});
+ res.env.insert({match[1], Var { .exported = exported.count(match[1]) > 0, .quoted = match[2] }});
}
else if (std::regex_search(pos, file.cend(), match, assocArrayRegex, std::regex_constants::match_continuous)) {
pos = match[0].second;
- res.env.insert({match[1], Var { .associative = true, .value = match[2] }});
+ res.env.insert({match[1], Var { .associative = true, .quoted = match[2] }});
}
else if (std::regex_search(pos, file.cend(), match, functionRegex, std::regex_constants::match_continuous)) {
@@ -92,6 +92,8 @@ BuildEnvironment readEnvironment(const Path & path)
path, file.substr(pos - file.cbegin(), 60));
}
+ res.env.erase("__output");
+
return res;
}
@@ -125,27 +127,35 @@ StorePath getDerivationEnvironment(ref<Store> store, const StorePath & drvPath)
/* Rehash and write the derivation. FIXME: would be nice to use
'buildDerivation', but that's privileged. */
drv.name += "-env";
- for (auto & output : drv.outputs)
- drv.env.erase(output.first);
- drv.outputs = {{"out", DerivationOutput { .output = DerivationOutputInputAddressed { .path = StorePath::dummy }}}};
- drv.env["out"] = "";
- drv.env["_outputs_saved"] = drv.env["outputs"];
- drv.env["outputs"] = "out";
+ for (auto & output : drv.outputs) {
+ output.second = { .output = DerivationOutputInputAddressed { .path = StorePath::dummy } };
+ drv.env[output.first] = "";
+ }
drv.inputSrcs.insert(std::move(getEnvShPath));
Hash h = std::get<0>(hashDerivationModulo(*store, drv, true));
- auto shellOutPath = store->makeOutputPath("out", h, drv.name);
- drv.outputs.insert_or_assign("out", DerivationOutput { .output = DerivationOutputInputAddressed {
- .path = shellOutPath
- } });
- drv.env["out"] = store->printStorePath(shellOutPath);
- auto shellDrvPath2 = writeDerivation(store, drv);
- /* Build the derivation. */
- store->buildPaths({{shellDrvPath2}});
+ for (auto & output : drv.outputs) {
+ auto outPath = store->makeOutputPath(output.first, h, drv.name);
+ output.second = { .output = DerivationOutputInputAddressed { .path = outPath } };
+ drv.env[output.first] = store->printStorePath(outPath);
+ }
- assert(store->isValidPath(shellOutPath));
+ auto shellDrvPath = writeDerivation(*store, drv);
- return shellOutPath;
+ /* Build the derivation. */
+ store->buildPaths({{shellDrvPath}});
+
+ for (auto & [_0, outputAndOptPath] : drv.outputsAndOptPaths(*store)) {
+ auto & [_1, optPath] = outputAndOptPath;
+ assert(optPath);
+ auto & outPath = *optPath;
+ assert(store->isValidPath(outPath));
+ auto outPathS = store->toRealPath(outPath);
+ if (lstat(outPathS).st_size)
+ return outPath;
+ }
+
+ throw Error("get-env.sh failed to produce an environment");
}
struct Common : InstallableCommand, MixProfile
@@ -171,8 +181,12 @@ struct Common : InstallableCommand, MixProfile
"UID",
};
- void makeRcScript(const BuildEnvironment & buildEnvironment, std::ostream & out)
+ std::string makeRcScript(
+ const BuildEnvironment & buildEnvironment,
+ const Path & outputsDir = absPath(".") + "/outputs")
{
+ std::ostringstream out;
+
out << "unset shellHook\n";
out << "nix_saved_PATH=\"$PATH\"\n";
@@ -180,9 +194,9 @@ struct Common : InstallableCommand, MixProfile
for (auto & i : buildEnvironment.env) {
if (!ignoreVars.count(i.first) && !hasPrefix(i.first, "BASH_")) {
if (i.second.associative)
- out << fmt("declare -A %s=(%s)\n", i.first, i.second.value);
+ out << fmt("declare -A %s=(%s)\n", i.first, i.second.quoted);
else {
- out << fmt("%s=%s\n", i.first, i.second.value);
+ out << fmt("%s=%s\n", i.first, i.second.quoted);
if (i.second.exported)
out << fmt("export %s\n", i.first);
}
@@ -193,13 +207,26 @@ struct Common : InstallableCommand, MixProfile
out << buildEnvironment.bashFunctions << "\n";
- // FIXME: set outputs
-
out << "export NIX_BUILD_TOP=\"$(mktemp -d --tmpdir nix-shell.XXXXXX)\"\n";
for (auto & i : {"TMP", "TMPDIR", "TEMP", "TEMPDIR"})
out << fmt("export %s=\"$NIX_BUILD_TOP\"\n", i);
out << "eval \"$shellHook\"\n";
+
+ /* Substitute occurrences of output paths. */
+ auto outputs = buildEnvironment.env.find("outputs");
+ assert(outputs != buildEnvironment.env.end());
+
+ // FIXME: properly unquote 'outputs'.
+ StringMap rewrites;
+ for (auto & outputName : tokenizeString<std::vector<std::string>>(replaceStrings(outputs->second.quoted, "'", ""))) {
+ auto from = buildEnvironment.env.find(outputName);
+ assert(from != buildEnvironment.env.end());
+ // FIXME: unquote
+ rewrites.insert({from->second.quoted, outputsDir + "/" + outputName});
+ }
+
+ return rewriteStrings(out.str(), rewrites);
}
Strings getDefaultFlakeAttrPaths() override
@@ -240,6 +267,7 @@ struct Common : InstallableCommand, MixProfile
struct CmdDevelop : Common, MixEnvironment
{
std::vector<std::string> command;
+ std::optional<std::string> phase;
CmdDevelop()
{
@@ -253,6 +281,43 @@ struct CmdDevelop : Common, MixEnvironment
command = ss;
}}
});
+
+ addFlag({
+ .longName = "phase",
+ .description = "phase to run (e.g. `build` or `configure`)",
+ .labels = {"phase-name"},
+ .handler = {&phase},
+ });
+
+ addFlag({
+ .longName = "configure",
+ .description = "run the configure phase",
+ .handler = {&phase, {"configure"}},
+ });
+
+ addFlag({
+ .longName = "build",
+ .description = "run the build phase",
+ .handler = {&phase, {"build"}},
+ });
+
+ addFlag({
+ .longName = "check",
+ .description = "run the check phase",
+ .handler = {&phase, {"check"}},
+ });
+
+ addFlag({
+ .longName = "install",
+ .description = "run the install phase",
+ .handler = {&phase, {"install"}},
+ });
+
+ addFlag({
+ .longName = "installcheck",
+ .description = "run the installcheck phase",
+ .handler = {&phase, {"installCheck"}},
+ });
}
std::string description() override
@@ -288,19 +353,31 @@ struct CmdDevelop : Common, MixEnvironment
auto [rcFileFd, rcFilePath] = createTempFile("nix-shell");
- std::ostringstream ss;
- makeRcScript(buildEnvironment, ss);
+ auto script = makeRcScript(buildEnvironment);
+
+ if (verbosity >= lvlDebug)
+ script += "set -x\n";
- ss << fmt("rm -f '%s'\n", rcFilePath);
+ script += fmt("rm -f '%s'\n", rcFilePath);
+
+ if (phase) {
+ if (!command.empty())
+ throw UsageError("you cannot use both '--command' and '--phase'");
+ // FIXME: foundMakefile is set by buildPhase, need to get
+ // rid of that.
+ script += fmt("foundMakefile=1\n");
+ script += fmt("runHook %1%Phase\n", *phase);
+ script += fmt("exit 0\n", *phase);
+ }
- if (!command.empty()) {
+ else if (!command.empty()) {
std::vector<std::string> args;
for (auto s : command)
args.push_back(shellEscape(s));
- ss << fmt("exec %s\n", concatStringsSep(" ", args));
+ script += fmt("exec %s\n", concatStringsSep(" ", args));
}
- writeFull(rcFileFd.get(), ss.str());
+ writeFull(rcFileFd.get(), script);
stopProgressBar();
@@ -362,7 +439,7 @@ struct CmdPrintDevEnv : Common
stopProgressBar();
- makeRcScript(buildEnvironment, std::cout);
+ std::cout << makeRcScript(buildEnvironment);
}
};
diff --git a/src/nix/get-env.sh b/src/nix/get-env.sh
index 2e0e83561..091c0f573 100644
--- a/src/nix/get-env.sh
+++ b/src/nix/get-env.sh
@@ -1,12 +1,6 @@
set -e
if [ -e .attrs.sh ]; then source .attrs.sh; fi
-outputs=$_outputs_saved
-for __output in $_outputs_saved; do
- declare "$__output"="$out"
-done
-unset _outputs_saved __output
-
export IN_NIX_SHELL=impure
export dontAddDisableDepTrack=1
@@ -14,5 +8,12 @@ if [[ -n $stdenv ]]; then
source $stdenv/setup
fi
-export > $out
-set >> $out
+for __output in $outputs; do
+ if [[ -z $__done ]]; then
+ export > ${!__output}
+ set >> ${!__output}
+ __done=1
+ else
+ echo -n >> ${!__output}
+ fi
+done
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index 2bde85cb7..bb9578a11 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -64,7 +64,7 @@ struct NixRepl
void mainLoop(const std::vector<std::string> & files);
StringSet completePrefix(string prefix);
bool getLine(string & input, const std::string &prompt);
- Path getDerivationPath(Value & v);
+ StorePath getDerivationPath(Value & v);
bool processLine(string line);
void loadFile(const Path & path);
void initEnv();
@@ -375,13 +375,16 @@ bool isVarName(const string & s)
}
-Path NixRepl::getDerivationPath(Value & v) {
+StorePath NixRepl::getDerivationPath(Value & v) {
auto drvInfo = getDerivation(*state, v, false);
if (!drvInfo)
throw Error("expression does not evaluate to a derivation, so I can't build it");
- Path drvPath = drvInfo->queryDrvPath();
- if (drvPath == "" || !state->store->isValidPath(state->store->parseStorePath(drvPath)))
- throw Error("expression did not evaluate to a valid derivation");
+ Path drvPathRaw = drvInfo->queryDrvPath();
+ if (drvPathRaw == "")
+ throw Error("expression did not evaluate to a valid derivation (no drv path)");
+ StorePath drvPath = state->store->parseStorePath(drvPathRaw);
+ if (!state->store->isValidPath(drvPath))
+ throw Error("expression did not evaluate to a valid derivation (invalid drv path)");
return drvPath;
}
@@ -474,29 +477,30 @@ bool NixRepl::processLine(string line)
evalString("drv: (import <nixpkgs> {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f);
state->callFunction(f, v, result, Pos());
- Path drvPath = getDerivationPath(result);
- runProgram(settings.nixBinDir + "/nix-shell", Strings{drvPath});
+ StorePath drvPath = getDerivationPath(result);
+ runProgram(settings.nixBinDir + "/nix-shell", Strings{state->store->printStorePath(drvPath)});
}
else if (command == ":b" || command == ":i" || command == ":s") {
Value v;
evalString(arg, v);
- Path drvPath = getDerivationPath(v);
+ StorePath drvPath = getDerivationPath(v);
+ Path drvPathRaw = state->store->printStorePath(drvPath);
if (command == ":b") {
/* We could do the build in this process using buildPaths(),
but doing it in a child makes it easier to recover from
problems / SIGINT. */
- if (runProgram(settings.nixBinDir + "/nix", Strings{"build", "--no-link", drvPath}) == 0) {
- auto outputs = state->store->queryDerivationOutputMap(state->store->parseStorePath(drvPath));
+ if (runProgram(settings.nixBinDir + "/nix", Strings{"build", "--no-link", drvPathRaw}) == 0) {
+ auto drv = state->store->readDerivation(drvPath);
std::cout << std::endl << "this derivation produced the following outputs:" << std::endl;
- for (auto & i : outputs)
- std::cout << fmt(" %s -> %s\n", i.first, state->store->printStorePath(i.second));
+ for (auto & i : drv.outputsAndOptPaths(*state->store))
+ std::cout << fmt(" %s -> %s\n", i.first, state->store->printStorePath(*i.second.second));
}
} else if (command == ":i") {
- runProgram(settings.nixBinDir + "/nix-env", Strings{"-i", drvPath});
+ runProgram(settings.nixBinDir + "/nix-env", Strings{"-i", drvPathRaw});
} else {
- runProgram(settings.nixBinDir + "/nix-shell", Strings{drvPath});
+ runProgram(settings.nixBinDir + "/nix-shell", Strings{drvPathRaw});
}
}