forked from lix-project/lix
Move code around
This commit is contained in:
parent
5446eae949
commit
0bc8f1669d
3 changed files with 216 additions and 189 deletions
|
@ -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();
|
||||||
|
|
|
@ -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
97
src/nix/installables.hh
Normal 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue