aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/generate-manpage.nix5
-rw-r--r--doc/manual/src/command-ref/nix-shell.md15
-rw-r--r--src/libcmd/installables.cc24
-rw-r--r--src/libcmd/installables.hh12
-rw-r--r--src/libstore/build/derivation-goal.cc73
-rw-r--r--src/libstore/build/derivation-goal.hh4
-rw-r--r--src/libstore/derivations.cc39
-rw-r--r--src/libstore/derivations.hh4
-rw-r--r--src/libstore/local-store.cc2
-rw-r--r--src/libstore/local-store.hh2
-rw-r--r--src/libstore/store-api.cc15
-rw-r--r--src/libstore/store-api.hh6
-rwxr-xr-xsrc/nix-build/nix-build.cc6
-rw-r--r--src/nix/app.cc19
-rw-r--r--src/nix/bundle.cc2
-rw-r--r--src/nix/develop.cc3
-rw-r--r--src/nix/flake.cc8
-rw-r--r--src/nix/main.cc23
-rw-r--r--src/nix/profile.cc8
-rw-r--r--src/nix/run.md7
-rw-r--r--tests/content-addressed.sh4
21 files changed, 187 insertions, 94 deletions
diff --git a/doc/manual/generate-manpage.nix b/doc/manual/generate-manpage.nix
index a563c31f8..964b57086 100644
--- a/doc/manual/generate-manpage.nix
+++ b/doc/manual/generate-manpage.nix
@@ -7,7 +7,10 @@ let
showCommand =
{ command, def, filename }:
- "# Name\n\n"
+ ''
+ **Warning**: This program is **experimental** and its interface is subject to change.
+ ''
+ + "# Name\n\n"
+ "`${command}` - ${def.description}\n\n"
+ "# Synopsis\n\n"
+ showSynopsis { inherit command; args = def.args; }
diff --git a/doc/manual/src/command-ref/nix-shell.md b/doc/manual/src/command-ref/nix-shell.md
index 88b675e71..54812a49f 100644
--- a/doc/manual/src/command-ref/nix-shell.md
+++ b/doc/manual/src/command-ref/nix-shell.md
@@ -232,22 +232,23 @@ terraform apply
> in a nix-shell shebang.
Finally, using the merging of multiple nix-shell shebangs the following
-Haskell script uses a specific branch of Nixpkgs/NixOS (the 18.03 stable
+Haskell script uses a specific branch of Nixpkgs/NixOS (the 20.03 stable
branch):
```haskell
#! /usr/bin/env nix-shell
-#! nix-shell -i runghc -p "haskellPackages.ghcWithPackages (ps: [ps.HTTP ps.tagsoup])"
-#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-18.03.tar.gz
+#! nix-shell -i runghc -p "haskellPackages.ghcWithPackages (ps: [ps.download-curl ps.tagsoup])"
+#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-20.03.tar.gz
-import Network.HTTP
+import Network.Curl.Download
import Text.HTML.TagSoup
+import Data.Either
+import Data.ByteString.Char8 (unpack)
-- Fetch nixos.org and print all hrefs.
main = do
- resp <- Network.HTTP.simpleHTTP (getRequest "http://nixos.org/")
- body <- getResponseBody resp
- let tags = filter (isTagOpenName "a") $ parseTags body
+ resp <- openURI "https://nixos.org/"
+ let tags = filter (isTagOpenName "a") $ parseTags $ unpack $ fromRight undefined resp
let tags' = map (fromAttrib "href") tags
mapM_ putStrLn $ filter (/= "") tags'
```
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index 9ad02b5f0..4739dc974 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -496,6 +496,23 @@ static std::string showAttrPaths(const std::vector<std::string> & paths)
return s;
}
+InstallableFlake::InstallableFlake(
+ SourceExprCommand * cmd,
+ ref<EvalState> state,
+ FlakeRef && flakeRef,
+ Strings && attrPaths,
+ Strings && prefixes,
+ const flake::LockFlags & lockFlags)
+ : InstallableValue(state),
+ flakeRef(flakeRef),
+ attrPaths(attrPaths),
+ prefixes(prefixes),
+ lockFlags(lockFlags)
+{
+ if (cmd && cmd->getAutoArgs(*state)->size())
+ throw UsageError("'--arg' and '--argstr' are incompatible with flakes");
+}
+
std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableFlake::toDerivation()
{
auto lockedFlake = getLockedFlake();
@@ -628,9 +645,12 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
try {
auto [flakeRef, fragment] = parseFlakeRefWithFragment(s, absPath("."));
result.push_back(std::make_shared<InstallableFlake>(
- getEvalState(), std::move(flakeRef),
+ this,
+ getEvalState(),
+ std::move(flakeRef),
fragment == "" ? getDefaultFlakeAttrPaths() : Strings{fragment},
- getDefaultFlakeAttrPathPrefixes(), lockFlags));
+ getDefaultFlakeAttrPathPrefixes(),
+ lockFlags));
continue;
} catch (...) {
ex = std::current_exception();
diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh
index f37b3f829..b714f097b 100644
--- a/src/libcmd/installables.hh
+++ b/src/libcmd/installables.hh
@@ -104,11 +104,13 @@ struct InstallableFlake : InstallableValue
const flake::LockFlags & lockFlags;
mutable std::shared_ptr<flake::LockedFlake> _lockedFlake;
- InstallableFlake(ref<EvalState> state, FlakeRef && flakeRef,
- Strings && attrPaths, Strings && prefixes, const flake::LockFlags & lockFlags)
- : InstallableValue(state), flakeRef(flakeRef), attrPaths(attrPaths),
- prefixes(prefixes), lockFlags(lockFlags)
- { }
+ InstallableFlake(
+ SourceExprCommand * cmd,
+ ref<EvalState> state,
+ FlakeRef && flakeRef,
+ Strings && attrPaths,
+ Strings && prefixes,
+ const flake::LockFlags & lockFlags);
std::string what() override { return flakeRef.to_string() + "#" + *attrPaths.begin(); }
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index eeaec4f2c..d8a89a2d0 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -124,6 +124,17 @@ DerivationGoal::DerivationGoal(const StorePath & drvPath, const BasicDerivation
, buildMode(buildMode)
{
this->drv = std::make_unique<BasicDerivation>(BasicDerivation(drv));
+
+ auto outputHashes = staticOutputHashes(worker.store, drv);
+ for (auto &[outputName, outputHash] : outputHashes)
+ initialOutputs.insert({
+ outputName,
+ InitialOutput{
+ .wanted = true, // Will be refined later
+ .outputHash = outputHash
+ }
+ });
+
state = &DerivationGoal::haveDerivation;
name = fmt(
"building of '%s' from in-memory derivation",
@@ -258,8 +269,20 @@ void DerivationGoal::loadDerivation()
assert(worker.store.isValidPath(drvPath));
+ auto fullDrv = new Derivation(worker.store.derivationFromPath(drvPath));
+
+ auto outputHashes = staticOutputHashes(worker.store, *fullDrv);
+ for (auto &[outputName, outputHash] : outputHashes)
+ initialOutputs.insert({
+ outputName,
+ InitialOutput{
+ .wanted = true, // Will be refined later
+ .outputHash = outputHash
+ }
+ });
+
/* Get the derivation. */
- drv = std::unique_ptr<BasicDerivation>(new Derivation(worker.store.derivationFromPath(drvPath)));
+ drv = std::unique_ptr<BasicDerivation>(fullDrv);
haveDerivation();
}
@@ -506,6 +529,7 @@ void DerivationGoal::inputsRealised()
Derivation drvResolved { *std::move(attempt) };
auto pathResolved = writeDerivation(worker.store, drvResolved);
+ resolvedDrv = drvResolved;
auto msg = fmt("Resolved derivation: '%s' -> '%s'",
worker.store.printStorePath(drvPath),
@@ -1019,7 +1043,37 @@ void DerivationGoal::buildDone()
}
void DerivationGoal::resolvedFinished() {
- done(BuildResult::Built);
+ assert(resolvedDrv);
+
+ auto resolvedHashes = staticOutputHashes(worker.store, *resolvedDrv);
+
+ // `wantedOutputs` might be empty, which means “all the outputs”
+ auto realWantedOutputs = wantedOutputs;
+ if (realWantedOutputs.empty())
+ realWantedOutputs = resolvedDrv->outputNames();
+
+ for (auto & wantedOutput : realWantedOutputs) {
+ assert(initialOutputs.count(wantedOutput) != 0);
+ assert(resolvedHashes.count(wantedOutput) != 0);
+ auto realisation = worker.store.queryRealisation(
+ DrvOutput{resolvedHashes.at(wantedOutput), wantedOutput}
+ );
+ // We've just built it, but maybe the build failed, in which case the
+ // realisation won't be there
+ if (realisation) {
+ auto newRealisation = *realisation;
+ newRealisation.id = DrvOutput{initialOutputs.at(wantedOutput).outputHash, wantedOutput};
+ worker.store.registerDrvOutput(newRealisation);
+ } else {
+ // If we don't have a realisation, then it must mean that something
+ // failed when building the resolved drv
+ assert(!result.success());
+ }
+ }
+
+ // This is potentially a bit fishy in terms of error reporting. Not sure
+ // how to do it in a cleaner way
+ amDone(nrFailed == 0 ? ecSuccess : ecFailed, ex);
}
HookReply DerivationGoal::tryBuildHook()
@@ -3790,9 +3844,8 @@ void DerivationGoal::checkPathValidity()
{
bool checkHash = buildMode == bmRepair;
for (auto & i : queryPartialDerivationOutputMap()) {
- InitialOutput info {
- .wanted = wantOutput(i.first, wantedOutputs),
- };
+ InitialOutput & info = initialOutputs.at(i.first);
+ info.wanted = wantOutput(i.first, wantedOutputs);
if (i.second) {
auto outputPath = *i.second;
info.known = {
@@ -3804,7 +3857,15 @@ void DerivationGoal::checkPathValidity()
: PathStatus::Corrupt,
};
}
- initialOutputs.insert_or_assign(i.first, info);
+ if (settings.isExperimentalFeatureEnabled("ca-derivations")) {
+ if (auto real = worker.store.queryRealisation(
+ DrvOutput{initialOutputs.at(i.first).outputHash, i.first})) {
+ info.known = {
+ .path = real->outPath,
+ .status = PathStatus::Valid,
+ };
+ }
+ }
}
}
diff --git a/src/libstore/build/derivation-goal.hh b/src/libstore/build/derivation-goal.hh
index 8ee0be9e1..761100d3a 100644
--- a/src/libstore/build/derivation-goal.hh
+++ b/src/libstore/build/derivation-goal.hh
@@ -37,6 +37,7 @@ struct InitialOutputStatus {
struct InitialOutput {
bool wanted;
+ Hash outputHash;
std::optional<InitialOutputStatus> known;
};
@@ -48,6 +49,9 @@ struct DerivationGoal : public Goal
/* The path of the derivation. */
StorePath drvPath;
+ /* The path of the corresponding resolved derivation */
+ std::optional<BasicDerivation> resolvedDrv;
+
/* The specific outputs that we need to build. Empty means all of
them. */
StringSet wantedOutputs;
diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc
index 7466c7d41..6d0742b4f 100644
--- a/src/libstore/derivations.cc
+++ b/src/libstore/derivations.cc
@@ -745,7 +745,7 @@ static void rewriteDerivation(Store & store, BasicDerivation & drv, const String
}
-std::optional<BasicDerivation> Derivation::tryResolveUncached(Store & store) {
+std::optional<BasicDerivation> Derivation::tryResolve(Store & store) {
BasicDerivation resolved { *this };
// Input paths that we'll want to rewrite in the derivation
@@ -756,8 +756,13 @@ std::optional<BasicDerivation> Derivation::tryResolveUncached(Store & store) {
StringSet newOutputNames;
for (auto & outputName : input.second) {
auto actualPathOpt = inputDrvOutputs.at(outputName);
- if (!actualPathOpt)
+ if (!actualPathOpt) {
+ warn("output %s of input %s missing, aborting the resolving",
+ outputName,
+ store.printStorePath(input.first)
+ );
return std::nullopt;
+ }
auto actualPath = *actualPathOpt;
inputRewrites.emplace(
downstreamPlaceholder(store, input.first, outputName),
@@ -771,34 +776,4 @@ std::optional<BasicDerivation> Derivation::tryResolveUncached(Store & store) {
return resolved;
}
-std::optional<BasicDerivation> Derivation::tryResolve(Store& store)
-{
- auto drvPath = writeDerivation(store, *this, NoRepair, false);
- return Derivation::tryResolve(store, drvPath);
-}
-
-std::optional<BasicDerivation> Derivation::tryResolve(Store& store, const StorePath& drvPath)
-{
- // This is quite dirty and leaky, but will disappear once #4340 is merged
- static Sync<std::map<StorePath, std::optional<Derivation>>> resolutionsCache;
-
- {
- auto resolutions = resolutionsCache.lock();
- auto resolvedDrvIter = resolutions->find(drvPath);
- if (resolvedDrvIter != resolutions->end()) {
- auto & [_, resolvedDrv] = *resolvedDrvIter;
- return *resolvedDrv;
- }
- }
-
- /* Try resolve drv and use that path instead. */
- auto drv = store.readDerivation(drvPath);
- auto attempt = drv.tryResolveUncached(store);
- if (!attempt)
- return std::nullopt;
- /* Store in memo table. */
- resolutionsCache.lock()->insert_or_assign(drvPath, *attempt);
- return *attempt;
-}
-
}
diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh
index 3d8f19aef..4e5985fab 100644
--- a/src/libstore/derivations.hh
+++ b/src/libstore/derivations.hh
@@ -138,14 +138,10 @@ struct Derivation : BasicDerivation
2. Input placeholders are replaced with realized input store paths. */
std::optional<BasicDerivation> tryResolve(Store & store);
- static std::optional<BasicDerivation> tryResolve(Store & store, const StorePath & drvPath);
Derivation() = default;
Derivation(const BasicDerivation & bd) : BasicDerivation(bd) { }
Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { }
-
-private:
- std::optional<BasicDerivation> tryResolveUncached(Store & store);
};
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index f45af2bac..0962418dd 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -883,7 +883,7 @@ StorePathSet LocalStore::queryValidDerivers(const StorePath & path)
std::map<std::string, std::optional<StorePath>>
-LocalStore::queryDerivationOutputMapNoResolve(const StorePath& path_)
+LocalStore::queryPartialDerivationOutputMap(const StorePath & path_)
{
auto path = path_;
auto outputs = retrySQLite<std::map<std::string, std::optional<StorePath>>>([&]() {
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 9d235ba0a..780cc0f07 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -127,7 +127,7 @@ public:
StorePathSet queryValidDerivers(const StorePath & path) override;
- std::map<std::string, std::optional<StorePath>> queryDerivationOutputMapNoResolve(const StorePath & path) override;
+ std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path) override;
std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 37c11fe86..2658f7617 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -366,7 +366,7 @@ bool Store::PathInfoCacheValue::isKnownNow()
return std::chrono::steady_clock::now() < time_point + ttl;
}
-std::map<std::string, std::optional<StorePath>> Store::queryDerivationOutputMapNoResolve(const StorePath & path)
+std::map<std::string, std::optional<StorePath>> Store::queryPartialDerivationOutputMap(const StorePath & path)
{
std::map<std::string, std::optional<StorePath>> outputs;
auto drv = readInvalidDerivation(path);
@@ -376,19 +376,6 @@ std::map<std::string, std::optional<StorePath>> Store::queryDerivationOutputMapN
return outputs;
}
-std::map<std::string, std::optional<StorePath>> Store::queryPartialDerivationOutputMap(const StorePath & path)
-{
- if (settings.isExperimentalFeatureEnabled("ca-derivations")) {
- auto resolvedDrv = Derivation::tryResolve(*this, path);
- if (resolvedDrv) {
- auto resolvedDrvPath = writeDerivation(*this, *resolvedDrv, NoRepair, true);
- if (isValidPath(resolvedDrvPath))
- return queryDerivationOutputMapNoResolve(resolvedDrvPath);
- }
- }
- return queryDerivationOutputMapNoResolve(path);
-}
-
OutputPathMap Store::queryDerivationOutputMap(const StorePath & path) {
auto resp = queryPartialDerivationOutputMap(path);
OutputPathMap result;
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 9e98eb8f9..6dcd43ed1 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -415,12 +415,6 @@ public:
`std::nullopt`. */
virtual std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap(const StorePath & path);
- /*
- * Similar to `queryPartialDerivationOutputMap`, but doesn't try to resolve
- * the derivation
- */
- virtual std::map<std::string, std::optional<StorePath>> queryDerivationOutputMapNoResolve(const StorePath & path);
-
/* Query the mapping outputName=>outputPath for the given derivation.
Assume every output has a mapping and throw an exception otherwise. */
OutputPathMap queryDerivationOutputMap(const StorePath & path);
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index 361f9730d..d975cd16d 100755
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -518,9 +518,11 @@ static void main_nix_build(int argc, char * * argv)
if (counter)
drvPrefix += fmt("-%d", counter + 1);
- auto builtOutputs = store->queryDerivationOutputMap(drvPath);
+ auto builtOutputs = store->queryPartialDerivationOutputMap(drvPath);
- auto outputPath = builtOutputs.at(outputName);
+ auto maybeOutputPath = builtOutputs.at(outputName);
+ assert(maybeOutputPath);
+ auto outputPath = *maybeOutputPath;
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>()) {
std::string symlink = drvPrefix;
diff --git a/src/nix/app.cc b/src/nix/app.cc
index 80acbf658..cf147c631 100644
--- a/src/nix/app.cc
+++ b/src/nix/app.cc
@@ -12,11 +12,16 @@ App Installable::toApp(EvalState & state)
auto type = cursor->getAttr("type")->getString();
+ auto checkProgram = [&](const Path & program)
+ {
+ if (!state.store->isInStore(program))
+ throw Error("app program '%s' is not in the Nix store", program);
+ };
+
if (type == "app") {
auto [program, context] = cursor->getAttr("program")->getStringWithContext();
- if (!state.store->isInStore(program))
- throw Error("app program '%s' is not in the Nix store", program);
+ checkProgram(program);
std::vector<StorePathWithOutputs> context2;
for (auto & [path, name] : context)
@@ -33,9 +38,17 @@ App Installable::toApp(EvalState & state)
auto outPath = cursor->getAttr(state.sOutPath)->getString();
auto outputName = cursor->getAttr(state.sOutputName)->getString();
auto name = cursor->getAttr(state.sName)->getString();
+ auto aMeta = cursor->maybeGetAttr("meta");
+ auto aMainProgram = aMeta ? aMeta->maybeGetAttr("mainProgram") : nullptr;
+ auto mainProgram =
+ aMainProgram
+ ? aMainProgram->getString()
+ : DrvName(name).name;
+ auto program = outPath + "/bin/" + mainProgram;
+ checkProgram(program);
return App {
.context = { { drvPath, {outputName} } },
- .program = outPath + "/bin/" + DrvName(name).name,
+ .program = program,
};
}
diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc
index 1789e4598..48f4eb6e3 100644
--- a/src/nix/bundle.cc
+++ b/src/nix/bundle.cc
@@ -74,7 +74,7 @@ struct CmdBundle : InstallableCommand
auto [bundlerFlakeRef, bundlerName] = parseFlakeRefWithFragment(bundler, absPath("."));
const flake::LockFlags lockFlags{ .writeLockFile = false };
- auto bundler = InstallableFlake(
+ auto bundler = InstallableFlake(this,
evalState, std::move(bundlerFlakeRef),
Strings{bundlerName == "" ? "defaultBundler" : bundlerName},
Strings({"bundlers."}), lockFlags);
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index 3c44fdb0e..d0b140570 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -59,7 +59,7 @@ BuildEnvironment readEnvironment(const Path & path)
R"re((?:\$?"(?:[^"\\]|\\[$`"\\\n])*"))re";
static std::string squotedStringRegex =
- R"re((?:\$?'(?:[^'\\]|\\[abeEfnrtv\\'"?])*'))re";
+ R"re((?:\$?(?:'(?:[^'\\]|\\[abeEfnrtv\\'"?])*'|\\')+))re";
static std::string indexedArrayRegex =
R"re((?:\(( *\[[0-9]+\]="(?:[^"\\]|\\.)*")*\)))re";
@@ -443,6 +443,7 @@ struct CmdDevelop : Common, MixEnvironment
auto state = getEvalState();
auto bashInstallable = std::make_shared<InstallableFlake>(
+ this,
state,
installable->nixpkgsFlakeRef(),
Strings{"bashInteractive"},
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 4cd7d77a0..b9cde5d6d 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -595,7 +595,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
auto [templateFlakeRef, templateName] = parseFlakeRefWithFragment(templateUrl, absPath("."));
- auto installable = InstallableFlake(
+ auto installable = InstallableFlake(nullptr,
evalState, std::move(templateFlakeRef),
Strings{templateName == "" ? "defaultTemplate" : templateName},
Strings(attrsPathPrefixes), lockFlags);
@@ -880,7 +880,8 @@ struct CmdFlakeShow : FlakeCommand
|| attrPath[0] == "nixosConfigurations"
|| attrPath[0] == "nixosModules"
|| attrPath[0] == "defaultApp"
- || attrPath[0] == "templates"))
+ || attrPath[0] == "templates"
+ || attrPath[0] == "overlays"))
|| ((attrPath.size() == 1 || attrPath.size() == 2)
&& (attrPath[0] == "checks"
|| attrPath[0] == "packages"
@@ -943,7 +944,8 @@ struct CmdFlakeShow : FlakeCommand
else {
logger->cout("%s: %s",
headerPrefix,
- attrPath.size() == 1 && attrPath[0] == "overlay" ? "Nixpkgs overlay" :
+ (attrPath.size() == 1 && attrPath[0] == "overlay")
+ || (attrPath.size() == 2 && attrPath[0] == "overlays") ? "Nixpkgs overlay" :
attrPath.size() == 2 && attrPath[0] == "nixosConfigurations" ? "NixOS configuration" :
attrPath.size() == 2 && attrPath[0] == "nixosModules" ? "NixOS module" :
ANSI_YELLOW "unknown" ANSI_NORMAL);
diff --git a/src/nix/main.cc b/src/nix/main.cc
index ef5e41a55..1b68cf15b 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -17,6 +17,10 @@
#include <netdb.h>
#include <netinet/in.h>
+#if __linux__
+#include <sys/resource.h>
+#endif
+
#include <nlohmann/json.hpp>
extern std::string chrootHelperName;
@@ -61,6 +65,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
bool printBuildLogs = false;
bool useNet = true;
bool refresh = false;
+ bool showVersion = false;
NixArgs() : MultiCommand(RegisterCommand::getCommandsFor({})), MixCommonArgs("nix")
{
@@ -87,7 +92,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
addFlag({
.longName = "version",
.description = "Show version information.",
- .handler = {[&]() { if (!completions) printVersion(programName); }},
+ .handler = {[&]() { showVersion = true; }},
});
addFlag({
@@ -280,6 +285,11 @@ void mainWrapped(int argc, char * * argv)
initPlugins();
+ if (args.showVersion) {
+ printVersion(programName);
+ return;
+ }
+
if (!args.command)
throw UsageError("no subcommand specified");
@@ -319,6 +329,17 @@ void mainWrapped(int argc, char * * argv)
int main(int argc, char * * argv)
{
+ // Increase the default stack size for the evaluator and for
+ // libstdc++'s std::regex.
+ #if __linux__
+ rlim_t stackSize = 64 * 1024 * 1024;
+ struct rlimit limit;
+ if (getrlimit(RLIMIT_STACK, &limit) == 0 && limit.rlim_cur < stackSize) {
+ limit.rlim_cur = stackSize;
+ setrlimit(RLIMIT_STACK, &limit);
+ }
+ #endif
+
return nix::handleExceptions(argv[0], [&]() {
nix::mainWrapped(argc, argv);
});
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index 827f8be5a..4d275f577 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -399,7 +399,13 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
Activity act(*logger, lvlChatty, actUnknown,
fmt("checking '%s' for updates", element.source->attrPath));
- InstallableFlake installable(getEvalState(), FlakeRef(element.source->originalRef), {element.source->attrPath}, {}, lockFlags);
+ InstallableFlake installable(
+ this,
+ getEvalState(),
+ FlakeRef(element.source->originalRef),
+ {element.source->attrPath},
+ {},
+ lockFlags);
auto [attrPath, resolvedRef, drv] = installable.toDerivation();
diff --git a/src/nix/run.md b/src/nix/run.md
index c178e8b13..a76750376 100644
--- a/src/nix/run.md
+++ b/src/nix/run.md
@@ -43,9 +43,10 @@ program specified by the app definition.
If *installable* evaluates to a derivation, it will try to execute the
program `<out>/bin/<name>`, where *out* is the primary output store
-path of the derivation and *name* is the name part of the value of the
-`name` attribute of the derivation (e.g. if `name` is set to
-`hello-1.10`, it will run `$out/bin/hello`).
+path of the derivation and *name* is the `meta.mainProgram` attribute
+of the derivation if it exists, and otherwise the name part of the
+value of the `name` attribute of the derivation (e.g. if `name` is set
+to `hello-1.10`, it will run `$out/bin/hello`).
# Flake output attributes
diff --git a/tests/content-addressed.sh b/tests/content-addressed.sh
index e8ac88609..7e32e1f28 100644
--- a/tests/content-addressed.sh
+++ b/tests/content-addressed.sh
@@ -48,6 +48,10 @@ testCutoff () {
testGC () {
nix-instantiate --experimental-features ca-derivations ./content-addressed.nix -A rootCA --arg seed 5
nix-collect-garbage --experimental-features ca-derivations --option keep-derivations true
+ clearStore
+ buildAttr rootCA 1 --out-link $TEST_ROOT/rootCA
+ nix-collect-garbage --experimental-features ca-derivations
+ buildAttr rootCA 1 -j0
}
testNixCommand () {