From ec613603ba324bf12f8f554d74fb1a02c6e9b472 Mon Sep 17 00:00:00 2001 From: regnat Date: Wed, 12 May 2021 16:19:51 +0200 Subject: DerivedPathWithHints -> BuiltPath Just a renaming for now --- src/nix/develop.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 498a7b45c..3762e5bcc 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -265,7 +265,7 @@ struct Common : InstallableCommand, MixProfile for (auto & [installable_, dir_] : redirects) { auto dir = absPath(dir_); auto installable = parseInstallable(store, installable_); - auto buildable = installable->toDerivedPathWithHints(); + auto buildable = installable->toBuiltPath(); auto doRedirect = [&](const StorePath & path) { auto from = store->printStorePath(path); @@ -277,10 +277,10 @@ struct Common : InstallableCommand, MixProfile } }; std::visit(overloaded { - [&](const DerivedPathWithHints::Opaque & bo) { + [&](const BuiltPath::Opaque & bo) { doRedirect(bo.path); }, - [&](const DerivedPathWithHints::Built & bfd) { + [&](const BuiltPath::Built & bfd) { for (auto & [outputName, path] : bfd.outputs) if (path) doRedirect(*path); }, -- cgit v1.2.3 From 21050846457f356346204dd52fb7a6d49f710688 Mon Sep 17 00:00:00 2001 From: regnat Date: Mon, 17 May 2021 08:45:08 +0200 Subject: Enfore the use of properly built paths in libcmd Replace `DerivedPathWithHints` by a new `BuiltPath` type that serves as a proof that the corresponding path has been built. --- src/nix/develop.cc | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 3762e5bcc..2b64d9a31 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -265,9 +265,9 @@ struct Common : InstallableCommand, MixProfile for (auto & [installable_, dir_] : redirects) { auto dir = absPath(dir_); auto installable = parseInstallable(store, installable_); - auto buildable = installable->toBuiltPath(); - auto doRedirect = [&](const StorePath & path) - { + auto builtPaths = toStorePaths( + store, Realise::Nothing, OperateOn::Output, {installable}); + for (auto & path: builtPaths) { auto from = store->printStorePath(path); if (script.find(from) == std::string::npos) warn("'%s' (path '%s') is not used by this build environment", installable->what(), from); @@ -275,16 +275,7 @@ struct Common : InstallableCommand, MixProfile printInfo("redirecting '%s' to '%s'", from, dir); rewrites.insert({from, dir}); } - }; - std::visit(overloaded { - [&](const BuiltPath::Opaque & bo) { - doRedirect(bo.path); - }, - [&](const BuiltPath::Built & bfd) { - for (auto & [outputName, path] : bfd.outputs) - if (path) doRedirect(*path); - }, - }, buildable.raw()); + } } return rewriteStrings(script, rewrites); -- cgit v1.2.3 From 5fd8cf76676a280ae2b7a86ddabc6b14b41ebfe5 Mon Sep 17 00:00:00 2001 From: Matthew Bauer Date: Mon, 17 May 2021 15:07:00 -0500 Subject: Source bashrc first in nix develop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ~/.bashrc should be sourced first in the rc script so that PATH & other env vars give precedence over the bashrc PATH. Also, in my bashrc I alias rm as: alias rm='rm -Iv' To avoid running this alias (which shows ‘removed '/tmp/nix-shell.*'), we can just prefix rm with command. --- src/nix/develop.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 2b64d9a31..10f843651 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -395,7 +395,7 @@ struct CmdDevelop : Common, MixEnvironment if (verbosity >= lvlDebug) script += "set -x\n"; - script += fmt("rm -f '%s'\n", rcFilePath); + script += fmt("command rm -f '%s'\n", rcFilePath); if (phase) { if (!command.empty()) @@ -414,7 +414,7 @@ struct CmdDevelop : Common, MixEnvironment } else { - script += "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc;\n"; + script = "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc;\n" + script; if (developSettings.bashPrompt != "") script += fmt("[ -n \"$PS1\" ] && PS1=%s;\n", shellEscape(developSettings.bashPrompt)); if (developSettings.bashPromptSuffix != "") -- cgit v1.2.3 From 2cf591a134f3ec6f634b47eeb522f422c64a9d33 Mon Sep 17 00:00:00 2001 From: regnat Date: Fri, 11 Jun 2021 13:31:19 +0200 Subject: Make `nix develop` work with CA derivations Fix #4823 --- src/nix/develop.cc | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 10f843651..aeeaf3e13 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -144,17 +144,26 @@ StorePath getDerivationEnvironment(ref 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) { - 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)); + if (settings.isExperimentalFeatureEnabled("ca-derivations")) { + for (auto & output : drv.outputs) { + output.second = { + .output = DerivationOutputDeferred{}, + }; + drv.env[output.first] = ""; + } + } else { + for (auto & output : drv.outputs) { + output.second = { .output = DerivationOutputInputAddressed { .path = StorePath::dummy } }; + drv.env[output.first] = ""; + } + Hash h = std::get<0>(hashDerivationModulo(*store, drv, true)); - 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); + 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); + } } auto shellDrvPath = writeDerivation(*store, drv); @@ -162,8 +171,7 @@ StorePath getDerivationEnvironment(ref store, const StorePath & drvPath) /* Build the derivation. */ store->buildPaths({DerivedPath::Built{shellDrvPath}}); - for (auto & [_0, outputAndOptPath] : drv.outputsAndOptPaths(*store)) { - auto & [_1, optPath] = outputAndOptPath; + for (auto & [_0, optPath] : store->queryPartialDerivationOutputMap(shellDrvPath)) { assert(optPath); auto & outPath = *optPath; assert(store->isValidPath(outPath)); -- cgit v1.2.3 From e6150de90d8db101209fc6363f5f7696ee8192c4 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 15 Jun 2021 12:06:01 +0200 Subject: nix develop: Filter out NIX_REMOTE When recursive Nix is enabled, NIX_REMOTE is set to unix:///build/.nix-socket, which doesn't work outside of the sandbox. --- src/nix/develop.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 10f843651..e51de2de8 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -185,6 +185,7 @@ struct Common : InstallableCommand, MixProfile "NIX_BUILD_TOP", "NIX_ENFORCE_PURITY", "NIX_LOG_FD", + "NIX_REMOTE", "PPID", "PWD", "SHELLOPTS", -- cgit v1.2.3 From ce674cb2cf97fc14ce48acef7f8ef88f4ac771f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Mon, 21 Jun 2021 15:52:01 +0200 Subject: Properly set the output env variables Co-authored-by: John Ericson --- src/nix/develop.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index aeeaf3e13..350b08648 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -150,7 +150,7 @@ StorePath getDerivationEnvironment(ref store, const StorePath & drvPath) output.second = { .output = DerivationOutputDeferred{}, }; - drv.env[output.first] = ""; + drv.env[output.first] = hashPlaceholder(output.first); } } else { for (auto & output : drv.outputs) { -- cgit v1.2.3 From 447928bdb55d160617387e7ac5954f9a8f36004b Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Thu, 13 May 2021 01:20:49 +0200 Subject: Fix usage of structured attrs for `nix develop` --- src/nix/develop.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index e51de2de8..3443fab73 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -256,6 +256,11 @@ struct Common : InstallableCommand, MixProfile // FIXME: properly unquote 'outputs'. StringMap rewrites; for (auto & outputName : tokenizeString>(replaceStrings(outputs->second.quoted, "'", ""))) { + std::regex ptrn(R"re(\[([A-z0-9]+)\]=.*)re"); + std::smatch match; + if (std::regex_match(outputName, match, ptrn)) { + outputName = match[1]; + } auto from = buildEnvironment.env.find(outputName); assert(from != buildEnvironment.env.end()); // FIXME: unquote -- cgit v1.2.3 From 3504c811a55ecd58e0712cf24829c67c192f5e80 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Tue, 18 May 2021 15:07:30 +0200 Subject: Add testcase for `nix develop` with `__structuredAttrs` --- src/nix/develop.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 3443fab73..ee782c4ec 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -256,6 +256,9 @@ struct Common : InstallableCommand, MixProfile // FIXME: properly unquote 'outputs'. StringMap rewrites; for (auto & outputName : tokenizeString>(replaceStrings(outputs->second.quoted, "'", ""))) { + // Hacky way to obtain the key of an associate array. This is needed for strctured attrs where + // `outputs` is an associative array. If the regex isn't matched, the non-structured-attrs behavior will + // be used. std::regex ptrn(R"re(\[([A-z0-9]+)\]=.*)re"); std::smatch match; if (std::regex_match(outputName, match, ptrn)) { -- cgit v1.2.3 From bf7960a4ede0f5ba7e88b939ed0f33aa6087cbc6 Mon Sep 17 00:00:00 2001 From: regnat Date: Tue, 29 Jun 2021 10:13:42 +0200 Subject: develop: Discard the input{Overrides,Updates} when getting bash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `nix develop` is getting bash from an (assumed existing) `nixpkgs` flake. However, when doing so, it reuses the `lockFlags` passed to the current flake, including the `--input-overrides` and `--input-update` which generally don’t make sense anymore at that point (and trigger a warning because of that) Clear these overrides before getting the nixpkgs flake to get rid of the warning. --- src/nix/develop.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index d77ff52d7..6c089469d 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -443,13 +443,17 @@ struct CmdDevelop : Common, MixEnvironment try { auto state = getEvalState(); + auto nixpkgsLockFlags = lockFlags; + nixpkgsLockFlags.inputOverrides = {}; + nixpkgsLockFlags.inputUpdates = {}; + auto bashInstallable = std::make_shared( this, state, installable->nixpkgsFlakeRef(), Strings{"bashInteractive"}, Strings{"legacyPackages." + settings.thisSystem.get() + "."}, - lockFlags); + nixpkgsLockFlags); shell = state->store->printStorePath( toStorePath(state->store, Realise::Outputs, OperateOn::Output, bashInstallable)) + "/bin/bash"; -- cgit v1.2.3 From 087c5f5325c46485a9bc5f8e7f2620af6bf6bf56 Mon Sep 17 00:00:00 2001 From: Michael Fellinger Date: Mon, 5 Jul 2021 12:00:08 +0200 Subject: Fix devShell handling of env values including @ and % --- src/nix/develop.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 6c089469d..699ec0b99 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -54,7 +54,7 @@ BuildEnvironment readEnvironment(const Path & path) R"re((?:[a-zA-Z_][a-zA-Z0-9_]*))re"; static std::string simpleStringRegex = - R"re((?:[a-zA-Z0-9_/:\.\-\+=]*))re"; + R"re((?:[a-zA-Z0-9_/:\.\-\+=@%]*))re"; static std::string dquotedStringRegex = R"re((?:\$?"(?:[^"\\]|\\[$`"\\\n])*"))re"; -- cgit v1.2.3 From b1f1347ade81d1f04f2d490baceefb3c4de0b4e3 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 9 Jul 2021 00:47:57 +0200 Subject: nix develop: Don't parse bash environment with regexes Instead have get-env.sh dump the bash environment as JSON. This should be a lot less error-prone. Fixes #4992. --- src/nix/develop.cc | 170 +++++++++++++++++++++++++---------------------------- 1 file changed, 81 insertions(+), 89 deletions(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 699ec0b99..e00f0d575 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -8,7 +8,7 @@ #include "affinity.hh" #include "progress-bar.hh" -#include +#include using namespace nix; @@ -25,94 +25,98 @@ static DevelopSettings developSettings; static GlobalConfig::Register rDevelopSettings(&developSettings); -struct Var -{ - bool exported = true; - bool associative = false; - std::string quoted; // quoted string or array -}; - struct BuildEnvironment { - std::map env; - std::string bashFunctions; -}; - -BuildEnvironment readEnvironment(const Path & path) -{ - BuildEnvironment res; - - std::set exported; - - debug("reading environment file '%s'", path); - - auto file = readFile(path); - - auto pos = file.cbegin(); - - static std::string varNameRegex = - R"re((?:[a-zA-Z_][a-zA-Z0-9_]*))re"; - - static std::string simpleStringRegex = - R"re((?:[a-zA-Z0-9_/:\.\-\+=@%]*))re"; - - static std::string dquotedStringRegex = - R"re((?:\$?"(?:[^"\\]|\\[$`"\\\n])*"))re"; + struct String + { + bool exported; + std::string value; + }; - static std::string squotedStringRegex = - R"re((?:\$?(?:'(?:[^'\\]|\\[abeEfnrtv\\'"?])*'|\\')+))re"; + using Array = std::vector; - static std::string indexedArrayRegex = - R"re((?:\(( *\[[0-9]+\]="(?:[^"\\]|\\.)*")*\)))re"; + using Associative = std::map; - static std::regex declareRegex( - "^declare -a?x (" + varNameRegex + ")(=(" + - dquotedStringRegex + "|" + indexedArrayRegex + "))?\n"); + using Value = std::variant; - static std::regex varRegex( - "^(" + varNameRegex + ")=(" + simpleStringRegex + "|" + squotedStringRegex + "|" + indexedArrayRegex + ")\n"); + std::map vars; + std::map bashFunctions; - /* Note: we distinguish between an indexed and associative array - using the space before the closing parenthesis. Will - undoubtedly regret this some day. */ - static std::regex assocArrayRegex( - "^(" + varNameRegex + ")=" + R"re((?:\(( *\[[^\]]+\]="(?:[^"\\]|\\.)*")* *\)))re" + "\n"); + static BuildEnvironment fromJSON(const Path & path) + { + BuildEnvironment res; - static std::regex functionRegex( - "^" + varNameRegex + " \\(\\) *\n"); + std::set exported; - while (pos != file.end()) { + debug("reading environment file '%s'", path); - std::smatch match; + auto json = nlohmann::json::parse(readFile(path)); - if (std::regex_search(pos, file.cend(), match, declareRegex, std::regex_constants::match_continuous)) { - pos = match[0].second; - exported.insert(match[1]); + for (auto & [name, info] : json["variables"].items()) { + std::string type = info["type"]; + if (type == "var" || type == "exported") + res.vars.insert({name, BuildEnvironment::String { .exported = type == "exported", .value = info["value"] }}); + else if (type == "array") + res.vars.insert({name, (Array) info["value"]}); + else if (type == "associative") + res.vars.insert({name, (Associative) info["value"]}); } - 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, .quoted = match[2] }}); + for (auto & [name, def] : json["bashFunctions"].items()) { + res.bashFunctions.insert({name, def}); } - 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, .quoted = match[2] }}); - } + return res; + } - else if (std::regex_search(pos, file.cend(), match, functionRegex, std::regex_constants::match_continuous)) { - res.bashFunctions = std::string(pos, file.cend()); - break; + void toBash(std::ostream & out, const std::set & ignoreVars) const + { + for (auto & [name, value] : vars) { + if (!ignoreVars.count(name) && !hasPrefix(name, "BASH_")) { + if (auto str = std::get_if(&value)) { + out << fmt("%s=%s\n", name, shellEscape(str->value)); + if (str->exported) + out << fmt("export %s\n", name); + } + else if (auto arr = std::get_if(&value)) { + out << "declare -a " << name << "=("; + for (auto & s : *arr) + out << shellEscape(s) << " "; + out << ")\n"; + } + else if (auto arr = std::get_if(&value)) { + out << "declare -A " << name << "=("; + for (auto & [n, v] : *arr) + out << "[" << shellEscape(n) << "]=" << shellEscape(v) << " "; + out << ")\n"; + } + } } - else throw Error("shell environment '%s' has unexpected line '%s'", - path, file.substr(pos - file.cbegin(), 60)); + for (auto & [name, def] : bashFunctions) { + out << name << " ()\n{\n" << def << "}\n"; + } } - res.env.erase("__output"); + static std::string getString(const Value & value) + { + if (auto str = std::get_if(&value)) + return str->value; + else + throw Error("bash variable is not a string"); + } - return res; -} + static Array getStrings(const Value & value) + { + if (auto str = std::get_if(&value)) + return tokenizeString(str->value); + else if (auto arr = std::get_if(&value)) { + return *arr; + } + else + throw Error("bash variable is not a string or array"); + } +}; const static std::string getEnvSh = #include "get-env.sh.gen.hh" @@ -185,7 +189,7 @@ StorePath getDerivationEnvironment(ref store, const StorePath & drvPath) struct Common : InstallableCommand, MixProfile { - std::set ignoreVars{ + std::set ignoreVars{ "BASHOPTS", "EUID", "HOME", // FIXME: don't ignore in pure mode? @@ -233,22 +237,10 @@ struct Common : InstallableCommand, MixProfile out << "nix_saved_PATH=\"$PATH\"\n"; - 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.quoted); - else { - out << fmt("%s=%s\n", i.first, i.second.quoted); - if (i.second.exported) - out << fmt("export %s\n", i.first); - } - } - } + buildEnvironment.toBash(out, ignoreVars); out << "PATH=\"$PATH:$nix_saved_PATH\"\n"; - out << buildEnvironment.bashFunctions << "\n"; - out << "export NIX_BUILD_TOP=\"$(mktemp -d -t nix-shell.XXXXXX)\"\n"; for (auto & i : {"TMP", "TMPDIR", "TEMP", "TEMPDIR"}) out << fmt("export %s=\"$NIX_BUILD_TOP\"\n", i); @@ -258,16 +250,16 @@ struct Common : InstallableCommand, MixProfile auto script = out.str(); /* Substitute occurrences of output paths. */ - auto outputs = buildEnvironment.env.find("outputs"); - assert(outputs != buildEnvironment.env.end()); + auto outputs = buildEnvironment.vars.find("outputs"); + assert(outputs != buildEnvironment.vars.end()); // FIXME: properly unquote 'outputs'. StringMap rewrites; - for (auto & outputName : tokenizeString>(replaceStrings(outputs->second.quoted, "'", ""))) { - auto from = buildEnvironment.env.find(outputName); - assert(from != buildEnvironment.env.end()); + for (auto & outputName : BuildEnvironment::getStrings(outputs->second)) { + auto from = buildEnvironment.vars.find(outputName); + assert(from != buildEnvironment.vars.end()); // FIXME: unquote - rewrites.insert({from->second.quoted, outputsDir + "/" + outputName}); + rewrites.insert({BuildEnvironment::getString(from->second), outputsDir + "/" + outputName}); } /* Substitute redirects. */ @@ -321,7 +313,7 @@ struct Common : InstallableCommand, MixProfile updateProfile(shellOutPath); - return {readEnvironment(strPath), strPath}; + return {BuildEnvironment::fromJSON(strPath), strPath}; } }; -- cgit v1.2.3 From 5f6375a816803d17c8ec0f7c2ef960c848be6166 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 9 Jul 2021 01:02:47 +0200 Subject: nix develop: Filter some bash magic variables --- src/nix/develop.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index e00f0d575..9b2945ba3 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -72,7 +72,7 @@ struct BuildEnvironment void toBash(std::ostream & out, const std::set & ignoreVars) const { for (auto & [name, value] : vars) { - if (!ignoreVars.count(name) && !hasPrefix(name, "BASH_")) { + if (!ignoreVars.count(name)) { if (auto str = std::get_if(&value)) { out << fmt("%s=%s\n", name, shellEscape(str->value)); if (str->exported) @@ -191,17 +191,13 @@ struct Common : InstallableCommand, MixProfile { std::set ignoreVars{ "BASHOPTS", - "EUID", "HOME", // FIXME: don't ignore in pure mode? - "HOSTNAME", "NIX_BUILD_TOP", "NIX_ENFORCE_PURITY", "NIX_LOG_FD", "NIX_REMOTE", "PPID", - "PWD", "SHELLOPTS", - "SHLVL", "SSL_CERT_FILE", // FIXME: only want to ignore /no-cert-file.crt "TEMP", "TEMPDIR", -- cgit v1.2.3 From 86fb01c4bee0c4f451504c0f6fd2066d2adc8fc2 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 9 Jul 2021 12:10:48 +0200 Subject: nix print-dev-env: Add --json flag --- src/nix/develop.cc | 59 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 7 deletions(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 9b2945ba3..ca04f297d 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -31,6 +31,11 @@ struct BuildEnvironment { bool exported; std::string value; + + bool operator == (const String & other) const + { + return exported == other.exported && value == other.value; + } }; using Array = std::vector; @@ -42,15 +47,13 @@ struct BuildEnvironment std::map vars; std::map bashFunctions; - static BuildEnvironment fromJSON(const Path & path) + static BuildEnvironment fromJSON(std::string_view in) { BuildEnvironment res; std::set exported; - debug("reading environment file '%s'", path); - - auto json = nlohmann::json::parse(readFile(path)); + auto json = nlohmann::json::parse(in); for (auto & [name, info] : json["variables"].items()) { std::string type = info["type"]; @@ -69,6 +72,38 @@ struct BuildEnvironment return res; } + std::string toJSON() const + { + auto res = nlohmann::json::object(); + + auto vars2 = nlohmann::json::object(); + for (auto & [name, value] : vars) { + auto info = nlohmann::json::object(); + if (auto str = std::get_if(&value)) { + info["type"] = str->exported ? "exported" : "var"; + info["value"] = str->value; + } + else if (auto arr = std::get_if(&value)) { + info["type"] = "array"; + info["value"] = *arr; + } + else if (auto arr = std::get_if(&value)) { + info["type"] = "associative"; + info["value"] = *arr; + } + vars2[name] = std::move(info); + } + res["variables"] = std::move(vars2); + + res["bashFunctions"] = bashFunctions; + + auto json = res.dump(); + + assert(BuildEnvironment::fromJSON(json) == *this); + + return json; + } + void toBash(std::ostream & out, const std::set & ignoreVars) const { for (auto & [name, value] : vars) { @@ -116,6 +151,11 @@ struct BuildEnvironment else throw Error("bash variable is not a string or array"); } + + bool operator == (const BuildEnvironment & other) const + { + return vars == other.vars && bashFunctions == other.bashFunctions; + } }; const static std::string getEnvSh = @@ -309,7 +349,9 @@ struct Common : InstallableCommand, MixProfile updateProfile(shellOutPath); - return {BuildEnvironment::fromJSON(strPath), strPath}; + debug("reading environment file '%s'", strPath); + + return {BuildEnvironment::fromJSON(readFile(strPath)), strPath}; } }; @@ -462,7 +504,7 @@ struct CmdDevelop : Common, MixEnvironment } }; -struct CmdPrintDevEnv : Common +struct CmdPrintDevEnv : Common, MixJSON { std::string description() override { @@ -484,7 +526,10 @@ struct CmdPrintDevEnv : Common stopProgressBar(); - std::cout << makeRcScript(store, buildEnvironment); + logger->writeToStdout( + json + ? buildEnvironment.toJSON() + : makeRcScript(store, buildEnvironment)); } }; -- cgit v1.2.3 From 037c86ee04d681170cedaf71f9d75c186abe9719 Mon Sep 17 00:00:00 2001 From: regnat Date: Tue, 13 Jul 2021 11:44:19 +0200 Subject: nix develop: Search in `devShells.${system}` by default Make `nix develop .#foo` search `.#devShells.${system}.foo` first --- src/nix/develop.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 26f53db09..9ac2791f8 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -326,6 +326,12 @@ struct Common : InstallableCommand, MixProfile { return {"devShell." + settings.thisSystem.get(), "defaultPackage." + settings.thisSystem.get()}; } + Strings getDefaultFlakeAttrPathPrefixes() override + { + auto res = SourceExprCommand::getDefaultFlakeAttrPathPrefixes(); + res.emplace_front("devShells." + settings.thisSystem.get()); + return res; + } StorePath getShellOutPath(ref store) { -- cgit v1.2.3 From 8d9f7048cd3b09fb58f6bad0328f644b0ddaaa16 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 16 Jul 2021 16:04:47 +0200 Subject: Use eval-store in more places In particular, this now works: $ nix path-info --eval-store auto --store https://cache.nixos.org nixpkgs#hello Previously this would fail as it would try to upload the hello .drv to cache.nixos.org. Now the .drv is instantiated in the local store, and then we check for the existence of the outputs in cache.nixos.org. --- src/nix/develop.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 9ac2791f8..cb173b91b 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -307,7 +307,7 @@ struct Common : InstallableCommand, MixProfile auto dir = absPath(dir_); auto installable = parseInstallable(store, installable_); auto builtPaths = toStorePaths( - store, Realise::Nothing, OperateOn::Output, {installable}); + getEvalStore(), store, Realise::Nothing, OperateOn::Output, {installable}); for (auto & path: builtPaths) { auto from = store->printStorePath(path); if (script.find(from) == std::string::npos) @@ -495,8 +495,8 @@ struct CmdDevelop : Common, MixEnvironment Strings{"legacyPackages." + settings.thisSystem.get() + "."}, nixpkgsLockFlags); - shell = state->store->printStorePath( - toStorePath(state->store, Realise::Outputs, OperateOn::Output, bashInstallable)) + "/bin/bash"; + shell = store->printStorePath( + toStorePath(getEvalStore(), store, Realise::Outputs, OperateOn::Output, bashInstallable)) + "/bin/bash"; } catch (Error &) { ignoreException(); } -- cgit v1.2.3 From eb6db4fd384f34ca426116cd353c02af7d0f9214 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 19 Jul 2021 15:43:08 +0200 Subject: buildPaths(): Add an evalStore argument With this, we don't have to copy the entire .drv closure to the destination store ahead of time (or at all). Instead, buildPaths() reads .drv files from the eval store and copies inputSrcs to the destination store if it needs to build a derivation. Issue #5025. --- src/nix/develop.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index cb173b91b..9a93cdb03 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -171,15 +171,15 @@ const static std::string getEnvSh = modified derivation with the same dependencies and nearly the same initial environment variables, that just writes the resulting environment to a file and exits. */ -StorePath getDerivationEnvironment(ref store, const StorePath & drvPath) +static StorePath getDerivationEnvironment(ref store, ref evalStore, const StorePath & drvPath) { - auto drv = store->derivationFromPath(drvPath); + auto drv = evalStore->derivationFromPath(drvPath); auto builder = baseNameOf(drv.builder); if (builder != "bash") throw Error("'nix develop' only works on derivations that use 'bash' as their builder"); - auto getEnvShPath = store->addTextToStore("get-env.sh", getEnvSh, {}); + auto getEnvShPath = evalStore->addTextToStore("get-env.sh", getEnvSh, {}); drv.args = {store->printStorePath(getEnvShPath)}; @@ -205,7 +205,7 @@ StorePath getDerivationEnvironment(ref store, const StorePath & drvPath) output.second = { .output = DerivationOutputInputAddressed { .path = StorePath::dummy } }; drv.env[output.first] = ""; } - Hash h = std::get<0>(hashDerivationModulo(*store, drv, true)); + Hash h = std::get<0>(hashDerivationModulo(*evalStore, drv, true)); for (auto & output : drv.outputs) { auto outPath = store->makeOutputPath(output.first, h, drv.name); @@ -214,12 +214,12 @@ StorePath getDerivationEnvironment(ref store, const StorePath & drvPath) } } - auto shellDrvPath = writeDerivation(*store, drv); + auto shellDrvPath = writeDerivation(*evalStore, drv); /* Build the derivation. */ - store->buildPaths({DerivedPath::Built{shellDrvPath}}); + store->buildPaths({DerivedPath::Built{shellDrvPath}}, bmNormal, evalStore); - for (auto & [_0, optPath] : store->queryPartialDerivationOutputMap(shellDrvPath)) { + for (auto & [_0, optPath] : evalStore->queryPartialDerivationOutputMap(shellDrvPath)) { assert(optPath); auto & outPath = *optPath; assert(store->isValidPath(outPath)); @@ -347,7 +347,7 @@ struct Common : InstallableCommand, MixProfile auto & drvPath = *drvs.begin(); - return getDerivationEnvironment(store, drvPath); + return getDerivationEnvironment(store, getEvalStore(), drvPath); } } @@ -361,7 +361,7 @@ struct Common : InstallableCommand, MixProfile debug("reading environment file '%s'", strPath); - return {BuildEnvironment::fromJSON(readFile(strPath)), strPath}; + return {BuildEnvironment::fromJSON(readFile(store->toRealPath(shellOutPath))), strPath}; } }; -- cgit v1.2.3 From ed5ad59dc16d8207f14c23f7fca903ee408eb54e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 27 Jul 2021 14:23:24 +0200 Subject: nix develop: Support chroot stores Fixes #5024. --- src/nix/develop.cc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 9a93cdb03..55023545d 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -7,6 +7,7 @@ #include "derivations.hh" #include "affinity.hh" #include "progress-bar.hh" +#include "run.hh" #include @@ -472,8 +473,6 @@ struct CmdDevelop : Common, MixEnvironment writeFull(rcFileFd.get(), script); - stopProgressBar(); - setEnviron(); // prevent garbage collection until shell exits setenv("NIX_GCROOT", gcroot.data(), 1); @@ -506,11 +505,7 @@ struct CmdDevelop : Common, MixEnvironment auto args = phase || !command.empty() ? Strings{std::string(baseNameOf(shell)), rcFilePath} : Strings{std::string(baseNameOf(shell)), "--rcfile", rcFilePath}; - restoreProcessContext(); - - execvp(shell.c_str(), stringsToCharPtrs(args).data()); - - throw SysError("executing shell '%s'", shell); + runProgramInStore(store, shell, args); } }; -- cgit v1.2.3 From d7fe36116e029a714aaf0594e06e5d056f70f7d5 Mon Sep 17 00:00:00 2001 From: Matthew Kenigsberg Date: Thu, 19 Aug 2021 15:42:13 -0500 Subject: nix develop --phase: chdir to flake directory For git+file and path flakes, chdir to flake directory so that phases that expect to be in the flake directory can run Fixes https://github.com/NixOS/nix/issues/3976 --- src/nix/develop.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 55023545d..40e9d98b0 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -9,6 +9,7 @@ #include "progress-bar.hh" #include "run.hh" +#include #include using namespace nix; @@ -505,6 +506,20 @@ struct CmdDevelop : Common, MixEnvironment auto args = phase || !command.empty() ? Strings{std::string(baseNameOf(shell)), rcFilePath} : Strings{std::string(baseNameOf(shell)), "--rcfile", rcFilePath}; + // Need to chdir since phases assume in flake directory + if (phase) { + // chdir if installable is a flake of type git+file or path + auto installableFlake = std::dynamic_pointer_cast(installable); + if (installableFlake) { + auto sourcePath = installableFlake->getLockedFlake()->flake.resolvedRef.input.getSourcePath(); + if (sourcePath) { + if (chdir(sourcePath->c_str()) == -1) { + throw SysError("chdir to '%s' failed", *sourcePath); + } + } + } + } + runProgramInStore(store, shell, args); } }; -- cgit v1.2.3 From d7b6c8f59197c5b5a0f8a8ea077538372992d7ef Mon Sep 17 00:00:00 2001 From: Jan Tojnar Date: Sat, 21 Aug 2021 01:24:03 +0200 Subject: nix develop: Fix `devShells` lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It currently fails with the following error: error: flake 'git+file://…' does not provide attribute 'devShells.x86_64-linuxhaskell', 'packages.x86_64-linux.haskell', 'legacyPackages.x86_64-linux.haskell' or 'haskell' --- src/nix/develop.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 55023545d..c823f16c8 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -330,7 +330,7 @@ struct Common : InstallableCommand, MixProfile Strings getDefaultFlakeAttrPathPrefixes() override { auto res = SourceExprCommand::getDefaultFlakeAttrPathPrefixes(); - res.emplace_front("devShells." + settings.thisSystem.get()); + res.emplace_front("devShells." + settings.thisSystem.get() + "."); return res; } -- cgit v1.2.3 From e399c6ab7fbe21e32683a1a4128ff655b276c9bf Mon Sep 17 00:00:00 2001 From: Artturin Date: Sat, 9 Oct 2021 01:19:50 +0300 Subject: nix develop: add --unpack --- src/nix/develop.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index c20b9f272..f22335023 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -392,6 +392,12 @@ struct CmdDevelop : Common, MixEnvironment .handler = {&phase}, }); + addFlag({ + .longName = "unpack", + .description = "Run the `unpack` phase.", + .handler = {&phase, {"unpack"}}, + }); + addFlag({ .longName = "configure", .description = "Run the `configure` phase.", -- cgit v1.2.3 From af99941279b80c962ec9cae3e5fa32976a3f5744 Mon Sep 17 00:00:00 2001 From: regnat Date: Mon, 25 Oct 2021 15:53:01 +0200 Subject: Make experimental-features a proper type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than having them plain strings scattered through the whole codebase, create an enum containing all the known experimental features. This means that - Nix can now `warn` when an unkwown experimental feature is passed (making it much nicer to spot typos and spot deprecated features) - It’s now easy to remove a feature altogether (once the feature isn’t experimental anymore or is dropped) by just removing the field for the enum and letting the compiler point us to all the now invalid usages of it. --- src/nix/develop.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nix/develop.cc') diff --git a/src/nix/develop.cc b/src/nix/develop.cc index f22335023..5aad53919 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -195,7 +195,7 @@ static StorePath getDerivationEnvironment(ref store, ref evalStore 'buildDerivation', but that's privileged. */ drv.name += "-env"; drv.inputSrcs.insert(std::move(getEnvShPath)); - if (settings.isExperimentalFeatureEnabled("ca-derivations")) { + if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) { for (auto & output : drv.outputs) { output.second = { .output = DerivationOutputDeferred{}, -- cgit v1.2.3