aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/value.hh8
-rw-r--r--src/nix/build.cc19
-rw-r--r--src/nix/command.cc7
-rw-r--r--src/nix/command.hh4
-rw-r--r--src/nix/installables.cc233
-rw-r--r--src/nix/installables.hh55
-rw-r--r--src/nix/log.cc35
-rw-r--r--src/nix/path-info.cc1
-rw-r--r--src/nix/run.cc19
9 files changed, 257 insertions, 124 deletions
diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh
index 802e8ed2e..9df516f06 100644
--- a/src/libexpr/value.hh
+++ b/src/libexpr/value.hh
@@ -220,6 +220,14 @@ static inline void mkApp(Value & v, Value & left, Value & right)
}
+static inline void mkPrimOpApp(Value & v, Value & left, Value & right)
+{
+ v.type = tPrimOpApp;
+ v.app.left = &left;
+ v.app.right = &right;
+}
+
+
static inline void mkStringNoCopy(Value & v, const char * s)
{
v.type = tString;
diff --git a/src/nix/build.cc b/src/nix/build.cc
index 812464d75..0a34c68f8 100644
--- a/src/nix/build.cc
+++ b/src/nix/build.cc
@@ -6,7 +6,7 @@
using namespace nix;
-struct CmdBuild : StoreCommand, MixDryRun, MixInstallables
+struct CmdBuild : MixDryRun, MixInstallables
{
CmdBuild()
{
@@ -24,22 +24,9 @@ struct CmdBuild : StoreCommand, MixDryRun, MixInstallables
void run(ref<Store> store) override
{
- auto elems = evalInstallables(store);
+ auto paths = buildInstallables(store, dryRun);
- PathSet pathsToBuild;
-
- for (auto & elem : elems) {
- if (elem.isDrv)
- pathsToBuild.insert(elem.drvPath);
- else
- pathsToBuild.insert(elem.outPaths.begin(), elem.outPaths.end());
- }
-
- printMissing(store, pathsToBuild);
-
- if (dryRun) return;
-
- store->buildPaths(pathsToBuild);
+ printInfo("build result: %s", showPaths(paths));
}
};
diff --git a/src/nix/command.cc b/src/nix/command.cc
index a1b2c120a..4034de96c 100644
--- a/src/nix/command.cc
+++ b/src/nix/command.cc
@@ -79,6 +79,13 @@ StoreCommand::StoreCommand()
mkFlag(0, "store", "store-uri", "URI of the Nix store to use", &storeUri);
}
+ref<Store> StoreCommand::getStore()
+{
+ if (!_store)
+ _store = createStore();
+ return ref<Store>(_store);
+}
+
ref<Store> StoreCommand::createStore()
{
return openStore(storeUri);
diff --git a/src/nix/command.hh b/src/nix/command.hh
index fa6c21abf..bb667ee32 100644
--- a/src/nix/command.hh
+++ b/src/nix/command.hh
@@ -33,8 +33,12 @@ struct StoreCommand : virtual Command
std::string storeUri;
StoreCommand();
void run() override;
+ ref<Store> getStore();
virtual ref<Store> createStore();
virtual void run(ref<Store>) = 0;
+
+private:
+ std::shared_ptr<Store> _store;
};
/* A command that operates on zero or more store paths. */
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index 8341bbc5a..70007d62a 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -6,16 +6,21 @@
#include "get-drvs.hh"
#include "installables.hh"
#include "store-api.hh"
+#include "shared.hh"
+
+#include <regex>
namespace nix {
-Value * MixInstallables::buildSourceExpr(EvalState & state)
+Value * MixInstallables::getSourceExpr(EvalState & state)
{
- Value * vRoot = state.allocValue();
+ if (vSourceExpr) return vSourceExpr;
+
+ vSourceExpr = state.allocValue();
if (file != "") {
Expr * e = state.parseExprFromFile(resolveExprPath(lookupFileArg(state, file)));
- state.eval(e, *vRoot);
+ state.eval(e, *vSourceExpr);
}
else {
@@ -24,7 +29,7 @@ Value * MixInstallables::buildSourceExpr(EvalState & state)
auto searchPath = state.getSearchPath();
- state.mkAttrs(*vRoot, searchPath.size());
+ state.mkAttrs(*vSourceExpr, searchPath.size());
std::unordered_set<std::string> seen;
@@ -32,76 +37,208 @@ Value * MixInstallables::buildSourceExpr(EvalState & state)
if (i.first == "") continue;
if (seen.count(i.first)) continue;
seen.insert(i.first);
- if (!pathExists(i.second)) continue;
- mkApp(*state.allocAttr(*vRoot, state.symbols.create(i.first)),
+#if 0
+ auto res = state.resolveSearchPathElem(i);
+ if (!res.first) continue;
+ if (!pathExists(res.second)) continue;
+ mkApp(*state.allocAttr(*vSourceExpr, state.symbols.create(i.first)),
state.getBuiltin("import"),
- mkString(*state.allocValue(), i.second));
+ mkString(*state.allocValue(), res.second));
+#endif
+ Value * v1 = state.allocValue();
+ mkPrimOpApp(*v1, state.getBuiltin("findFile"), state.getBuiltin("nixPath"));
+ Value * v2 = state.allocValue();
+ mkApp(*v2, *v1, mkString(*state.allocValue(), i.first));
+ mkApp(*state.allocAttr(*vSourceExpr, state.symbols.create(i.first)),
+ state.getBuiltin("import"), *v2);
}
- vRoot->attrs->sort();
+ vSourceExpr->attrs->sort();
}
- return vRoot;
+ return vSourceExpr;
}
-UserEnvElems MixInstallables::evalInstallables(ref<Store> store)
+struct InstallableStoreDrv : Installable
+{
+ Path storePath;
+
+ InstallableStoreDrv(const Path & storePath) : storePath(storePath) { }
+
+ std::string what() override { return storePath; }
+
+ PathSet toBuildable() override
+ {
+ return {storePath};
+ }
+};
+
+struct InstallableStorePath : Installable
{
- UserEnvElems res;
+ Path storePath;
+
+ InstallableStorePath(const Path & storePath) : storePath(storePath) { }
+
+ std::string what() override { return storePath; }
+
+ PathSet toBuildable() override
+ {
+ return {storePath};
+ }
+};
+
+struct InstallableExpr : Installable
+{
+ MixInstallables & installables;
+ std::string text;
+
+ InstallableExpr(MixInstallables & installables, const std::string & text)
+ : installables(installables), text(text) { }
+
+ std::string what() override { return text; }
+
+ PathSet toBuildable() override
+ {
+ auto state = installables.getEvalState();
+
+ auto v = toValue(*state);
+
+ // FIXME
+ std::map<string, string> autoArgs_;
+ Bindings & autoArgs(*evalAutoArgs(*state, autoArgs_));
+
+ DrvInfos drvs;
+ getDerivations(*state, *v, "", autoArgs, drvs, false);
+
+ PathSet res;
+
+ for (auto & i : drvs)
+ res.insert(i.queryDrvPath());
+
+ return res;
+ }
+
+ Value * toValue(EvalState & state) override
+ {
+ auto v = state.allocValue();
+ state.eval(state.parseExprFromString(text, absPath(".")), *v);
+ return v;
+ }
+};
+
+struct InstallableAttrPath : Installable
+{
+ MixInstallables & installables;
+ std::string attrPath;
+
+ InstallableAttrPath(MixInstallables & installables, const std::string & attrPath)
+ : installables(installables), attrPath(attrPath)
+ { }
+
+ std::string what() override { return attrPath; }
+
+ PathSet toBuildable() override
+ {
+ auto state = installables.getEvalState();
+
+ auto v = toValue(*state);
+
+ // FIXME
+ std::map<string, string> autoArgs_;
+ Bindings & autoArgs(*evalAutoArgs(*state, autoArgs_));
+
+ DrvInfos drvs;
+ getDerivations(*state, *v, "", autoArgs, drvs, false);
+
+ PathSet res;
+
+ for (auto & i : drvs)
+ res.insert(i.queryDrvPath());
+
+ return res;
+ }
+
+ Value * toValue(EvalState & state) override
+ {
+ auto source = installables.getSourceExpr(state);
+
+ // FIXME
+ std::map<string, string> autoArgs_;
+ Bindings & autoArgs(*evalAutoArgs(state, autoArgs_));
+
+ Value * v = findAlongAttrPath(state, attrPath, autoArgs, *source);
+ state.forceValue(*v);
+
+ return v;
+ }
+};
+
+// FIXME: extend
+std::string attrRegex = R"([A-Za-z_][A-Za-z0-9-_+]*)";
+static std::regex attrPathRegex(fmt(R"(%1%(\.%1%)*)", attrRegex));
+
+std::vector<std::shared_ptr<Installable>> MixInstallables::parseInstallables(ref<Store> store, Strings installables)
+{
+ std::vector<std::shared_ptr<Installable>> result;
for (auto & installable : installables) {
if (std::string(installable, 0, 1) == "/") {
if (store->isStorePath(installable)) {
+ if (isDerivation(installable))
+ result.push_back(std::make_shared<InstallableStoreDrv>(installable));
+ else
+ result.push_back(std::make_shared<InstallableStorePath>(installable));
+ }
- if (isDerivation(installable)) {
- UserEnvElem elem;
- // FIXME: handle empty case, drop version
- elem.attrPath = {storePathToName(installable)};
- elem.isDrv = true;
- elem.drvPath = installable;
- res.push_back(elem);
- }
-
- else {
- UserEnvElem elem;
- // FIXME: handle empty case, drop version
- elem.attrPath = {storePathToName(installable)};
- elem.isDrv = false;
- elem.outPaths = {installable};
- res.push_back(elem);
- }
+ else {
+ result.push_back(std::make_shared<InstallableStorePath>(
+ store->toStorePath(store->followLinksToStore(installable))));
}
- else
- throw UsageError(format("don't know what to do with ‘%1%’") % installable);
}
- else {
-
- EvalState state({}, store);
+ else if (installable.compare(0, 1, "(") == 0)
+ result.push_back(std::make_shared<InstallableExpr>(*this, installable));
- auto vRoot = buildSourceExpr(state);
+ else if (std::regex_match(installable, attrPathRegex))
+ result.push_back(std::make_shared<InstallableAttrPath>(*this, installable));
- std::map<string, string> autoArgs_;
- Bindings & autoArgs(*evalAutoArgs(state, autoArgs_));
+ else
+ throw UsageError("don't know what to do with argument ‘%s’", installable);
+ }
- Value & v(*findAlongAttrPath(state, installable, autoArgs, *vRoot));
- state.forceValue(v);
+ return result;
+}
- DrvInfos drvs;
- getDerivations(state, v, "", autoArgs, drvs, false);
+PathSet MixInstallables::buildInstallables(ref<Store> store, bool dryRun)
+{
+ PathSet buildables;
- for (auto & i : drvs) {
- UserEnvElem elem;
- elem.isDrv = true;
- elem.drvPath = i.queryDrvPath();
- res.push_back(elem);
- }
- }
+ for (auto & i : installables) {
+ auto b = i->toBuildable();
+ buildables.insert(b.begin(), b.end());
}
- return res;
+ printMissing(store, buildables);
+
+ if (!dryRun)
+ store->buildPaths(buildables);
+
+ return buildables;
+}
+
+ref<EvalState> MixInstallables::getEvalState()
+{
+ if (!evalState)
+ evalState = std::make_shared<EvalState>(Strings{}, getStore());
+ return ref<EvalState>(evalState);
+}
+
+void MixInstallables::prepare()
+{
+ installables = parseInstallables(getStore(), _installables);
}
}
diff --git a/src/nix/installables.hh b/src/nix/installables.hh
index a58f7dc59..5f0b0a292 100644
--- a/src/nix/installables.hh
+++ b/src/nix/installables.hh
@@ -1,48 +1,61 @@
#pragma once
#include "args.hh"
+#include "command.hh"
namespace nix {
-struct UserEnvElem
-{
- Strings attrPath;
+struct Value;
+class EvalState;
+class Expr;
- // FIXME: should use boost::variant or so.
- bool isDrv;
+struct Installable
+{
+ virtual std::string what() = 0;
- // Derivation case:
- Path drvPath;
- StringSet outputNames;
+ virtual PathSet toBuildable()
+ {
+ throw Error("argument ‘%s’ cannot be built", what());
+ }
- // Non-derivation case:
- PathSet outPaths;
+ virtual Value * toValue(EvalState & state)
+ {
+ throw Error("argument ‘%s’ cannot be evaluated", what());
+ }
};
-typedef std::vector<UserEnvElem> UserEnvElems;
-
-struct Value;
-class EvalState;
-
-struct MixInstallables : virtual Args
+struct MixInstallables : virtual Args, StoreCommand
{
- Strings installables;
+ std::vector<std::shared_ptr<Installable>> installables;
Path file;
MixInstallables()
{
mkFlag('f', "file", "file", "evaluate FILE rather than the default", &file);
- expectArgs("installables", &installables);
+ expectArgs("installables", &_installables);
}
- UserEnvElems evalInstallables(ref<Store> store);
-
/* Return a value representing the Nix expression from which we
are installing. This is either the file specified by ‘--file’,
or an attribute set constructed from $NIX_PATH, e.g. ‘{ nixpkgs
= import ...; bla = import ...; }’. */
- Value * buildSourceExpr(EvalState & state);
+ Value * getSourceExpr(EvalState & state);
+
+ std::vector<std::shared_ptr<Installable>> parseInstallables(ref<Store> store, Strings installables);
+
+ PathSet buildInstallables(ref<Store> store, bool dryRun);
+
+ ref<EvalState> getEvalState();
+
+ void prepare() override;
+
+private:
+
+ Strings _installables;
+
+ std::shared_ptr<EvalState> evalState;
+ Value * vSourceExpr = 0;
};
}
diff --git a/src/nix/log.cc b/src/nix/log.cc
index d8a3830e9..75f3c1ab0 100644
--- a/src/nix/log.cc
+++ b/src/nix/log.cc
@@ -6,7 +6,7 @@
using namespace nix;
-struct CmdLog : StoreCommand, MixInstallables
+struct CmdLog : MixInstallables
{
CmdLog()
{
@@ -24,32 +24,23 @@ struct CmdLog : StoreCommand, MixInstallables
void run(ref<Store> store) override
{
- auto elems = evalInstallables(store);
-
- PathSet paths;
-
- for (auto & elem : elems) {
- if (elem.isDrv)
- paths.insert(elem.drvPath);
- else
- paths.insert(elem.outPaths.begin(), elem.outPaths.end());
- }
-
auto subs = getDefaultSubstituters();
subs.push_front(store);
- for (auto & path : paths) {
- bool found = false;
- for (auto & sub : subs) {
- auto log = sub->getBuildLog(path);
- if (!log) continue;
- std::cout << *log;
- found = true;
- break;
+ for (auto & inst : installables) {
+ for (auto & path : inst->toBuildable()) {
+ bool found = false;
+ for (auto & sub : subs) {
+ auto log = sub->getBuildLog(path);
+ if (!log) continue;
+ std::cout << *log;
+ found = true;
+ break;
+ }
+ if (!found)
+ throw Error("build log of path ‘%s’ is not available", path);
}
- if (!found)
- throw Error("build log of path ‘%s’ is not available", path);
}
}
};
diff --git a/src/nix/path-info.cc b/src/nix/path-info.cc
index 30b193798..f16209238 100644
--- a/src/nix/path-info.cc
+++ b/src/nix/path-info.cc
@@ -99,7 +99,6 @@ struct CmdPathInfo : StorePathsCommand, MixJSON
}
}
-
}
};
diff --git a/src/nix/run.cc b/src/nix/run.cc
index a30031ad0..f3333b777 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -13,7 +13,7 @@
using namespace nix;
-struct CmdRun : StoreCommand, MixInstallables
+struct CmdRun : MixInstallables
{
CmdRun()
{
@@ -31,20 +31,7 @@ struct CmdRun : StoreCommand, MixInstallables
void run(ref<Store> store) override
{
- auto elems = evalInstallables(store);
-
- PathSet pathsToBuild;
-
- for (auto & elem : elems) {
- if (elem.isDrv)
- pathsToBuild.insert(elem.drvPath);
- else
- pathsToBuild.insert(elem.outPaths.begin(), elem.outPaths.end());
- }
-
- printMissing(store, pathsToBuild);
-
- store->buildPaths(pathsToBuild);
+ auto paths = buildInstallables(store, false);
auto store2 = store.dynamic_pointer_cast<LocalStore>();
@@ -104,7 +91,7 @@ struct CmdRun : StoreCommand, MixInstallables
}
PathSet outPaths;
- for (auto & path : pathsToBuild)
+ for (auto & path : paths)
if (isDerivation(path)) {
Derivation drv = store->derivationFromPath(path);
for (auto & output : drv.outputs)