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 = [
# see assertion in package.nix why these two are disabled
# "stdenv"
# "gccStdenv"
"gccStdenv"
"clangStdenv"
"stdenv"
"libcxxStdenv"
"ccacheStdenv"
];
@ -122,11 +121,7 @@
name = "${stdenvName}Packages";
value = f stdenvName;
}) 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.
nixpkgsFor = forAllSystems (

View file

@ -167,18 +167,10 @@ endif
# frees one would expect when the objects are unique_ptrs. these problems
# often show up as memory corruption when nesting generators (since we do
# 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(
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.
@ -237,7 +229,6 @@ configdata += {
}
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_required = is_x64 ? get_option('cpuid') : false

View file

@ -15,14 +15,11 @@
brotli,
bzip2,
callPackage,
capnproto-lix ? __forDefaults.capnproto-lix,
capnproto,
cmake,
curl,
doxygen,
editline-lix ? __forDefaults.editline-lix,
editline,
fetchpatch,
git,
gtest,
jq,
@ -39,7 +36,6 @@
mercurial,
meson,
ninja,
ncurses,
openssl,
pegtl,
pkg-config,
@ -83,44 +79,12 @@
boehmgc-nix = boehmgc.override { enableLargeConfig = true; };
editline-lix = editline.overrideAttrs (prev: {
patches = (prev.patches or [ ]) ++ [
# 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 ];
configureFlags = prev.configureFlags or [ ] ++ [ (lib.enableFeature true "sigstop") ];
});
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
inherit (__forDefaults) canRunInstalled;
inherit (lib) fileset;
@ -256,7 +220,6 @@ stdenv.mkDerivation (finalAttrs: {
ninja
cmake
rustc
capnproto-lix
]
++ [
(lib.getBin lowdown)
@ -297,7 +260,6 @@ stdenv.mkDerivation (finalAttrs: {
libsodium
toml11
pegtl
capnproto-lix
]
++ lib.optionals hostPlatform.isLinux [
libseccomp

View file

@ -7,32 +7,6 @@
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
{
if (str == "true") return AcceptFlakeConfig::True;

View file

@ -13,9 +13,6 @@ namespace nix {
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
{
FetchSettings();

View file

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

View file

@ -213,7 +213,7 @@ struct DerivationGoal : public Goal
*/
std::optional<DerivationType> derivationType;
typedef kj::Promise<Result<WorkResult>> (DerivationGoal::*GoalState)(bool inBuildSlot) noexcept;
typedef WorkResult (DerivationGoal::*GoalState)(bool inBuildSlot);
GoalState state;
BuildMode buildMode;
@ -246,7 +246,7 @@ struct DerivationGoal : public Goal
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.
@ -256,18 +256,18 @@ struct DerivationGoal : public Goal
/**
* The states.
*/
kj::Promise<Result<WorkResult>> getDerivation(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> loadDerivation(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> haveDerivation(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> outputsSubstitutionTried(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> gaveUpOnSubstitution(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> closureRepaired(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> inputsRealised(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> tryToBuild(bool inBuildSlot) noexcept;
virtual kj::Promise<Result<WorkResult>> tryLocalBuild(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> buildDone(bool inBuildSlot) noexcept;
WorkResult getDerivation(bool inBuildSlot);
WorkResult loadDerivation(bool inBuildSlot);
WorkResult haveDerivation(bool inBuildSlot);
WorkResult outputsSubstitutionTried(bool inBuildSlot);
WorkResult gaveUpOnSubstitution(bool inBuildSlot);
WorkResult closureRepaired(bool inBuildSlot);
WorkResult inputsRealised(bool inBuildSlot);
WorkResult tryToBuild(bool inBuildSlot);
virtual WorkResult tryLocalBuild(bool inBuildSlot);
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?
@ -346,7 +346,7 @@ struct DerivationGoal : public Goal
*/
virtual void killChild();
kj::Promise<Result<WorkResult>> repairClosure() noexcept;
WorkResult repairClosure();
void started();

View file

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

View file

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

View file

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

View file

@ -1,11 +1,9 @@
#pragma once
///@file
#include "result.hh"
#include "types.hh"
#include "store-api.hh"
#include "build-result.hh"
#include <kj/async.h>
namespace nix {
@ -163,7 +161,7 @@ public:
trace("goal destroyed");
}
virtual kj::Promise<Result<WorkResult>> work(bool inBuildSlot) noexcept = 0;
virtual WorkResult work(bool inBuildSlot) = 0;
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
try {
Goal::WorkResult LocalDerivationGoal::tryLocalBuild(bool inBuildSlot)
{
#if __APPLE__
additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or("");
#endif
@ -159,7 +159,7 @@ try {
state = &DerivationGoal::tryToBuild;
outputLocks.unlock();
if (0U != settings.maxBuildJobs) {
return {WaitForSlot{}};
return WaitForSlot{};
}
if (getMachines().empty()) {
throw Error(
@ -214,7 +214,7 @@ try {
if (!actLock)
actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting,
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;
started();
return {WaitForWorld{std::move(fds), true}};
return WaitForWorld{std::move(fds), true};
} catch (BuildError & e) {
outputLocks.unlock();
buildUser.reset();
auto report = done(BuildResult::InputRejected, {}, std::move(e));
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.
*/
kj::Promise<Result<WorkResult>> tryLocalBuild(bool inBuildSlot) noexcept override;
WorkResult tryLocalBuild(bool inBuildSlot) override;
/**
* 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);
}
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::init(bool inBuildSlot) noexcept
try {
Goal::WorkResult PathSubstitutionGoal::init(bool inBuildSlot)
{
trace("init");
worker.store.addTempRoot(storePath);
/* If the path already exists we're done. */
if (!repair && worker.store.isValidPath(storePath)) {
return {done(ecSuccess, BuildResult::AlreadyValid)};
return done(ecSuccess, BuildResult::AlreadyValid);
}
if (settings.readOnlyMode)
@ -68,13 +68,11 @@ try {
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
return tryNext(inBuildSlot);
} catch (...) {
return {std::current_exception()};
}
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryNext(bool inBuildSlot) noexcept
try {
Goal::WorkResult PathSubstitutionGoal::tryNext(bool inBuildSlot)
{
trace("trying next substituter");
cleanup();
@ -89,10 +87,10 @@ try {
/* Hack: don't indicate failure if there were no substituters.
In that case the calling derivation should just do a
build. */
return {done(
return done(
substituterFailed ? ecFailed : ecNoSubstituters,
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();
@ -169,22 +167,20 @@ try {
return referencesValid(inBuildSlot);
} else {
state = &PathSubstitutionGoal::referencesValid;
return {std::move(result)};
return result;
}
} catch (...) {
return {std::current_exception()};
}
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::referencesValid(bool inBuildSlot) noexcept
try {
Goal::WorkResult PathSubstitutionGoal::referencesValid(bool inBuildSlot)
{
trace("all references realised");
if (nrFailed > 0) {
return {done(
return done(
nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed,
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)
@ -193,17 +189,15 @@ try {
state = &PathSubstitutionGoal::tryToRun;
return tryToRun(inBuildSlot);
} catch (...) {
return {std::current_exception()};
}
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::tryToRun(bool inBuildSlot) noexcept
try {
Goal::WorkResult PathSubstitutionGoal::tryToRun(bool inBuildSlot)
{
trace("trying to run");
if (!inBuildSlot) {
return {WaitForSlot{}};
return WaitForSlot{};
}
maintainRunningSubstitutions = worker.runningSubstitutions.addTemporarily(1);
@ -234,14 +228,12 @@ try {
});
state = &PathSubstitutionGoal::finished;
return {WaitForWorld{{outPipe.readSide.get()}, true}};
} catch (...) {
return {std::current_exception()};
return WaitForWorld{{outPipe.readSide.get()}, true};
}
kj::Promise<Result<Goal::WorkResult>> PathSubstitutionGoal::finished(bool inBuildSlot) noexcept
try {
Goal::WorkResult PathSubstitutionGoal::finished(bool inBuildSlot)
{
trace("substitute finished");
worker.childTerminated(this);
@ -282,9 +274,7 @@ try {
worker.doneNarSize += maintainExpectedNar.delta();
maintainExpectedNar.reset();
return {done(ecSuccess, BuildResult::Substituted)};
} catch (...) {
return {std::current_exception()};
return done(ecSuccess, BuildResult::Substituted);
}

View file

@ -67,7 +67,7 @@ struct PathSubstitutionGoal : public Goal
NotifyingCounter<uint64_t>::Bump maintainExpectedSubstitutions,
maintainRunningSubstitutions, maintainExpectedNar, maintainExpectedDownload;
typedef kj::Promise<Result<WorkResult>> (PathSubstitutionGoal::*GoalState)(bool inBuildSlot) noexcept;
typedef WorkResult (PathSubstitutionGoal::*GoalState)(bool inBuildSlot);
GoalState state;
/**
@ -101,16 +101,16 @@ public:
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.
*/
kj::Promise<Result<WorkResult>> init(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> tryNext(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> referencesValid(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> tryToRun(bool inBuildSlot) noexcept;
kj::Promise<Result<WorkResult>> finished(bool inBuildSlot) noexcept;
WorkResult init(bool inBuildSlot);
WorkResult tryNext(bool inBuildSlot);
WorkResult referencesValid(bool inBuildSlot);
WorkResult tryToRun(bool inBuildSlot);
WorkResult finished(bool inBuildSlot);
/**
* Callback used by the worker to write to the log.

View file

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

View file

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

View file

@ -269,31 +269,11 @@ Path Settings::getDefaultSSLCertFile()
const std::string nixVersion = PACKAGE_VERSION;
void to_json(nlohmann::json & j, const SandboxMode & e)
{
if (e == SandboxMode::smEnabled) {
j = true;
} 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));
}
}
NLOHMANN_JSON_SERIALIZE_ENUM(SandboxMode, {
{SandboxMode::smEnabled, true},
{SandboxMode::smRelaxed, "relaxed"},
{SandboxMode::smDisabled, false},
});
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;
void to_json(nlohmann::json & j, const SandboxMode & e);
void from_json(const nlohmann::json & j, SandboxMode & e);
struct MaxBuildJobsSetting : public BaseSetting<unsigned int>
{
MaxBuildJobsSetting(Config * options,
@ -640,10 +637,10 @@ public:
PathsSetting<std::optional<Path>> diffHook{
this, std::nullopt, "diff-hook",
R"(
Path to an executable capable of diffing build results. The hook is
executed if `run-diff-hook` is true, and the output of a build is
known to not be the same. This program is not executed to determine
if two results are the same.
Absolute path to an executable capable of diffing build
results. The hook is executed if `run-diff-hook` is true, and the
output of a build is known to not be the same. This program is not
executed to determine if two results are the same.
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

View file

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

View file

@ -18,19 +18,15 @@ namespace fs = std::filesystem;
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)
{
if (path.empty() || path[0] != '/') {
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 {
path = concatStrings(*dir, "/", path);
}

View file

@ -29,13 +29,6 @@ namespace nix {
struct Sink;
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
* specified directory, or the current directory otherwise. The path

View file

@ -105,7 +105,6 @@ libutil_headers = files(
'regex-combinators.hh',
'regex.hh',
'repair-flag.hh',
'result.hh',
'serialise.hh',
'shlex.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.
*
* > 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)
{

View file

@ -353,9 +353,6 @@ void mainWrapped(int argc, char * * argv)
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];
if (legacy) return legacy(argc, argv);
@ -364,6 +361,7 @@ void mainWrapped(int argc, char * * argv)
evalSettings.pureEval = true;
setLogFormat(LogFormat::bar);
Finally f([] { logger->pause(); });
settings.verboseBuild = false;
// FIXME: stop messing about with log verbosity depending on if it is interactive use
if (isatty(STDERR_FILENO)) {

View file

@ -1,20 +1,25 @@
#pragma once
#include "types.hh"
#include "environment-variables.hh"
#include "file-system.hh"
#include "types.hh"
namespace nix {
// TODO: These helpers should be available in all unit tests.
/**
* The path to the unit test data directory. See the contributing guide
* 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.
*/
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 "types.hh"
#include "test-data.hh"
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
* 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 "args.hh"
#include "file-system.hh"
#include "environment-variables.hh"
#include "logging.hh"
#include "tests/test-data.hh"
#include <sstream>
#include <gtest/gtest.h>
@ -291,35 +287,6 @@ namespace nix {
), 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) {
Config config;
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/hash.cc',
'libutil-support/tests/terminal-code-eater.cc',
'libutil-support/tests/test-data.cc',
)
libutil_test_support = library(
'lixutil-test-support',
@ -96,6 +95,7 @@ libstore_test_support_sources = files(
'libstore-support/tests/derived-path.cc',
'libstore-support/tests/outputs-spec.cc',
'libstore-support/tests/path.cc',
'libstore-support/tests/test-data.hh',
)
libstore_test_support = library(