2016-08-09 13:24:19 +03:00
|
|
|
#include <cstring>
|
2016-09-20 16:10:51 +03:00
|
|
|
#include <fstream>
|
|
|
|
#include <iostream>
|
2021-05-02 18:24:14 +03:00
|
|
|
#include <filesystem>
|
2016-08-09 13:24:19 +03:00
|
|
|
#include <regex>
|
|
|
|
#include <sstream>
|
|
|
|
#include <vector>
|
2021-05-02 18:24:14 +03:00
|
|
|
#include <map>
|
2016-09-20 16:10:51 +03:00
|
|
|
|
2021-05-02 18:24:14 +03:00
|
|
|
#include <nlohmann/json.hpp>
|
|
|
|
|
|
|
|
#include "parsed-derivations.hh"
|
2016-08-09 13:24:19 +03:00
|
|
|
#include "store-api.hh"
|
2020-10-09 23:18:08 +03:00
|
|
|
#include "local-fs-store.hh"
|
2016-08-09 13:24:19 +03:00
|
|
|
#include "globals.hh"
|
|
|
|
#include "derivations.hh"
|
2016-09-20 16:10:51 +03:00
|
|
|
#include "util.hh"
|
|
|
|
#include "shared.hh"
|
2021-03-02 05:50:41 +02:00
|
|
|
#include "path-with-outputs.hh"
|
2017-07-20 14:32:01 +03:00
|
|
|
#include "eval.hh"
|
2017-07-25 16:09:06 +03:00
|
|
|
#include "eval-inline.hh"
|
2017-07-20 14:32:01 +03:00
|
|
|
#include "get-drvs.hh"
|
2017-10-24 13:45:11 +03:00
|
|
|
#include "common-eval-args.hh"
|
2017-07-25 16:09:06 +03:00
|
|
|
#include "attr-path.hh"
|
2021-01-26 13:22:24 +02:00
|
|
|
#include "legacy.hh"
|
2016-08-09 13:24:19 +03:00
|
|
|
|
|
|
|
using namespace nix;
|
2017-05-03 16:01:15 +03:00
|
|
|
using namespace std::string_literals;
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2020-06-17 05:19:15 +03:00
|
|
|
extern char * * environ __attribute__((weak));
|
2016-10-19 16:21:18 +03:00
|
|
|
|
2016-08-31 17:08:00 +03:00
|
|
|
/* Recreate the effect of the perl shellwords function, breaking up a
|
|
|
|
* string into arguments like a shell word, including escapes
|
|
|
|
*/
|
2022-02-25 17:00:00 +02:00
|
|
|
static std::vector<std::string> shellwords(const std::string & s)
|
2016-08-09 13:24:19 +03:00
|
|
|
{
|
2016-09-12 13:06:13 +03:00
|
|
|
std::regex whitespace("^(\\s+).*");
|
2016-08-09 13:24:19 +03:00
|
|
|
auto begin = s.cbegin();
|
2022-02-25 17:00:00 +02:00
|
|
|
std::vector<std::string> res;
|
2016-09-12 14:22:23 +03:00
|
|
|
std::string cur;
|
2016-08-09 13:24:19 +03:00
|
|
|
enum state {
|
|
|
|
sBegin,
|
|
|
|
sQuote
|
|
|
|
};
|
|
|
|
state st = sBegin;
|
|
|
|
auto it = begin;
|
|
|
|
for (; it != s.cend(); ++it) {
|
|
|
|
if (st == sBegin) {
|
2016-09-12 13:06:13 +03:00
|
|
|
std::smatch match;
|
2016-08-09 13:24:19 +03:00
|
|
|
if (regex_search(it, s.cend(), match, whitespace)) {
|
2016-09-12 14:22:23 +03:00
|
|
|
cur.append(begin, it);
|
|
|
|
res.push_back(cur);
|
|
|
|
cur.clear();
|
2016-08-09 13:24:19 +03:00
|
|
|
it = match[1].second;
|
|
|
|
begin = it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch (*it) {
|
|
|
|
case '"':
|
2016-09-12 14:22:23 +03:00
|
|
|
cur.append(begin, it);
|
2016-08-09 13:24:19 +03:00
|
|
|
begin = it + 1;
|
|
|
|
st = st == sBegin ? sQuote : sBegin;
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
/* perl shellwords mostly just treats the next char as part of the string with no special processing */
|
2016-09-12 14:22:23 +03:00
|
|
|
cur.append(begin, it);
|
2016-08-09 13:24:19 +03:00
|
|
|
begin = ++it;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-09-12 14:22:23 +03:00
|
|
|
cur.append(begin, it);
|
|
|
|
if (!cur.empty()) res.push_back(cur);
|
2016-08-09 13:24:19 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-10-06 14:36:55 +03:00
|
|
|
static void main_nix_build(int argc, char * * argv)
|
2016-09-21 17:21:47 +03:00
|
|
|
{
|
2017-07-25 16:09:06 +03:00
|
|
|
auto dryRun = false;
|
|
|
|
auto runEnv = std::regex_search(argv[0], std::regex("nix-shell$"));
|
|
|
|
auto pure = false;
|
|
|
|
auto fromArgs = false;
|
|
|
|
auto packages = false;
|
|
|
|
// Same condition as bash uses for interactive shells
|
|
|
|
auto interactive = isatty(STDIN_FILENO) && isatty(STDERR_FILENO);
|
|
|
|
Strings attrPaths;
|
|
|
|
Strings left;
|
|
|
|
BuildMode buildMode = bmNormal;
|
|
|
|
bool readStdin = false;
|
|
|
|
|
|
|
|
std::string envCommand; // interactive shell
|
|
|
|
Strings envExclude;
|
|
|
|
|
|
|
|
auto myName = runEnv ? "nix-shell" : "nix-build";
|
|
|
|
|
|
|
|
auto inShebang = false;
|
|
|
|
std::string script;
|
2022-02-25 17:00:00 +02:00
|
|
|
std::vector<std::string> savedArgs;
|
2017-07-25 16:09:06 +03:00
|
|
|
|
|
|
|
AutoDelete tmpDir(createTempDir("", myName));
|
|
|
|
|
|
|
|
std::string outLink = "./result";
|
|
|
|
|
2018-08-02 04:28:49 +03:00
|
|
|
// List of environment variables kept for --pure
|
2022-02-25 17:00:00 +02:00
|
|
|
std::set<std::string> keepVars{
|
2021-11-21 17:52:01 +02:00
|
|
|
"HOME", "XDG_RUNTIME_DIR", "USER", "LOGNAME", "DISPLAY",
|
|
|
|
"WAYLAND_DISPLAY", "WAYLAND_SOCKET", "PATH", "TERM", "IN_NIX_SHELL",
|
2020-09-05 06:05:43 +03:00
|
|
|
"NIX_SHELL_PRESERVE_PROMPT", "TZ", "PAGER", "NIX_BUILD_SHELL", "SHLVL",
|
2020-02-14 07:11:22 +02:00
|
|
|
"http_proxy", "https_proxy", "ftp_proxy", "all_proxy", "no_proxy"
|
|
|
|
};
|
2018-08-02 04:28:49 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
Strings args;
|
|
|
|
for (int i = 1; i < argc; ++i)
|
|
|
|
args.push_back(argv[i]);
|
|
|
|
|
2017-09-18 14:28:00 +03:00
|
|
|
// Heuristic to see if we're invoked as a shebang script, namely,
|
|
|
|
// if we have at least one argument, it's the name of an
|
|
|
|
// executable file, and it starts with "#!".
|
2019-12-14 17:37:20 +02:00
|
|
|
if (runEnv && argc > 1) {
|
2017-07-25 16:09:06 +03:00
|
|
|
script = argv[1];
|
2017-09-18 14:28:00 +03:00
|
|
|
try {
|
2017-07-25 16:09:06 +03:00
|
|
|
auto lines = tokenizeString<Strings>(readFile(script), "\n");
|
|
|
|
if (std::regex_search(lines.front(), std::regex("^#!"))) {
|
|
|
|
lines.pop_front();
|
|
|
|
inShebang = true;
|
|
|
|
for (int i = 2; i < argc; ++i)
|
|
|
|
savedArgs.push_back(argv[i]);
|
|
|
|
args.clear();
|
|
|
|
for (auto line : lines) {
|
|
|
|
line = chomp(line);
|
|
|
|
std::smatch match;
|
|
|
|
if (std::regex_match(line, match, std::regex("^#!\\s*nix-shell (.*)$")))
|
|
|
|
for (const auto & word : shellwords(match[1].str()))
|
|
|
|
args.push_back(word);
|
2016-08-09 13:24:19 +03:00
|
|
|
}
|
|
|
|
}
|
2017-09-18 14:28:00 +03:00
|
|
|
} catch (SysError &) { }
|
2017-07-25 16:09:06 +03:00
|
|
|
}
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-10-24 13:45:11 +03:00
|
|
|
struct MyArgs : LegacyArgs, MixEvalArgs
|
|
|
|
{
|
|
|
|
using LegacyArgs::LegacyArgs;
|
|
|
|
};
|
|
|
|
|
|
|
|
MyArgs myArgs(myName, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
2017-07-25 16:09:06 +03:00
|
|
|
if (*arg == "--help") {
|
|
|
|
deletePath(tmpDir);
|
|
|
|
showManPage(myName);
|
|
|
|
}
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "--version")
|
|
|
|
printVersion(myName);
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2018-02-01 18:09:56 +02:00
|
|
|
else if (*arg == "--add-drv-link" || *arg == "--indirect")
|
2017-07-25 16:09:06 +03:00
|
|
|
; // obsolete
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "--no-out-link" || *arg == "--no-link")
|
|
|
|
outLink = (Path) tmpDir + "/result";
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "--attr" || *arg == "-A")
|
|
|
|
attrPaths.push_back(getArg(*arg, arg, end));
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "--drv-link")
|
|
|
|
getArg(*arg, arg, end); // obsolete
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "--out-link" || *arg == "-o")
|
|
|
|
outLink = getArg(*arg, arg, end);
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "--dry-run")
|
|
|
|
dryRun = true;
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "--run-env") // obsolete
|
|
|
|
runEnv = true;
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2020-07-30 03:53:02 +03:00
|
|
|
else if (runEnv && (*arg == "--command" || *arg == "--run")) {
|
2017-07-25 16:09:06 +03:00
|
|
|
if (*arg == "--run")
|
|
|
|
interactive = false;
|
|
|
|
envCommand = getArg(*arg, arg, end) + "\nexit";
|
|
|
|
}
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "--check")
|
|
|
|
buildMode = bmCheck;
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "--exclude")
|
|
|
|
envExclude.push_back(getArg(*arg, arg, end));
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "--expr" || *arg == "-E")
|
|
|
|
fromArgs = true;
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "--pure") pure = true;
|
|
|
|
else if (*arg == "--impure") pure = false;
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2020-07-30 03:50:06 +03:00
|
|
|
else if (runEnv && (*arg == "--packages" || *arg == "-p"))
|
2017-07-25 16:09:06 +03:00
|
|
|
packages = true;
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (inShebang && *arg == "-i") {
|
|
|
|
auto interpreter = getArg(*arg, arg, end);
|
|
|
|
interactive = false;
|
|
|
|
auto execArgs = "";
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
// Überhack to support Perl. Perl examines the shebang and
|
|
|
|
// executes it unless it contains the string "perl" or "indir",
|
|
|
|
// or (undocumented) argv[0] does not contain "perl". Exploit
|
|
|
|
// the latter by doing "exec -a".
|
|
|
|
if (std::regex_search(interpreter, std::regex("perl")))
|
|
|
|
execArgs = "-a PERL";
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
std::ostringstream joined;
|
|
|
|
for (const auto & i : savedArgs)
|
|
|
|
joined << shellEscape(i) << ' ';
|
|
|
|
|
|
|
|
if (std::regex_search(interpreter, std::regex("ruby"))) {
|
|
|
|
// Hack for Ruby. Ruby also examines the shebang. It tries to
|
|
|
|
// read the shebang to understand which packages to read from. Since
|
|
|
|
// this is handled via nix-shell -p, we wrap our ruby script execution
|
|
|
|
// in ruby -e 'load' which ignores the shebangs.
|
2023-03-02 16:44:19 +02:00
|
|
|
envCommand = fmt("exec %1% %2% -e 'load(ARGV.shift)' -- %3% %4%", execArgs, interpreter, shellEscape(script), joined.str());
|
2017-07-25 16:09:06 +03:00
|
|
|
} else {
|
2023-03-02 16:44:19 +02:00
|
|
|
envCommand = fmt("exec %1% %2% %3% %4%", execArgs, interpreter, shellEscape(script), joined.str());
|
2016-08-09 13:24:19 +03:00
|
|
|
}
|
2017-07-25 16:09:06 +03:00
|
|
|
}
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2018-08-02 04:28:49 +03:00
|
|
|
else if (*arg == "--keep")
|
|
|
|
keepVars.insert(getArg(*arg, arg, end));
|
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg == "-")
|
|
|
|
readStdin = true;
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else if (*arg != "" && arg->at(0) == '-')
|
|
|
|
return false;
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
else
|
|
|
|
left.push_back(*arg);
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
return true;
|
|
|
|
});
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-10-24 13:45:11 +03:00
|
|
|
myArgs.parseCmdline(args);
|
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
if (packages && fromArgs)
|
2017-07-30 14:27:57 +03:00
|
|
|
throw UsageError("'-p' and '-E' are mutually exclusive");
|
2017-07-25 16:09:06 +03:00
|
|
|
|
|
|
|
auto store = openStore();
|
2021-07-15 15:28:33 +03:00
|
|
|
auto evalStore = myArgs.evalStoreUrl ? openStore(*myArgs.evalStoreUrl) : store;
|
2017-07-25 16:09:06 +03:00
|
|
|
|
2021-07-15 15:28:33 +03:00
|
|
|
auto state = std::make_unique<EvalState>(myArgs.searchPath, evalStore, store);
|
2023-04-28 17:57:37 +03:00
|
|
|
state->repair = myArgs.repair;
|
|
|
|
if (myArgs.repair) buildMode = bmRepair;
|
2017-07-25 16:09:06 +03:00
|
|
|
|
2019-10-27 18:58:25 +02:00
|
|
|
auto autoArgs = myArgs.getAutoArgs(*state);
|
|
|
|
|
2022-06-14 00:01:13 +03:00
|
|
|
auto autoArgsWithInNixShell = autoArgs;
|
2019-10-27 18:58:25 +02:00
|
|
|
if (runEnv) {
|
2022-06-14 00:01:13 +03:00
|
|
|
auto newArgs = state->buildBindings(autoArgsWithInNixShell->size() + 1);
|
2022-01-04 18:39:16 +02:00
|
|
|
newArgs.alloc("inNixShell").mkBool(true);
|
|
|
|
for (auto & i : *autoArgs) newArgs.insert(i);
|
2022-06-14 00:01:13 +03:00
|
|
|
autoArgsWithInNixShell = newArgs.finish();
|
2019-10-27 18:58:25 +02:00
|
|
|
}
|
2017-07-25 16:09:06 +03:00
|
|
|
|
|
|
|
if (packages) {
|
|
|
|
std::ostringstream joined;
|
2021-07-31 17:55:53 +03:00
|
|
|
joined << "{...}@args: with import <nixpkgs> args; (pkgs.runCommandCC or pkgs.runCommand) \"shell\" { buildInputs = [ ";
|
2017-07-25 16:09:06 +03:00
|
|
|
for (const auto & i : left)
|
|
|
|
joined << '(' << i << ") ";
|
|
|
|
joined << "]; } \"\"";
|
|
|
|
fromArgs = true;
|
|
|
|
left = {joined.str()};
|
|
|
|
} else if (!fromArgs) {
|
|
|
|
if (left.empty() && runEnv && pathExists("shell.nix"))
|
|
|
|
left = {"shell.nix"};
|
|
|
|
if (left.empty())
|
|
|
|
left = {"default.nix"};
|
|
|
|
}
|
2017-07-20 14:32:01 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
if (runEnv)
|
|
|
|
setenv("IN_NIX_SHELL", pure ? "pure" : "impure", 1);
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-11-24 19:07:29 +02:00
|
|
|
DrvInfos drvs;
|
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
/* Parse the expressions. */
|
|
|
|
std::vector<Expr *> exprs;
|
|
|
|
|
|
|
|
if (readStdin)
|
2018-06-12 18:26:36 +03:00
|
|
|
exprs = {state->parseStdin()};
|
2017-07-25 16:09:06 +03:00
|
|
|
else
|
|
|
|
for (auto i : left) {
|
|
|
|
if (fromArgs)
|
2023-04-06 14:15:50 +03:00
|
|
|
exprs.push_back(state->parseExprFromString(std::move(i), state->rootPath(CanonPath::fromCwd())));
|
2019-05-08 15:18:57 +03:00
|
|
|
else {
|
|
|
|
auto absolute = i;
|
|
|
|
try {
|
|
|
|
absolute = canonPath(absPath(i), true);
|
2019-09-22 22:29:33 +03:00
|
|
|
} catch (Error & e) {};
|
2020-03-04 14:55:15 +02:00
|
|
|
auto [path, outputNames] = parsePathWithOutputs(absolute);
|
2021-07-16 13:47:59 +03:00
|
|
|
if (evalStore->isStorePath(path) && hasSuffix(path, ".drv"))
|
|
|
|
drvs.push_back(DrvInfo(*state, evalStore, absolute));
|
2019-10-02 17:26:15 +03:00
|
|
|
else
|
|
|
|
/* If we're in a #! script, interpret filenames
|
|
|
|
relative to the script. */
|
|
|
|
exprs.push_back(state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state,
|
|
|
|
inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i)))));
|
2019-05-08 15:18:57 +03:00
|
|
|
}
|
2016-08-09 13:24:19 +03:00
|
|
|
}
|
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
/* Evaluate them into derivations. */
|
|
|
|
if (attrPaths.empty()) attrPaths = {""};
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
for (auto e : exprs) {
|
|
|
|
Value vRoot;
|
2018-06-12 18:26:36 +03:00
|
|
|
state->eval(e, vRoot);
|
2017-07-03 12:54:30 +03:00
|
|
|
|
2022-06-14 00:01:13 +03:00
|
|
|
std::function<bool(const Value & v)> takesNixShellAttr;
|
|
|
|
takesNixShellAttr = [&](const Value & v) {
|
|
|
|
if (!runEnv) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool add = false;
|
|
|
|
if (v.type() == nFunction && v.lambda.fun->hasFormals()) {
|
|
|
|
for (auto & i : v.lambda.fun->formals->formals) {
|
|
|
|
if (state->symbols[i.name] == "inNixShell") {
|
|
|
|
add = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return add;
|
|
|
|
};
|
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
for (auto & i : attrPaths) {
|
2022-06-14 00:01:13 +03:00
|
|
|
Value & v(*findAlongAttrPath(
|
|
|
|
*state,
|
|
|
|
i,
|
|
|
|
takesNixShellAttr(vRoot) ? *autoArgsWithInNixShell : *autoArgs,
|
|
|
|
vRoot
|
|
|
|
).first);
|
2022-02-04 01:31:33 +02:00
|
|
|
state->forceValue(v, [&]() { return v.determinePos(noPos); });
|
2022-06-14 00:01:13 +03:00
|
|
|
getDerivations(
|
|
|
|
*state,
|
|
|
|
v,
|
|
|
|
"",
|
|
|
|
takesNixShellAttr(v) ? *autoArgsWithInNixShell : *autoArgs,
|
|
|
|
drvs,
|
|
|
|
false
|
|
|
|
);
|
2017-07-25 16:09:06 +03:00
|
|
|
}
|
|
|
|
}
|
2016-09-20 16:39:08 +03:00
|
|
|
|
2023-10-09 17:25:53 +03:00
|
|
|
state->maybePrintStats();
|
2018-09-01 04:03:32 +03:00
|
|
|
|
2022-03-11 16:42:09 +02:00
|
|
|
auto buildPaths = [&](const std::vector<DerivedPath> & paths) {
|
2017-07-25 16:09:06 +03:00
|
|
|
/* Note: we do this even when !printMissing to efficiently
|
|
|
|
fetch binary cache data. */
|
2020-07-30 14:10:49 +03:00
|
|
|
uint64_t downloadSize, narSize;
|
2019-12-05 20:11:09 +02:00
|
|
|
StorePathSet willBuild, willSubstitute, unknown;
|
2017-07-25 16:09:06 +03:00
|
|
|
store->queryMissing(paths,
|
|
|
|
willBuild, willSubstitute, unknown, downloadSize, narSize);
|
2016-09-20 16:39:08 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
if (settings.printMissing)
|
|
|
|
printMissing(ref<Store>(store), willBuild, willSubstitute, unknown, downloadSize, narSize);
|
2016-09-20 16:39:08 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
if (!dryRun)
|
2021-07-19 16:43:08 +03:00
|
|
|
store->buildPaths(paths, buildMode, evalStore);
|
2017-07-25 16:09:06 +03:00
|
|
|
};
|
2017-02-24 18:25:00 +02:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
if (runEnv) {
|
|
|
|
if (drvs.size() != 1)
|
|
|
|
throw UsageError("nix-shell requires a single derivation");
|
2017-01-06 21:30:14 +02:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
auto & drvInfo = drvs.front();
|
2022-03-02 11:57:19 +02:00
|
|
|
auto drv = evalStore->derivationFromPath(drvInfo.requireDrvPath());
|
2017-01-06 21:30:14 +02:00
|
|
|
|
2022-03-11 16:42:09 +02:00
|
|
|
std::vector<DerivedPath> pathsToBuild;
|
2021-07-16 13:47:59 +03:00
|
|
|
RealisedPath::Set pathsToCopy;
|
2017-02-01 14:00:21 +02:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
/* Figure out what bash shell to use. If $NIX_BUILD_SHELL
|
|
|
|
is not set, then build bashInteractive from
|
|
|
|
<nixpkgs>. */
|
2019-11-22 17:06:44 +02:00
|
|
|
auto shell = getEnv("NIX_BUILD_SHELL");
|
2021-11-26 10:56:48 +02:00
|
|
|
std::optional<StorePath> shellDrv;
|
2016-09-20 16:39:08 +03:00
|
|
|
|
2019-11-22 17:06:44 +02:00
|
|
|
if (!shell) {
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2016-09-21 17:21:47 +03:00
|
|
|
try {
|
2023-04-06 14:15:50 +03:00
|
|
|
auto expr = state->parseExprFromString(
|
|
|
|
"(import <nixpkgs> {}).bashInteractive",
|
|
|
|
state->rootPath(CanonPath::fromCwd()));
|
2017-07-25 16:09:06 +03:00
|
|
|
|
|
|
|
Value v;
|
2018-06-12 18:26:36 +03:00
|
|
|
state->eval(expr, v);
|
2017-07-25 16:09:06 +03:00
|
|
|
|
2018-06-12 18:26:36 +03:00
|
|
|
auto drv = getDerivation(*state, v, false);
|
2017-07-25 16:09:06 +03:00
|
|
|
if (!drv)
|
2017-07-30 14:27:57 +03:00
|
|
|
throw Error("the 'bashInteractive' attribute in <nixpkgs> did not evaluate to a derivation");
|
2017-07-25 16:09:06 +03:00
|
|
|
|
2022-03-02 11:57:19 +02:00
|
|
|
auto bashDrv = drv->requireDrvPath();
|
2022-03-11 16:42:09 +02:00
|
|
|
pathsToBuild.push_back(DerivedPath::Built {
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
.drvPath = makeConstantStorePathRef(bashDrv),
|
2023-01-12 01:57:18 +02:00
|
|
|
.outputs = OutputsSpec::Names {"out"},
|
2022-03-11 16:42:09 +02:00
|
|
|
});
|
2021-07-16 13:47:59 +03:00
|
|
|
pathsToCopy.insert(bashDrv);
|
2021-11-26 10:56:48 +02:00
|
|
|
shellDrv = bashDrv;
|
2017-07-25 16:09:06 +03:00
|
|
|
|
|
|
|
} catch (Error & e) {
|
2021-01-21 01:27:36 +02:00
|
|
|
logError(e.info());
|
|
|
|
notice("will use bash from your environment");
|
2017-07-25 16:09:06 +03:00
|
|
|
shell = "bash";
|
2016-09-21 17:21:47 +03:00
|
|
|
}
|
2017-07-25 16:09:06 +03:00
|
|
|
}
|
|
|
|
|
Allow dynamic derivation deps in `inputDrvs`
We use the same nested map representation we used for goals, again in
order to save space. We might someday want to combine with `inputDrvs`,
by doing `V = bool` instead of `V = std::set<OutputName>`, but we are
not doing that yet for sake of a smaller diff.
The ATerm format for Derivations also needs to be extended, in addition
to the in-memory format. To accomodate this, we added a new basic
versioning scheme, so old versions of Nix will get nice errors. (And
going forward, if the ATerm format changes again the errors will be even
better.)
`parsedStrings`, an internal function used as part of parsing
derivations in A-Term format, used to consume the final `]` but expect
the initial `[` to already be consumed. This made for what looked like
unbalanced brackets at callsites, which was confusing. Now it consumes
both which is hopefully less confusing.
As part of testing, we also created a unit test for the A-Term format for
regular non-experimental derivations too.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Apply suggestions from code review
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2021-10-02 01:05:53 +03:00
|
|
|
std::function<void(ref<SingleDerivedPath>, const DerivedPathMap<StringSet>::ChildNode &)> accumDerivedPath;
|
|
|
|
|
|
|
|
accumDerivedPath = [&](ref<SingleDerivedPath> inputDrv, const DerivedPathMap<StringSet>::ChildNode & inputNode) {
|
|
|
|
if (!inputNode.value.empty())
|
|
|
|
pathsToBuild.push_back(DerivedPath::Built {
|
|
|
|
.drvPath = inputDrv,
|
|
|
|
.outputs = OutputsSpec::Names { inputNode.value },
|
|
|
|
});
|
|
|
|
for (const auto & [outputName, childNode] : inputNode.childMap)
|
|
|
|
accumDerivedPath(
|
|
|
|
make_ref<SingleDerivedPath>(SingleDerivedPath::Built { inputDrv, outputName }),
|
|
|
|
childNode);
|
|
|
|
};
|
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
// Build or fetch all dependencies of the derivation.
|
Allow dynamic derivation deps in `inputDrvs`
We use the same nested map representation we used for goals, again in
order to save space. We might someday want to combine with `inputDrvs`,
by doing `V = bool` instead of `V = std::set<OutputName>`, but we are
not doing that yet for sake of a smaller diff.
The ATerm format for Derivations also needs to be extended, in addition
to the in-memory format. To accomodate this, we added a new basic
versioning scheme, so old versions of Nix will get nice errors. (And
going forward, if the ATerm format changes again the errors will be even
better.)
`parsedStrings`, an internal function used as part of parsing
derivations in A-Term format, used to consume the final `]` but expect
the initial `[` to already be consumed. This made for what looked like
unbalanced brackets at callsites, which was confusing. Now it consumes
both which is hopefully less confusing.
As part of testing, we also created a unit test for the A-Term format for
regular non-experimental derivations too.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Apply suggestions from code review
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2021-10-02 01:05:53 +03:00
|
|
|
for (const auto & [inputDrv0, inputNode] : drv.inputDrvs.map) {
|
2022-03-11 16:42:09 +02:00
|
|
|
// To get around lambda capturing restrictions in the
|
|
|
|
// standard.
|
|
|
|
const auto & inputDrv = inputDrv0;
|
2019-12-05 20:11:09 +02:00
|
|
|
if (std::all_of(envExclude.cbegin(), envExclude.cend(),
|
2022-02-25 17:00:00 +02:00
|
|
|
[&](const std::string & exclude) {
|
2022-03-11 16:42:09 +02:00
|
|
|
return !std::regex_search(store->printStorePath(inputDrv), std::regex(exclude));
|
2022-02-25 17:00:00 +02:00
|
|
|
}))
|
2021-07-16 13:47:59 +03:00
|
|
|
{
|
Allow dynamic derivation deps in `inputDrvs`
We use the same nested map representation we used for goals, again in
order to save space. We might someday want to combine with `inputDrvs`,
by doing `V = bool` instead of `V = std::set<OutputName>`, but we are
not doing that yet for sake of a smaller diff.
The ATerm format for Derivations also needs to be extended, in addition
to the in-memory format. To accomodate this, we added a new basic
versioning scheme, so old versions of Nix will get nice errors. (And
going forward, if the ATerm format changes again the errors will be even
better.)
`parsedStrings`, an internal function used as part of parsing
derivations in A-Term format, used to consume the final `]` but expect
the initial `[` to already be consumed. This made for what looked like
unbalanced brackets at callsites, which was confusing. Now it consumes
both which is hopefully less confusing.
As part of testing, we also created a unit test for the A-Term format for
regular non-experimental derivations too.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Apply suggestions from code review
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2021-10-02 01:05:53 +03:00
|
|
|
accumDerivedPath(makeConstantStorePathRef(inputDrv), inputNode);
|
2022-03-11 16:42:09 +02:00
|
|
|
pathsToCopy.insert(inputDrv);
|
2021-07-16 13:47:59 +03:00
|
|
|
}
|
2022-03-11 16:42:09 +02:00
|
|
|
}
|
2021-07-16 13:47:59 +03:00
|
|
|
for (const auto & src : drv.inputSrcs) {
|
2022-03-11 16:42:09 +02:00
|
|
|
pathsToBuild.push_back(DerivedPath::Opaque{src});
|
2021-07-16 13:47:59 +03:00
|
|
|
pathsToCopy.insert(src);
|
|
|
|
}
|
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
buildPaths(pathsToBuild);
|
2016-08-09 13:24:19 +03:00
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
if (dryRun) return;
|
2016-09-12 13:06:13 +03:00
|
|
|
|
2021-11-26 10:56:48 +02:00
|
|
|
if (shellDrv) {
|
|
|
|
auto shellDrvOutputs = store->queryPartialDerivationOutputMap(shellDrv.value());
|
|
|
|
shell = store->printStorePath(shellDrvOutputs.at("out").value()) + "/bin/bash";
|
|
|
|
}
|
|
|
|
|
2023-03-17 16:33:48 +02:00
|
|
|
if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
|
2021-05-20 14:55:00 +03:00
|
|
|
auto resolvedDrv = drv.tryResolve(*store);
|
2021-06-22 12:29:55 +03:00
|
|
|
assert(resolvedDrv && "Successfully resolved the derivation");
|
2021-05-20 14:55:00 +03:00
|
|
|
drv = *resolvedDrv;
|
|
|
|
}
|
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
// Set the environment.
|
|
|
|
auto env = getEnv();
|
|
|
|
|
2019-11-22 17:06:44 +02:00
|
|
|
auto tmp = getEnv("TMPDIR");
|
|
|
|
if (!tmp) tmp = getEnv("XDG_RUNTIME_DIR").value_or("/tmp");
|
2017-07-25 16:09:06 +03:00
|
|
|
|
|
|
|
if (pure) {
|
|
|
|
decltype(env) newEnv;
|
|
|
|
for (auto & i : env)
|
|
|
|
if (keepVars.count(i.first))
|
|
|
|
newEnv.emplace(i);
|
|
|
|
env = newEnv;
|
|
|
|
// NixOS hack: prevent /etc/bashrc from sourcing /etc/profile.
|
|
|
|
env["__ETC_PROFILE_SOURCED"] = "1";
|
2016-08-09 13:24:19 +03:00
|
|
|
}
|
2017-07-25 16:09:06 +03:00
|
|
|
|
2019-11-22 17:06:44 +02:00
|
|
|
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = *tmp;
|
2017-07-25 16:09:06 +03:00
|
|
|
env["NIX_STORE"] = store->storeDir;
|
|
|
|
env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores);
|
|
|
|
|
2022-05-04 08:44:32 +03:00
|
|
|
auto passAsFile = tokenizeString<StringSet>(getOr(drv.env, "passAsFile", ""));
|
2017-07-25 16:09:06 +03:00
|
|
|
|
|
|
|
bool keepTmp = false;
|
|
|
|
int fileNr = 0;
|
|
|
|
|
|
|
|
for (auto & var : drv.env)
|
|
|
|
if (passAsFile.count(var.first)) {
|
|
|
|
keepTmp = true;
|
2022-02-25 17:00:00 +02:00
|
|
|
auto fn = ".attr-" + std::to_string(fileNr++);
|
2017-07-25 16:09:06 +03:00
|
|
|
Path p = (Path) tmpDir + "/" + fn;
|
|
|
|
writeFile(p, var.second);
|
|
|
|
env[var.first + "Path"] = p;
|
|
|
|
} else
|
|
|
|
env[var.first] = var.second;
|
|
|
|
|
2021-05-02 18:24:14 +03:00
|
|
|
std::string structuredAttrsRC;
|
|
|
|
|
|
|
|
if (env.count("__json")) {
|
|
|
|
StorePathSet inputs;
|
Allow dynamic derivation deps in `inputDrvs`
We use the same nested map representation we used for goals, again in
order to save space. We might someday want to combine with `inputDrvs`,
by doing `V = bool` instead of `V = std::set<OutputName>`, but we are
not doing that yet for sake of a smaller diff.
The ATerm format for Derivations also needs to be extended, in addition
to the in-memory format. To accomodate this, we added a new basic
versioning scheme, so old versions of Nix will get nice errors. (And
going forward, if the ATerm format changes again the errors will be even
better.)
`parsedStrings`, an internal function used as part of parsing
derivations in A-Term format, used to consume the final `]` but expect
the initial `[` to already be consumed. This made for what looked like
unbalanced brackets at callsites, which was confusing. Now it consumes
both which is hopefully less confusing.
As part of testing, we also created a unit test for the A-Term format for
regular non-experimental derivations too.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Apply suggestions from code review
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2021-10-02 01:05:53 +03:00
|
|
|
|
|
|
|
std::function<void(const StorePath &, const DerivedPathMap<StringSet>::ChildNode &)> accumInputClosure;
|
|
|
|
|
|
|
|
accumInputClosure = [&](const StorePath & inputDrv, const DerivedPathMap<StringSet>::ChildNode & inputNode) {
|
|
|
|
auto outputs = evalStore->queryPartialDerivationOutputMap(inputDrv);
|
|
|
|
for (auto & i : inputNode.value) {
|
2021-05-02 18:24:14 +03:00
|
|
|
auto o = outputs.at(i);
|
|
|
|
store->computeFSClosure(*o, inputs);
|
|
|
|
}
|
Allow dynamic derivation deps in `inputDrvs`
We use the same nested map representation we used for goals, again in
order to save space. We might someday want to combine with `inputDrvs`,
by doing `V = bool` instead of `V = std::set<OutputName>`, but we are
not doing that yet for sake of a smaller diff.
The ATerm format for Derivations also needs to be extended, in addition
to the in-memory format. To accomodate this, we added a new basic
versioning scheme, so old versions of Nix will get nice errors. (And
going forward, if the ATerm format changes again the errors will be even
better.)
`parsedStrings`, an internal function used as part of parsing
derivations in A-Term format, used to consume the final `]` but expect
the initial `[` to already be consumed. This made for what looked like
unbalanced brackets at callsites, which was confusing. Now it consumes
both which is hopefully less confusing.
As part of testing, we also created a unit test for the A-Term format for
regular non-experimental derivations too.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Apply suggestions from code review
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2021-10-02 01:05:53 +03:00
|
|
|
for (const auto & [outputName, childNode] : inputNode.childMap)
|
|
|
|
accumInputClosure(*outputs.at(outputName), childNode);
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const auto & [inputDrv, inputNode] : drv.inputDrvs.map)
|
|
|
|
accumInputClosure(inputDrv, inputNode);
|
2021-05-02 18:24:14 +03:00
|
|
|
|
2022-03-02 11:57:19 +02:00
|
|
|
ParsedDerivation parsedDrv(drvInfo.requireDrvPath(), drv);
|
2021-05-02 18:24:14 +03:00
|
|
|
|
2021-06-24 16:06:07 +03:00
|
|
|
if (auto structAttrs = parsedDrv.prepareStructuredAttrs(*store, inputs)) {
|
2021-05-13 17:11:56 +03:00
|
|
|
auto json = structAttrs.value();
|
2021-06-22 21:37:25 +03:00
|
|
|
structuredAttrsRC = writeStructuredAttrsShell(json);
|
2021-05-13 17:11:56 +03:00
|
|
|
|
2021-05-09 18:46:16 +03:00
|
|
|
auto attrsJSON = (Path) tmpDir + "/.attrs.json";
|
2021-05-13 17:11:56 +03:00
|
|
|
writeFile(attrsJSON, json.dump());
|
|
|
|
|
2021-05-09 18:46:16 +03:00
|
|
|
auto attrsSH = (Path) tmpDir + "/.attrs.sh";
|
2021-05-13 17:11:56 +03:00
|
|
|
writeFile(attrsSH, structuredAttrsRC);
|
|
|
|
|
2021-06-22 20:45:08 +03:00
|
|
|
env["NIX_ATTRS_SH_FILE"] = attrsSH;
|
|
|
|
env["NIX_ATTRS_JSON_FILE"] = attrsJSON;
|
2021-05-09 18:46:16 +03:00
|
|
|
keepTmp = true;
|
2021-05-02 18:24:14 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
/* Run a shell using the derivation's environment. For
|
|
|
|
convenience, source $stdenv/setup to setup additional
|
|
|
|
environment variables and shell functions. Also don't
|
|
|
|
lose the current $PATH directories. */
|
|
|
|
auto rcfile = (Path) tmpDir + "/rc";
|
2021-05-02 18:24:14 +03:00
|
|
|
std::string rc = fmt(
|
2022-01-23 05:58:00 +02:00
|
|
|
R"(_nix_shell_clean_tmpdir() { command rm -rf %1%; }; )"s +
|
2020-01-17 08:44:00 +02:00
|
|
|
(keepTmp ?
|
|
|
|
"trap _nix_shell_clean_tmpdir EXIT; "
|
|
|
|
"exitHooks+=(_nix_shell_clean_tmpdir); "
|
|
|
|
"failureHooks+=(_nix_shell_clean_tmpdir); ":
|
|
|
|
"_nix_shell_clean_tmpdir; ") +
|
2019-10-09 15:46:44 +03:00
|
|
|
(pure ? "" : "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc;") +
|
2017-07-25 16:09:06 +03:00
|
|
|
"%2%"
|
2021-08-07 01:30:49 +03:00
|
|
|
// always clear PATH.
|
|
|
|
// when nix-shell is run impure, we rehydrate it with the `p=$PATH` above
|
|
|
|
"unset PATH;"
|
2021-05-02 18:24:14 +03:00
|
|
|
"dontAddDisableDepTrack=1;\n"
|
2021-05-09 18:46:16 +03:00
|
|
|
+ structuredAttrsRC +
|
2021-05-02 18:24:14 +03:00
|
|
|
"\n[ -e $stdenv/setup ] && source $stdenv/setup; "
|
2017-07-25 16:09:06 +03:00
|
|
|
"%3%"
|
2020-01-17 08:44:00 +02:00
|
|
|
"PATH=%4%:\"$PATH\"; "
|
2018-09-27 19:40:19 +03:00
|
|
|
"SHELL=%5%; "
|
2022-02-05 18:56:51 +02:00
|
|
|
"BASH=%5%; "
|
2017-07-25 16:09:06 +03:00
|
|
|
"set +e; "
|
2023-02-01 22:43:26 +02:00
|
|
|
R"s([ -n "$PS1" -a -z "$NIX_SHELL_PRESERVE_PROMPT" ] && )s" +
|
|
|
|
(getuid() == 0 ? R"s(PS1='\n\[\033[1;31m\][nix-shell:\w]\$\[\033[0m\] '; )s"
|
|
|
|
: R"s(PS1='\n\[\033[1;32m\][nix-shell:\w]\$\[\033[0m\] '; )s") +
|
2017-07-25 16:09:06 +03:00
|
|
|
"if [ \"$(type -t runHook)\" = function ]; then runHook shellHook; fi; "
|
|
|
|
"unset NIX_ENFORCE_PURITY; "
|
|
|
|
"shopt -u nullglob; "
|
2018-09-27 19:40:19 +03:00
|
|
|
"unset TZ; %6%"
|
2021-03-04 00:46:15 +02:00
|
|
|
"shopt -s execfail;"
|
2018-09-27 19:40:19 +03:00
|
|
|
"%7%",
|
2020-01-17 08:44:00 +02:00
|
|
|
shellEscape(tmpDir),
|
2017-07-25 16:09:06 +03:00
|
|
|
(pure ? "" : "p=$PATH; "),
|
|
|
|
(pure ? "" : "PATH=$PATH:$p; unset p; "),
|
2020-01-17 08:44:00 +02:00
|
|
|
shellEscape(dirOf(*shell)),
|
|
|
|
shellEscape(*shell),
|
2022-02-25 17:00:00 +02:00
|
|
|
(getenv("TZ") ? (std::string("export TZ=") + shellEscape(getenv("TZ")) + "; ") : ""),
|
2021-05-02 18:24:14 +03:00
|
|
|
envCommand);
|
|
|
|
vomit("Sourcing nix-shell with file %s and contents:\n%s", rcfile, rc);
|
|
|
|
writeFile(rcfile, rc);
|
2017-07-25 16:09:06 +03:00
|
|
|
|
|
|
|
Strings envStrs;
|
|
|
|
for (auto & i : env)
|
|
|
|
envStrs.push_back(i.first + "=" + i.second);
|
|
|
|
|
|
|
|
auto args = interactive
|
|
|
|
? Strings{"bash", "--rcfile", rcfile}
|
|
|
|
: Strings{"bash", rcfile};
|
|
|
|
|
|
|
|
auto envPtrs = stringsToCharPtrs(envStrs);
|
|
|
|
|
|
|
|
environ = envPtrs.data();
|
|
|
|
|
|
|
|
auto argPtrs = stringsToCharPtrs(args);
|
|
|
|
|
2021-04-07 14:10:02 +03:00
|
|
|
restoreProcessContext();
|
2017-07-25 16:09:06 +03:00
|
|
|
|
2022-06-11 16:13:58 +03:00
|
|
|
logger->stop();
|
|
|
|
|
2019-11-22 17:06:44 +02:00
|
|
|
execvp(shell->c_str(), argPtrs.data());
|
2017-07-25 16:09:06 +03:00
|
|
|
|
2019-11-22 17:06:44 +02:00
|
|
|
throw SysError("executing shell '%s'", *shell);
|
2017-07-25 16:09:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
2022-03-11 16:42:09 +02:00
|
|
|
std::vector<DerivedPath> pathsToBuild;
|
2020-11-13 18:49:27 +02:00
|
|
|
std::vector<std::pair<StorePath, std::string>> pathsToBuildOrdered;
|
2021-07-16 10:37:33 +03:00
|
|
|
RealisedPath::Set drvsToCopy;
|
2017-07-25 16:09:06 +03:00
|
|
|
|
2020-08-07 22:09:26 +03:00
|
|
|
std::map<StorePath, std::pair<size_t, StringSet>> drvMap;
|
2017-07-25 16:09:06 +03:00
|
|
|
|
|
|
|
for (auto & drvInfo : drvs) {
|
2022-03-02 11:57:19 +02:00
|
|
|
auto drvPath = drvInfo.requireDrvPath();
|
2017-07-25 16:09:06 +03:00
|
|
|
|
|
|
|
auto outputName = drvInfo.queryOutputName();
|
|
|
|
if (outputName == "")
|
2020-08-07 22:09:26 +03:00
|
|
|
throw Error("derivation '%s' lacks an 'outputName' attribute", store->printStorePath(drvPath));
|
2017-07-25 16:09:06 +03:00
|
|
|
|
Make the Derived Path family of types inductive for dynamic derivations
We want to be able to write down `foo.drv^bar.drv^baz`:
`foo.drv^bar.drv` is the dynamic derivation (since it is itself a
derivation output, `bar.drv` from `foo.drv`).
To that end, we create `Single{Derivation,BuiltPath}` types, that are
very similar except instead of having multiple outputs (in a set or
map), they have a single one. This is for everything to the left of the
rightmost `^`.
`NixStringContextElem` has an analogous change, and now can reuse
`SingleDerivedPath` at the top level. In fact, if we ever get rid of
`DrvDeep`, `NixStringContextElem` could be replaced with
`SingleDerivedPath` entirely!
Important note: some JSON formats have changed.
We already can *produce* dynamic derivations, but we can't refer to them
directly. Today, we can merely express building or example at the top
imperatively over time by building `foo.drv^bar.drv`, and then with a
second nix invocation doing `<result-from-first>^baz`, but this is not
declarative. The ethos of Nix of being able to write down the full plan
everything you want to do, and then execute than plan with a single
command, and for that we need the new inductive form of these types.
Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-01-16 00:39:04 +02:00
|
|
|
pathsToBuild.push_back(DerivedPath::Built{
|
|
|
|
.drvPath = makeConstantStorePathRef(drvPath),
|
|
|
|
.outputs = OutputsSpec::Names{outputName},
|
|
|
|
});
|
2020-11-13 18:49:27 +02:00
|
|
|
pathsToBuildOrdered.push_back({drvPath, {outputName}});
|
2021-07-16 10:37:33 +03:00
|
|
|
drvsToCopy.insert(drvPath);
|
2017-07-25 16:09:06 +03:00
|
|
|
|
2020-08-07 22:09:26 +03:00
|
|
|
auto i = drvMap.find(drvPath);
|
|
|
|
if (i != drvMap.end())
|
|
|
|
i->second.second.insert(outputName);
|
2021-07-16 10:37:33 +03:00
|
|
|
else
|
2020-08-07 22:09:26 +03:00
|
|
|
drvMap[drvPath] = {drvMap.size(), {outputName}};
|
2017-07-25 16:09:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
buildPaths(pathsToBuild);
|
|
|
|
|
|
|
|
if (dryRun) return;
|
|
|
|
|
2020-08-07 22:09:26 +03:00
|
|
|
std::vector<StorePath> outPaths;
|
|
|
|
|
2020-11-13 18:49:27 +02:00
|
|
|
for (auto & [drvPath, outputName] : pathsToBuildOrdered) {
|
|
|
|
auto & [counter, _wantedOutputs] = drvMap.at({drvPath});
|
2020-08-07 22:09:26 +03:00
|
|
|
std::string drvPrefix = outLink;
|
|
|
|
if (counter)
|
|
|
|
drvPrefix += fmt("-%d", counter + 1);
|
|
|
|
|
2021-07-19 16:43:08 +03:00
|
|
|
auto builtOutputs = evalStore->queryPartialDerivationOutputMap(drvPath);
|
2020-08-07 22:09:26 +03:00
|
|
|
|
2020-12-08 21:38:37 +02:00
|
|
|
auto maybeOutputPath = builtOutputs.at(outputName);
|
|
|
|
assert(maybeOutputPath);
|
|
|
|
auto outputPath = *maybeOutputPath;
|
2020-08-07 22:09:26 +03:00
|
|
|
|
2020-11-13 18:49:27 +02:00
|
|
|
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>()) {
|
|
|
|
std::string symlink = drvPrefix;
|
|
|
|
if (outputName != "out") symlink += "-" + outputName;
|
|
|
|
store2->addPermRoot(outputPath, absPath(symlink));
|
2020-08-07 22:09:26 +03:00
|
|
|
}
|
2020-11-13 18:49:27 +02:00
|
|
|
|
|
|
|
outPaths.push_back(outputPath);
|
2020-08-07 22:09:26 +03:00
|
|
|
}
|
2017-07-25 16:09:06 +03:00
|
|
|
|
2022-06-11 16:13:58 +03:00
|
|
|
logger->stop();
|
|
|
|
|
2017-07-25 16:09:06 +03:00
|
|
|
for (auto & path : outPaths)
|
2020-08-07 22:09:26 +03:00
|
|
|
std::cout << store->printStorePath(path) << '\n';
|
2017-07-25 16:09:06 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-06 14:36:55 +03:00
|
|
|
static RegisterLegacyCommand r_nix_build("nix-build", main_nix_build);
|
|
|
|
static RegisterLegacyCommand r_nix_shell("nix-shell", main_nix_build);
|