I’m trying to write a very simple derivation that does not use a builder shell script, but rather calls a tool directly for simplicity/efficiency.
Let’s say that it looks something like the following:
derivation {
name = "hello";
system = "x86_64-linux";
builder = "${pkgs.cue}/bin/cue";
args = [
"export"
./hello.cue
"--outfile"
"$out"
"--out"
"yaml"
];
}
I’ve randomly picked CUE as an example because it’s a pretty simple tool that takes an input and outputs a file at a given location.
This does not work, because $out is treated as a literal file path, and not substituted with the environment variable. This seems to mean
For comparison, in Buck2 (and Bazel works basically the same way), I would write a rule (i.e. a function that produces targets, roughly equivalent to a function that returns a derivation in Nix) that looks something like the following:
def cue(ctx: AnalysisContext):
output = ctx.actions.declare_output("hello.yaml")
# Taking `cue` from the system for brevity, it would normally be a store path.
ctx.actions.run([
"cue",
"export",
ctx.attrs.src,
"--outfile",
output.as_output(),
"--out",
"yaml",
])
return output
(I’ve intentionally simplified the above a little bit to remove irrelevant boilerplate and make it more palatable to non-Buck users, don’t try running this at home as-is)
The point is: Buck can directly exec the cue binary and pass it an output path to write to, without wrapping it in a shell script just to grab $out from the environment.
Is something similar possible in Nix?