aboutsummaryrefslogtreecommitdiff
path: root/src/nix/eval.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix/eval.cc')
-rw-r--r--src/nix/eval.cc92
1 files changed, 62 insertions, 30 deletions
diff --git a/src/nix/eval.cc b/src/nix/eval.cc
index 43ce46546..65d61e005 100644
--- a/src/nix/eval.cc
+++ b/src/nix/eval.cc
@@ -3,6 +3,7 @@
#include "shared.hh"
#include "store-api.hh"
#include "eval.hh"
+#include "eval-inline.hh"
#include "json.hh"
#include "value-to-json.hh"
#include "progress-bar.hh"
@@ -13,17 +14,29 @@ struct CmdEval : MixJSON, InstallableCommand
{
bool raw = false;
std::optional<std::string> apply;
+ std::optional<Path> writeTo;
CmdEval()
{
- mkFlag(0, "raw", "print strings unquoted", &raw);
+ addFlag({
+ .longName = "raw",
+ .description = "Print strings without quotes or escaping.",
+ .handler = {&raw, true},
+ });
addFlag({
.longName = "apply",
- .description = "apply a function to each argument",
+ .description = "Apply the function *expr* to each argument.",
.labels = {"expr"},
.handler = {&apply},
});
+
+ addFlag({
+ .longName = "write-to",
+ .description = "Write a string or attrset of strings to *path*.",
+ .labels = {"path"},
+ .handler = {&writeTo},
+ });
}
std::string description() override
@@ -31,30 +44,11 @@ struct CmdEval : MixJSON, InstallableCommand
return "evaluate a Nix expression";
}
- Examples examples() override
+ std::string doc() override
{
- return {
- {
- "To evaluate a Nix expression given on the command line:",
- "nix eval --expr '1 + 2'"
- },
- {
- "To evaluate a Nix expression from a file or URI:",
- "nix eval -f ./my-nixpkgs hello.name"
- },
- {
- "To get the current version of Nixpkgs:",
- "nix eval --raw nixpkgs#lib.version"
- },
- {
- "To print the store path of the Hello package:",
- "nix eval --raw nixpkgs#hello"
- },
- {
- "To get a list of checks in the 'nix' flake:",
- "nix eval nix#checks.x86_64-linux --apply builtins.attrNames"
- },
- };
+ return
+ #include "eval.md"
+ ;
}
Category category() override { return catSecondary; }
@@ -66,7 +60,7 @@ struct CmdEval : MixJSON, InstallableCommand
auto state = getEvalState();
- auto v = installable->toValue(*state).first;
+ auto [v, pos] = installable->toValue(*state);
PathSet context;
if (apply) {
@@ -77,15 +71,53 @@ struct CmdEval : MixJSON, InstallableCommand
v = vRes;
}
- if (raw) {
+ if (writeTo) {
+ stopProgressBar();
+
+ if (pathExists(*writeTo))
+ throw Error("path '%s' already exists", *writeTo);
+
+ std::function<void(Value & v, const Pos & pos, const Path & path)> recurse;
+
+ recurse = [&](Value & v, const Pos & pos, const Path & path)
+ {
+ state->forceValue(v);
+ if (v.type() == nString)
+ // FIXME: disallow strings with contexts?
+ writeFile(path, v.string.s);
+ else if (v.type() == nAttrs) {
+ if (mkdir(path.c_str(), 0777) == -1)
+ throw SysError("creating directory '%s'", path);
+ for (auto & attr : *v.attrs)
+ try {
+ if (attr.name == "." || attr.name == "..")
+ throw Error("invalid file name '%s'", attr.name);
+ recurse(*attr.value, *attr.pos, path + "/" + std::string(attr.name));
+ } catch (Error & e) {
+ e.addTrace(*attr.pos, hintfmt("while evaluating the attribute '%s'", attr.name));
+ throw;
+ }
+ }
+ else
+ throw TypeError("value at '%s' is not a string or an attribute set", pos);
+ };
+
+ recurse(*v, pos, *writeTo);
+ }
+
+ else if (raw) {
stopProgressBar();
std::cout << state->coerceToString(noPos, *v, context);
- } else if (json) {
+ }
+
+ else if (json) {
JSONPlaceholder jsonOut(std::cout);
printValueAsJSON(*state, true, *v, jsonOut, context);
- } else {
+ }
+
+ else {
state->forceValueDeep(*v);
- logger->stdout("%s", *v);
+ logger->cout("%s", *v);
}
}
};