Skip to content

Commit

Permalink
Merge commit 'd5cef6c33a051dfc672cb1e5f4739948b167315b' into ca-drv-e…
Browse files Browse the repository at this point in the history
…xotic
  • Loading branch information
Ericson2314 committed Apr 5, 2021
2 parents cdc9f34 + d5cef6c commit 386765e
Show file tree
Hide file tree
Showing 35 changed files with 502 additions and 216 deletions.
32 changes: 4 additions & 28 deletions src/libcmd/installables.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,6 @@

namespace nix {

nlohmann::json BuildableOpaque::toJSON(ref<Store> store) const {
nlohmann::json res;
res["path"] = store->printStorePath(path);
return res;
}

nlohmann::json BuildableFromDrv::toJSON(ref<Store> store) const {
nlohmann::json res;
res["drvPath"] = store->printStorePath(drvPath);
for (const auto& [output, path] : outputs) {
res["outputs"][output] = path ? store->printStorePath(*path) : "";
}
return res;
}

nlohmann::json buildablesToJSON(const Buildables & buildables, ref<Store> store) {
auto res = nlohmann::json::array();
for (const Buildable & buildable : buildables) {
std::visit([&res, store](const auto & buildable) {
res.push_back(buildable.toJSON(store));
}, buildable);
}
return res;
}

void completeFlakeInputPath(
ref<EvalState> evalState,
const FlakeRef & flakeRef,
Expand Down Expand Up @@ -704,19 +679,20 @@ Buildables build(ref<Store> store, Realise mode,

Buildables buildables;

std::vector<StorePathWithOutputs> pathsToBuild;
std::vector<BuildableReq> pathsToBuild;

for (auto & i : installables) {
for (auto & b : i->toBuildables()) {
std::visit(overloaded {
[&](BuildableOpaque bo) {
pathsToBuild.push_back({bo.path});
pathsToBuild.push_back(bo);
},
[&](BuildableFromDrv bfd) {
StringSet outputNames;
for (auto & output : bfd.outputs)
outputNames.insert(output.first);
pathsToBuild.push_back({bfd.drvPath, outputNames});
pathsToBuild.push_back(
BuildableReqFromDrv{bfd.drvPath, outputNames});
},
}, b);
buildables.push_back(std::move(b));
Expand Down
23 changes: 2 additions & 21 deletions src/libcmd/installables.hh
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,20 @@

#include "util.hh"
#include "path.hh"
#include "path-with-outputs.hh"
#include "buildable.hh"
#include "eval.hh"
#include "flake/flake.hh"

#include <optional>

#include <nlohmann/json_fwd.hpp>

namespace nix {

struct DrvInfo;
struct SourceExprCommand;

namespace eval_cache { class EvalCache; class AttrCursor; }

struct BuildableOpaque {
StorePath path;
nlohmann::json toJSON(ref<Store> store) const;
};

struct BuildableFromDrv {
StorePath drvPath;
std::map<std::string, std::optional<StorePath>> outputs;
nlohmann::json toJSON(ref<Store> store) const;
};

typedef std::variant<
BuildableOpaque,
BuildableFromDrv
> Buildable;

typedef std::vector<Buildable> Buildables;
nlohmann::json buildablesToJSON(const Buildables & buildables, ref<Store> store);

struct App
{
std::vector<StorePathWithOutputs> context;
Expand Down
3 changes: 2 additions & 1 deletion src/libexpr/get-drvs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "util.hh"
#include "eval-inline.hh"
#include "store-api.hh"
#include "path-with-outputs.hh"

#include <cstring>
#include <regex>
Expand All @@ -19,7 +20,7 @@ DrvInfo::DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs)
DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPathWithOutputs)
: state(&state), attrs(nullptr), attrPath("")
{
auto [drvPath, selectedOutputs] = store->parsePathWithOutputs(drvPathWithOutputs);
auto [drvPath, selectedOutputs] = parsePathWithOutputs(*store, drvPathWithOutputs);

this->drvPath = store->printStorePath(drvPath);

Expand Down
12 changes: 7 additions & 5 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,32 @@ InvalidPathError::InvalidPathError(const Path & path) :

void EvalState::realiseContext(const PathSet & context)
{
std::vector<StorePathWithOutputs> drvs;
std::vector<BuildableReqFromDrv> drvs;

for (auto & i : context) {
auto [ctxS, outputName] = decodeContext(i);
auto ctx = store->parseStorePath(ctxS);
if (!store->isValidPath(ctx))
throw InvalidPathError(store->printStorePath(ctx));
if (!outputName.empty() && ctx.isDerivation()) {
drvs.push_back(StorePathWithOutputs{ctx, {outputName}});
drvs.push_back({ctx, {outputName}});
}
}

if (drvs.empty()) return;

if (!evalSettings.enableImportFromDerivation)
throw EvalError("attempted to realize '%1%' during evaluation but 'allow-import-from-derivation' is false",
store->printStorePath(drvs.begin()->path));
store->printStorePath(drvs.begin()->drvPath));

/* For performance, prefetch all substitute info. */
StorePathSet willBuild, willSubstitute, unknown;
uint64_t downloadSize, narSize;
store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize);
std::vector<BuildableReq> buildReqs;
for (auto & d : drvs) buildReqs.emplace_back(BuildableReq { d });
store->queryMissing(buildReqs, willBuild, willSubstitute, unknown, downloadSize, narSize);

store->buildPaths(drvs);
store->buildPaths(buildReqs);

/* Add the output of this derivations to the allowed
paths. */
Expand Down
2 changes: 1 addition & 1 deletion src/libmain/shared.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void printGCWarning()
}


void printMissing(ref<Store> store, const std::vector<StorePathWithOutputs> & paths, Verbosity lvl)
void printMissing(ref<Store> store, const std::vector<BuildableReq> & paths, Verbosity lvl)
{
uint64_t downloadSize, narSize;
StorePathSet willBuild, willSubstitute, unknown;
Expand Down
3 changes: 2 additions & 1 deletion src/libmain/shared.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "args.hh"
#include "common-args.hh"
#include "path.hh"
#include "buildable.hh"

#include <signal.h>

Expand Down Expand Up @@ -42,7 +43,7 @@ struct StorePathWithOutputs;

void printMissing(
ref<Store> store,
const std::vector<StorePathWithOutputs> & paths,
const std::vector<BuildableReq> & paths,
Verbosity lvl = lvlInfo);

void printMissing(ref<Store> store, const StorePathSet & willBuild,
Expand Down
4 changes: 2 additions & 2 deletions src/libstore/build/derivation-goal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ DerivationGoal::DerivationGoal(const StorePath & drvPath,
state = &DerivationGoal::getDerivation;
name = fmt(
"building of '%s' from .drv file",
StorePathWithOutputs { drvPath, wantedOutputs }.to_string(worker.store));
BuildableReqFromDrv { drvPath, wantedOutputs }.to_string(worker.store));
trace("created");

mcExpectedBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.expectedBuilds);
Expand All @@ -94,7 +94,7 @@ DerivationGoal::DerivationGoal(const StorePath & drvPath, const BasicDerivation
state = &DerivationGoal::haveDerivation;
name = fmt(
"building of '%s' from in-memory derivation",
StorePathWithOutputs { drvPath, drv.outputNames() }.to_string(worker.store));
BuildableReqFromDrv { drvPath, drv.outputNames() }.to_string(worker.store));
trace("created");

mcExpectedBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.expectedBuilds);
Expand Down
16 changes: 10 additions & 6 deletions src/libstore/build/entry-points.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@

namespace nix {

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

Goals goals;
for (auto & path : drvPaths) {
if (path.path.isDerivation())
goals.insert(worker.makeDerivationGoal(path.path, path.outputs, buildMode));
else
goals.insert(worker.makePathSubstitutionGoal(path.path, buildMode == bmRepair ? Repair : NoRepair));
for (auto & br : reqs) {
std::visit(overloaded {
[&](BuildableReqFromDrv bfd) {
goals.insert(worker.makeDerivationGoal(bfd.drvPath, bfd.outputs, buildMode));
},
[&](BuildableOpaque bo) {
goals.insert(worker.makePathSubstitutionGoal(bo.path, buildMode == bmRepair ? Repair : NoRepair));
},
}, br.raw());
}

worker.run(goals);
Expand Down
52 changes: 37 additions & 15 deletions src/libstore/build/local-derivation-goal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,26 @@ void LocalDerivationGoal::writeStructuredAttrs()
chownToBuilder(tmpDir + "/.attrs.sh");
}


static StorePath pathPartOfReq(const BuildableReq & req)
{
return std::visit(overloaded {
[&](BuildableOpaque bo) {
return bo.path;
},
[&](BuildableReqFromDrv bfd) {
return bfd.drvPath;
},
}, req.raw());
}


bool LocalDerivationGoal::isAllowed(const BuildableReq & req)
{
return this->isAllowed(pathPartOfReq(req));
}


struct RestrictedStoreConfig : virtual LocalFSStoreConfig
{
using LocalFSStoreConfig::LocalFSStoreConfig;
Expand Down Expand Up @@ -1312,25 +1332,27 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
// an allowed derivation
{ throw Error("queryRealisation"); }

void buildPaths(const std::vector<StorePathWithOutputs> & paths, BuildMode buildMode) override
void buildPaths(const std::vector<BuildableReq> & paths, BuildMode buildMode) override
{
if (buildMode != bmNormal) throw Error("unsupported build mode");

StorePathSet newPaths;

for (auto & path : paths) {
if (!goal.isAllowed(path.path))
throw InvalidPath("cannot build unknown path '%s' in recursive Nix", printStorePath(path.path));
for (auto & req : paths) {
if (!goal.isAllowed(req))
throw InvalidPath("cannot build '%s' in recursive Nix because path is unknown", req.to_string(*next));
}

next->buildPaths(paths, buildMode);

for (auto & path : paths) {
if (!path.path.isDerivation()) continue;
auto outputs = next->queryDerivationOutputMap(path.path);
for (auto & output : outputs)
if (wantOutput(output.first, path.outputs))
newPaths.insert(output.second);
auto p = std::get_if<BuildableReqFromDrv>(&path);
if (!p) continue;
auto & bfd = *p;
auto outputs = next->queryDerivationOutputMap(bfd.drvPath);
for (auto & [outputName, outputPath] : outputs)
if (wantOutput(outputName, bfd.outputs))
newPaths.insert(outputPath);
}

StorePathSet closure;
Expand Down Expand Up @@ -1358,20 +1380,20 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
void addSignatures(const StorePath & storePath, const StringSet & sigs) override
{ unsupported("addSignatures"); }

void queryMissing(const std::vector<StorePathWithOutputs> & targets,
void queryMissing(const std::vector<BuildableReq> & targets,
StorePathSet & willBuild, StorePathSet & willSubstitute, StorePathSet & unknown,
uint64_t & downloadSize, uint64_t & narSize) override
{
/* This is slightly impure since it leaks information to the
client about what paths will be built/substituted or are
already present. Probably not a big deal. */

std::vector<StorePathWithOutputs> allowed;
for (auto & path : targets) {
if (goal.isAllowed(path.path))
allowed.emplace_back(path);
std::vector<BuildableReq> allowed;
for (auto & req : targets) {
if (goal.isAllowed(req))
allowed.emplace_back(req);
else
unknown.insert(path.path);
unknown.insert(pathPartOfReq(req));
}

next->queryMissing(allowed, willBuild, willSubstitute,
Expand Down
1 change: 1 addition & 0 deletions src/libstore/build/local-derivation-goal.hh
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ struct LocalDerivationGoal : public DerivationGoal
{
return inputPaths.count(path) || addedPaths.count(path);
}
bool isAllowed(const BuildableReq & req);

friend struct RestrictedStore;

Expand Down
6 changes: 3 additions & 3 deletions src/libstore/build/worker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,14 @@ void Worker::waitForAWhile(GoalPtr goal)

void Worker::run(const Goals & _topGoals)
{
std::vector<nix::StorePathWithOutputs> topPaths;
std::vector<nix::BuildableReq> topPaths;

for (auto & i : _topGoals) {
topGoals.insert(i);
if (auto goal = dynamic_cast<DerivationGoal *>(i.get())) {
topPaths.push_back({goal->drvPath, goal->wantedOutputs});
topPaths.push_back(BuildableReqFromDrv{goal->drvPath, goal->wantedOutputs});
} else if (auto goal = dynamic_cast<PathSubstitutionGoal *>(i.get())) {
topPaths.push_back({goal->storePath});
topPaths.push_back(BuildableOpaque{goal->storePath});
}
}

Expand Down
Loading

0 comments on commit 386765e

Please sign in to comment.