Compare commits
1 commit
main
...
repl-overl
Author | SHA1 | Date | |
---|---|---|---|
|
47677c645e |
34 changed files with 176 additions and 459 deletions
|
@ -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.
|
|
11
flake.nix
11
flake.nix
|
@ -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 (
|
||||||
|
|
11
meson.build
11
meson.build
|
@ -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
|
||||||
|
|
40
package.nix
40
package.nix
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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, {});
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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, we’re done */
|
/* If the derivation already exists, we’re 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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) { }
|
||||||
|
|
||||||
|
|
|
@ -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()};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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()};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
puppy = doggy
|
|
|
@ -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(
|
||||||
|
|
Loading…
Add table
Reference in a new issue