Skip to content

Commit

Permalink
Merge branches 'build-1', 'build-2', 'build-3', 'build-4', 'build-5',…
Browse files Browse the repository at this point in the history
… 'build-6', 'build-7' and 'build-8' into split_build_cc
  • Loading branch information
Ericson2314 committed Oct 11, 2020
9 parents a4f0fec + 3bab1c5 + 819fe84 + 159054f + 4bdff7d + d24ffe0 + eed53ed + dbc5886 + bcb67e1 commit 8cc510f
Show file tree
Hide file tree
Showing 8 changed files with 4,882 additions and 0 deletions.
3,724 changes: 3,724 additions & 0 deletions src/libstore/build/derivation-goal.cc

Large diffs are not rendered by default.

88 changes: 88 additions & 0 deletions src/libstore/build/goal.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include "build.hh"

namespace nix {


bool CompareGoalPtrs::operator() (const GoalPtr & a, const GoalPtr & b) const {
string s1 = a->key();
string s2 = b->key();
return s1 < s2;
}


void addToWeakGoals(WeakGoals & goals, GoalPtr p)
{
// FIXME: necessary?
// FIXME: O(n)
for (auto & i : goals)
if (i.lock() == p) return;
goals.push_back(p);
}


void Goal::addWaitee(GoalPtr waitee)
{
waitees.insert(waitee);
addToWeakGoals(waitee->waiters, shared_from_this());
}


void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
{
assert(waitees.find(waitee) != waitees.end());
waitees.erase(waitee);

trace(fmt("waitee '%s' done; %d left", waitee->name, waitees.size()));

if (result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure) ++nrFailed;

if (result == ecNoSubstituters) ++nrNoSubstituters;

if (result == ecIncompleteClosure) ++nrIncompleteClosure;

if (waitees.empty() || (result == ecFailed && !settings.keepGoing)) {

/* If we failed and keepGoing is not set, we remove all
remaining waitees. */
for (auto & goal : waitees) {
WeakGoals waiters2;
for (auto & j : goal->waiters)
if (j.lock() != shared_from_this()) waiters2.push_back(j);
goal->waiters = waiters2;
}
waitees.clear();

worker.wakeUp(shared_from_this());
}
}


void Goal::amDone(ExitCode result, std::optional<Error> ex)
{
trace("done");
assert(exitCode == ecBusy);
assert(result == ecSuccess || result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure);
exitCode = result;

if (ex) {
if (!waiters.empty())
logError(ex->info());
else
this->ex = std::move(*ex);
}

for (auto & i : waiters) {
GoalPtr goal = i.lock();
if (goal) goal->waiteeDone(shared_from_this(), result);
}
waiters.clear();
worker.removeGoal(shared_from_this());
}


void Goal::trace(const FormatOrString & fs)
{
debug("%1%: %2%", name, fs.s);
}

}
71 changes: 71 additions & 0 deletions src/libstore/build/hook-instance.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include "build.hh"

namespace nix {

HookInstance::HookInstance()
{
debug("starting build hook '%s'", settings.buildHook);

/* Create a pipe to get the output of the child. */
fromHook.create();

/* Create the communication pipes. */
toHook.create();

/* Create a pipe to get the output of the builder. */
builderOut.create();

/* Fork the hook. */
pid = startProcess([&]() {

commonChildInit(fromHook);

if (chdir("/") == -1) throw SysError("changing into /");

/* Dup the communication pipes. */
if (dup2(toHook.readSide.get(), STDIN_FILENO) == -1)
throw SysError("dupping to-hook read side");

/* Use fd 4 for the builder's stdout/stderr. */
if (dup2(builderOut.writeSide.get(), 4) == -1)
throw SysError("dupping builder's stdout/stderr");

/* Hack: pass the read side of that fd to allow build-remote
to read SSH error messages. */
if (dup2(builderOut.readSide.get(), 5) == -1)
throw SysError("dupping builder's stdout/stderr");

Strings args = {
std::string(baseNameOf(settings.buildHook.get())),
std::to_string(verbosity),
};

execv(settings.buildHook.get().c_str(), stringsToCharPtrs(args).data());

throw SysError("executing '%s'", settings.buildHook);
});

pid.setSeparatePG(true);
fromHook.writeSide = -1;
toHook.readSide = -1;

sink = FdSink(toHook.writeSide.get());
std::map<std::string, Config::SettingInfo> settings;
globalConfig.getSettings(settings);
for (auto & setting : settings)
sink << 1 << setting.first << setting.second.value;
sink << 0;
}


HookInstance::~HookInstance()
{
try {
toHook.writeSide = -1;
if (pid != -1) pid.kill();
} catch (...) {
ignoreException();
}
}

}
123 changes: 123 additions & 0 deletions src/libstore/build/local-store-build.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include "build.hh"

namespace nix {

static void primeCache(Store & store, const std::vector<StorePathWithOutputs> & paths)
{
StorePathSet willBuild, willSubstitute, unknown;
uint64_t downloadSize, narSize;
store.queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);

if (!willBuild.empty() && 0 == settings.maxBuildJobs && getMachines().empty())
throw Error(
"%d derivations need to be built, but neither local builds ('--max-jobs') "
"nor remote builds ('--builders') are enabled", willBuild.size());
}


void LocalStore::buildPaths(const std::vector<StorePathWithOutputs> & drvPaths, BuildMode buildMode)
{
Worker worker(*this);

primeCache(*this, drvPaths);

Goals goals;
for (auto & path : drvPaths) {
if (path.path.isDerivation())
goals.insert(worker.makeDerivationGoal(path.path, path.outputs, buildMode));
else
goals.insert(worker.makeSubstitutionGoal(path.path, buildMode == bmRepair ? Repair : NoRepair));
}

worker.run(goals);

StorePathSet failed;
std::optional<Error> ex;
for (auto & i : goals) {
if (i->ex) {
if (ex)
logError(i->ex->info());
else
ex = i->ex;
}
if (i->exitCode != Goal::ecSuccess) {
DerivationGoal * i2 = dynamic_cast<DerivationGoal *>(i.get());
if (i2) failed.insert(i2->getDrvPath());
else failed.insert(dynamic_cast<SubstitutionGoal *>(i.get())->getStorePath());
}
}

if (failed.size() == 1 && ex) {
ex->status = worker.exitStatus();
throw *ex;
} else if (!failed.empty()) {
if (ex) logError(ex->info());
throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed));
}
}

BuildResult LocalStore::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode)
{
Worker worker(*this);
auto goal = worker.makeBasicDerivationGoal(drvPath, drv, {}, buildMode);

BuildResult result;

try {
worker.run(Goals{goal});
result = goal->getResult();
} catch (Error & e) {
result.status = BuildResult::MiscFailure;
result.errorMsg = e.msg();
}

return result;
}


void LocalStore::ensurePath(const StorePath & path)
{
/* If the path is already valid, we're done. */
if (isValidPath(path)) return;

primeCache(*this, {{path}});

Worker worker(*this);
GoalPtr goal = worker.makeSubstitutionGoal(path);
Goals goals = {goal};

worker.run(goals);

if (goal->exitCode != Goal::ecSuccess) {
if (goal->ex) {
goal->ex->status = worker.exitStatus();
throw *goal->ex;
} else
throw Error(worker.exitStatus(), "path '%s' does not exist and cannot be created", printStorePath(path));
}
}


void LocalStore::repairPath(const StorePath & path)
{
Worker worker(*this);
GoalPtr goal = worker.makeSubstitutionGoal(path, Repair);
Goals goals = {goal};

worker.run(goals);

if (goal->exitCode != Goal::ecSuccess) {
/* Since substituting the path didn't work, if we have a valid
deriver, then rebuild the deriver. */
auto info = queryPathInfo(path);
if (info->deriver && isValidPath(*info->deriver)) {
goals.clear();
goals.insert(worker.makeDerivationGoal(*info->deriver, StringSet(), bmRepair));
worker.run(goals);
} else
throw Error(worker.exitStatus(), "cannot repair path '%s'", printStorePath(path));
}
}

}
Loading

0 comments on commit 8cc510f

Please sign in to comment.