Split {,local-}derivation-goal.{cc,hh}
This separates the scheduling logic (including simple hook pathway) from the local-store needing code. This should be the final split for now. I'm reasonably happy with how it's turning out, even before I'm done moving code into `local-derivation-goal`. Benefits: 1. This will help "witness" that the hook case is indeed a lot simpler, and also compensate for the increased complexity that comes from content-addressed derivation outputs. 2. It also moves us ever so slightly towards a world where we could use off-the-shelf storage or sandboxing, since `local-derivation-goal` would be gutted in those cases, but `derivation-goal` should remain nearly the same. The new `#if 0` in the new files will be deleted in the following commit. I keep it here so if it turns out more stuff can be moved over, it's easy to do so in a way that preserves ordering --- and thus prevents conflicts. N.B. ```sh git diff HEAD^^ --color-moved --find-copies-harder --patience --stat ``` makes nicer output.
This commit is contained in:
parent
05cc5a8587
commit
68f4c728ec
File diff suppressed because it is too large
Load diff
|
@ -2,7 +2,8 @@
|
|||
|
||||
#include "parsed-derivations.hh"
|
||||
#include "lock.hh"
|
||||
#include "local-store.hh"
|
||||
#include "store-api.hh"
|
||||
#include "pathlocks.hh"
|
||||
#include "goal.hh"
|
||||
|
||||
namespace nix {
|
||||
|
@ -79,18 +80,6 @@ struct DerivationGoal : public Goal
|
|||
|
||||
std::map<std::string, InitialOutput> initialOutputs;
|
||||
|
||||
/* User selected for running the builder. */
|
||||
std::unique_ptr<UserLock> buildUser;
|
||||
|
||||
/* The process ID of the builder. */
|
||||
Pid pid;
|
||||
|
||||
/* The temporary directory. */
|
||||
Path tmpDir;
|
||||
|
||||
/* The path of the temporary directory in the sandbox. */
|
||||
Path tmpDirInSandbox;
|
||||
|
||||
/* File descriptor for the log file. */
|
||||
AutoCloseFD fdLogFile;
|
||||
std::shared_ptr<BufferedSink> logFileSink, logSink;
|
||||
|
@ -106,79 +95,15 @@ struct DerivationGoal : public Goal
|
|||
|
||||
std::string currentHookLine;
|
||||
|
||||
/* Pipe for the builder's standard output/error. */
|
||||
Pipe builderOut;
|
||||
|
||||
/* Pipe for synchronising updates to the builder namespaces. */
|
||||
Pipe userNamespaceSync;
|
||||
|
||||
/* The mount namespace of the builder, used to add additional
|
||||
paths to the sandbox as a result of recursive Nix calls. */
|
||||
AutoCloseFD sandboxMountNamespace;
|
||||
|
||||
/* On Linux, whether we're doing the build in its own user
|
||||
namespace. */
|
||||
bool usingUserNamespace = true;
|
||||
|
||||
/* The build hook. */
|
||||
std::unique_ptr<HookInstance> hook;
|
||||
|
||||
/* Whether we're currently doing a chroot build. */
|
||||
bool useChroot = false;
|
||||
|
||||
Path chrootRootDir;
|
||||
|
||||
/* RAII object to delete the chroot directory. */
|
||||
std::shared_ptr<AutoDelete> autoDelChroot;
|
||||
|
||||
/* The sort of derivation we are building. */
|
||||
DerivationType derivationType;
|
||||
|
||||
/* Whether to run the build in a private network namespace. */
|
||||
bool privateNetwork = false;
|
||||
|
||||
typedef void (DerivationGoal::*GoalState)();
|
||||
GoalState state;
|
||||
|
||||
/* Stuff we need to pass to initChild(). */
|
||||
struct ChrootPath {
|
||||
Path source;
|
||||
bool optional;
|
||||
ChrootPath(Path source = "", bool optional = false)
|
||||
: source(source), optional(optional)
|
||||
{ }
|
||||
};
|
||||
typedef map<Path, ChrootPath> DirsInChroot; // maps target path to source path
|
||||
DirsInChroot dirsInChroot;
|
||||
|
||||
typedef map<string, string> Environment;
|
||||
Environment env;
|
||||
|
||||
#if __APPLE__
|
||||
typedef string SandboxProfile;
|
||||
SandboxProfile additionalSandboxProfile;
|
||||
#endif
|
||||
|
||||
/* Hash rewriting. */
|
||||
StringMap inputRewrites, outputRewrites;
|
||||
typedef map<StorePath, StorePath> RedirectedOutputs;
|
||||
RedirectedOutputs redirectedOutputs;
|
||||
|
||||
/* The outputs paths used during the build.
|
||||
|
||||
- Input-addressed derivations or fixed content-addressed outputs are
|
||||
sometimes built when some of their outputs already exist, and can not
|
||||
be hidden via sandboxing. We use temporary locations instead and
|
||||
rewrite after the build. Otherwise the regular predetermined paths are
|
||||
put here.
|
||||
|
||||
- Floating content-addressed derivations do not know their final build
|
||||
output paths until the outputs are hashed, so random locations are
|
||||
used, and then renamed. The randomness helps guard against hidden
|
||||
self-references.
|
||||
*/
|
||||
OutputPathMap scratchOutputs;
|
||||
|
||||
/* The final output paths of the build.
|
||||
|
||||
- For input-addressed derivations, always the precomputed paths
|
||||
|
@ -191,11 +116,6 @@ struct DerivationGoal : public Goal
|
|||
|
||||
BuildMode buildMode;
|
||||
|
||||
/* If we're repairing without a chroot, there may be outputs that
|
||||
are valid but corrupt. So we redirect these outputs to
|
||||
temporary paths. */
|
||||
StorePathSet redirectedBadOutputs;
|
||||
|
||||
BuildResult result;
|
||||
|
||||
/* The current round, if we're building multiple times. */
|
||||
|
@ -203,17 +123,6 @@ struct DerivationGoal : public Goal
|
|||
|
||||
size_t nrRounds;
|
||||
|
||||
/* Path registration info from the previous round, if we're
|
||||
building multiple times. Since this contains the hash, it
|
||||
allows us to compare whether two rounds produced the same
|
||||
result. */
|
||||
std::map<Path, ValidPathInfo> prevInfos;
|
||||
|
||||
uid_t sandboxUid() { return usingUserNamespace ? 1000 : buildUser->getUID(); }
|
||||
gid_t sandboxGid() { return usingUserNamespace ? 100 : buildUser->getGID(); }
|
||||
|
||||
const static Path homeDir;
|
||||
|
||||
std::unique_ptr<MaintainCount<uint64_t>> mcExpectedBuilds, mcRunningBuilds;
|
||||
|
||||
std::unique_ptr<Activity> act;
|
||||
|
@ -226,39 +135,13 @@ struct DerivationGoal : public Goal
|
|||
/* The remote machine on which we're building. */
|
||||
std::string machineName;
|
||||
|
||||
/* The recursive Nix daemon socket. */
|
||||
AutoCloseFD daemonSocket;
|
||||
|
||||
/* The daemon main thread. */
|
||||
std::thread daemonThread;
|
||||
|
||||
/* The daemon worker threads. */
|
||||
std::vector<std::thread> daemonWorkerThreads;
|
||||
|
||||
/* Paths that were added via recursive Nix calls. */
|
||||
StorePathSet addedPaths;
|
||||
|
||||
/* Recursive Nix calls are only allowed to build or realize paths
|
||||
in the original input closure or added via a recursive Nix call
|
||||
(so e.g. you can't do 'nix-store -r /nix/store/<bla>' where
|
||||
/nix/store/<bla> is some arbitrary path in a binary cache). */
|
||||
bool isAllowed(const StorePath & path)
|
||||
{
|
||||
return inputPaths.count(path) || addedPaths.count(path);
|
||||
}
|
||||
|
||||
friend struct RestrictedStore;
|
||||
|
||||
DerivationGoal(const StorePath & drvPath,
|
||||
const StringSet & wantedOutputs, Worker & worker,
|
||||
BuildMode buildMode = bmNormal);
|
||||
DerivationGoal(const StorePath & drvPath, const BasicDerivation & drv,
|
||||
const StringSet & wantedOutputs, Worker & worker,
|
||||
BuildMode buildMode = bmNormal);
|
||||
~DerivationGoal();
|
||||
|
||||
/* Whether we need to perform hash rewriting if there are valid output paths. */
|
||||
bool needsHashRewrite();
|
||||
virtual ~DerivationGoal();
|
||||
|
||||
void timedOut(Error && ex) override;
|
||||
|
||||
|
@ -280,7 +163,7 @@ struct DerivationGoal : public Goal
|
|||
void closureRepaired();
|
||||
void inputsRealised();
|
||||
void tryToBuild();
|
||||
void tryLocalBuild();
|
||||
virtual void tryLocalBuild();
|
||||
void buildDone();
|
||||
|
||||
void resolvedFinished();
|
||||
|
@ -288,40 +171,11 @@ struct DerivationGoal : public Goal
|
|||
/* Is the build hook willing to perform the build? */
|
||||
HookReply tryBuildHook();
|
||||
|
||||
/* Start building a derivation. */
|
||||
void startBuilder();
|
||||
|
||||
/* Fill in the environment for the builder. */
|
||||
void initEnv();
|
||||
|
||||
/* Setup tmp dir location. */
|
||||
void initTmpDir();
|
||||
|
||||
/* Write a JSON file containing the derivation attributes. */
|
||||
void writeStructuredAttrs();
|
||||
|
||||
void startDaemon();
|
||||
|
||||
void stopDaemon();
|
||||
|
||||
/* Add 'path' to the set of paths that may be referenced by the
|
||||
outputs, and make it appear in the sandbox. */
|
||||
void addDependency(const StorePath & path);
|
||||
|
||||
/* Make a file owned by the builder. */
|
||||
void chownToBuilder(const Path & path);
|
||||
|
||||
/* Run the builder's process. */
|
||||
void runChild();
|
||||
virtual int getChildStatus();
|
||||
|
||||
/* Check that the derivation outputs all exist and register them
|
||||
as valid. */
|
||||
void registerOutputs();
|
||||
|
||||
/* Check that an output meets the requirements specified by the
|
||||
'outputChecks' attribute (or the legacy
|
||||
'{allowed,disallowed}{References,Requisites}' attributes). */
|
||||
void checkOutputs(const std::map<std::string, ValidPathInfo> & outputs);
|
||||
virtual void registerOutputs();
|
||||
|
||||
/* Open a log file and a pipe to it. */
|
||||
Path openLogFile();
|
||||
|
@ -329,8 +183,18 @@ struct DerivationGoal : public Goal
|
|||
/* Close the log file. */
|
||||
void closeLogFile();
|
||||
|
||||
/* Delete the temporary directory, if we have one. */
|
||||
void deleteTmpDir(bool force);
|
||||
/* Close the read side of the logger pipe. */
|
||||
virtual void closeReadPipes();
|
||||
|
||||
/* Cleanup hooks for buildDone() */
|
||||
virtual void cleanupHookFinally();
|
||||
virtual void cleanupPreChildKill();
|
||||
virtual void cleanupPostChildKill();
|
||||
virtual bool cleanupDecideWhetherDiskFull();
|
||||
virtual void cleanupPostOutputsRegisteredModeCheck();
|
||||
virtual void cleanupPostOutputsRegisteredModeNonCheck();
|
||||
|
||||
virtual bool isReadDesc(int fd);
|
||||
|
||||
/* Callback used by the worker to write to the log. */
|
||||
void handleChildOutput(int fd, const string & data) override;
|
||||
|
@ -347,17 +211,7 @@ struct DerivationGoal : public Goal
|
|||
void checkPathValidity();
|
||||
|
||||
/* Forcibly kill the child process, if any. */
|
||||
void killChild();
|
||||
|
||||
/* Create alternative path calculated from but distinct from the
|
||||
input, so we can avoid overwriting outputs (or other store paths)
|
||||
that already exist. */
|
||||
StorePath makeFallbackPath(const StorePath & path);
|
||||
/* Make a path to another based on the output name along with the
|
||||
derivation hash. */
|
||||
/* FIXME add option to randomize, so we can audit whether our
|
||||
rewrites caught everything */
|
||||
StorePath makeFallbackPath(std::string_view outputName);
|
||||
virtual void killChild();
|
||||
|
||||
void repairClosure();
|
||||
|
||||
|
@ -370,4 +224,6 @@ struct DerivationGoal : public Goal
|
|||
StorePathSet exportReferences(const StorePathSet & storePaths);
|
||||
};
|
||||
|
||||
MakeError(NotDeterministic, BuildError);
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "worker.hh"
|
||||
#include "substitution-goal.hh"
|
||||
#include "derivation-goal.hh"
|
||||
#include "local-store.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "derivation-goal.hh"
|
||||
#include "local-derivation-goal.hh"
|
||||
#include "hook-instance.hh"
|
||||
#include "worker.hh"
|
||||
#include "builtins.hh"
|
||||
|
@ -75,7 +75,6 @@ void handleDiffHook(
|
|||
diffHookOptions.uid = uid;
|
||||
diffHookOptions.gid = gid;
|
||||
diffHookOptions.chdir = "/";
|
||||
|
||||
auto diffRes = runProgram(diffHookOptions);
|
||||
if (!statusOk(diffRes.first))
|
||||
throw ExecError(diffRes.first,
|
||||
|
@ -94,8 +93,9 @@ void handleDiffHook(
|
|||
}
|
||||
}
|
||||
|
||||
const Path DerivationGoal::homeDir = "/homeless-shelter";
|
||||
const Path LocalDerivationGoal::homeDir = "/homeless-shelter";
|
||||
|
||||
#if 0
|
||||
DerivationGoal::DerivationGoal(const StorePath & drvPath,
|
||||
const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode)
|
||||
: Goal(worker)
|
||||
|
@ -138,19 +138,20 @@ DerivationGoal::DerivationGoal(const StorePath & drvPath, const BasicDerivation
|
|||
garbage-collected. (See isActiveTempFile() in gc.cc.) */
|
||||
worker.store.addTempRoot(this->drvPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
DerivationGoal::~DerivationGoal()
|
||||
LocalDerivationGoal::~LocalDerivationGoal()
|
||||
{
|
||||
/* Careful: we should never ever throw an exception from a
|
||||
destructor. */
|
||||
try { deleteTmpDir(false); } catch (...) { ignoreException(); }
|
||||
try { killChild(); } catch (...) { ignoreException(); }
|
||||
try { stopDaemon(); } catch (...) { ignoreException(); }
|
||||
try { deleteTmpDir(false); } catch (...) { ignoreException(); }
|
||||
try { closeLogFile(); } catch (...) { ignoreException(); }
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
string DerivationGoal::key()
|
||||
{
|
||||
/* Ensure that derivations get built in order of their name,
|
||||
|
@ -159,9 +160,10 @@ string DerivationGoal::key()
|
|||
derivation goals (due to "b$"). */
|
||||
return "b$" + std::string(drvPath.name()) + "$" + worker.store.printStorePath(drvPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
inline bool DerivationGoal::needsHashRewrite()
|
||||
inline bool LocalDerivationGoal::needsHashRewrite()
|
||||
{
|
||||
#if __linux__
|
||||
return !useChroot;
|
||||
|
@ -172,7 +174,15 @@ inline bool DerivationGoal::needsHashRewrite()
|
|||
}
|
||||
|
||||
|
||||
void DerivationGoal::killChild()
|
||||
LocalStore & LocalDerivationGoal::getLocalStore()
|
||||
{
|
||||
auto p = dynamic_cast<LocalStore *>(&worker.store);
|
||||
assert(p);
|
||||
return *p;
|
||||
}
|
||||
|
||||
|
||||
void LocalDerivationGoal::killChild()
|
||||
{
|
||||
if (pid != -1) {
|
||||
worker.childTerminated(this);
|
||||
|
@ -193,17 +203,11 @@ void DerivationGoal::killChild()
|
|||
assert(pid == -1);
|
||||
}
|
||||
|
||||
hook.reset();
|
||||
}
|
||||
|
||||
|
||||
void DerivationGoal::timedOut(Error && ex)
|
||||
{
|
||||
killChild();
|
||||
done(BuildResult::TimedOut, ex);
|
||||
DerivationGoal::killChild();
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void DerivationGoal::work()
|
||||
{
|
||||
(this->*state)();
|
||||
|
@ -695,15 +699,9 @@ void DerivationGoal::tryToBuild()
|
|||
state = &DerivationGoal::tryLocalBuild;
|
||||
worker.wakeUp(shared_from_this());
|
||||
}
|
||||
#endif
|
||||
|
||||
void DerivationGoal::tryLocalBuild() {
|
||||
/* Make sure that we are allowed to start a build. */
|
||||
if (!dynamic_cast<LocalStore *>(&worker.store)) {
|
||||
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://nixos.org/nix/manual/#chap-distributed-builds");
|
||||
}
|
||||
void LocalDerivationGoal::tryLocalBuild() {
|
||||
unsigned int curBuilds = worker.getNrLocalBuilds();
|
||||
if (curBuilds >= settings.maxBuildJobs) {
|
||||
worker.waitForBuildSlot(shared_from_this());
|
||||
|
@ -757,7 +755,6 @@ void DerivationGoal::tryLocalBuild() {
|
|||
started();
|
||||
}
|
||||
|
||||
|
||||
static void chmod_(const Path & path, mode_t mode)
|
||||
{
|
||||
if (chmod(path.c_str(), mode) == -1)
|
||||
|
@ -785,51 +782,125 @@ static void movePath(const Path & src, const Path & dst)
|
|||
}
|
||||
|
||||
|
||||
void replaceValidPath(const Path & storePath, const Path & tmpPath)
|
||||
extern void replaceValidPath(const Path & storePath, const Path & tmpPath);
|
||||
|
||||
|
||||
int LocalDerivationGoal::getChildStatus()
|
||||
{
|
||||
/* We can't atomically replace storePath (the original) with
|
||||
tmpPath (the replacement), so we have to move it out of the
|
||||
way first. We'd better not be interrupted here, because if
|
||||
we're repairing (say) Glibc, we end up with a broken system. */
|
||||
Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % random()).str();
|
||||
if (pathExists(storePath))
|
||||
movePath(storePath, oldPath);
|
||||
return hook ? DerivationGoal::getChildStatus() : pid.kill();
|
||||
}
|
||||
|
||||
try {
|
||||
movePath(tmpPath, storePath);
|
||||
} catch (...) {
|
||||
try {
|
||||
// attempt to recover
|
||||
movePath(oldPath, storePath);
|
||||
} catch (...) {
|
||||
ignoreException();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
deletePath(oldPath);
|
||||
void LocalDerivationGoal::closeReadPipes()
|
||||
{
|
||||
if (hook) {
|
||||
DerivationGoal::closeReadPipes();
|
||||
} else
|
||||
builderOut.readSide = -1;
|
||||
}
|
||||
|
||||
|
||||
MakeError(NotDeterministic, BuildError);
|
||||
void LocalDerivationGoal::cleanupHookFinally()
|
||||
{
|
||||
/* Release the build user at the end of this function. We don't do
|
||||
it right away because we don't want another build grabbing this
|
||||
uid and then messing around with our output. */
|
||||
buildUser.reset();
|
||||
}
|
||||
|
||||
|
||||
void LocalDerivationGoal::cleanupPreChildKill()
|
||||
{
|
||||
sandboxMountNamespace = -1;
|
||||
}
|
||||
|
||||
|
||||
void LocalDerivationGoal::cleanupPostChildKill()
|
||||
{
|
||||
/* When running under a build user, make sure that all processes
|
||||
running under that uid are gone. This is to prevent a
|
||||
malicious user from leaving behind a process that keeps files
|
||||
open and modifies them after they have been chown'ed to
|
||||
root. */
|
||||
if (buildUser) buildUser->kill();
|
||||
|
||||
/* Terminate the recursive Nix daemon. */
|
||||
stopDaemon();
|
||||
}
|
||||
|
||||
|
||||
bool LocalDerivationGoal::cleanupDecideWhetherDiskFull()
|
||||
{
|
||||
bool diskFull = false;
|
||||
|
||||
/* Heuristically check whether the build failure may have
|
||||
been caused by a disk full condition. We have no way
|
||||
of knowing whether the build actually got an ENOSPC.
|
||||
So instead, check if the disk is (nearly) full now. If
|
||||
so, we don't mark this build as a permanent failure. */
|
||||
#if HAVE_STATVFS
|
||||
{
|
||||
auto & localStore = getLocalStore();
|
||||
uint64_t required = 8ULL * 1024 * 1024; // FIXME: make configurable
|
||||
struct statvfs st;
|
||||
if (statvfs(localStore.realStoreDir.c_str(), &st) == 0 &&
|
||||
(uint64_t) st.f_bavail * st.f_bsize < required)
|
||||
diskFull = true;
|
||||
if (statvfs(tmpDir.c_str(), &st) == 0 &&
|
||||
(uint64_t) st.f_bavail * st.f_bsize < required)
|
||||
diskFull = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
deleteTmpDir(false);
|
||||
|
||||
/* Move paths out of the chroot for easier debugging of
|
||||
build failures. */
|
||||
if (useChroot && buildMode == bmNormal)
|
||||
for (auto & [_, status] : initialOutputs) {
|
||||
if (!status.known) continue;
|
||||
if (buildMode != bmCheck && status.known->isValid()) continue;
|
||||
auto p = worker.store.printStorePath(status.known->path);
|
||||
if (pathExists(chrootRootDir + p))
|
||||
rename((chrootRootDir + p).c_str(), p.c_str());
|
||||
}
|
||||
|
||||
return diskFull;
|
||||
}
|
||||
|
||||
|
||||
void LocalDerivationGoal::cleanupPostOutputsRegisteredModeCheck()
|
||||
{
|
||||
deleteTmpDir(true);
|
||||
}
|
||||
|
||||
|
||||
void LocalDerivationGoal::cleanupPostOutputsRegisteredModeNonCheck()
|
||||
{
|
||||
/* Delete unused redirected outputs (when doing hash rewriting). */
|
||||
for (auto & i : redirectedOutputs)
|
||||
deletePath(worker.store.Store::toRealPath(i.second));
|
||||
|
||||
/* Delete the chroot (if we were using one). */
|
||||
autoDelChroot.reset(); /* this runs the destructor */
|
||||
|
||||
cleanupPostOutputsRegisteredModeCheck();
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void DerivationGoal::buildDone()
|
||||
{
|
||||
trace("build done");
|
||||
|
||||
/* Release the build user at the end of this function. We don't do
|
||||
it right away because we don't want another build grabbing this
|
||||
uid and then messing around with our output. */
|
||||
Finally releaseBuildUser([&]() { buildUser.reset(); });
|
||||
Finally releaseBuildUser([&](){ this->cleanupHookFinally(); });
|
||||
|
||||
sandboxMountNamespace = -1;
|
||||
cleanupPreChildKill();
|
||||
|
||||
/* Since we got an EOF on the logger pipe, the builder is presumed
|
||||
to have terminated. In fact, the builder could also have
|
||||
simply have closed its end of the pipe, so just to be sure,
|
||||
kill it. */
|
||||
int status = hook ? hook->pid.kill() : pid.kill();
|
||||
int status = getChildStatus();
|
||||
|
||||
debug("builder process for '%s' finished", worker.store.printStorePath(drvPath));
|
||||
|
||||
|
@ -840,24 +911,12 @@ void DerivationGoal::buildDone()
|
|||
worker.childTerminated(this);
|
||||
|
||||
/* Close the read side of the logger pipe. */
|
||||
if (hook) {
|
||||
hook->builderOut.readSide = -1;
|
||||
hook->fromHook.readSide = -1;
|
||||
} else
|
||||
builderOut.readSide = -1;
|
||||
closeReadPipes();
|
||||
|
||||
/* Close the log file. */
|
||||
closeLogFile();
|
||||
|
||||
/* When running under a build user, make sure that all processes
|
||||
running under that uid are gone. This is to prevent a
|
||||
malicious user from leaving behind a process that keeps files
|
||||
open and modifies them after they have been chown'ed to
|
||||
root. */
|
||||
if (buildUser) buildUser->kill();
|
||||
|
||||
/* Terminate the recursive Nix daemon. */
|
||||
stopDaemon();
|
||||
cleanupPostChildKill();
|
||||
|
||||
bool diskFull = false;
|
||||
|
||||
|
@ -866,36 +925,7 @@ void DerivationGoal::buildDone()
|
|||
/* Check the exit status. */
|
||||
if (!statusOk(status)) {
|
||||
|
||||
/* Heuristically check whether the build failure may have
|
||||
been caused by a disk full condition. We have no way
|
||||
of knowing whether the build actually got an ENOSPC.
|
||||
So instead, check if the disk is (nearly) full now. If
|
||||
so, we don't mark this build as a permanent failure. */
|
||||
#if HAVE_STATVFS
|
||||
if (auto localStore = dynamic_cast<LocalStore *>(&worker.store)) {
|
||||
uint64_t required = 8ULL * 1024 * 1024; // FIXME: make configurable
|
||||
struct statvfs st;
|
||||
if (statvfs(localStore->realStoreDir.c_str(), &st) == 0 &&
|
||||
(uint64_t) st.f_bavail * st.f_bsize < required)
|
||||
diskFull = true;
|
||||
if (statvfs(tmpDir.c_str(), &st) == 0 &&
|
||||
(uint64_t) st.f_bavail * st.f_bsize < required)
|
||||
diskFull = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
deleteTmpDir(false);
|
||||
|
||||
/* Move paths out of the chroot for easier debugging of
|
||||
build failures. */
|
||||
if (useChroot && buildMode == bmNormal)
|
||||
for (auto & [_, status] : initialOutputs) {
|
||||
if (!status.known) continue;
|
||||
if (buildMode != bmCheck && status.known->isValid()) continue;
|
||||
auto p = worker.store.printStorePath(status.known->path);
|
||||
if (pathExists(chrootRootDir + p))
|
||||
rename((chrootRootDir + p).c_str(), p.c_str());
|
||||
}
|
||||
diskFull |= cleanupDecideWhetherDiskFull();
|
||||
|
||||
auto msg = fmt("builder for '%s' %s",
|
||||
yellowtxt(worker.store.printStorePath(drvPath)),
|
||||
|
@ -975,19 +1005,12 @@ void DerivationGoal::buildDone()
|
|||
}
|
||||
|
||||
if (buildMode == bmCheck) {
|
||||
deleteTmpDir(true);
|
||||
cleanupPostOutputsRegisteredModeCheck();
|
||||
done(BuildResult::Built);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Delete unused redirected outputs (when doing hash rewriting). */
|
||||
for (auto & i : redirectedOutputs)
|
||||
deletePath(worker.store.Store::toRealPath(i.second));
|
||||
|
||||
/* Delete the chroot (if we were using one). */
|
||||
autoDelChroot.reset(); /* this runs the destructor */
|
||||
|
||||
deleteTmpDir(true);
|
||||
cleanupPostOutputsRegisteredModeNonCheck();
|
||||
|
||||
/* Repeat the build if necessary. */
|
||||
if (curRound++ < nrRounds) {
|
||||
|
@ -1169,15 +1192,17 @@ HookReply DerivationGoal::tryBuildHook()
|
|||
|
||||
return rpAccept;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int childEntry(void * arg)
|
||||
{
|
||||
((DerivationGoal *) arg)->runChild();
|
||||
((LocalDerivationGoal *) arg)->runChild();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
StorePathSet DerivationGoal::exportReferences(const StorePathSet & storePaths)
|
||||
{
|
||||
StorePathSet paths;
|
||||
|
@ -1212,6 +1237,7 @@ StorePathSet DerivationGoal::exportReferences(const StorePathSet & storePaths)
|
|||
|
||||
return paths;
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::once_flag dns_resolve_flag;
|
||||
|
||||
|
@ -1230,7 +1256,7 @@ static void preloadNSS() {
|
|||
}
|
||||
|
||||
|
||||
void linkOrCopy(const Path & from, const Path & to)
|
||||
static void linkOrCopy(const Path & from, const Path & to)
|
||||
{
|
||||
if (link(from.c_str(), to.c_str()) == -1) {
|
||||
/* Hard-linking fails if we exceed the maximum link count on a
|
||||
|
@ -1247,7 +1273,7 @@ void linkOrCopy(const Path & from, const Path & to)
|
|||
}
|
||||
|
||||
|
||||
void DerivationGoal::startBuilder()
|
||||
void LocalDerivationGoal::startBuilder()
|
||||
{
|
||||
/* Right platform? */
|
||||
if (!parsedDrv->canBuildLocally(worker.store))
|
||||
|
@ -1285,15 +1311,13 @@ void DerivationGoal::startBuilder()
|
|||
useChroot = !(derivationIsImpure(derivationType)) && !noChroot;
|
||||
}
|
||||
|
||||
if (auto localStoreP = dynamic_cast<LocalStore *>(&worker.store)) {
|
||||
auto & localStore = *localStoreP;
|
||||
if (localStore.storeDir != localStore.realStoreDir) {
|
||||
#if __linux__
|
||||
useChroot = true;
|
||||
#else
|
||||
throw Error("building using a diverted store is not supported on this platform");
|
||||
#endif
|
||||
}
|
||||
auto & localStore = getLocalStore();
|
||||
if (localStore.storeDir != localStore.realStoreDir) {
|
||||
#if __linux__
|
||||
useChroot = true;
|
||||
#else
|
||||
throw Error("building using a diverted store is not supported on this platform");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Create a temporary directory where the build will take
|
||||
|
@ -1850,7 +1874,7 @@ void DerivationGoal::startBuilder()
|
|||
}
|
||||
|
||||
|
||||
void DerivationGoal::initTmpDir() {
|
||||
void LocalDerivationGoal::initTmpDir() {
|
||||
/* In a sandbox, for determinism, always use the same temporary
|
||||
directory. */
|
||||
#if __linux__
|
||||
|
@ -1899,7 +1923,7 @@ void DerivationGoal::initTmpDir() {
|
|||
}
|
||||
|
||||
|
||||
void DerivationGoal::initEnv()
|
||||
void LocalDerivationGoal::initEnv()
|
||||
{
|
||||
env.clear();
|
||||
|
||||
|
@ -1960,7 +1984,7 @@ void DerivationGoal::initEnv()
|
|||
static std::regex shVarName("[A-Za-z_][A-Za-z0-9_]*");
|
||||
|
||||
|
||||
void DerivationGoal::writeStructuredAttrs()
|
||||
void LocalDerivationGoal::writeStructuredAttrs()
|
||||
{
|
||||
auto structuredAttrs = parsedDrv->getStructuredAttrs();
|
||||
if (!structuredAttrs) return;
|
||||
|
@ -2079,9 +2103,9 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
|
|||
{
|
||||
ref<LocalStore> next;
|
||||
|
||||
DerivationGoal & goal;
|
||||
LocalDerivationGoal & goal;
|
||||
|
||||
RestrictedStore(const Params & params, ref<LocalStore> next, DerivationGoal & goal)
|
||||
RestrictedStore(const Params & params, ref<LocalStore> next, LocalDerivationGoal & goal)
|
||||
: StoreConfig(params)
|
||||
, LocalFSStoreConfig(params)
|
||||
, RestrictedStoreConfig(params)
|
||||
|
@ -2256,15 +2280,14 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
|
|||
};
|
||||
|
||||
|
||||
void DerivationGoal::startDaemon()
|
||||
void LocalDerivationGoal::startDaemon()
|
||||
{
|
||||
settings.requireExperimentalFeature("recursive-nix");
|
||||
|
||||
Store::Params params;
|
||||
params["path-info-cache-size"] = "0";
|
||||
params["store"] = worker.store.storeDir;
|
||||
if (auto localStore = dynamic_cast<LocalStore *>(&worker.store))
|
||||
params["root"] = localStore->rootDir;
|
||||
params["root"] = getLocalStore().rootDir;
|
||||
params["state"] = "/no-such-path";
|
||||
params["log"] = "/no-such-path";
|
||||
auto store = make_ref<RestrictedStore>(params,
|
||||
|
@ -2322,7 +2345,7 @@ void DerivationGoal::startDaemon()
|
|||
}
|
||||
|
||||
|
||||
void DerivationGoal::stopDaemon()
|
||||
void LocalDerivationGoal::stopDaemon()
|
||||
{
|
||||
if (daemonSocket && shutdown(daemonSocket.get(), SHUT_RDWR) == -1)
|
||||
throw SysError("shutting down daemon socket");
|
||||
|
@ -2340,7 +2363,7 @@ void DerivationGoal::stopDaemon()
|
|||
}
|
||||
|
||||
|
||||
void DerivationGoal::addDependency(const StorePath & path)
|
||||
void LocalDerivationGoal::addDependency(const StorePath & path)
|
||||
{
|
||||
if (isAllowed(path)) return;
|
||||
|
||||
|
@ -2397,8 +2420,7 @@ void DerivationGoal::addDependency(const StorePath & path)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void DerivationGoal::chownToBuilder(const Path & path)
|
||||
void LocalDerivationGoal::chownToBuilder(const Path & path)
|
||||
{
|
||||
if (!buildUser) return;
|
||||
if (chown(path.c_str(), buildUser->getUID(), buildUser->getGID()) == -1)
|
||||
|
@ -2469,7 +2491,7 @@ void setupSeccomp()
|
|||
}
|
||||
|
||||
|
||||
void DerivationGoal::runChild()
|
||||
void LocalDerivationGoal::runChild()
|
||||
{
|
||||
/* Warning: in the child we should absolutely not make any SQLite
|
||||
calls! */
|
||||
|
@ -2977,7 +2999,7 @@ void DerivationGoal::runChild()
|
|||
}
|
||||
|
||||
|
||||
void DerivationGoal::registerOutputs()
|
||||
void LocalDerivationGoal::registerOutputs()
|
||||
{
|
||||
/* When using a build hook, the build hook can register the output
|
||||
as valid (by doing `nix-store --import'). If so we don't have
|
||||
|
@ -2987,14 +3009,8 @@ void DerivationGoal::registerOutputs()
|
|||
floating content-addressed derivations this isn't the case.
|
||||
*/
|
||||
if (hook) {
|
||||
bool allValid = true;
|
||||
for (auto & [outputName, outputPath] : worker.store.queryPartialDerivationOutputMap(drvPath)) {
|
||||
if (!outputPath || !worker.store.isValidPath(*outputPath))
|
||||
allValid = false;
|
||||
else
|
||||
finalOutputs.insert_or_assign(outputName, *outputPath);
|
||||
}
|
||||
if (allValid) return;
|
||||
DerivationGoal::registerOutputs();
|
||||
return;
|
||||
}
|
||||
|
||||
std::map<std::string, ValidPathInfo> infos;
|
||||
|
@ -3349,10 +3365,7 @@ void DerivationGoal::registerOutputs()
|
|||
}
|
||||
}
|
||||
|
||||
auto localStoreP = dynamic_cast<LocalStore *>(&worker.store);
|
||||
if (!localStoreP)
|
||||
throw Unsupported("can only register outputs with local store, but this is %s", worker.store.getUri());
|
||||
auto & localStore = *localStoreP;
|
||||
auto & localStore = getLocalStore();
|
||||
|
||||
if (buildMode == bmCheck) {
|
||||
|
||||
|
@ -3481,10 +3494,7 @@ void DerivationGoal::registerOutputs()
|
|||
paths referenced by each of them. If there are cycles in the
|
||||
outputs, this will fail. */
|
||||
{
|
||||
auto localStoreP = dynamic_cast<LocalStore *>(&worker.store);
|
||||
if (!localStoreP)
|
||||
throw Unsupported("can only register outputs with local store, but this is %s", worker.store.getUri());
|
||||
auto & localStore = *localStoreP;
|
||||
auto & localStore = getLocalStore();
|
||||
|
||||
ValidPathInfos infos2;
|
||||
for (auto & [outputName, newInfo] : infos) {
|
||||
|
@ -3513,7 +3523,7 @@ void DerivationGoal::registerOutputs()
|
|||
}
|
||||
|
||||
|
||||
void DerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & outputs)
|
||||
void LocalDerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & outputs)
|
||||
{
|
||||
std::map<Path, const ValidPathInfo &> outputsByPath;
|
||||
for (auto & output : outputs)
|
||||
|
@ -3678,6 +3688,7 @@ void DerivationGoal::checkOutputs(const std::map<Path, ValidPathInfo> & outputs)
|
|||
}
|
||||
|
||||
|
||||
#if 0
|
||||
Path DerivationGoal::openLogFile()
|
||||
{
|
||||
logSize = 0;
|
||||
|
@ -3720,9 +3731,10 @@ void DerivationGoal::closeLogFile()
|
|||
logSink = logFileSink = 0;
|
||||
fdLogFile = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void DerivationGoal::deleteTmpDir(bool force)
|
||||
void LocalDerivationGoal::deleteTmpDir(bool force)
|
||||
{
|
||||
if (tmpDir != "") {
|
||||
/* Don't keep temporary directories for builtins because they
|
||||
|
@ -3738,10 +3750,17 @@ void DerivationGoal::deleteTmpDir(bool force)
|
|||
}
|
||||
|
||||
|
||||
bool LocalDerivationGoal::isReadDesc(int fd)
|
||||
{
|
||||
return (hook && DerivationGoal::isReadDesc(fd)) ||
|
||||
(!hook && fd == builderOut.readSide.get());
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void DerivationGoal::handleChildOutput(int fd, const string & data)
|
||||
{
|
||||
if ((hook && fd == hook->builderOut.readSide.get()) ||
|
||||
(!hook && fd == builderOut.readSide.get()))
|
||||
if (isReadDesc(fd))
|
||||
{
|
||||
logSize += data.size();
|
||||
if (settings.maxLogSize && logSize > settings.maxLogSize) {
|
||||
|
@ -3855,9 +3874,10 @@ void DerivationGoal::checkPathValidity()
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
StorePath DerivationGoal::makeFallbackPath(std::string_view outputName)
|
||||
StorePath LocalDerivationGoal::makeFallbackPath(std::string_view outputName)
|
||||
{
|
||||
return worker.store.makeStorePath(
|
||||
"rewrite:" + std::string(drvPath.to_string()) + ":name:" + std::string(outputName),
|
||||
|
@ -3865,7 +3885,7 @@ StorePath DerivationGoal::makeFallbackPath(std::string_view outputName)
|
|||
}
|
||||
|
||||
|
||||
StorePath DerivationGoal::makeFallbackPath(const StorePath & path)
|
||||
StorePath LocalDerivationGoal::makeFallbackPath(const StorePath & path)
|
||||
{
|
||||
return worker.store.makeStorePath(
|
||||
"rewrite:" + std::string(drvPath.to_string()) + ":" + std::string(path.to_string()),
|
||||
|
@ -3873,6 +3893,7 @@ StorePath DerivationGoal::makeFallbackPath(const StorePath & path)
|
|||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void DerivationGoal::done(BuildResult::Status status, std::optional<Error> ex)
|
||||
{
|
||||
result.status = status;
|
||||
|
@ -3897,6 +3918,7 @@ void DerivationGoal::done(BuildResult::Status status, std::optional<Error> ex)
|
|||
|
||||
worker.updateProgress();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,48 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "parsed-derivations.hh"
|
||||
#include "lock.hh"
|
||||
#include "derivation-goal.hh"
|
||||
#include "local-store.hh"
|
||||
#include "goal.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
using std::map;
|
||||
|
||||
struct HookInstance;
|
||||
|
||||
typedef enum {rpAccept, rpDecline, rpPostpone} HookReply;
|
||||
|
||||
/* Unless we are repairing, we don't both to test validity and just assume it,
|
||||
so the choices are `Absent` or `Valid`. */
|
||||
enum struct PathStatus {
|
||||
Corrupt,
|
||||
Absent,
|
||||
Valid,
|
||||
};
|
||||
|
||||
struct InitialOutputStatus {
|
||||
StorePath path;
|
||||
PathStatus status;
|
||||
/* Valid in the store, and additionally non-corrupt if we are repairing */
|
||||
bool isValid() const {
|
||||
return status == PathStatus::Valid;
|
||||
}
|
||||
/* Merely present, allowed to be corrupt */
|
||||
bool isPresent() const {
|
||||
return status == PathStatus::Corrupt
|
||||
|| status == PathStatus::Valid;
|
||||
}
|
||||
};
|
||||
|
||||
struct InitialOutput {
|
||||
bool wanted;
|
||||
Hash outputHash;
|
||||
std::optional<InitialOutputStatus> known;
|
||||
};
|
||||
|
||||
struct DerivationGoal : public Goal
|
||||
struct LocalDerivationGoal : public DerivationGoal
|
||||
{
|
||||
LocalStore & getLocalStore();
|
||||
|
||||
#if 0
|
||||
/* Whether to use an on-disk .drv file. */
|
||||
bool useDerivation;
|
||||
|
||||
|
@ -78,6 +45,7 @@ struct DerivationGoal : public Goal
|
|||
StorePathSet inputPaths;
|
||||
|
||||
std::map<std::string, InitialOutput> initialOutputs;
|
||||
#endif
|
||||
|
||||
/* User selected for running the builder. */
|
||||
std::unique_ptr<UserLock> buildUser;
|
||||
|
@ -91,6 +59,7 @@ struct DerivationGoal : public Goal
|
|||
/* The path of the temporary directory in the sandbox. */
|
||||
Path tmpDirInSandbox;
|
||||
|
||||
#if 0
|
||||
/* File descriptor for the log file. */
|
||||
AutoCloseFD fdLogFile;
|
||||
std::shared_ptr<BufferedSink> logFileSink, logSink;
|
||||
|
@ -105,6 +74,7 @@ struct DerivationGoal : public Goal
|
|||
size_t currentLogLinePos = 0; // to handle carriage return
|
||||
|
||||
std::string currentHookLine;
|
||||
#endif
|
||||
|
||||
/* Pipe for the builder's standard output/error. */
|
||||
Pipe builderOut;
|
||||
|
@ -120,8 +90,10 @@ struct DerivationGoal : public Goal
|
|||
namespace. */
|
||||
bool usingUserNamespace = true;
|
||||
|
||||
#if 0
|
||||
/* The build hook. */
|
||||
std::unique_ptr<HookInstance> hook;
|
||||
#endif
|
||||
|
||||
/* Whether we're currently doing a chroot build. */
|
||||
bool useChroot = false;
|
||||
|
@ -131,14 +103,18 @@ struct DerivationGoal : public Goal
|
|||
/* RAII object to delete the chroot directory. */
|
||||
std::shared_ptr<AutoDelete> autoDelChroot;
|
||||
|
||||
#if 0
|
||||
/* The sort of derivation we are building. */
|
||||
DerivationType derivationType;
|
||||
#endif
|
||||
|
||||
/* Whether to run the build in a private network namespace. */
|
||||
bool privateNetwork = false;
|
||||
|
||||
#if 0
|
||||
typedef void (DerivationGoal::*GoalState)();
|
||||
GoalState state;
|
||||
#endif
|
||||
|
||||
/* Stuff we need to pass to initChild(). */
|
||||
struct ChrootPath {
|
||||
|
@ -179,6 +155,7 @@ struct DerivationGoal : public Goal
|
|||
*/
|
||||
OutputPathMap scratchOutputs;
|
||||
|
||||
#if 0
|
||||
/* The final output paths of the build.
|
||||
|
||||
- For input-addressed derivations, always the precomputed paths
|
||||
|
@ -190,18 +167,21 @@ struct DerivationGoal : public Goal
|
|||
OutputPathMap finalOutputs;
|
||||
|
||||
BuildMode buildMode;
|
||||
#endif
|
||||
|
||||
/* If we're repairing without a chroot, there may be outputs that
|
||||
are valid but corrupt. So we redirect these outputs to
|
||||
temporary paths. */
|
||||
StorePathSet redirectedBadOutputs;
|
||||
|
||||
#if 0
|
||||
BuildResult result;
|
||||
|
||||
/* The current round, if we're building multiple times. */
|
||||
size_t curRound = 1;
|
||||
|
||||
size_t nrRounds;
|
||||
#endif
|
||||
|
||||
/* Path registration info from the previous round, if we're
|
||||
building multiple times. Since this contains the hash, it
|
||||
|
@ -214,6 +194,7 @@ struct DerivationGoal : public Goal
|
|||
|
||||
const static Path homeDir;
|
||||
|
||||
#if 0
|
||||
std::unique_ptr<MaintainCount<uint64_t>> mcExpectedBuilds, mcRunningBuilds;
|
||||
|
||||
std::unique_ptr<Activity> act;
|
||||
|
@ -225,6 +206,7 @@ struct DerivationGoal : public Goal
|
|||
|
||||
/* The remote machine on which we're building. */
|
||||
std::string machineName;
|
||||
#endif
|
||||
|
||||
/* The recursive Nix daemon socket. */
|
||||
AutoCloseFD daemonSocket;
|
||||
|
@ -249,17 +231,14 @@ struct DerivationGoal : public Goal
|
|||
|
||||
friend struct RestrictedStore;
|
||||
|
||||
DerivationGoal(const StorePath & drvPath,
|
||||
const StringSet & wantedOutputs, Worker & worker,
|
||||
BuildMode buildMode = bmNormal);
|
||||
DerivationGoal(const StorePath & drvPath, const BasicDerivation & drv,
|
||||
const StringSet & wantedOutputs, Worker & worker,
|
||||
BuildMode buildMode = bmNormal);
|
||||
~DerivationGoal();
|
||||
using DerivationGoal::DerivationGoal;
|
||||
|
||||
virtual ~LocalDerivationGoal() override;
|
||||
|
||||
/* Whether we need to perform hash rewriting if there are valid output paths. */
|
||||
bool needsHashRewrite();
|
||||
|
||||
#if 0
|
||||
void timedOut(Error && ex) override;
|
||||
|
||||
string key() override;
|
||||
|
@ -280,13 +259,16 @@ struct DerivationGoal : public Goal
|
|||
void closureRepaired();
|
||||
void inputsRealised();
|
||||
void tryToBuild();
|
||||
void tryLocalBuild();
|
||||
#endif
|
||||
void tryLocalBuild() override;
|
||||
#if 0
|
||||
void buildDone();
|
||||
|
||||
void resolvedFinished();
|
||||
|
||||
/* Is the build hook willing to perform the build? */
|
||||
HookReply tryBuildHook();
|
||||
#endif
|
||||
|
||||
/* Start building a derivation. */
|
||||
void startBuilder();
|
||||
|
@ -311,27 +293,46 @@ struct DerivationGoal : public Goal
|
|||
/* Make a file owned by the builder. */
|
||||
void chownToBuilder(const Path & path);
|
||||
|
||||
int getChildStatus() override;
|
||||
|
||||
/* Run the builder's process. */
|
||||
void runChild();
|
||||
|
||||
/* Check that the derivation outputs all exist and register them
|
||||
as valid. */
|
||||
void registerOutputs();
|
||||
void registerOutputs() override;
|
||||
|
||||
/* Check that an output meets the requirements specified by the
|
||||
'outputChecks' attribute (or the legacy
|
||||
'{allowed,disallowed}{References,Requisites}' attributes). */
|
||||
void checkOutputs(const std::map<std::string, ValidPathInfo> & outputs);
|
||||
|
||||
#if 0
|
||||
/* Open a log file and a pipe to it. */
|
||||
Path openLogFile();
|
||||
|
||||
/* Close the log file. */
|
||||
void closeLogFile();
|
||||
#endif
|
||||
|
||||
/* Close the read side of the logger pipe. */
|
||||
void closeReadPipes() override;
|
||||
|
||||
/* Cleanup hooks for buildDone() */
|
||||
void cleanupHookFinally() override;
|
||||
void cleanupPreChildKill() override;
|
||||
void cleanupPostChildKill() override;
|
||||
bool cleanupDecideWhetherDiskFull() override;
|
||||
void cleanupPostOutputsRegisteredModeCheck() override;
|
||||
void cleanupPostOutputsRegisteredModeNonCheck() override;
|
||||
|
||||
bool isReadDesc(int fd) override;
|
||||
|
||||
|
||||
/* Delete the temporary directory, if we have one. */
|
||||
void deleteTmpDir(bool force);
|
||||
|
||||
#if 0
|
||||
/* Callback used by the worker to write to the log. */
|
||||
void handleChildOutput(int fd, const string & data) override;
|
||||
void handleEOF(int fd) override;
|
||||
|
@ -345,9 +346,10 @@ struct DerivationGoal : public Goal
|
|||
|
||||
/* Return the set of (in)valid paths. */
|
||||
void checkPathValidity();
|
||||
#endif
|
||||
|
||||
/* Forcibly kill the child process, if any. */
|
||||
void killChild();
|
||||
void killChild() override;
|
||||
|
||||
/* Create alternative path calculated from but distinct from the
|
||||
input, so we can avoid overwriting outputs (or other store paths)
|
||||
|
@ -359,6 +361,7 @@ struct DerivationGoal : public Goal
|
|||
rewrites caught everything */
|
||||
StorePath makeFallbackPath(std::string_view outputName);
|
||||
|
||||
#if 0
|
||||
void repairClosure();
|
||||
|
||||
void started();
|
||||
|
@ -368,6 +371,7 @@ struct DerivationGoal : public Goal
|
|||
std::optional<Error> ex = {});
|
||||
|
||||
StorePathSet exportReferences(const StorePathSet & storePaths);
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "machines.hh"
|
||||
#include "worker.hh"
|
||||
#include "substitution-goal.hh"
|
||||
#include "derivation-goal.hh"
|
||||
#include "local-derivation-goal.hh"
|
||||
#include "hook-instance.hh"
|
||||
|
||||
#include <poll.h>
|
||||
|
@ -59,8 +59,10 @@ std::shared_ptr<DerivationGoal> Worker::makeDerivationGoalCommon(
|
|||
std::shared_ptr<DerivationGoal> Worker::makeDerivationGoal(const StorePath & drvPath,
|
||||
const StringSet & wantedOutputs, BuildMode buildMode)
|
||||
{
|
||||
return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() {
|
||||
return std::make_shared<DerivationGoal>(drvPath, wantedOutputs, *this, buildMode);
|
||||
return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() -> std::shared_ptr<DerivationGoal> {
|
||||
return !dynamic_cast<LocalStore *>(&store)
|
||||
? std::make_shared</* */DerivationGoal>(drvPath, wantedOutputs, *this, buildMode)
|
||||
: std::make_shared<LocalDerivationGoal>(drvPath, wantedOutputs, *this, buildMode);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -68,8 +70,10 @@ std::shared_ptr<DerivationGoal> Worker::makeDerivationGoal(const StorePath & drv
|
|||
std::shared_ptr<DerivationGoal> Worker::makeBasicDerivationGoal(const StorePath & drvPath,
|
||||
const BasicDerivation & drv, const StringSet & wantedOutputs, BuildMode buildMode)
|
||||
{
|
||||
return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() {
|
||||
return std::make_shared<DerivationGoal>(drvPath, drv, wantedOutputs, *this, buildMode);
|
||||
return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() -> std::shared_ptr<DerivationGoal> {
|
||||
return !dynamic_cast<LocalStore *>(&store)
|
||||
? std::make_shared</* */DerivationGoal>(drvPath, drv, wantedOutputs, *this, buildMode)
|
||||
: std::make_shared<LocalDerivationGoal>(drvPath, drv, wantedOutputs, *this, buildMode);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -280,7 +280,7 @@ private:
|
|||
|
||||
void createUser(const std::string & userName, uid_t userId) override;
|
||||
|
||||
friend struct DerivationGoal;
|
||||
friend struct LocalDerivationGoal;
|
||||
friend struct SubstitutionGoal;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue