2020-10-11 19:17:24 +03:00
|
|
|
#pragma once
|
2023-04-01 06:18:41 +03:00
|
|
|
///@file
|
2020-10-11 19:17:24 +03:00
|
|
|
|
|
|
|
#include "parsed-derivations.hh"
|
|
|
|
#include "lock.hh"
|
2023-01-12 01:57:18 +02:00
|
|
|
#include "outputs-spec.hh"
|
2021-02-26 17:20:33 +02:00
|
|
|
#include "store-api.hh"
|
|
|
|
#include "pathlocks.hh"
|
2020-10-12 20:15:32 +03:00
|
|
|
#include "goal.hh"
|
2009-01-12 18:30:32 +02:00
|
|
|
|
2006-09-05 00:06:23 +03:00
|
|
|
namespace nix {
|
|
|
|
|
|
|
|
using std::map;
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2014-01-21 19:29:55 +02:00
|
|
|
struct HookInstance;
|
2004-06-18 21:09:32 +03:00
|
|
|
|
2010-08-25 23:44:28 +03:00
|
|
|
typedef enum {rpAccept, rpDecline, rpPostpone} HookReply;
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Unless we are repairing, we don't both to test validity and just assume it,
|
|
|
|
* so the choices are `Absent` or `Valid`.
|
|
|
|
*/
|
2020-09-15 18:19:45 +03:00
|
|
|
enum struct PathStatus {
|
|
|
|
Corrupt,
|
|
|
|
Absent,
|
|
|
|
Valid,
|
|
|
|
};
|
|
|
|
|
2020-09-04 18:15:51 +03:00
|
|
|
struct InitialOutputStatus {
|
2020-08-07 22:09:26 +03:00
|
|
|
StorePath path;
|
2020-09-15 18:19:45 +03:00
|
|
|
PathStatus status;
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Valid in the store, and additionally non-corrupt if we are repairing
|
|
|
|
*/
|
2020-08-07 22:09:26 +03:00
|
|
|
bool isValid() const {
|
2020-09-15 18:19:45 +03:00
|
|
|
return status == PathStatus::Valid;
|
|
|
|
}
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Merely present, allowed to be corrupt
|
|
|
|
*/
|
2020-09-15 18:19:45 +03:00
|
|
|
bool isPresent() const {
|
|
|
|
return status == PathStatus::Corrupt
|
|
|
|
|| status == PathStatus::Valid;
|
2020-08-07 22:09:26 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-09-04 18:15:51 +03:00
|
|
|
struct InitialOutput {
|
2020-08-07 22:09:26 +03:00
|
|
|
bool wanted;
|
2021-02-04 15:41:49 +02:00
|
|
|
Hash outputHash;
|
2020-09-04 18:15:51 +03:00
|
|
|
std::optional<InitialOutputStatus> known;
|
2020-08-07 22:09:26 +03:00
|
|
|
};
|
|
|
|
|
2020-11-18 15:36:15 +02:00
|
|
|
struct DerivationGoal : public Goal
|
2004-05-11 21:05:44 +03:00
|
|
|
{
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Whether to use an on-disk .drv file.
|
|
|
|
*/
|
Allow remote builds without sending the derivation closure
Previously, to build a derivation remotely, we had to copy the entire
closure of the .drv file to the remote machine, even though we only
need the top-level derivation. This is very wasteful: the closure can
contain thousands of store paths, and in some Hydra use cases, include
source paths that are very large (e.g. Git/Mercurial checkouts).
So now there is a new operation, StoreAPI::buildDerivation(), that
performs a build from an in-memory representation of a derivation
(BasicDerivation) rather than from a on-disk .drv file. The only files
that need to be in the Nix store are the sources of the derivation
(drv.inputSrcs), and the needed output paths of the dependencies (as
described by drv.inputDrvs). "nix-store --serve" exposes this
interface.
Note that this is a privileged operation, because you can construct a
derivation that builds any store path whatsoever. Fixing this will
require changing the hashing scheme (i.e., the output paths should be
computed from the other fields in BasicDerivation, allowing them to be
verified without access to other derivations). However, this would be
quite nice because it would allow .drv-free building (e.g. "nix-env
-i" wouldn't have to write any .drv files to disk).
Fixes #173.
2015-07-17 18:57:40 +03:00
|
|
|
bool useDerivation;
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/** The path of the derivation. */
|
2019-12-05 20:11:09 +02:00
|
|
|
StorePath drvPath;
|
2004-05-11 21:05:44 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* The goal for the corresponding resolved derivation
|
|
|
|
*/
|
2021-12-13 17:56:44 +02:00
|
|
|
std::shared_ptr<DerivationGoal> resolvedDrvGoal;
|
2021-01-27 11:03:05 +02:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* The specific outputs that we need to build. Empty means all of
|
|
|
|
* them.
|
|
|
|
*/
|
2023-01-12 01:57:18 +02:00
|
|
|
OutputsSpec wantedOutputs;
|
2012-11-26 18:15:09 +02:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Mapping from input derivations + output names to actual store
|
|
|
|
* paths. This is filled in by waiteeDone() as each dependency
|
|
|
|
* finishes, before inputsRealised() is reached.
|
|
|
|
*/
|
2022-03-30 17:31:01 +03:00
|
|
|
std::map<std::pair<StorePath, std::string>, StorePath> inputDrvOutputs;
|
|
|
|
|
2023-02-14 20:25:55 +02:00
|
|
|
/**
|
|
|
|
* See `needRestart`; just for that field.
|
|
|
|
*/
|
|
|
|
enum struct NeedRestartForMoreOutputs {
|
|
|
|
/**
|
|
|
|
* The goal state machine is progressing based on the current value of
|
|
|
|
* `wantedOutputs. No actions are needed.
|
|
|
|
*/
|
|
|
|
OutputsUnmodifedDontNeed,
|
|
|
|
/**
|
|
|
|
* `wantedOutputs` has been extended, but the state machine is
|
|
|
|
* proceeding according to its old value, so we need to restart.
|
|
|
|
*/
|
|
|
|
OutputsAddedDoNeed,
|
|
|
|
/**
|
|
|
|
* The goal state machine has progressed to the point of doing a build,
|
|
|
|
* in which case all outputs will be produced, so extensions to
|
|
|
|
* `wantedOutputs` no longer require a restart.
|
|
|
|
*/
|
|
|
|
BuildInProgressWillNotNeed,
|
|
|
|
};
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Whether additional wanted outputs have been added.
|
|
|
|
*/
|
2023-02-14 20:25:55 +02:00
|
|
|
NeedRestartForMoreOutputs needRestart = NeedRestartForMoreOutputs::OutputsUnmodifedDontNeed;
|
2012-11-26 18:15:09 +02:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
2023-02-14 20:25:55 +02:00
|
|
|
* See `retrySubstitution`; just for that field.
|
2023-04-07 16:55:28 +03:00
|
|
|
*/
|
2023-02-14 20:25:55 +02:00
|
|
|
enum RetrySubstitution {
|
|
|
|
/**
|
|
|
|
* No issues have yet arose, no need to restart.
|
|
|
|
*/
|
|
|
|
NoNeed,
|
|
|
|
/**
|
|
|
|
* Something failed and there is an incomplete closure. Let's retry
|
|
|
|
* substituting.
|
|
|
|
*/
|
|
|
|
YesNeed,
|
|
|
|
/**
|
|
|
|
* We are current or have already retried substitution, and whether or
|
|
|
|
* not something goes wrong we will not retry again.
|
|
|
|
*/
|
|
|
|
AlreadyRetried,
|
|
|
|
};
|
2022-03-25 00:25:12 +02:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
2023-02-14 20:25:55 +02:00
|
|
|
* Whether to retry substituting the outputs after building the
|
|
|
|
* inputs. This is done in case of an incomplete closure.
|
2023-04-07 16:55:28 +03:00
|
|
|
*/
|
2023-02-14 20:25:55 +02:00
|
|
|
RetrySubstitution retrySubstitution = RetrySubstitution::NoNeed;
|
2013-01-02 13:38:28 +02:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* The derivation stored at drvPath.
|
|
|
|
*/
|
2021-02-23 15:12:11 +02:00
|
|
|
std::unique_ptr<Derivation> drv;
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2018-09-28 15:31:16 +03:00
|
|
|
std::unique_ptr<ParsedDerivation> parsedDrv;
|
2018-09-28 13:43:01 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* The remainder is state held during the build.
|
|
|
|
*/
|
2004-05-11 21:05:44 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Locks on (fixed) output paths.
|
|
|
|
*/
|
2004-05-11 21:05:44 +03:00
|
|
|
PathLocks outputLocks;
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* All input paths (that is, the union of FS closures of the
|
|
|
|
* immediate input paths).
|
|
|
|
*/
|
2019-12-05 20:11:09 +02:00
|
|
|
StorePathSet inputPaths;
|
2004-05-11 21:05:44 +03:00
|
|
|
|
2020-09-04 18:15:51 +03:00
|
|
|
std::map<std::string, InitialOutput> initialOutputs;
|
2013-06-13 17:43:20 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* File descriptor for the log file.
|
|
|
|
*/
|
2012-07-17 16:40:12 +03:00
|
|
|
AutoCloseFD fdLogFile;
|
2016-05-04 16:46:25 +03:00
|
|
|
std::shared_ptr<BufferedSink> logFileSink, logSink;
|
2004-05-11 21:05:44 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Number of bytes received from the builder's stdout/stderr.
|
|
|
|
*/
|
2013-09-02 12:58:18 +03:00
|
|
|
unsigned long logSize;
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* The most recent log lines.
|
|
|
|
*/
|
2016-04-25 17:47:46 +03:00
|
|
|
std::list<std::string> logTail;
|
|
|
|
|
|
|
|
std::string currentLogLine;
|
2016-04-28 15:27:00 +03:00
|
|
|
size_t currentLogLinePos = 0; // to handle carriage return
|
2016-04-25 17:47:46 +03:00
|
|
|
|
2017-10-24 14:41:52 +03:00
|
|
|
std::string currentHookLine;
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* The build hook.
|
|
|
|
*/
|
2017-01-19 16:15:09 +02:00
|
|
|
std::unique_ptr<HookInstance> hook;
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* The sort of derivation we are building.
|
|
|
|
*/
|
2023-08-16 19:29:23 +03:00
|
|
|
std::optional<DerivationType> derivationType;
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2005-01-19 13:16:11 +02:00
|
|
|
typedef void (DerivationGoal::*GoalState)();
|
2004-06-18 21:09:32 +03:00
|
|
|
GoalState state;
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2014-02-18 00:04:52 +02:00
|
|
|
BuildMode buildMode;
|
|
|
|
|
2017-08-15 16:31:59 +03:00
|
|
|
std::unique_ptr<MaintainCount<uint64_t>> mcExpectedBuilds, mcRunningBuilds;
|
|
|
|
|
|
|
|
std::unique_ptr<Activity> act;
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Activity that denotes waiting for a lock.
|
|
|
|
*/
|
2020-06-15 17:03:29 +03:00
|
|
|
std::unique_ptr<Activity> actLock;
|
|
|
|
|
2017-08-21 13:01:21 +03:00
|
|
|
std::map<ActivityId, Activity> builderActivities;
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* The remote machine on which we're building.
|
|
|
|
*/
|
2017-10-24 15:24:57 +03:00
|
|
|
std::string machineName;
|
|
|
|
|
2020-08-22 23:44:47 +03:00
|
|
|
DerivationGoal(const StorePath & drvPath,
|
2023-01-12 01:57:18 +02:00
|
|
|
const OutputsSpec & wantedOutputs, Worker & worker,
|
2020-08-22 23:44:47 +03:00
|
|
|
BuildMode buildMode = bmNormal);
|
2020-06-16 23:20:18 +03:00
|
|
|
DerivationGoal(const StorePath & drvPath, const BasicDerivation & drv,
|
2023-01-12 01:57:18 +02:00
|
|
|
const OutputsSpec & wantedOutputs, Worker & worker,
|
2020-08-22 23:44:47 +03:00
|
|
|
BuildMode buildMode = bmNormal);
|
2021-02-26 17:20:33 +02:00
|
|
|
virtual ~DerivationGoal();
|
2019-05-12 23:47:41 +03:00
|
|
|
|
2020-06-15 20:25:35 +03:00
|
|
|
void timedOut(Error && ex) override;
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
std::string key() override;
|
2014-11-24 17:48:04 +02:00
|
|
|
|
2015-09-18 02:22:06 +03:00
|
|
|
void work() override;
|
2004-06-20 00:45:04 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Add wanted outputs to an already existing derivation goal.
|
|
|
|
*/
|
2023-01-12 01:57:18 +02:00
|
|
|
void addWantedOutputs(const OutputsSpec & outputs);
|
2012-11-26 18:15:09 +02:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* The states.
|
|
|
|
*/
|
Allow remote builds without sending the derivation closure
Previously, to build a derivation remotely, we had to copy the entire
closure of the .drv file to the remote machine, even though we only
need the top-level derivation. This is very wasteful: the closure can
contain thousands of store paths, and in some Hydra use cases, include
source paths that are very large (e.g. Git/Mercurial checkouts).
So now there is a new operation, StoreAPI::buildDerivation(), that
performs a build from an in-memory representation of a derivation
(BasicDerivation) rather than from a on-disk .drv file. The only files
that need to be in the Nix store are the sources of the derivation
(drv.inputSrcs), and the needed output paths of the dependencies (as
described by drv.inputDrvs). "nix-store --serve" exposes this
interface.
Note that this is a privileged operation, because you can construct a
derivation that builds any store path whatsoever. Fixing this will
require changing the hashing scheme (i.e., the output paths should be
computed from the other fields in BasicDerivation, allowing them to be
verified without access to other derivations). However, this would be
quite nice because it would allow .drv-free building (e.g. "nix-env
-i" wouldn't have to write any .drv files to disk).
Fixes #173.
2015-07-17 18:57:40 +03:00
|
|
|
void getDerivation();
|
|
|
|
void loadDerivation();
|
2006-12-08 01:58:36 +02:00
|
|
|
void haveDerivation();
|
2020-08-07 22:09:26 +03:00
|
|
|
void outputsSubstitutionTried();
|
|
|
|
void gaveUpOnSubstitution();
|
2012-10-03 17:38:09 +03:00
|
|
|
void closureRepaired();
|
2005-01-19 13:16:11 +02:00
|
|
|
void inputsRealised();
|
2004-06-18 21:09:32 +03:00
|
|
|
void tryToBuild();
|
2021-02-26 17:20:33 +02:00
|
|
|
virtual void tryLocalBuild();
|
2004-06-18 21:09:32 +03:00
|
|
|
void buildDone();
|
|
|
|
|
2020-08-22 23:44:47 +03:00
|
|
|
void resolvedFinished();
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Is the build hook willing to perform the build?
|
|
|
|
*/
|
2004-06-20 00:45:04 +03:00
|
|
|
HookReply tryBuildHook();
|
|
|
|
|
2021-02-26 17:20:33 +02:00
|
|
|
virtual int getChildStatus();
|
2012-06-25 22:45:16 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Check that the derivation outputs all exist and register them
|
|
|
|
* as valid.
|
|
|
|
*/
|
2023-04-15 01:18:32 +03:00
|
|
|
virtual SingleDrvOutputs registerOutputs();
|
2018-10-22 22:49:56 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Open a log file and a pipe to it.
|
|
|
|
*/
|
2008-11-12 13:08:27 +02:00
|
|
|
Path openLogFile();
|
2004-06-18 21:09:32 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Sign the newly built realisation if the store allows it
|
|
|
|
*/
|
2021-03-08 18:32:20 +02:00
|
|
|
virtual void signRealisation(Realisation&) {}
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Close the log file.
|
|
|
|
*/
|
2012-05-30 17:12:29 +03:00
|
|
|
void closeLogFile();
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Close the read side of the logger pipe.
|
|
|
|
*/
|
2021-02-26 17:20:33 +02:00
|
|
|
virtual void closeReadPipes();
|
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Cleanup hooks for buildDone()
|
|
|
|
*/
|
2021-02-26 17:20:33 +02:00
|
|
|
virtual void cleanupHookFinally();
|
|
|
|
virtual void cleanupPreChildKill();
|
|
|
|
virtual void cleanupPostChildKill();
|
|
|
|
virtual bool cleanupDecideWhetherDiskFull();
|
|
|
|
virtual void cleanupPostOutputsRegisteredModeCheck();
|
|
|
|
virtual void cleanupPostOutputsRegisteredModeNonCheck();
|
|
|
|
|
|
|
|
virtual bool isReadDesc(int fd);
|
2004-06-18 21:09:32 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Callback used by the worker to write to the log.
|
|
|
|
*/
|
2022-02-25 17:00:00 +02:00
|
|
|
void handleChildOutput(int fd, std::string_view data) override;
|
2015-09-18 02:22:06 +03:00
|
|
|
void handleEOF(int fd) override;
|
2016-04-25 17:47:46 +03:00
|
|
|
void flushLine();
|
2004-06-29 12:41:50 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Wrappers around the corresponding Store methods that first consult the
|
|
|
|
* derivation. This is currently needed because when there is no drv file
|
|
|
|
* there also is no DB entry.
|
|
|
|
*/
|
2020-08-20 21:14:12 +03:00
|
|
|
std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap();
|
|
|
|
OutputPathMap queryDerivationOutputMap();
|
2020-08-07 22:09:26 +03:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Update 'initialOutputs' to determine the current status of the
|
|
|
|
* outputs of the derivation. Also returns a Boolean denoting
|
|
|
|
* whether all outputs are valid and non-corrupt, and a
|
2023-01-31 13:51:12 +02:00
|
|
|
* 'SingleDrvOutputs' structure containing the valid outputs.
|
2023-04-07 16:55:28 +03:00
|
|
|
*/
|
2023-04-15 01:18:32 +03:00
|
|
|
std::pair<bool, SingleDrvOutputs> checkPathValidity();
|
2022-03-08 20:50:46 +02:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Aborts if any output is not valid or corrupt, and otherwise
|
2023-01-31 13:51:12 +02:00
|
|
|
* returns a 'SingleDrvOutputs' structure containing all outputs.
|
2023-04-07 16:55:28 +03:00
|
|
|
*/
|
2023-04-15 01:18:32 +03:00
|
|
|
SingleDrvOutputs assertPathValidity();
|
2009-03-25 23:05:42 +02:00
|
|
|
|
2023-04-07 16:55:28 +03:00
|
|
|
/**
|
|
|
|
* Forcibly kill the child process, if any.
|
|
|
|
*/
|
2021-02-26 17:20:33 +02:00
|
|
|
virtual void killChild();
|
2012-10-03 17:38:09 +03:00
|
|
|
|
|
|
|
void repairClosure();
|
2015-07-20 04:15:45 +03:00
|
|
|
|
2020-05-14 17:00:54 +03:00
|
|
|
void started();
|
|
|
|
|
2020-06-15 20:25:35 +03:00
|
|
|
void done(
|
|
|
|
BuildResult::Status status,
|
2023-04-15 01:18:32 +03:00
|
|
|
SingleDrvOutputs builtOutputs = {},
|
2020-06-15 20:25:35 +03:00
|
|
|
std::optional<Error> ex = {});
|
2018-04-17 13:03:27 +03:00
|
|
|
|
2022-03-30 17:31:01 +03:00
|
|
|
void waiteeDone(GoalPtr waitee, ExitCode result) override;
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
StorePathSet exportReferences(const StorePathSet & storePaths);
|
2023-05-08 21:45:46 +03:00
|
|
|
|
|
|
|
JobCategory jobCategory() override { return JobCategory::Build; };
|
2004-05-11 21:05:44 +03:00
|
|
|
};
|
|
|
|
|
2021-02-26 17:20:33 +02:00
|
|
|
MakeError(NotDeterministic, BuildError);
|
|
|
|
|
2006-09-05 00:06:23 +03:00
|
|
|
}
|