diff options
Diffstat (limited to 'src/nix/eval.cc')
-rw-r--r-- | src/nix/eval.cc | 92 |
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); } } }; |