Compare commits

..

1 commit

Author SHA1 Message Date
Rebecca Turner
47677c645e
repl-overlays: Provide an elaborate example
This is the repl overlay from my dotfiles, which I think provides a
reasonable and ergonomic set of variables. We can iterate on this over
time, or (perhaps?) provide a sentinel value like `repl-overlays =
<DEFAULT>` to include a "suggested default" overlay like this one.
2024-09-01 15:28:59 -07:00
34 changed files with 176 additions and 459 deletions

View file

@ -1,10 +0,0 @@
---
synopsis: "`Alt+Left` and `Alt+Right` go back/forwards by words in `nix repl`"
issues: [fj#501]
cls: [1883]
category: Fixes
credits: 9999years
---
`nix repl` now recognizes `Alt+Left` and `Alt+Right` for navigating by words
when entering input in `nix repl` on more terminals/platforms.

View file

@ -99,10 +99,9 @@
]; ];
stdenvs = [ stdenvs = [
# see assertion in package.nix why these two are disabled "gccStdenv"
# "stdenv"
# "gccStdenv"
"clangStdenv" "clangStdenv"
"stdenv"
"libcxxStdenv" "libcxxStdenv"
"ccacheStdenv" "ccacheStdenv"
]; ];
@ -122,11 +121,7 @@
name = "${stdenvName}Packages"; name = "${stdenvName}Packages";
value = f stdenvName; value = f stdenvName;
}) stdenvs }) stdenvs
) );
// {
# TODO delete this and reënable gcc stdenvs once gcc compiles kj coros correctly
stdenvPackages = f "clangStdenv";
};
# Memoize nixpkgs for different platforms for efficiency. # Memoize nixpkgs for different platforms for efficiency.
nixpkgsFor = forAllSystems ( nixpkgsFor = forAllSystems (

View file

@ -167,18 +167,10 @@ endif
# frees one would expect when the objects are unique_ptrs. these problems # frees one would expect when the objects are unique_ptrs. these problems
# often show up as memory corruption when nesting generators (since we do # often show up as memory corruption when nesting generators (since we do
# treat generators like owned memory) and will cause inexplicable crashs. # treat generators like owned memory) and will cause inexplicable crashs.
#
# gcc 13 does not compile capnp coroutine code correctly. a newer version
# may fix this. (cf. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102051)
# we allow gcc 13 here anyway because CI uses it for clang-tidy, and when
# the compiler crashes outright if won't produce any bad binaries either.
assert( assert(
cxx.get_id() != 'gcc' or cxx.version().version_compare('>=13'), cxx.get_id() != 'gcc' or cxx.version().version_compare('>=13'),
'GCC is known to miscompile coroutines, use clang.' 'GCC 12 and earlier are known to miscompile lix coroutines, use GCC 13 or clang.'
) )
if cxx.get_id() == 'gcc'
warning('GCC is known to crash while building coroutines, use clang.')
endif
# Translate some historical and Mesony CPU names to Lixy CPU names. # Translate some historical and Mesony CPU names to Lixy CPU names.
@ -237,7 +229,6 @@ configdata += {
} }
boost = dependency('boost', required : true, modules : ['container'], include_type : 'system') boost = dependency('boost', required : true, modules : ['container'], include_type : 'system')
kj = dependency('kj-async', required : true, include_type : 'system')
# cpuid only makes sense on x86_64 # cpuid only makes sense on x86_64
cpuid_required = is_x64 ? get_option('cpuid') : false cpuid_required = is_x64 ? get_option('cpuid') : false

View file

@ -15,14 +15,11 @@
brotli, brotli,
bzip2, bzip2,
callPackage, callPackage,
capnproto-lix ? __forDefaults.capnproto-lix,
capnproto,
cmake, cmake,
curl, curl,
doxygen, doxygen,
editline-lix ? __forDefaults.editline-lix, editline-lix ? __forDefaults.editline-lix,
editline, editline,
fetchpatch,
git, git,
gtest, gtest,
jq, jq,
@ -39,7 +36,6 @@
mercurial, mercurial,
meson, meson,
ninja, ninja,
ncurses,
openssl, openssl,
pegtl, pegtl,
pkg-config, pkg-config,
@ -83,44 +79,12 @@
boehmgc-nix = boehmgc.override { enableLargeConfig = true; }; boehmgc-nix = boehmgc.override { enableLargeConfig = true; };
editline-lix = editline.overrideAttrs (prev: { editline-lix = editline.overrideAttrs (prev: {
patches = (prev.patches or [ ]) ++ [ configureFlags = prev.configureFlags or [ ] ++ [ (lib.enableFeature true "sigstop") ];
# Recognize `Alt-Left` and `Alt-Right` for navigating by words in more
# terminals/shells/platforms.
#
# See: https://github.com/troglobit/editline/pull/70/commits
(fetchpatch {
url = "https://github.com/troglobit/editline/pull/70/commits/d0f2a5bc2300b96b2434c7838184c1dfd6a639f5.diff";
hash = "sha256-0bbtYDUlk1wA0kpTtlaNI6KaCjLmAesZjcWBJZ+DpyQ=";
})
(fetchpatch {
url = "https://github.com/troglobit/editline/pull/70/commits/4c4455353a0a88bee09d5f27c28f81f747682fed.diff";
hash = "sha256-nVezspwVzeB/8zENeKgwPVum0W1MLv4dOW0967WbX5w=";
})
];
configureFlags = (prev.configureFlags or [ ]) ++ [
# Enable SIGSTOP (Ctrl-Z) behavior.
(lib.enableFeature true "sigstop")
# Enable ANSI arrow keys.
(lib.enableFeature true "arrow-keys")
# Use termcap library to query terminal size.
(lib.enableFeature (ncurses != null) "termcap")
];
nativeBuildInputs = (prev.nativeBuildInputs or [ ]) ++ [ ncurses ];
}); });
build-release-notes = callPackage ./maintainers/build-release-notes.nix { }; build-release-notes = callPackage ./maintainers/build-release-notes.nix { };
# needs explicit c++20 to enable coroutine support
capnproto-lix = capnproto.overrideAttrs { CXXFLAGS = "-std=c++20"; };
}, },
}: }:
# gcc miscompiles coroutines at least until 13.2, possibly longer
assert stdenv.cc.isClang || lintInsteadOfBuild;
let let
inherit (__forDefaults) canRunInstalled; inherit (__forDefaults) canRunInstalled;
inherit (lib) fileset; inherit (lib) fileset;
@ -256,7 +220,6 @@ stdenv.mkDerivation (finalAttrs: {
ninja ninja
cmake cmake
rustc rustc
capnproto-lix
] ]
++ [ ++ [
(lib.getBin lowdown) (lib.getBin lowdown)
@ -297,7 +260,6 @@ stdenv.mkDerivation (finalAttrs: {
libsodium libsodium
toml11 toml11
pegtl pegtl
capnproto-lix
] ]
++ lib.optionals hostPlatform.isLinux [ ++ lib.optionals hostPlatform.isLinux [
libseccomp libseccomp

View file

@ -7,32 +7,6 @@
namespace nix { namespace nix {
void to_json(nlohmann::json & j, const AcceptFlakeConfig & e)
{
if (e == AcceptFlakeConfig::False) {
j = false;
} else if (e == AcceptFlakeConfig::Ask) {
j = "ask";
} else if (e == AcceptFlakeConfig::True) {
j = true;
} else {
abort();
}
}
void from_json(const nlohmann::json & j, AcceptFlakeConfig & e)
{
if (j == false) {
e = AcceptFlakeConfig::False;
} else if (j == "ask") {
e = AcceptFlakeConfig::Ask;
} else if (j == true) {
e = AcceptFlakeConfig::True;
} else {
throw Error("Invalid accept-flake-config value '%s'", std::string(j));
}
}
template<> AcceptFlakeConfig BaseSetting<AcceptFlakeConfig>::parse(const std::string & str, const ApplyConfigOptions & options) const template<> AcceptFlakeConfig BaseSetting<AcceptFlakeConfig>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {
if (str == "true") return AcceptFlakeConfig::True; if (str == "true") return AcceptFlakeConfig::True;

View file

@ -13,9 +13,6 @@ namespace nix {
enum class AcceptFlakeConfig { False, Ask, True }; enum class AcceptFlakeConfig { False, Ask, True };
void to_json(nlohmann::json & j, const AcceptFlakeConfig & e);
void from_json(const nlohmann::json & j, AcceptFlakeConfig & e);
struct FetchSettings : public Config struct FetchSettings : public Config
{ {
FetchSettings(); FetchSettings();

View file

@ -92,7 +92,7 @@ void ProgressBar::resume()
nextWakeup = draw(*state, {}); nextWakeup = draw(*state, {});
state.wait_for(quitCV, std::chrono::milliseconds(50)); state.wait_for(quitCV, std::chrono::milliseconds(50));
} }
eraseProgressDisplay(*state); writeLogsToStderr("\r\e[K");
}); });
} }
@ -558,8 +558,7 @@ std::optional<char> ProgressBar::ask(std::string_view msg)
{ {
auto state(state_.lock()); auto state(state_.lock());
if (state->paused > 0 || !isatty(STDIN_FILENO)) return {}; if (state->paused > 0 || !isatty(STDIN_FILENO)) return {};
eraseProgressDisplay(*state); std::cerr << fmt("\r\e[K%s ", msg);
std::cerr << msg;
auto s = trim(readLine(STDIN_FILENO)); auto s = trim(readLine(STDIN_FILENO));
if (s.size() != 1) return {}; if (s.size() != 1) return {};
draw(*state, {}); draw(*state, {});

View file

@ -131,7 +131,7 @@ Goal::Finished DerivationGoal::timedOut(Error && ex)
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::work(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::work(bool inBuildSlot)
{ {
return (this->*state)(inBuildSlot); return (this->*state)(inBuildSlot);
} }
@ -157,8 +157,8 @@ void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::getDerivation(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::getDerivation(bool inBuildSlot)
try { {
trace("init"); trace("init");
/* The first thing to do is to make sure that the derivation /* The first thing to do is to make sure that the derivation
@ -170,22 +170,16 @@ try {
state = &DerivationGoal::loadDerivation; state = &DerivationGoal::loadDerivation;
return {WaitForGoals{{worker.goalFactory().makePathSubstitutionGoal(drvPath)}}}; return WaitForGoals{{worker.goalFactory().makePathSubstitutionGoal(drvPath)}};
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::loadDerivation(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::loadDerivation(bool inBuildSlot)
try { {
trace("loading derivation"); trace("loading derivation");
if (nrFailed != 0) { if (nrFailed != 0) {
return {done( return done(BuildResult::MiscFailure, {}, Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath)));
BuildResult::MiscFailure,
{},
Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath))
)};
} }
/* `drvPath' should already be a root, but let's be on the safe /* `drvPath' should already be a root, but let's be on the safe
@ -208,13 +202,11 @@ try {
assert(drv); assert(drv);
return haveDerivation(inBuildSlot); return haveDerivation(inBuildSlot);
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::haveDerivation(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::haveDerivation(bool inBuildSlot)
try { {
trace("have derivation"); trace("have derivation");
parsedDrv = std::make_unique<ParsedDerivation>(drvPath, *drv); parsedDrv = std::make_unique<ParsedDerivation>(drvPath, *drv);
@ -263,7 +255,7 @@ try {
/* If they are all valid, then we're done. */ /* If they are all valid, then we're done. */
if (allValid && buildMode == bmNormal) { if (allValid && buildMode == bmNormal) {
return {done(BuildResult::AlreadyValid, std::move(validOutputs))}; return done(BuildResult::AlreadyValid, std::move(validOutputs));
} }
/* We are first going to try to create the invalid output paths /* We are first going to try to create the invalid output paths
@ -298,29 +290,20 @@ try {
return outputsSubstitutionTried(inBuildSlot); return outputsSubstitutionTried(inBuildSlot);
} else { } else {
state = &DerivationGoal::outputsSubstitutionTried; state = &DerivationGoal::outputsSubstitutionTried;
return {std::move(result)}; return result;
} }
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::outputsSubstitutionTried(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::outputsSubstitutionTried(bool inBuildSlot)
try { {
trace("all outputs substituted (maybe)"); trace("all outputs substituted (maybe)");
assert(drv->type().isPure()); assert(drv->type().isPure());
if (nrFailed > 0 && nrFailed > nrNoSubstituters + nrIncompleteClosure && !settings.tryFallback) if (nrFailed > 0 && nrFailed > nrNoSubstituters + nrIncompleteClosure && !settings.tryFallback) {
{ return done(BuildResult::TransientFailure, {},
return {done( Error("some substitutes for the outputs of derivation '%s' failed (usually happens due to networking issues); try '--fallback' to build derivation from source ",
BuildResult::TransientFailure, worker.store.printStorePath(drvPath)));
{},
Error(
"some substitutes for the outputs of derivation '%s' failed (usually happens due "
"to networking issues); try '--fallback' to build derivation from source ",
worker.store.printStorePath(drvPath)
)
)};
} }
/* If the substitutes form an incomplete closure, then we should /* If the substitutes form an incomplete closure, then we should
@ -360,7 +343,7 @@ try {
auto [allValid, validOutputs] = checkPathValidity(); auto [allValid, validOutputs] = checkPathValidity();
if (buildMode == bmNormal && allValid) { if (buildMode == bmNormal && allValid) {
return {done(BuildResult::Substituted, std::move(validOutputs))}; return done(BuildResult::Substituted, std::move(validOutputs));
} }
if (buildMode == bmRepair && allValid) { if (buildMode == bmRepair && allValid) {
return repairClosure(); return repairClosure();
@ -371,15 +354,13 @@ try {
/* Nothing to wait for; tail call */ /* Nothing to wait for; tail call */
return gaveUpOnSubstitution(inBuildSlot); return gaveUpOnSubstitution(inBuildSlot);
} catch (...) {
return {std::current_exception()};
} }
/* At least one of the output paths could not be /* At least one of the output paths could not be
produced using a substitute. So we have to build instead. */ produced using a substitute. So we have to build instead. */
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::gaveUpOnSubstitution(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::gaveUpOnSubstitution(bool inBuildSlot)
try { {
WaitForGoals result; WaitForGoals result;
/* At this point we are building all outputs, so if more are wanted there /* At this point we are building all outputs, so if more are wanted there
@ -445,15 +426,13 @@ try {
return inputsRealised(inBuildSlot); return inputsRealised(inBuildSlot);
} else { } else {
state = &DerivationGoal::inputsRealised; state = &DerivationGoal::inputsRealised;
return {result}; return result;
} }
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::repairClosure() noexcept Goal::WorkResult DerivationGoal::repairClosure()
try { {
assert(drv->type().isPure()); assert(drv->type().isPure());
/* If we're repairing, we now know that our own outputs are valid. /* If we're repairing, we now know that our own outputs are valid.
@ -507,44 +486,34 @@ try {
} }
if (result.goals.empty()) { if (result.goals.empty()) {
return {done(BuildResult::AlreadyValid, assertPathValidity())}; return done(BuildResult::AlreadyValid, assertPathValidity());
} }
state = &DerivationGoal::closureRepaired; state = &DerivationGoal::closureRepaired;
return {result}; return result;
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::closureRepaired(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::closureRepaired(bool inBuildSlot)
try { {
trace("closure repaired"); trace("closure repaired");
if (nrFailed > 0) if (nrFailed > 0)
throw Error("some paths in the output closure of derivation '%s' could not be repaired", throw Error("some paths in the output closure of derivation '%s' could not be repaired",
worker.store.printStorePath(drvPath)); worker.store.printStorePath(drvPath));
return {done(BuildResult::AlreadyValid, assertPathValidity())}; return done(BuildResult::AlreadyValid, assertPathValidity());
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::inputsRealised(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::inputsRealised(bool inBuildSlot)
try { {
trace("all inputs realised"); trace("all inputs realised");
if (nrFailed != 0) { if (nrFailed != 0) {
if (!useDerivation) if (!useDerivation)
throw Error("some dependencies of '%s' are missing", worker.store.printStorePath(drvPath)); throw Error("some dependencies of '%s' are missing", worker.store.printStorePath(drvPath));
return {done( return done(BuildResult::DependencyFailed, {}, Error(
BuildResult::DependencyFailed,
{},
Error(
"%s dependencies of derivation '%s' failed to build", "%s dependencies of derivation '%s' failed to build",
nrFailed, nrFailed, worker.store.printStorePath(drvPath)));
worker.store.printStorePath(drvPath)
)
)};
} }
if (retrySubstitution == RetrySubstitution::YesNeed) { if (retrySubstitution == RetrySubstitution::YesNeed) {
@ -615,7 +584,7 @@ try {
pathResolved, wantedOutputs, buildMode); pathResolved, wantedOutputs, buildMode);
state = &DerivationGoal::resolvedFinished; state = &DerivationGoal::resolvedFinished;
return {WaitForGoals{{resolvedDrvGoal}}}; return WaitForGoals{{resolvedDrvGoal}};
} }
std::function<void(const StorePath &, const DerivedPathMap<StringSet>::ChildNode &)> accumInputPaths; std::function<void(const StorePath &, const DerivedPathMap<StringSet>::ChildNode &)> accumInputPaths;
@ -681,8 +650,6 @@ try {
build hook. */ build hook. */
state = &DerivationGoal::tryToBuild; state = &DerivationGoal::tryToBuild;
return tryToBuild(inBuildSlot); return tryToBuild(inBuildSlot);
} catch (...) {
return {std::current_exception()};
} }
void DerivationGoal::started() void DerivationGoal::started()
@ -698,8 +665,8 @@ void DerivationGoal::started()
mcRunningBuilds = worker.runningBuilds.addTemporarily(1); mcRunningBuilds = worker.runningBuilds.addTemporarily(1);
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::tryToBuild(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::tryToBuild(bool inBuildSlot)
try { {
trace("trying to build"); trace("trying to build");
/* Obtain locks on all output paths, if the paths are known a priori. /* Obtain locks on all output paths, if the paths are known a priori.
@ -733,7 +700,7 @@ try {
if (!actLock) if (!actLock)
actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting, actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting,
fmt("waiting for lock on %s", Magenta(showPaths(lockFiles)))); fmt("waiting for lock on %s", Magenta(showPaths(lockFiles))));
return {WaitForAWhile{}}; return WaitForAWhile{};
} }
actLock.reset(); actLock.reset();
@ -750,7 +717,7 @@ try {
if (buildMode != bmCheck && allValid) { if (buildMode != bmCheck && allValid) {
debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath)); debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath));
outputLocks.setDeletion(true); outputLocks.setDeletion(true);
return {done(BuildResult::AlreadyValid, std::move(validOutputs))}; return done(BuildResult::AlreadyValid, std::move(validOutputs));
} }
/* If any of the outputs already exist but are not valid, delete /* If any of the outputs already exist but are not valid, delete
@ -798,7 +765,7 @@ try {
}, },
hookReply); hookReply);
if (result) { if (result) {
return {std::move(*result)}; return std::move(*result);
} }
} }
@ -806,18 +773,13 @@ try {
state = &DerivationGoal::tryLocalBuild; state = &DerivationGoal::tryLocalBuild;
return tryLocalBuild(inBuildSlot); return tryLocalBuild(inBuildSlot);
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::tryLocalBuild(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::tryLocalBuild(bool inBuildSlot) {
try {
throw Error( throw Error(
"unable to build with a primary store that isn't a local store; " "unable to build with a primary store that isn't a local store; "
"either pass a different '--store' or enable remote builds." "either pass a different '--store' or enable remote builds."
"\nhttps://docs.lix.systems/manual/lix/stable/advanced-topics/distributed-builds.html"); "\nhttps://docs.lix.systems/manual/lix/stable/advanced-topics/distributed-builds.html");
} catch (...) {
return {std::current_exception()};
} }
@ -973,8 +935,8 @@ void runPostBuildHook(
proc.getStdout()->drainInto(sink); proc.getStdout()->drainInto(sink);
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::buildDone(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::buildDone(bool inBuildSlot)
try { {
trace("build done"); trace("build done");
Finally releaseBuildUser([&](){ this->cleanupHookFinally(); }); Finally releaseBuildUser([&](){ this->cleanupHookFinally(); });
@ -1068,7 +1030,7 @@ try {
outputLocks.setDeletion(true); outputLocks.setDeletion(true);
outputLocks.unlock(); outputLocks.unlock();
return {done(BuildResult::Built, std::move(builtOutputs))}; return done(BuildResult::Built, std::move(builtOutputs));
} catch (BuildError & e) { } catch (BuildError & e) {
outputLocks.unlock(); outputLocks.unlock();
@ -1089,14 +1051,12 @@ try {
BuildResult::PermanentFailure; BuildResult::PermanentFailure;
} }
return {done(st, {}, std::move(e))}; return done(st, {}, std::move(e));
} }
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::resolvedFinished(bool inBuildSlot) noexcept Goal::WorkResult DerivationGoal::resolvedFinished(bool inBuildSlot)
try { {
trace("resolved derivation finished"); trace("resolved derivation finished");
assert(resolvedDrvGoal); assert(resolvedDrvGoal);
@ -1163,9 +1123,7 @@ try {
if (status == BuildResult::AlreadyValid) if (status == BuildResult::AlreadyValid)
status = BuildResult::ResolvesToAlreadyValid; status = BuildResult::ResolvesToAlreadyValid;
return {done(status, std::move(builtOutputs))}; return done(status, std::move(builtOutputs));
} catch (...) {
return {std::current_exception()};
} }
HookReply DerivationGoal::tryBuildHook(bool inBuildSlot) HookReply DerivationGoal::tryBuildHook(bool inBuildSlot)

View file

@ -213,7 +213,7 @@ struct DerivationGoal : public Goal
*/ */
std::optional<DerivationType> derivationType; std::optional<DerivationType> derivationType;
typedef kj::Promise<Result<WorkResult>> (DerivationGoal::*GoalState)(bool inBuildSlot) noexcept; typedef WorkResult (DerivationGoal::*GoalState)(bool inBuildSlot);
GoalState state; GoalState state;
BuildMode buildMode; BuildMode buildMode;
@ -246,7 +246,7 @@ struct DerivationGoal : public Goal
std::string key() override; std::string key() override;
kj::Promise<Result<WorkResult>> work(bool inBuildSlot) noexcept override; WorkResult work(bool inBuildSlot) override;
/** /**
* Add wanted outputs to an already existing derivation goal. * Add wanted outputs to an already existing derivation goal.
@ -256,18 +256,18 @@ struct DerivationGoal : public Goal
/** /**
* The states. * The states.
*/ */
kj::Promise<Result<WorkResult>> getDerivation(bool inBuildSlot) noexcept; WorkResult getDerivation(bool inBuildSlot);
kj::Promise<Result<WorkResult>> loadDerivation(bool inBuildSlot) noexcept; WorkResult loadDerivation(bool inBuildSlot);
kj::Promise<Result<WorkResult>> haveDerivation(bool inBuildSlot) noexcept; WorkResult haveDerivation(bool inBuildSlot);
kj::Promise<Result<WorkResult>> outputsSubstitutionTried(bool inBuildSlot) noexcept; WorkResult outputsSubstitutionTried(bool inBuildSlot);
kj::Promise<Result<WorkResult>> gaveUpOnSubstitution(bool inBuildSlot) noexcept; WorkResult gaveUpOnSubstitution(bool inBuildSlot);
kj::Promise<Result<WorkResult>> closureRepaired(bool inBuildSlot) noexcept; WorkResult closureRepaired(bool inBuildSlot);
kj::Promise<Result<WorkResult>> inputsRealised(bool inBuildSlot) noexcept; WorkResult inputsRealised(bool inBuildSlot);
kj::Promise<Result<WorkResult>> tryToBuild(bool inBuildSlot) noexcept; WorkResult tryToBuild(bool inBuildSlot);
virtual kj::Promise<Result<WorkResult>> tryLocalBuild(bool inBuildSlot) noexcept; virtual WorkResult tryLocalBuild(bool inBuildSlot);
kj::Promise<Result<WorkResult>> buildDone(bool inBuildSlot) noexcept; WorkResult buildDone(bool inBuildSlot);
kj::Promise<Result<WorkResult>> resolvedFinished(bool inBuildSlot) noexcept; WorkResult resolvedFinished(bool inBuildSlot);
/** /**
* Is the build hook willing to perform the build? * Is the build hook willing to perform the build?
@ -346,7 +346,7 @@ struct DerivationGoal : public Goal
*/ */
virtual void killChild(); virtual void killChild();
kj::Promise<Result<WorkResult>> repairClosure() noexcept; WorkResult repairClosure();
void started(); void started();

View file

@ -22,27 +22,25 @@ DrvOutputSubstitutionGoal::DrvOutputSubstitutionGoal(
} }
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::init(bool inBuildSlot) noexcept Goal::WorkResult DrvOutputSubstitutionGoal::init(bool inBuildSlot)
try { {
trace("init"); trace("init");
/* If the derivation already exists, were done */ /* If the derivation already exists, were done */
if (worker.store.queryRealisation(id)) { if (worker.store.queryRealisation(id)) {
return {Finished{ecSuccess, std::move(buildResult)}}; return Finished{ecSuccess, std::move(buildResult)};
} }
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>(); subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
return tryNext(inBuildSlot); return tryNext(inBuildSlot);
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::tryNext(bool inBuildSlot) noexcept Goal::WorkResult DrvOutputSubstitutionGoal::tryNext(bool inBuildSlot)
try { {
trace("trying next substituter"); trace("trying next substituter");
if (!inBuildSlot) { if (!inBuildSlot) {
return {WaitForSlot{}}; return WaitForSlot{};
} }
maintainRunningSubstitutions = worker.runningSubstitutions.addTemporarily(1); maintainRunningSubstitutions = worker.runningSubstitutions.addTemporarily(1);
@ -59,7 +57,7 @@ try {
/* Hack: don't indicate failure if there were no substituters. /* Hack: don't indicate failure if there were no substituters.
In that case the calling derivation should just do a In that case the calling derivation should just do a
build. */ build. */
return {Finished{substituterFailed ? ecFailed : ecNoSubstituters, std::move(buildResult)}}; return Finished{substituterFailed ? ecFailed : ecNoSubstituters, std::move(buildResult)};
} }
sub = subs.front(); sub = subs.front();
@ -79,13 +77,11 @@ try {
}); });
state = &DrvOutputSubstitutionGoal::realisationFetched; state = &DrvOutputSubstitutionGoal::realisationFetched;
return {WaitForWorld{{downloadState->outPipe.readSide.get()}, true}}; return WaitForWorld{{downloadState->outPipe.readSide.get()}, true};
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::realisationFetched(bool inBuildSlot) noexcept Goal::WorkResult DrvOutputSubstitutionGoal::realisationFetched(bool inBuildSlot)
try { {
worker.childTerminated(this); worker.childTerminated(this);
maintainRunningSubstitutions.reset(); maintainRunningSubstitutions.reset();
@ -126,37 +122,31 @@ try {
return outPathValid(inBuildSlot); return outPathValid(inBuildSlot);
} else { } else {
state = &DrvOutputSubstitutionGoal::outPathValid; state = &DrvOutputSubstitutionGoal::outPathValid;
return {std::move(result)}; return result;
} }
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::outPathValid(bool inBuildSlot) noexcept Goal::WorkResult DrvOutputSubstitutionGoal::outPathValid(bool inBuildSlot)
try { {
assert(outputInfo); assert(outputInfo);
trace("output path substituted"); trace("output path substituted");
if (nrFailed > 0) { if (nrFailed > 0) {
debug("The output path of the derivation output '%s' could not be substituted", id.to_string()); debug("The output path of the derivation output '%s' could not be substituted", id.to_string());
return {Finished{ return Finished{
nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed, nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed,
std::move(buildResult), std::move(buildResult),
}}; };
} }
worker.store.registerDrvOutput(*outputInfo); worker.store.registerDrvOutput(*outputInfo);
return finished(); return finished();
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::finished() noexcept Goal::WorkResult DrvOutputSubstitutionGoal::finished()
try { {
trace("finished"); trace("finished");
return {Finished{ecSuccess, std::move(buildResult)}}; return Finished{ecSuccess, std::move(buildResult)};
} catch (...) {
return {std::current_exception()};
} }
std::string DrvOutputSubstitutionGoal::key() std::string DrvOutputSubstitutionGoal::key()
@ -166,7 +156,7 @@ std::string DrvOutputSubstitutionGoal::key()
return "a$" + std::string(id.to_string()); return "a$" + std::string(id.to_string());
} }
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::work(bool inBuildSlot) noexcept Goal::WorkResult DrvOutputSubstitutionGoal::work(bool inBuildSlot)
{ {
return (this->*state)(inBuildSlot); return (this->*state)(inBuildSlot);
} }

View file

@ -65,20 +65,20 @@ public:
std::optional<ContentAddress> ca = std::nullopt std::optional<ContentAddress> ca = std::nullopt
); );
typedef kj::Promise<Result<WorkResult>> (DrvOutputSubstitutionGoal::*GoalState)(bool inBuildSlot) noexcept; typedef WorkResult (DrvOutputSubstitutionGoal::*GoalState)(bool inBuildSlot);
GoalState state; GoalState state;
kj::Promise<Result<WorkResult>> init(bool inBuildSlot) noexcept; WorkResult init(bool inBuildSlot);
kj::Promise<Result<WorkResult>> tryNext(bool inBuildSlot) noexcept; WorkResult tryNext(bool inBuildSlot);
kj::Promise<Result<WorkResult>> realisationFetched(bool inBuildSlot) noexcept; WorkResult realisationFetched(bool inBuildSlot);
kj::Promise<Result<WorkResult>> outPathValid(bool inBuildSlot) noexcept; WorkResult outPathValid(bool inBuildSlot);
kj::Promise<Result<WorkResult>> finished() noexcept; WorkResult finished();
Finished timedOut(Error && ex) override { abort(); }; Finished timedOut(Error && ex) override { abort(); };
std::string key() override; std::string key() override;
kj::Promise<Result<WorkResult>> work(bool inBuildSlot) noexcept override; WorkResult work(bool inBuildSlot) override;
JobCategory jobCategory() const override { JobCategory jobCategory() const override {
return JobCategory::Substitution; return JobCategory::Substitution;

View file

@ -6,17 +6,11 @@
namespace nix { namespace nix {
static auto runWorker(Worker & worker, auto mkGoals)
{
return worker.run(mkGoals);
}
void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMode, std::shared_ptr<Store> evalStore) void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMode, std::shared_ptr<Store> evalStore)
{ {
auto aio = kj::setupAsyncIo(); Worker worker(*this, evalStore ? *evalStore : *this);
Worker worker(*this, evalStore ? *evalStore : *this, aio);
auto goals = runWorker(worker, [&](GoalFactory & gf) { auto goals = worker.run([&](GoalFactory & gf) {
Goals goals; Goals goals;
for (auto & br : reqs) for (auto & br : reqs)
goals.insert(gf.makeGoal(br, buildMode)); goals.insert(gf.makeGoal(br, buildMode));
@ -54,12 +48,10 @@ std::vector<KeyedBuildResult> Store::buildPathsWithResults(
BuildMode buildMode, BuildMode buildMode,
std::shared_ptr<Store> evalStore) std::shared_ptr<Store> evalStore)
{ {
auto aio = kj::setupAsyncIo(); Worker worker(*this, evalStore ? *evalStore : *this);
Worker worker(*this, evalStore ? *evalStore : *this, aio);
std::vector<std::pair<const DerivedPath &, GoalPtr>> state; std::vector<std::pair<const DerivedPath &, GoalPtr>> state;
auto goals = runWorker(worker, [&](GoalFactory & gf) { auto goals = worker.run([&](GoalFactory & gf) {
Goals goals; Goals goals;
for (const auto & req : reqs) { for (const auto & req : reqs) {
auto goal = gf.makeGoal(req, buildMode); auto goal = gf.makeGoal(req, buildMode);
@ -80,11 +72,10 @@ std::vector<KeyedBuildResult> Store::buildPathsWithResults(
BuildResult Store::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, BuildResult Store::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode) BuildMode buildMode)
{ {
auto aio = kj::setupAsyncIo(); Worker worker(*this, *this);
Worker worker(*this, *this, aio);
try { try {
auto goals = runWorker(worker, [&](GoalFactory & gf) -> Goals { auto goals = worker.run([&](GoalFactory & gf) -> Goals {
return Goals{gf.makeBasicDerivationGoal(drvPath, drv, OutputsSpec::All{}, buildMode)}; return Goals{gf.makeBasicDerivationGoal(drvPath, drv, OutputsSpec::All{}, buildMode)};
}); });
auto goal = *goals.begin(); auto goal = *goals.begin();
@ -106,12 +97,10 @@ void Store::ensurePath(const StorePath & path)
/* If the path is already valid, we're done. */ /* If the path is already valid, we're done. */
if (isValidPath(path)) return; if (isValidPath(path)) return;
auto aio = kj::setupAsyncIo(); Worker worker(*this, *this);
Worker worker(*this, *this, aio);
auto goals = runWorker(worker, [&](GoalFactory & gf) { auto goals =
return Goals{gf.makePathSubstitutionGoal(path)}; worker.run([&](GoalFactory & gf) { return Goals{gf.makePathSubstitutionGoal(path)}; });
});
auto goal = *goals.begin(); auto goal = *goals.begin();
if (goal->exitCode != Goal::ecSuccess) { if (goal->exitCode != Goal::ecSuccess) {
@ -126,10 +115,9 @@ void Store::ensurePath(const StorePath & path)
void Store::repairPath(const StorePath & path) void Store::repairPath(const StorePath & path)
{ {
auto aio = kj::setupAsyncIo(); Worker worker(*this, *this);
Worker worker(*this, *this, aio);
auto goals = runWorker(worker, [&](GoalFactory & gf) { auto goals = worker.run([&](GoalFactory & gf) {
return Goals{gf.makePathSubstitutionGoal(path, Repair)}; return Goals{gf.makePathSubstitutionGoal(path, Repair)};
}); });
auto goal = *goals.begin(); auto goal = *goals.begin();

View file

@ -1,11 +1,9 @@
#pragma once #pragma once
///@file ///@file
#include "result.hh"
#include "types.hh" #include "types.hh"
#include "store-api.hh" #include "store-api.hh"
#include "build-result.hh" #include "build-result.hh"
#include <kj/async.h>
namespace nix { namespace nix {
@ -163,7 +161,7 @@ public:
trace("goal destroyed"); trace("goal destroyed");
} }
virtual kj::Promise<Result<WorkResult>> work(bool inBuildSlot) noexcept = 0; virtual WorkResult work(bool inBuildSlot) = 0;
virtual void waiteeDone(GoalPtr waitee) { } virtual void waiteeDone(GoalPtr waitee) { }

View file

@ -149,8 +149,8 @@ void LocalDerivationGoal::killSandbox(bool getStats)
} }
kj::Promise<Result<Goal::WorkResult>> LocalDerivationGoal::tryLocalBuild(bool inBuildSlot) noexcept Goal::WorkResult LocalDerivationGoal::tryLocalBuild(bool inBuildSlot)
try { {
#if __APPLE__ #if __APPLE__
additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or(""); additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or("");
#endif #endif
@ -159,7 +159,7 @@ try {
state = &DerivationGoal::tryToBuild; state = &DerivationGoal::tryToBuild;
outputLocks.unlock(); outputLocks.unlock();
if (0U != settings.maxBuildJobs) { if (0U != settings.maxBuildJobs) {
return {WaitForSlot{}}; return WaitForSlot{};
} }
if (getMachines().empty()) { if (getMachines().empty()) {
throw Error( throw Error(
@ -214,7 +214,7 @@ try {
if (!actLock) if (!actLock)
actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting, actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting,
fmt("waiting for a free build user ID for '%s'", Magenta(worker.store.printStorePath(drvPath)))); fmt("waiting for a free build user ID for '%s'", Magenta(worker.store.printStorePath(drvPath))));
return {WaitForAWhile{}}; return WaitForAWhile{};
} }
} }
@ -250,17 +250,15 @@ try {
state = &DerivationGoal::buildDone; state = &DerivationGoal::buildDone;
started(); started();
return {WaitForWorld{std::move(fds), true}}; return WaitForWorld{std::move(fds), true};
} catch (BuildError & e) { } catch (BuildError & e) {
outputLocks.unlock(); outputLocks.unlock();
buildUser.reset(); buildUser.reset();
auto report = done(BuildResult::InputRejected, {}, std::move(e)); auto report = done(BuildResult::InputRejected, {}, std::move(e));
report.permanentFailure = true; report.permanentFailure = true;
return {std::move(report)}; return report;
} }
} catch (...) {
return {std::current_exception()};
} }

View file

@ -213,7 +213,7 @@ struct LocalDerivationGoal : public DerivationGoal
/** /**
* The additional states. * The additional states.
*/ */
kj::Promise<Result<WorkResult>> tryLocalBuild(bool inBuildSlot) noexcept override; WorkResult tryLocalBuild(bool inBuildSlot) override;
/** /**
* Start building a derivation. * Start building a derivation.

View file

@ -45,21 +45,21 @@ Goal::Finished PathSubstitutionGoal::done(
} }
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::work(bool inBuildSlot) noexcept Goal::WorkResult PathSubstitutionGoal::work(bool inBuildSlot)
{ {
return (this->*state)(inBuildSlot); return (this->*state)(inBuildSlot);
} }
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::init(bool inBuildSlot) noexcept Goal::WorkResult PathSubstitutionGoal::init(bool inBuildSlot)
try { {
trace("init"); trace("init");
worker.store.addTempRoot(storePath); worker.store.addTempRoot(storePath);
/* If the path already exists we're done. */ /* If the path already exists we're done. */
if (!repair && worker.store.isValidPath(storePath)) { if (!repair && worker.store.isValidPath(storePath)) {
return {done(ecSuccess, BuildResult::AlreadyValid)}; return done(ecSuccess, BuildResult::AlreadyValid);
} }
if (settings.readOnlyMode) if (settings.readOnlyMode)
@ -68,13 +68,11 @@ try {
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>(); subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
return tryNext(inBuildSlot); return tryNext(inBuildSlot);
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryNext(bool inBuildSlot) noexcept Goal::WorkResult PathSubstitutionGoal::tryNext(bool inBuildSlot)
try { {
trace("trying next substituter"); trace("trying next substituter");
cleanup(); cleanup();
@ -89,10 +87,10 @@ try {
/* Hack: don't indicate failure if there were no substituters. /* Hack: don't indicate failure if there were no substituters.
In that case the calling derivation should just do a In that case the calling derivation should just do a
build. */ build. */
return {done( return done(
substituterFailed ? ecFailed : ecNoSubstituters, substituterFailed ? ecFailed : ecNoSubstituters,
BuildResult::NoSubstituters, BuildResult::NoSubstituters,
fmt("path '%s' is required, but there is no substituter that can build it", worker.store.printStorePath(storePath)))}; fmt("path '%s' is required, but there is no substituter that can build it", worker.store.printStorePath(storePath)));
} }
sub = subs.front(); sub = subs.front();
@ -169,22 +167,20 @@ try {
return referencesValid(inBuildSlot); return referencesValid(inBuildSlot);
} else { } else {
state = &PathSubstitutionGoal::referencesValid; state = &PathSubstitutionGoal::referencesValid;
return {std::move(result)}; return result;
} }
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::referencesValid(bool inBuildSlot) noexcept Goal::WorkResult PathSubstitutionGoal::referencesValid(bool inBuildSlot)
try { {
trace("all references realised"); trace("all references realised");
if (nrFailed > 0) { if (nrFailed > 0) {
return {done( return done(
nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed, nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed,
BuildResult::DependencyFailed, BuildResult::DependencyFailed,
fmt("some references of path '%s' could not be realised", worker.store.printStorePath(storePath)))}; fmt("some references of path '%s' could not be realised", worker.store.printStorePath(storePath)));
} }
for (auto & i : info->references) for (auto & i : info->references)
@ -193,17 +189,15 @@ try {
state = &PathSubstitutionGoal::tryToRun; state = &PathSubstitutionGoal::tryToRun;
return tryToRun(inBuildSlot); return tryToRun(inBuildSlot);
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryToRun(bool inBuildSlot) noexcept Goal::WorkResult PathSubstitutionGoal::tryToRun(bool inBuildSlot)
try { {
trace("trying to run"); trace("trying to run");
if (!inBuildSlot) { if (!inBuildSlot) {
return {WaitForSlot{}}; return WaitForSlot{};
} }
maintainRunningSubstitutions = worker.runningSubstitutions.addTemporarily(1); maintainRunningSubstitutions = worker.runningSubstitutions.addTemporarily(1);
@ -234,14 +228,12 @@ try {
}); });
state = &PathSubstitutionGoal::finished; state = &PathSubstitutionGoal::finished;
return {WaitForWorld{{outPipe.readSide.get()}, true}}; return WaitForWorld{{outPipe.readSide.get()}, true};
} catch (...) {
return {std::current_exception()};
} }
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::finished(bool inBuildSlot) noexcept Goal::WorkResult PathSubstitutionGoal::finished(bool inBuildSlot)
try { {
trace("substitute finished"); trace("substitute finished");
worker.childTerminated(this); worker.childTerminated(this);
@ -282,9 +274,7 @@ try {
worker.doneNarSize += maintainExpectedNar.delta(); worker.doneNarSize += maintainExpectedNar.delta();
maintainExpectedNar.reset(); maintainExpectedNar.reset();
return {done(ecSuccess, BuildResult::Substituted)}; return done(ecSuccess, BuildResult::Substituted);
} catch (...) {
return {std::current_exception()};
} }

View file

@ -67,7 +67,7 @@ struct PathSubstitutionGoal : public Goal
NotifyingCounter<uint64_t>::Bump maintainExpectedSubstitutions, NotifyingCounter<uint64_t>::Bump maintainExpectedSubstitutions,
maintainRunningSubstitutions, maintainExpectedNar, maintainExpectedDownload; maintainRunningSubstitutions, maintainExpectedNar, maintainExpectedDownload;
typedef kj::Promise<Result<WorkResult>> (PathSubstitutionGoal::*GoalState)(bool inBuildSlot) noexcept; typedef WorkResult (PathSubstitutionGoal::*GoalState)(bool inBuildSlot);
GoalState state; GoalState state;
/** /**
@ -101,16 +101,16 @@ public:
return "a$" + std::string(storePath.name()) + "$" + worker.store.printStorePath(storePath); return "a$" + std::string(storePath.name()) + "$" + worker.store.printStorePath(storePath);
} }
kj::Promise<Result<WorkResult>> work(bool inBuildSlot) noexcept override; WorkResult work(bool inBuildSlot) override;
/** /**
* The states. * The states.
*/ */
kj::Promise<Result<WorkResult>> init(bool inBuildSlot) noexcept; WorkResult init(bool inBuildSlot);
kj::Promise<Result<WorkResult>> tryNext(bool inBuildSlot) noexcept; WorkResult tryNext(bool inBuildSlot);
kj::Promise<Result<WorkResult>> referencesValid(bool inBuildSlot) noexcept; WorkResult referencesValid(bool inBuildSlot);
kj::Promise<Result<WorkResult>> tryToRun(bool inBuildSlot) noexcept; WorkResult tryToRun(bool inBuildSlot);
kj::Promise<Result<WorkResult>> finished(bool inBuildSlot) noexcept; WorkResult finished(bool inBuildSlot);
/** /**
* Callback used by the worker to write to the log. * Callback used by the worker to write to the log.

View file

@ -11,13 +11,12 @@
namespace nix { namespace nix {
Worker::Worker(Store & store, Store & evalStore, kj::AsyncIoContext & aio) Worker::Worker(Store & store, Store & evalStore)
: act(*logger, actRealise) : act(*logger, actRealise)
, actDerivations(*logger, actBuilds) , actDerivations(*logger, actBuilds)
, actSubstitutions(*logger, actCopyPaths) , actSubstitutions(*logger, actCopyPaths)
, store(store) , store(store)
, evalStore(evalStore) , evalStore(evalStore)
, aio(aio)
{ {
/* Debugging: prevent recursive workers. */ /* Debugging: prevent recursive workers. */
nrLocalBuilds = 0; nrLocalBuilds = 0;
@ -380,7 +379,7 @@ Goals Worker::run(std::function<Goals (GoalFactory &)> req)
const bool inSlot = goal->jobCategory() == JobCategory::Substitution const bool inSlot = goal->jobCategory() == JobCategory::Substitution
? nrSubstitutions < std::max(1U, (unsigned int) settings.maxSubstitutionJobs) ? nrSubstitutions < std::max(1U, (unsigned int) settings.maxSubstitutionJobs)
: nrLocalBuilds < settings.maxBuildJobs; : nrLocalBuilds < settings.maxBuildJobs;
handleWorkResult(goal, goal->work(inSlot).wait(aio.waitScope).value()); handleWorkResult(goal, goal->work(inSlot));
updateStatistics(); updateStatistics();
if (topGoals.empty()) break; // stuff may have been cancelled if (topGoals.empty()) break; // stuff may have been cancelled

View file

@ -9,7 +9,6 @@
#include "realisation.hh" #include "realisation.hh"
#include <future> #include <future>
#include <kj/async-io.h>
#include <thread> #include <thread>
namespace nix { namespace nix {
@ -238,7 +237,6 @@ public:
Store & store; Store & store;
Store & evalStore; Store & evalStore;
kj::AsyncIoContext & aio;
struct HookState { struct HookState {
std::unique_ptr<HookInstance> instance; std::unique_ptr<HookInstance> instance;
@ -266,7 +264,7 @@ public:
NotifyingCounter<uint64_t> expectedNarSize{[this] { updateStatisticsLater(); }}; NotifyingCounter<uint64_t> expectedNarSize{[this] { updateStatisticsLater(); }};
NotifyingCounter<uint64_t> doneNarSize{[this] { updateStatisticsLater(); }}; NotifyingCounter<uint64_t> doneNarSize{[this] { updateStatisticsLater(); }};
Worker(Store & store, Store & evalStore, kj::AsyncIoContext & aio); Worker(Store & store, Store & evalStore);
~Worker(); ~Worker();
/** /**

View file

@ -269,31 +269,11 @@ Path Settings::getDefaultSSLCertFile()
const std::string nixVersion = PACKAGE_VERSION; const std::string nixVersion = PACKAGE_VERSION;
void to_json(nlohmann::json & j, const SandboxMode & e) NLOHMANN_JSON_SERIALIZE_ENUM(SandboxMode, {
{ {SandboxMode::smEnabled, true},
if (e == SandboxMode::smEnabled) { {SandboxMode::smRelaxed, "relaxed"},
j = true; {SandboxMode::smDisabled, false},
} else if (e == SandboxMode::smRelaxed) { });
j = "relaxed";
} else if (e == SandboxMode::smDisabled) {
j = false;
} else {
abort();
}
}
void from_json(const nlohmann::json & j, SandboxMode & e)
{
if (j == true) {
e = SandboxMode::smEnabled;
} else if (j == "relaxed") {
e = SandboxMode::smRelaxed;
} else if (j == false) {
e = SandboxMode::smDisabled;
} else {
throw Error("Invalid sandbox mode '%s'", std::string(j));
}
}
template<> SandboxMode BaseSetting<SandboxMode>::parse(const std::string & str, const ApplyConfigOptions & options) const template<> SandboxMode BaseSetting<SandboxMode>::parse(const std::string & str, const ApplyConfigOptions & options) const
{ {

View file

@ -14,9 +14,6 @@ namespace nix {
typedef enum { smEnabled, smRelaxed, smDisabled } SandboxMode; typedef enum { smEnabled, smRelaxed, smDisabled } SandboxMode;
void to_json(nlohmann::json & j, const SandboxMode & e);
void from_json(const nlohmann::json & j, SandboxMode & e);
struct MaxBuildJobsSetting : public BaseSetting<unsigned int> struct MaxBuildJobsSetting : public BaseSetting<unsigned int>
{ {
MaxBuildJobsSetting(Config * options, MaxBuildJobsSetting(Config * options,
@ -640,10 +637,10 @@ public:
PathsSetting<std::optional<Path>> diffHook{ PathsSetting<std::optional<Path>> diffHook{
this, std::nullopt, "diff-hook", this, std::nullopt, "diff-hook",
R"( R"(
Path to an executable capable of diffing build results. The hook is Absolute path to an executable capable of diffing build
executed if `run-diff-hook` is true, and the output of a build is results. The hook is executed if `run-diff-hook` is true, and the
known to not be the same. This program is not executed to determine output of a build is known to not be the same. This program is not
if two results are the same. executed to determine if two results are the same.
The diff hook is executed by the same user and group who ran the The diff hook is executed by the same user and group who ran the
build. However, the diff hook does not have write access to the build. However, the diff hook does not have write access to the

View file

@ -221,7 +221,6 @@ dependencies = [
aws_s3, aws_s3,
aws_sdk_transfer, aws_sdk_transfer,
nlohmann_json, nlohmann_json,
kj,
] ]
if host_machine.system() == 'freebsd' if host_machine.system() == 'freebsd'

View file

@ -18,19 +18,15 @@ namespace fs = std::filesystem;
namespace nix { namespace nix {
Path getCwd() {
char buf[PATH_MAX];
if (!getcwd(buf, sizeof(buf))) {
throw SysError("cannot get cwd");
}
return Path(buf);
}
Path absPath(Path path, std::optional<PathView> dir, bool resolveSymlinks) Path absPath(Path path, std::optional<PathView> dir, bool resolveSymlinks)
{ {
if (path.empty() || path[0] != '/') { if (path.empty() || path[0] != '/') {
if (!dir) { if (!dir) {
path = concatStrings(getCwd(), "/", path); char buf[PATH_MAX];
if (!getcwd(buf, sizeof(buf))) {
throw SysError("cannot get cwd");
}
path = concatStrings(buf, "/", path);
} else { } else {
path = concatStrings(*dir, "/", path); path = concatStrings(*dir, "/", path);
} }

View file

@ -29,13 +29,6 @@ namespace nix {
struct Sink; struct Sink;
struct Source; struct Source;
/**
* Get the current working directory.
*
* Throw an error if the current directory cannot get got.
*/
Path getCwd();
/** /**
* @return An absolutized path, resolving paths relative to the * @return An absolutized path, resolving paths relative to the
* specified directory, or the current directory otherwise. The path * specified directory, or the current directory otherwise. The path

View file

@ -105,7 +105,6 @@ libutil_headers = files(
'regex-combinators.hh', 'regex-combinators.hh',
'regex.hh', 'regex.hh',
'repair-flag.hh', 'repair-flag.hh',
'result.hh',
'serialise.hh', 'serialise.hh',
'shlex.hh', 'shlex.hh',
'signals.hh', 'signals.hh',

View file

@ -1,24 +0,0 @@
#pragma once
/// @file
#include <boost/outcome/std_outcome.hpp>
#include <boost/outcome/std_result.hpp>
#include <boost/outcome/success_failure.hpp>
#include <exception>
namespace nix {
template<typename T, typename E = std::exception_ptr>
using Result = boost::outcome_v2::std_result<T, E>;
template<typename T, typename D, typename E = std::exception_ptr>
using Outcome = boost::outcome_v2::std_outcome<T, D, E>;
namespace result {
using boost::outcome_v2::success;
using boost::outcome_v2::failure;
}
}

View file

@ -200,18 +200,8 @@ std::string showBytes(uint64_t bytes);
/** /**
* Provide an addition operator between `std::string` and `std::string_view` * Provide an addition operator between strings and string_views
* inexplicably omitted from the standard library. * inexplicably omitted from the standard library.
*
* > The reason for this is given in n3512 string_ref: a non-owning reference
* to a string, revision 2 by Jeffrey Yasskin:
* >
* > > I also omitted operator+(basic_string, basic_string_ref) because LLVM
* > > returns a lightweight object from this overload and only performs the
* > > concatenation lazily. If we define this overload, we'll have a hard time
* > > introducing that lightweight concatenation later.
*
* See: https://stackoverflow.com/a/47735624
*/ */
inline std::string operator + (const std::string & s1, std::string_view s2) inline std::string operator + (const std::string & s1, std::string_view s2)
{ {

View file

@ -353,9 +353,6 @@ void mainWrapped(int argc, char * * argv)
argv++; argc--; argv++; argc--;
} }
// Clean up the progress bar if shown using --log-format in a legacy command too.
// Otherwise, this is a harmless no-op.
Finally f([] { logger->pause(); });
{ {
auto legacy = (*RegisterLegacyCommand::commands)[programName]; auto legacy = (*RegisterLegacyCommand::commands)[programName];
if (legacy) return legacy(argc, argv); if (legacy) return legacy(argc, argv);
@ -364,6 +361,7 @@ void mainWrapped(int argc, char * * argv)
evalSettings.pureEval = true; evalSettings.pureEval = true;
setLogFormat(LogFormat::bar); setLogFormat(LogFormat::bar);
Finally f([] { logger->pause(); });
settings.verboseBuild = false; settings.verboseBuild = false;
// FIXME: stop messing about with log verbosity depending on if it is interactive use // FIXME: stop messing about with log verbosity depending on if it is interactive use
if (isatty(STDERR_FILENO)) { if (isatty(STDERR_FILENO)) {

View file

@ -1,20 +1,25 @@
#pragma once #pragma once
#include "types.hh"
#include "environment-variables.hh" #include "environment-variables.hh"
#include "file-system.hh" #include "types.hh"
namespace nix { namespace nix {
// TODO: These helpers should be available in all unit tests.
/** /**
* The path to the unit test data directory. See the contributing guide * The path to the unit test data directory. See the contributing guide
* in the manual for further details. * in the manual for further details.
*/ */
Path getUnitTestData(); static Path getUnitTestData() {
return getEnv("_NIX_TEST_UNIT_DATA").value();
}
/** /**
* Resolve a path under the unit test data directory to an absolute path. * Resolve a path under the unit test data directory to an absolute path.
*/ */
Path getUnitTestDataPath(std::string_view path); static Path getUnitTestDataPath(std::string_view path) {
return absPath(getUnitTestData() + "/" + path);
}
} }

View file

@ -9,10 +9,17 @@
#include <filesystem> #include <filesystem>
#include "types.hh" #include "types.hh"
#include "test-data.hh"
namespace nix { namespace nix {
/**
* The path to the unit test data directory. See the contributing guide
* in the manual for further details.
*/
static Path getUnitTestData() {
return getEnv("_NIX_TEST_UNIT_DATA").value();
}
/** /**
* Whether we should update "golden masters" instead of running tests * Whether we should update "golden masters" instead of running tests
* against them. See the contributing guide in the manual for further * against them. See the contributing guide in the manual for further

View file

@ -1,16 +0,0 @@
#include "test-data.hh"
#include "strings.hh"
namespace nix {
Path getUnitTestData()
{
return getEnv("_NIX_TEST_UNIT_DATA").value();
}
Path getUnitTestDataPath(std::string_view path)
{
return absPath(getUnitTestData() + "/" + path);
}
}

View file

@ -1,9 +1,5 @@
#include "config.hh" #include "config.hh"
#include "args.hh" #include "args.hh"
#include "file-system.hh"
#include "environment-variables.hh"
#include "logging.hh"
#include "tests/test-data.hh"
#include <sstream> #include <sstream>
#include <gtest/gtest.h> #include <gtest/gtest.h>
@ -291,35 +287,6 @@ namespace nix {
), Error); ), Error);
} }
TEST(Config, includeRelativePath) {
Config config;
Setting<std::string> setting{&config, "", "puppy", "description"};
config.applyConfig("include puppy.conf", {
.path = getUnitTestDataPath("nix.conf")
});
std::map<std::string, Config::SettingInfo> settings;
config.getSettings(settings);
ASSERT_FALSE(settings.empty());
ASSERT_EQ(settings["puppy"].value, "doggy");
}
TEST(Config, includeTildePath) {
Config config;
Setting<std::string> setting{&config, "", "puppy", "description"};
config.applyConfig("include ~/puppy.conf", {
.path = "/doesnt-exist",
.home = getUnitTestData()
});
std::map<std::string, Config::SettingInfo> settings;
config.getSettings(settings);
ASSERT_FALSE(settings.empty());
ASSERT_EQ(settings["puppy"].value, "doggy");
}
TEST(Config, applyConfigInvalidThrows) { TEST(Config, applyConfigInvalidThrows) {
Config config; Config config;
ASSERT_THROW(config.applyConfig("value == key"), UsageError); ASSERT_THROW(config.applyConfig("value == key"), UsageError);

View file

@ -1 +0,0 @@
puppy = doggy

View file

@ -19,7 +19,6 @@ libutil_test_support_sources = files(
'libutil-support/tests/cli-literate-parser.cc', 'libutil-support/tests/cli-literate-parser.cc',
'libutil-support/tests/hash.cc', 'libutil-support/tests/hash.cc',
'libutil-support/tests/terminal-code-eater.cc', 'libutil-support/tests/terminal-code-eater.cc',
'libutil-support/tests/test-data.cc',
) )
libutil_test_support = library( libutil_test_support = library(
'lixutil-test-support', 'lixutil-test-support',
@ -96,6 +95,7 @@ libstore_test_support_sources = files(
'libstore-support/tests/derived-path.cc', 'libstore-support/tests/derived-path.cc',
'libstore-support/tests/outputs-spec.cc', 'libstore-support/tests/outputs-spec.cc',
'libstore-support/tests/path.cc', 'libstore-support/tests/path.cc',
'libstore-support/tests/test-data.hh',
) )
libstore_test_support = library( libstore_test_support = library(