Move code around

This commit is contained in:
Eelco Dolstra 2019-10-14 14:40:16 +02:00
parent 5446eae949
commit 0bc8f1669d
3 changed files with 216 additions and 189 deletions

View file

@ -1,15 +1,15 @@
#pragma once #pragma once
#include "installables.hh"
#include "args.hh" #include "args.hh"
#include "common-eval-args.hh" #include "common-eval-args.hh"
#include <optional> #include <optional>
namespace nix { namespace nix {
extern std::string programPath; extern std::string programPath;
struct Value;
class Bindings;
class EvalState; class EvalState;
class Store; class Store;
@ -30,51 +30,6 @@ private:
std::shared_ptr<Store> _store; std::shared_ptr<Store> _store;
}; };
struct Buildable
{
Path drvPath; // may be empty
std::map<std::string, Path> outputs;
};
typedef std::vector<Buildable> Buildables;
struct App
{
PathSet context;
Path program;
// FIXME: add args, sandbox settings, metadata, ...
App(EvalState & state, Value & vApp);
};
struct Installable
{
virtual ~Installable() { }
virtual std::string what() = 0;
virtual Buildables toBuildables()
{
throw Error("argument '%s' cannot be built", what());
}
Buildable toBuildable();
App toApp(EvalState & state);
virtual Value * toValue(EvalState & state)
{
throw Error("argument '%s' cannot be evaluated", what());
}
/* Return a value only if this installable is a store path or a
symlink to it. */
virtual std::optional<Path> getStorePath()
{
return {};
}
};
struct EvalCommand : virtual StoreCommand, MixEvalArgs struct EvalCommand : virtual StoreCommand, MixEvalArgs
{ {
ref<EvalState> getEvalState(); ref<EvalState> getEvalState();

View file

@ -1,3 +1,4 @@
#include "installables.hh"
#include "command.hh" #include "command.hh"
#include "attr-path.hh" #include "attr-path.hh"
#include "common-eval-args.hh" #include "common-eval-args.hh"
@ -111,65 +112,58 @@ struct InstallableStorePath : Installable
} }
}; };
struct InstallableValue : Installable std::vector<flake::EvalCache::Derivation> InstallableValue::toDerivations()
{ {
SourceExprCommand & cmd; auto state = cmd.getEvalState();
InstallableValue(SourceExprCommand & cmd) : cmd(cmd) { } auto v = toValue(*state);
virtual std::vector<flake::EvalCache::Derivation> toDerivations() Bindings & autoArgs = *cmd.getAutoArgs(*state);
{
auto state = cmd.getEvalState();
auto v = toValue(*state); DrvInfos drvInfos;
getDerivations(*state, *v, "", autoArgs, drvInfos, false);
Bindings & autoArgs = *cmd.getAutoArgs(*state); std::vector<flake::EvalCache::Derivation> res;
for (auto & drvInfo : drvInfos) {
res.push_back({
drvInfo.queryDrvPath(),
drvInfo.queryOutPath(),
drvInfo.queryOutputName()
});
}
DrvInfos drvInfos; return res;
getDerivations(*state, *v, "", autoArgs, drvInfos, false); }
std::vector<flake::EvalCache::Derivation> res; Buildables InstallableValue::toBuildables()
for (auto & drvInfo : drvInfos) { {
res.push_back({ Buildables res;
drvInfo.queryDrvPath(),
drvInfo.queryOutPath(),
drvInfo.queryOutputName()
});
}
PathSet drvPaths;
for (auto & drv : toDerivations()) {
Buildable b{drv.drvPath};
drvPaths.insert(b.drvPath);
auto outputName = drv.outputName;
if (outputName == "")
throw Error("derivation '%s' lacks an 'outputName' attribute", b.drvPath);
b.outputs.emplace(outputName, drv.outPath);
res.push_back(std::move(b));
}
// Hack to recognize .all: if all drvs have the same drvPath,
// merge the buildables.
if (drvPaths.size() == 1) {
Buildable b{*drvPaths.begin()};
for (auto & b2 : res)
b.outputs.insert(b2.outputs.begin(), b2.outputs.end());
return {b};
} else
return res; return res;
} }
Buildables toBuildables() override
{
Buildables res;
PathSet drvPaths;
for (auto & drv : toDerivations()) {
Buildable b{drv.drvPath};
drvPaths.insert(b.drvPath);
auto outputName = drv.outputName;
if (outputName == "")
throw Error("derivation '%s' lacks an 'outputName' attribute", b.drvPath);
b.outputs.emplace(outputName, drv.outPath);
res.push_back(std::move(b));
}
// Hack to recognize .all: if all drvs have the same drvPath,
// merge the buildables.
if (drvPaths.size() == 1) {
Buildable b{*drvPaths.begin()};
for (auto & b2 : res)
b.outputs.insert(b2.outputs.begin(), b2.outputs.end());
return {b};
} else
return res;
}
};
struct InstallableExpr : InstallableValue struct InstallableExpr : InstallableValue
{ {
@ -254,123 +248,104 @@ void makeFlakeClosureGCRoot(Store & store,
store.addIndirectRoot(symlink); store.addIndirectRoot(symlink);
} }
struct InstallableFlake : InstallableValue std::vector<std::string> InstallableFlake::getActualAttrPaths()
{ {
FlakeRef flakeRef; std::vector<std::string> res;
Strings attrPaths;
Strings prefixes;
InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef, Strings attrPaths) for (auto & prefix : prefixes)
: InstallableValue(cmd), flakeRef(flakeRef), attrPaths(std::move(attrPaths)) res.push_back(prefix + *attrPaths.begin());
{ }
InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef, for (auto & s : attrPaths)
std::string attrPath, Strings && prefixes) res.push_back(s);
: InstallableValue(cmd), flakeRef(flakeRef), attrPaths{attrPath},
prefixes(prefixes)
{ }
std::string what() override { return flakeRef.to_string() + ":" + *attrPaths.begin(); } return res;
}
std::vector<std::string> getActualAttrPaths() Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::ResolvedFlake & resFlake)
{ {
std::vector<std::string> res; auto vFlake = state.allocValue();
for (auto & prefix : prefixes) callFlake(state, resFlake, *vFlake);
res.push_back(prefix + *attrPaths.begin());
for (auto & s : attrPaths) makeFlakeClosureGCRoot(*state.store, flakeRef, resFlake);
res.push_back(s);
return res; auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
} assert(aOutputs);
Value * getFlakeOutputs(EvalState & state, const flake::ResolvedFlake & resFlake) state.forceValue(*(*aOutputs)->value);
{
auto vFlake = state.allocValue();
callFlake(state, resFlake, *vFlake); return (*aOutputs)->value;
}
makeFlakeClosureGCRoot(*state.store, flakeRef, resFlake); std::vector<flake::EvalCache::Derivation> InstallableFlake::toDerivations()
{
auto state = cmd.getEvalState();
auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs")); auto resFlake = resolveFlake(*state, flakeRef, cmd.getLockFileMode());
assert(aOutputs);
state.forceValue(*(*aOutputs)->value); Value * vOutputs = nullptr;
return (*aOutputs)->value; auto emptyArgs = state->allocBindings(0);
}
std::vector<flake::EvalCache::Derivation> toDerivations() override auto & evalCache = flake::EvalCache::singleton();
{
auto state = cmd.getEvalState();
auto resFlake = resolveFlake(*state, flakeRef, cmd.getLockFileMode()); auto fingerprint = resFlake.getFingerprint();
Value * vOutputs = nullptr; for (auto & attrPath : getActualAttrPaths()) {
auto drv = evalCache.getDerivation(fingerprint, attrPath);
auto emptyArgs = state->allocBindings(0); if (drv) {
if (state->store->isValidPath(drv->drvPath))
auto & evalCache = flake::EvalCache::singleton(); return {*drv};
auto fingerprint = resFlake.getFingerprint();
for (auto & attrPath : getActualAttrPaths()) {
auto drv = evalCache.getDerivation(fingerprint, attrPath);
if (drv) {
if (state->store->isValidPath(drv->drvPath))
return {*drv};
}
if (!vOutputs)
vOutputs = getFlakeOutputs(*state, resFlake);
try {
auto * v = findAlongAttrPath(*state, attrPath, *emptyArgs, *vOutputs);
state->forceValue(*v);
auto drvInfo = getDerivation(*state, *v, false);
if (!drvInfo)
throw Error("flake output attribute '%s' is not a derivation", attrPath);
auto drv = flake::EvalCache::Derivation{
drvInfo->queryDrvPath(),
drvInfo->queryOutPath(),
drvInfo->queryOutputName()
};
evalCache.addDerivation(fingerprint, attrPath, drv);
return {drv};
} catch (AttrPathNotFound & e) {
}
} }
throw Error("flake '%s' does not provide attribute %s", if (!vOutputs)
flakeRef, concatStringsSep(", ", quoteStrings(attrPaths))); vOutputs = getFlakeOutputs(*state, resFlake);
}
Value * toValue(EvalState & state) override try {
{ auto * v = findAlongAttrPath(*state, attrPath, *emptyArgs, *vOutputs);
auto resFlake = resolveFlake(state, flakeRef, cmd.getLockFileMode()); state->forceValue(*v);
auto vOutputs = getFlakeOutputs(state, resFlake); auto drvInfo = getDerivation(*state, *v, false);
if (!drvInfo)
throw Error("flake output attribute '%s' is not a derivation", attrPath);
auto emptyArgs = state.allocBindings(0); auto drv = flake::EvalCache::Derivation{
drvInfo->queryDrvPath(),
drvInfo->queryOutPath(),
drvInfo->queryOutputName()
};
for (auto & attrPath : getActualAttrPaths()) { evalCache.addDerivation(fingerprint, attrPath, drv);
try {
auto * v = findAlongAttrPath(state, attrPath, *emptyArgs, *vOutputs); return {drv};
state.forceValue(*v); } catch (AttrPathNotFound & e) {
return v;
} catch (AttrPathNotFound & e) {
}
} }
throw Error("flake '%s' does not provide attribute %s",
flakeRef, concatStringsSep(", ", quoteStrings(attrPaths)));
} }
};
throw Error("flake '%s' does not provide attribute %s",
flakeRef, concatStringsSep(", ", quoteStrings(attrPaths)));
}
Value * InstallableFlake::toValue(EvalState & state)
{
auto resFlake = resolveFlake(state, flakeRef, cmd.getLockFileMode());
auto vOutputs = getFlakeOutputs(state, resFlake);
auto emptyArgs = state.allocBindings(0);
for (auto & attrPath : getActualAttrPaths()) {
try {
auto * v = findAlongAttrPath(state, attrPath, *emptyArgs, *vOutputs);
state.forceValue(*v);
return v;
} catch (AttrPathNotFound & e) {
}
}
throw Error("flake '%s' does not provide attribute %s",
flakeRef, concatStringsSep(", ", quoteStrings(attrPaths)));
}
// FIXME: extend // FIXME: extend
std::string attrRegex = R"([A-Za-z_][A-Za-z0-9-_+]*)"; std::string attrRegex = R"([A-Za-z_][A-Za-z0-9-_+]*)";

97
src/nix/installables.hh Normal file
View file

@ -0,0 +1,97 @@
#pragma once
#include "util.hh"
#include "flake/eval-cache.hh"
#include <optional>
namespace nix {
struct Value;
class EvalState;
class SourceExprCommand;
struct Buildable
{
Path drvPath; // may be empty
std::map<std::string, Path> outputs;
};
typedef std::vector<Buildable> Buildables;
struct App
{
PathSet context;
Path program;
// FIXME: add args, sandbox settings, metadata, ...
App(EvalState & state, Value & vApp);
};
struct Installable
{
virtual ~Installable() { }
virtual std::string what() = 0;
virtual Buildables toBuildables()
{
throw Error("argument '%s' cannot be built", what());
}
Buildable toBuildable();
App toApp(EvalState & state);
virtual Value * toValue(EvalState & state)
{
throw Error("argument '%s' cannot be evaluated", what());
}
/* Return a value only if this installable is a store path or a
symlink to it. */
virtual std::optional<Path> getStorePath()
{
return {};
}
};
struct InstallableValue : Installable
{
SourceExprCommand & cmd;
InstallableValue(SourceExprCommand & cmd) : cmd(cmd) { }
virtual std::vector<flake::EvalCache::Derivation> toDerivations();
Buildables toBuildables() override;
};
struct InstallableFlake : InstallableValue
{
FlakeRef flakeRef;
Strings attrPaths;
Strings prefixes;
InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef, Strings attrPaths)
: InstallableValue(cmd), flakeRef(flakeRef), attrPaths(std::move(attrPaths))
{ }
InstallableFlake(SourceExprCommand & cmd, FlakeRef && flakeRef,
std::string attrPath, Strings && prefixes)
: InstallableValue(cmd), flakeRef(flakeRef), attrPaths{attrPath},
prefixes(prefixes)
{ }
std::string what() override { return flakeRef.to_string() + ":" + *attrPaths.begin(); }
std::vector<std::string> getActualAttrPaths();
Value * getFlakeOutputs(EvalState & state, const flake::ResolvedFlake & resFlake);
std::vector<flake::EvalCache::Derivation> toDerivations() override;
Value * toValue(EvalState & state) override;
};
}