Skip to content

Commit

Permalink
feat: add --apply flag
Browse files Browse the repository at this point in the history
Allow applying every eval'ed drv to a provided nix expression to evaluate arbitrary fields.

EXAMPLE

```
% ./result/bin/nix-eval-jobs --flake github:NixOS/patchelf#hydraJobs \
  --apply \
  'drv: {
     version = if drv ? version then drv.version else null;
   }'
warning: `--gc-roots-dir' not specified
{"attr":"coverage","attrPath":["coverage"],"version":null}
{"attr":"patchelf-win32","attrPath":["patchelf-win32"],"version":"0.18.0"}
{"attr":"patchelf-win64","attrPath":["patchelf-win64"],"version":"0.18.0"}
{"attr":"release","attrPath":["release"],"version":null}
{"attr":"tarball","attrPath":["tarball"],"version":"0.18.0"}
```
  • Loading branch information
ysndr committed Jan 15, 2025
1 parent cbae915 commit c6160ec
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ executable.
$ nix-eval-jobs --help
USAGE: nix-eval-jobs [options] expr

--apply apply the derivation to the provided Nix expression
--arg Pass the value *expr* as the argument *name* to Nix functions.
--argstr Pass the string *string* as the argument *name* to Nix functions.
--check-cache-status Check if the derivations are present locally or in any configured substituters (i.e. binary cache). The information will be exposed in the `cacheStatus` field of the JSON output.
Expand Down
6 changes: 6 additions & 0 deletions src/eval-args.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ MyArgs::MyArgs() : MixCommonArgs("nix-eval-jobs") {
.description = "treat the argument as a Nix expression",
.handler = {&fromArgs, true}});

addFlag(
{.longName = "apply",
.description = "apply the derivation to the provided Nix expression",
.labels = {"expr"},
.handler = {&applyExpr}});

// usually in MixFlakeOptions
addFlag({
.longName = "override-input",
Expand Down
1 change: 1 addition & 0 deletions src/eval-args.hh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class MyArgs : virtual public nix::MixEvalArgs,
public:
virtual ~MyArgs() = default;
std::string releaseExpr;
std::string applyExpr;
nix::Path gcRootsDir;
bool flake = false;
bool fromArgs = false;
Expand Down
22 changes: 22 additions & 0 deletions src/worker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <nix/attr-path.hh>
#include <nix/local-fs-store.hh>
#include <nix/installable-flake.hh>
#include <nix/value-to-json.hh>
#include <sys/resource.h>
#include <nlohmann/json.hpp>
#include <cstdio>
Expand Down Expand Up @@ -147,6 +148,7 @@ void worker(

if (v->type() == nix::nAttrs) {
if (auto packageInfo = nix::getDerivation(*state, *v, false)) {

std::optional<Constituents> maybeConstituents;
if (args.constituents) {
std::vector<std::string> constituents;
Expand Down Expand Up @@ -203,6 +205,26 @@ void worker(
}
maybeConstituents =
Constituents(constituents, namedConstituents);
} else if (args.applyExpr != "") {
auto applyExpr = state->parseExprFromString(
args.applyExpr, state->rootPath("."));

nix::Value vApply;
nix::Value vRes;

state->eval(applyExpr, vApply);

state->callFunction(vApply, *v, vRes, nix::noPos);
state->forceAttrs(
vRes, nix::noPos,
"apply needs to evaluate to an attrset");

nix::NixStringContext context;
std::stringstream ss;
nix::printValueAsJSON(*state, true, vRes, nix::noPos,
ss, context);

reply.update(nlohmann::json::parse(ss.str()));
}
auto drv = Drv(attrPathS, *state, *packageInfo, args,
maybeConstituents);
Expand Down
45 changes: 45 additions & 0 deletions tests/test_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,51 @@ def test_constituents_error() -> None:
assert aggregate["constituents"] == []


def test_apply() -> None:
with TemporaryDirectory() as tempdir:
applyExpr = """drv: {
the-name = drv.name;
version = drv.version or null;
}"""

cmd = [
str(BIN),
"--gc-roots-dir",
tempdir,
"--workers",
"1",
"--apply",
applyExpr,
"--flake",
".#hydraJobs",
]
res = subprocess.run(
cmd,
cwd=TEST_ROOT.joinpath("assets"),
text=True,
check=True,
stdout=subprocess.PIPE,
)

print(res.stdout)
results = [json.loads(r) for r in res.stdout.split("\n") if r]

assert len(results) == 5 # sanity check that we assert against all jobs

# Check that nix-eval-jobs applied the expression correctly
# and extracted 'version' as 'version' and 'name' as 'the-name'
assert results[0]["the-name"] == "job1"
assert results[0]["version"] is None
assert results[1]["the-name"].startswith("nix-")
assert results[1]["version"] is not None
assert results[2]["the-name"] == "package-with-deps"
assert results[2]["version"] is None
assert results[3]["the-name"] == "drvB"
assert results[3]["version"] is None
assert results[4]["the-name"].startswith("nix-")
assert results[4]["version"] is not None


@pytest.mark.infiniterecursion
def test_recursion_error() -> None:
with TemporaryDirectory() as tempdir:
Expand Down

0 comments on commit c6160ec

Please sign in to comment.