diff options
-rw-r--r-- | doc/manual/generate-manpage.nix | 5 | ||||
-rw-r--r-- | doc/manual/src/command-ref/nix-shell.md | 15 | ||||
-rw-r--r-- | src/libcmd/installables.cc | 24 | ||||
-rw-r--r-- | src/libcmd/installables.hh | 12 | ||||
-rw-r--r-- | src/libstore/build/derivation-goal.cc | 73 | ||||
-rw-r--r-- | src/libstore/build/derivation-goal.hh | 4 | ||||
-rw-r--r-- | src/libstore/derivations.cc | 39 | ||||
-rw-r--r-- | src/libstore/derivations.hh | 4 | ||||
-rw-r--r-- | src/libstore/local-store.cc | 2 | ||||
-rw-r--r-- | src/libstore/local-store.hh | 2 | ||||
-rw-r--r-- | src/libstore/store-api.cc | 15 | ||||
-rw-r--r-- | src/libstore/store-api.hh | 6 | ||||
-rwxr-xr-x | src/nix-build/nix-build.cc | 6 | ||||
-rw-r--r-- | src/nix/app.cc | 19 | ||||
-rw-r--r-- | src/nix/bundle.cc | 2 | ||||
-rw-r--r-- | src/nix/develop.cc | 3 | ||||
-rw-r--r-- | src/nix/flake.cc | 8 | ||||
-rw-r--r-- | src/nix/main.cc | 23 | ||||
-rw-r--r-- | src/nix/profile.cc | 8 | ||||
-rw-r--r-- | src/nix/run.md | 7 | ||||
-rw-r--r-- | tests/content-addressed.sh | 4 |
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 () { |