1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2024-09-20 11:11:03 -04:00

Merge branch 'drv-outputs-map-allow-missing' of github.com:obsidiansystems/nix into templated-daemon-protocol

This commit is contained in:
John Ericson 2020-08-07 18:51:01 +00:00
commit 8f92bb5ad9
16 changed files with 228 additions and 133 deletions

View file

@ -103,7 +103,7 @@ static int _main(int argc, char * * argv)
drvPath = store->parseStorePath(readString(source)); drvPath = store->parseStorePath(readString(source));
auto requiredFeatures = readStrings<std::set<std::string>>(source); auto requiredFeatures = readStrings<std::set<std::string>>(source);
auto canBuildLocally = amWilling auto canBuildLocally = amWilling
&& ( neededSystem == settings.thisSystem && ( neededSystem == settings.thisSystem
|| settings.extraPlatforms.get().count(neededSystem) > 0) || settings.extraPlatforms.get().count(neededSystem) > 0)
&& allSupportedLocally(requiredFeatures); && allSupportedLocally(requiredFeatures);
@ -170,7 +170,45 @@ static int _main(int argc, char * * argv)
if (rightType && !canBuildLocally) if (rightType && !canBuildLocally)
std::cerr << "# postpone\n"; std::cerr << "# postpone\n";
else else
{
// build the hint template.
string hintstring = "derivation: %s\nrequired (system, features): (%s, %s)";
hintstring += "\n%s available machines:";
hintstring += "\n(systems, maxjobs, supportedFeatures, mandatoryFeatures)";
for (unsigned int i = 0; i < machines.size(); ++i) {
hintstring += "\n(%s, %s, %s, %s)";
}
// add the template values.
string drvstr;
if (drvPath.has_value())
drvstr = drvPath->to_string();
else
drvstr = "<unknown>";
auto hint = hintformat(hintstring);
hint
% drvstr
% neededSystem
% concatStringsSep<StringSet>(", ", requiredFeatures)
% machines.size();
for (auto & m : machines) {
hint % concatStringsSep<vector<string>>(", ", m.systemTypes)
% m.maxJobs
% concatStringsSep<StringSet>(", ", m.supportedFeatures)
% concatStringsSep<StringSet>(", ", m.mandatoryFeatures);
}
logError({
.name = "Remote build",
.description = "Failed to find a machine for remote build!",
.hint = hint
});
std::cerr << "# decline\n"; std::cerr << "# decline\n";
}
break; break;
} }

View file

@ -405,7 +405,7 @@ Value & AttrCursor::forceValue()
return v; return v;
} }
std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name) std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErrors)
{ {
if (root->db) { if (root->db) {
if (!cachedValue) if (!cachedValue)
@ -422,9 +422,12 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name)
if (attr) { if (attr) {
if (std::get_if<missing_t>(&attr->second)) if (std::get_if<missing_t>(&attr->second))
return nullptr; return nullptr;
else if (std::get_if<failed_t>(&attr->second)) else if (std::get_if<failed_t>(&attr->second)) {
throw EvalError("cached failure of attribute '%s'", getAttrPathStr(name)); if (forceErrors)
else debug("reevaluating failed cached attribute '%s'");
else
throw CachedEvalError("cached failure of attribute '%s'", getAttrPathStr(name));
} else
return std::make_shared<AttrCursor>(root, return std::make_shared<AttrCursor>(root,
std::make_pair(shared_from_this(), name), nullptr, std::move(attr)); std::make_pair(shared_from_this(), name), nullptr, std::move(attr));
} }
@ -469,9 +472,9 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(std::string_view name)
return maybeGetAttr(root->state.symbols.create(name)); return maybeGetAttr(root->state.symbols.create(name));
} }
std::shared_ptr<AttrCursor> AttrCursor::getAttr(Symbol name) std::shared_ptr<AttrCursor> AttrCursor::getAttr(Symbol name, bool forceErrors)
{ {
auto p = maybeGetAttr(name); auto p = maybeGetAttr(name, forceErrors);
if (!p) if (!p)
throw Error("attribute '%s' does not exist", getAttrPathStr(name)); throw Error("attribute '%s' does not exist", getAttrPathStr(name));
return p; return p;
@ -600,7 +603,7 @@ bool AttrCursor::isDerivation()
StorePath AttrCursor::forceDerivation() StorePath AttrCursor::forceDerivation()
{ {
auto aDrvPath = getAttr(root->state.sDrvPath); auto aDrvPath = getAttr(root->state.sDrvPath, true);
auto drvPath = root->state.store->parseStorePath(aDrvPath->getString()); auto drvPath = root->state.store->parseStorePath(aDrvPath->getString());
if (!root->state.store->isValidPath(drvPath) && !settings.readOnlyMode) { if (!root->state.store->isValidPath(drvPath) && !settings.readOnlyMode) {
/* The eval cache contains 'drvPath', but the actual path has /* The eval cache contains 'drvPath', but the actual path has

View file

@ -9,6 +9,8 @@
namespace nix::eval_cache { namespace nix::eval_cache {
MakeError(CachedEvalError, EvalError);
class AttrDb; class AttrDb;
class AttrCursor; class AttrCursor;
@ -92,11 +94,11 @@ public:
std::string getAttrPathStr(Symbol name) const; std::string getAttrPathStr(Symbol name) const;
std::shared_ptr<AttrCursor> maybeGetAttr(Symbol name); std::shared_ptr<AttrCursor> maybeGetAttr(Symbol name, bool forceErrors = false);
std::shared_ptr<AttrCursor> maybeGetAttr(std::string_view name); std::shared_ptr<AttrCursor> maybeGetAttr(std::string_view name);
std::shared_ptr<AttrCursor> getAttr(Symbol name); std::shared_ptr<AttrCursor> getAttr(Symbol name, bool forceErrors = false);
std::shared_ptr<AttrCursor> getAttr(std::string_view name); std::shared_ptr<AttrCursor> getAttr(std::string_view name);

View file

@ -375,6 +375,9 @@ struct EvalSettings : Config
Setting<bool> traceFunctionCalls{this, false, "trace-function-calls", Setting<bool> traceFunctionCalls{this, false, "trace-function-calls",
"Emit log messages for each function entry and exit at the 'vomit' log level (-vvvv)."}; "Emit log messages for each function entry and exit at the 'vomit' log level (-vvvv)."};
Setting<bool> useEvalCache{this, true, "eval-cache",
"Whether to use the flake evaluation cache."};
}; };
extern EvalSettings evalSettings; extern EvalSettings evalSettings;

View file

@ -4880,8 +4880,17 @@ void Worker::run(const Goals & _topGoals)
waitForInput(); waitForInput();
else { else {
if (awake.empty() && 0 == settings.maxBuildJobs) if (awake.empty() && 0 == settings.maxBuildJobs)
throw Error("unable to start any build; either increase '--max-jobs' " {
"or enable remote builds"); if (getMachines().empty())
throw Error("unable to start any build; either increase '--max-jobs' "
"or enable remote builds."
"\nhttps://nixos.org/nix/manual/#chap-distributed-builds");
else
throw Error("unable to start any build; remote machines may not have "
"all required system features."
"\nhttps://nixos.org/nix/manual/#chap-distributed-builds");
}
assert(!awake.empty()); assert(!awake.empty());
} }
} }

View file

@ -32,6 +32,7 @@ void WorkerProto<std::string>::write(const Store & store, Sink & out, const std:
out << str; out << str;
} }
StorePath WorkerProto<StorePath>::read(const Store & store, Source & from) StorePath WorkerProto<StorePath>::read(const Store & store, Source & from)
{ {
return store.parseStorePath(readString(from)); return store.parseStorePath(readString(from));
@ -42,6 +43,7 @@ void WorkerProto<StorePath>::write(const Store & store, Sink & out, const StoreP
out << store.printStorePath(storePath); out << store.printStorePath(storePath);
} }
ContentAddress WorkerProto<ContentAddress>::read(const Store & store, Source & from) ContentAddress WorkerProto<ContentAddress>::read(const Store & store, Source & from)
{ {
return parseContentAddress(readString(from)); return parseContentAddress(readString(from));
@ -53,6 +55,29 @@ void WorkerProto<ContentAddress>::write(const Store & store, Sink & out, const C
} }
std::optional<StorePath> WorkerProto<std::optional<StorePath>>::read(const Store & store, Source & from)
{
auto s = readString(from);
return s == "" ? std::optional<StorePath> {} : store.parseStorePath(s);
}
void WorkerProto<std::optional<StorePath>>::write(const Store & store, Sink & out, const std::optional<StorePath> & storePathOpt)
{
out << (storePathOpt ? store.printStorePath(*storePathOpt) : "");
}
std::optional<ContentAddress> WorkerProto<std::optional<ContentAddress>>::read(const Store & store, Source & from)
{
return parseContentAddressOpt(readString(from));
}
void WorkerProto<std::optional<ContentAddress>>::write(const Store & store, Sink & out, const std::optional<ContentAddress> & caOpt)
{
out << (caOpt ? renderContentAddress(*caOpt) : "");
}
/* TODO: Separate these store impls into different files, give them better names */ /* TODO: Separate these store impls into different files, give them better names */
RemoteStore::RemoteStore(const Params & params) RemoteStore::RemoteStore(const Params & params)
: Store(params) : Store(params)

View file

@ -72,23 +72,16 @@ struct WorkerProto {
static void write(const Store & store, Sink & out, const T & t); static void write(const Store & store, Sink & out, const T & t);
}; };
template<> #define MAKE_WORKER_PROTO(T) \
struct WorkerProto<std::string> { template<> \
static std::string read(const Store & store, Source & from); struct WorkerProto< T > { \
static void write(const Store & store, Sink & out, const std::string & t); static T read(const Store & store, Source & from); \
}; static void write(const Store & store, Sink & out, const T & t); \
}
template<> MAKE_WORKER_PROTO(std::string);
struct WorkerProto<StorePath> { MAKE_WORKER_PROTO(StorePath);
static StorePath read(const Store & store, Source & from); MAKE_WORKER_PROTO(ContentAddress);
static void write(const Store & store, Sink & out, const StorePath & t);
};
template<>
struct WorkerProto<ContentAddress> {
static ContentAddress read(const Store & store, Source & from);
static void write(const Store & store, Sink & out, const ContentAddress & t);
};
template<typename T> template<typename T>
struct WorkerProto<std::set<T>> { struct WorkerProto<std::set<T>> {
@ -164,4 +157,13 @@ struct WorkerProto<std::optional<T>> {
}; };
/* Specialization which uses and empty string for the empty case, taking
advantage of the fact these types always serialize to non-empty strings.
This is done primarily for backwards compatability, so that T <=
std::optional<T>, where <= is the compatability partial order, T is one of
the types below.
*/
MAKE_WORKER_PROTO(std::optional<StorePath>);
MAKE_WORKER_PROTO(std::optional<ContentAddress>);
} }

View file

@ -8,7 +8,7 @@ namespace nix {
App Installable::toApp(EvalState & state) App Installable::toApp(EvalState & state)
{ {
auto [cursor, attrPath] = getCursor(state, true); auto [cursor, attrPath] = getCursor(state);
auto type = cursor->getAttr("type")->getString(); auto type = cursor->getAttr("type")->getString();

View file

@ -64,17 +64,24 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixProfile
if (dryRun) return; if (dryRun) return;
if (outLink != "") { if (outLink != "")
for (size_t i = 0; i < buildables.size(); ++i) { if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>())
for (auto & output : buildables[i].outputs) for (size_t i = 0; i < buildables.size(); ++i)
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>()) { std::visit(overloaded {
std::string symlink = outLink; [&](BuildableOpaque bo) {
if (i) symlink += fmt("-%d", i); std::string symlink = outLink;
if (output.first != "out") symlink += fmt("-%s", output.first); if (i) symlink += fmt("-%d", i);
store2->addPermRoot(output.second, absPath(symlink), true); store2->addPermRoot(bo.path, absPath(symlink), true);
} },
} [&](BuildableFromDrv bfd) {
} for (auto & output : bfd.outputs) {
std::string symlink = outLink;
if (i) symlink += fmt("-%d", i);
if (output.first != "out") symlink += fmt("-%s", output.first);
store2->addPermRoot(output.second, absPath(symlink), true);
}
},
}, buildables[i]);
updateProfile(buildables); updateProfile(buildables);
} }

View file

@ -128,20 +128,25 @@ void MixProfile::updateProfile(const Buildables & buildables)
{ {
if (!profile) return; if (!profile) return;
std::optional<StorePath> result; std::vector<StorePath> result;
for (auto & buildable : buildables) { for (auto & buildable : buildables) {
for (auto & output : buildable.outputs) { std::visit(overloaded {
if (result) [&](BuildableOpaque bo) {
throw Error("'--profile' requires that the arguments produce a single store path, but there are multiple"); result.push_back(bo.path);
result = output.second; },
} [&](BuildableFromDrv bfd) {
for (auto & output : bfd.outputs) {
result.push_back(output.second);
}
},
}, buildable);
} }
if (!result) if (result.size() != 1)
throw Error("'--profile' requires that the arguments produce a single store path, but there are none"); throw Error("'--profile' requires that the arguments produce a single store path, but there are %d", result.size());
updateProfile(*result); updateProfile(result[0]);
} }
MixDefaultProfile::MixDefaultProfile() MixDefaultProfile::MixDefaultProfile()

View file

@ -572,7 +572,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
Strings{templateName == "" ? "defaultTemplate" : templateName}, Strings{templateName == "" ? "defaultTemplate" : templateName},
Strings(attrsPathPrefixes), lockFlags); Strings(attrsPathPrefixes), lockFlags);
auto [cursor, attrPath] = installable.getCursor(*evalState, true); auto [cursor, attrPath] = installable.getCursor(*evalState);
auto templateDir = cursor->getAttr("path")->getString(); auto templateDir = cursor->getAttr("path")->getString();
@ -782,7 +782,6 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun
struct CmdFlakeShow : FlakeCommand struct CmdFlakeShow : FlakeCommand
{ {
bool showLegacy = false; bool showLegacy = false;
bool useEvalCache = true;
CmdFlakeShow() CmdFlakeShow()
{ {
@ -791,12 +790,6 @@ struct CmdFlakeShow : FlakeCommand
.description = "show the contents of the 'legacyPackages' output", .description = "show the contents of the 'legacyPackages' output",
.handler = {&showLegacy, true} .handler = {&showLegacy, true}
}); });
addFlag({
.longName = "no-eval-cache",
.description = "do not use the flake evaluation cache",
.handler = {[&]() { useEvalCache = false; }}
});
} }
std::string description() override std::string description() override
@ -934,7 +927,7 @@ struct CmdFlakeShow : FlakeCommand
} }
}; };
auto cache = openEvalCache(*state, flake, useEvalCache); auto cache = openEvalCache(*state, flake);
visit(*cache->getRoot(), {}, fmt(ANSI_BOLD "%s" ANSI_NORMAL, flake->flake.lockedRef), ""); visit(*cache->getRoot(), {}, fmt(ANSI_BOLD "%s" ANSI_NORMAL, flake->flake.lockedRef), "");
} }

View file

@ -183,8 +183,7 @@ void completeFlakeRefWithFragment(
auto flakeRef = parseFlakeRef(flakeRefS, absPath(".")); auto flakeRef = parseFlakeRef(flakeRefS, absPath("."));
auto evalCache = openEvalCache(*evalState, auto evalCache = openEvalCache(*evalState,
std::make_shared<flake::LockedFlake>(lockFlake(*evalState, flakeRef, lockFlags)), std::make_shared<flake::LockedFlake>(lockFlake(*evalState, flakeRef, lockFlags)));
true);
auto root = evalCache->getRoot(); auto root = evalCache->getRoot();
@ -273,7 +272,7 @@ Buildable Installable::toBuildable()
} }
std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>> std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
Installable::getCursors(EvalState & state, bool useEvalCache) Installable::getCursors(EvalState & state)
{ {
auto evalCache = auto evalCache =
std::make_shared<nix::eval_cache::EvalCache>(std::nullopt, state, std::make_shared<nix::eval_cache::EvalCache>(std::nullopt, state,
@ -282,9 +281,9 @@ Installable::getCursors(EvalState & state, bool useEvalCache)
} }
std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string> std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>
Installable::getCursor(EvalState & state, bool useEvalCache) Installable::getCursor(EvalState & state)
{ {
auto cursors = getCursors(state, useEvalCache); auto cursors = getCursors(state);
if (cursors.empty()) if (cursors.empty())
throw Error("cannot find flake attribute '%s'", what()); throw Error("cannot find flake attribute '%s'", what());
return cursors[0]; return cursors[0];
@ -308,16 +307,15 @@ struct InstallableStorePath : Installable
for (auto & [name, output] : drv.outputs) for (auto & [name, output] : drv.outputs)
outputs.emplace(name, output.path(*store, drv.name)); outputs.emplace(name, output.path(*store, drv.name));
return { return {
Buildable { BuildableFromDrv {
.drvPath = storePath, .drvPath = storePath,
.outputs = std::move(outputs) .outputs = std::move(outputs)
} }
}; };
} else { } else {
return { return {
Buildable { BuildableOpaque {
.drvPath = {}, .path = storePath,
.outputs = {{"out", storePath}}
} }
}; };
} }
@ -333,33 +331,20 @@ Buildables InstallableValue::toBuildables()
{ {
Buildables res; Buildables res;
StorePathSet drvPaths; std::map<StorePath, OutputPathMap> drvsToOutputs;
// Group by derivation, helps with .all in particular
for (auto & drv : toDerivations()) { for (auto & drv : toDerivations()) {
Buildable b{.drvPath = drv.drvPath};
drvPaths.insert(drv.drvPath);
auto outputName = drv.outputName; auto outputName = drv.outputName;
if (outputName == "") if (outputName == "")
throw Error("derivation '%s' lacks an 'outputName' attribute", state->store->printStorePath(*b.drvPath)); throw Error("derivation '%s' lacks an 'outputName' attribute", state->store->printStorePath(drv.drvPath));
drvsToOutputs[drv.drvPath].insert_or_assign(outputName, drv.outPath);
b.outputs.emplace(outputName, drv.outPath);
res.push_back(std::move(b));
} }
// Hack to recognize .all: if all drvs have the same drvPath, for (auto & i : drvsToOutputs)
// merge the buildables. res.push_back(BuildableFromDrv { i.first, i.second });
if (drvPaths.size() == 1) {
Buildable b{.drvPath = *drvPaths.begin()}; return res;
for (auto & b2 : res)
for (auto & output : b2.outputs)
b.outputs.insert_or_assign(output.first, output.second);
Buildables bs;
bs.push_back(std::move(b));
return bs;
} else
return res;
} }
struct InstallableAttrPath : InstallableValue struct InstallableAttrPath : InstallableValue
@ -434,12 +419,11 @@ Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::Locked
ref<eval_cache::EvalCache> openEvalCache( ref<eval_cache::EvalCache> openEvalCache(
EvalState & state, EvalState & state,
std::shared_ptr<flake::LockedFlake> lockedFlake, std::shared_ptr<flake::LockedFlake> lockedFlake)
bool useEvalCache)
{ {
auto fingerprint = lockedFlake->getFingerprint(); auto fingerprint = lockedFlake->getFingerprint();
return make_ref<nix::eval_cache::EvalCache>( return make_ref<nix::eval_cache::EvalCache>(
useEvalCache && evalSettings.pureEval evalSettings.useEvalCache && evalSettings.pureEval
? std::optional { std::cref(fingerprint) } ? std::optional { std::cref(fingerprint) }
: std::nullopt, : std::nullopt,
state, state,
@ -474,10 +458,9 @@ static std::string showAttrPaths(const std::vector<std::string> & paths)
std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableFlake::toDerivation() std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableFlake::toDerivation()
{ {
auto lockedFlake = getLockedFlake(); auto lockedFlake = getLockedFlake();
auto cache = openEvalCache(*state, lockedFlake, true); auto cache = openEvalCache(*state, lockedFlake);
auto root = cache->getRoot(); auto root = cache->getRoot();
for (auto & attrPath : getActualAttrPaths()) { for (auto & attrPath : getActualAttrPaths()) {
@ -531,11 +514,10 @@ std::pair<Value *, Pos> InstallableFlake::toValue(EvalState & state)
} }
std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>> std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
InstallableFlake::getCursors(EvalState & state, bool useEvalCache) InstallableFlake::getCursors(EvalState & state)
{ {
auto evalCache = openEvalCache(state, auto evalCache = openEvalCache(state,
std::make_shared<flake::LockedFlake>(lockFlake(state, flakeRef, lockFlags)), std::make_shared<flake::LockedFlake>(lockFlake(state, flakeRef, lockFlags)));
useEvalCache);
auto root = evalCache->getRoot(); auto root = evalCache->getRoot();
@ -656,14 +638,17 @@ Buildables build(ref<Store> store, Realise mode,
for (auto & i : installables) { for (auto & i : installables) {
for (auto & b : i->toBuildables()) { for (auto & b : i->toBuildables()) {
if (b.drvPath) { std::visit(overloaded {
StringSet outputNames; [&](BuildableOpaque bo) {
for (auto & output : b.outputs) pathsToBuild.push_back({bo.path});
outputNames.insert(output.first); },
pathsToBuild.push_back({*b.drvPath, outputNames}); [&](BuildableFromDrv bfd) {
} else StringSet outputNames;
for (auto & output : b.outputs) for (auto & output : bfd.outputs)
pathsToBuild.push_back({output.second}); outputNames.insert(output.first);
pathsToBuild.push_back({bfd.drvPath, outputNames});
},
}, b);
buildables.push_back(std::move(b)); buildables.push_back(std::move(b));
} }
} }
@ -684,16 +669,23 @@ StorePathSet toStorePaths(ref<Store> store,
if (operateOn == OperateOn::Output) { if (operateOn == OperateOn::Output) {
for (auto & b : build(store, mode, installables)) for (auto & b : build(store, mode, installables))
for (auto & output : b.outputs) std::visit(overloaded {
outPaths.insert(output.second); [&](BuildableOpaque bo) {
outPaths.insert(bo.path);
},
[&](BuildableFromDrv bfd) {
for (auto & output : bfd.outputs)
outPaths.insert(output.second);
},
}, b);
} else { } else {
if (mode == Realise::Nothing) if (mode == Realise::Nothing)
settings.readOnlyMode = true; settings.readOnlyMode = true;
for (auto & i : installables) for (auto & i : installables)
for (auto & b : i->toBuildables()) for (auto & b : i->toBuildables())
if (b.drvPath) if (auto bfd = std::get_if<BuildableFromDrv>(&b))
outPaths.insert(*b.drvPath); outPaths.insert(bfd->drvPath);
} }
return outPaths; return outPaths;
@ -717,20 +709,21 @@ StorePathSet toDerivations(ref<Store> store,
StorePathSet drvPaths; StorePathSet drvPaths;
for (auto & i : installables) for (auto & i : installables)
for (auto & b : i->toBuildables()) { for (auto & b : i->toBuildables())
if (!b.drvPath) { std::visit(overloaded {
if (!useDeriver) [&](BuildableOpaque bo) {
throw Error("argument '%s' did not evaluate to a derivation", i->what()); if (!useDeriver)
for (auto & output : b.outputs) { throw Error("argument '%s' did not evaluate to a derivation", i->what());
auto derivers = store->queryValidDerivers(output.second); auto derivers = store->queryValidDerivers(bo.path);
if (derivers.empty()) if (derivers.empty())
throw Error("'%s' does not have a known deriver", i->what()); throw Error("'%s' does not have a known deriver", i->what());
// FIXME: use all derivers? // FIXME: use all derivers?
drvPaths.insert(*derivers.begin()); drvPaths.insert(*derivers.begin());
} },
} else [&](BuildableFromDrv bfd) {
drvPaths.insert(*b.drvPath); drvPaths.insert(bfd.drvPath);
} },
}, b);
return drvPaths; return drvPaths;
} }

View file

@ -14,12 +14,20 @@ struct SourceExprCommand;
namespace eval_cache { class EvalCache; class AttrCursor; } namespace eval_cache { class EvalCache; class AttrCursor; }
struct Buildable struct BuildableOpaque {
{ StorePath path;
std::optional<StorePath> drvPath; };
struct BuildableFromDrv {
StorePath drvPath;
std::map<std::string, StorePath> outputs; std::map<std::string, StorePath> outputs;
}; };
typedef std::variant<
BuildableOpaque,
BuildableFromDrv
> Buildable;
typedef std::vector<Buildable> Buildables; typedef std::vector<Buildable> Buildables;
struct App struct App
@ -54,10 +62,10 @@ struct Installable
} }
virtual std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>> virtual std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
getCursors(EvalState & state, bool useEvalCache); getCursors(EvalState & state);
std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string> std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>
getCursor(EvalState & state, bool useEvalCache); getCursor(EvalState & state);
virtual FlakeRef nixpkgsFlakeRef() const virtual FlakeRef nixpkgsFlakeRef() const
{ {
@ -110,7 +118,7 @@ struct InstallableFlake : InstallableValue
std::pair<Value *, Pos> toValue(EvalState & state) override; std::pair<Value *, Pos> toValue(EvalState & state) override;
std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>> std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
getCursors(EvalState & state, bool useEvalCache) override; getCursors(EvalState & state) override;
std::shared_ptr<flake::LockedFlake> getLockedFlake() const; std::shared_ptr<flake::LockedFlake> getLockedFlake() const;
@ -119,7 +127,6 @@ struct InstallableFlake : InstallableValue
ref<eval_cache::EvalCache> openEvalCache( ref<eval_cache::EvalCache> openEvalCache(
EvalState & state, EvalState & state,
std::shared_ptr<flake::LockedFlake> lockedFlake, std::shared_ptr<flake::LockedFlake> lockedFlake);
bool useEvalCache);
} }

View file

@ -45,11 +45,14 @@ struct CmdLog : InstallableCommand
RunPager pager; RunPager pager;
for (auto & sub : subs) { for (auto & sub : subs) {
auto log = b.drvPath ? sub->getBuildLog(*b.drvPath) : nullptr; auto log = std::visit(overloaded {
for (auto & output : b.outputs) { [&](BuildableOpaque bo) {
if (log) break; return sub->getBuildLog(bo.path);
log = sub->getBuildLog(output.second); },
} [&](BuildableFromDrv bfd) {
return sub->getBuildLog(bfd.drvPath);
},
}, b);
if (!log) continue; if (!log) continue;
stopProgressBar(); stopProgressBar();
printInfo("got build log for '%s' from '%s'", installable->what(), sub->getUri()); printInfo("got build log for '%s' from '%s'", installable->what(), sub->getUri());

View file

@ -33,12 +33,17 @@ extern "C" {
#include "command.hh" #include "command.hh"
#include "finally.hh" #include "finally.hh"
#if HAVE_BOEHMGC
#define GC_INCLUDE_NEW #define GC_INCLUDE_NEW
#include <gc/gc_cpp.h> #include <gc/gc_cpp.h>
#endif
namespace nix { namespace nix {
struct NixRepl : gc struct NixRepl
#if HAVE_BOEHMGC
: gc
#endif
{ {
string curDir; string curDir;
std::unique_ptr<EvalState> state; std::unique_ptr<EvalState> state;

View file

@ -177,7 +177,7 @@ struct CmdSearch : InstallableCommand, MixJSON
} }
}; };
for (auto & [cursor, prefix] : installable->getCursors(*state, true)) for (auto & [cursor, prefix] : installable->getCursors(*state))
visit(*cursor, parseAttrPath(*state, prefix)); visit(*cursor, parseAttrPath(*state, prefix));
if (!json && !results) if (!json && !results)