Nix: Nix 2.0: Print out path to stdout with nix build

Created on 1 Mar 2018  Â·  23Comments  Â·  Source: NixOS/nix

This served as an extremely useful tool with nix-build in conjunction with --no-out-link. Two extremely common use cases:

  • $(nix-build ...)/bin/foo
  • nix-store -qR $(nix-build ...)

It's just nice to interpolate the path without having to copy paste it, and to make sure that the command you're running definitely has the latest version of the nix build output. It would be nice to have this back with nix build.

new cli

Most helpful comment

What about -o -? Other command line tools often use - to represent stdin and stdout. Seems fitting in this case to use -o - to mean "Don't make symlinks; just print on stdout."

All 23 comments

Trying to script around this doesn't seem viable because of GC roots. You can't isolate what the outputs of nix build were without putting them in an isolated temp dir, or else you can't know if result-100 was from this build or a previous one. And if you put them there, then moving them where the user wanted will leave dangling symlinks in the GC roots. This is technically fine, but writing a script that inherently leaves behind unwanted dangling symlinks sounds bad.

Technically speaking I think the pattern nix-store -qR $(nix-build ...) was always slightly broken in that once the nix-build command prints out the path and exits the path could be GC'd before nix-store parses its arguments and locks the path or whatever it does.

It's not a problem if you can be sure a GC isn't running concurrently or something, but just a thought.

Couldn't the "moving them where the user wanted" be done with nix-store --add-root $newlocation --indirect /nix/store/path? Not sure I understand what you're doing re:users though :).

Couldn't the "moving them where the user wanted" be done with nix-store --add-root $newlocation --indirect /nix/store/path?

@dtzWill This would still leave dangling symlinks in your gc roots (EDIT: from the symlinks in the isolated temp directory). Again, not technically a problem, but definitely undesirable to have a command be guaranteed to leave behind unwanted symlinks.

I'm with @ElvishJerricco; I used the stdout a lot. Even "nix build --no-link" does not output anything, so no reference at all to the outcome.

If someone wants to make the $(nix-build ) thing GC-safe, that can use a mktemp as symlink and then delete it. Annoying to impose this, though.

@viric I did figure out how to make such a thing, but it uses nix-store --delete (no argument) to wipe all hanging symlinks. I'd prefer to only wipe the ones created by the command, but this is somewhat reasonable.

https://gist.github.com/ElvishJerricco/e8193a5b4734877bc492e870625bc92f

@shlevy Thanks for that. To be clear though, I don't think a wrapper script is a good solution to this issue. It'd be far easier if nix build just output the paths. It seems really odd to me that nix build --no-link would just produce no usable output.

Maybe paths should only be output if --no-link is specified?

@ElvishJerricco This doesn't address the output path issue, just the GC safety issue that you have even with nix-build --no-out-link

sry if that's a bit but offtrack but what to do with multiple outputs ? I wished for nix-build to display all the built output paths but it only displays the first outputs = [ "dev" "out" "lib" ]; will display "$dev". It seems a bit brittle. Also nix-build will only create ./result-dev, I would expect ./result-lib to be created too.

@ElvishJerricco try building "foo.all" instead of "foo"! I use this often :).

@dtzWill Did you mean to mention @teto?

@dtzWill Did you mean to mention @teto?

Yes! Haha sorry about that.

Printing a link to stdout is very useful for simple (and maybe even single-use) interactive scripts where it is assumed that the user knows there is no GC running…

By the way, nix build applied to a .drv doesn't seem to create the result link by default, either (which is natural as it inherits behaviour from nix-store), so even with no extra flags there are cases where nix build doesn't produce anything pointing to the output.

Related: #1647

What about -o -? Other command line tools often use - to represent stdin and stdout. Seems fitting in this case to use -o - to mean "Don't make symlinks; just print on stdout."

Of course, it'd be good to be able to do both...

This also prevents nixos-rebuild using nix 2.0 commands, since it relies quite a bit on getting the result path on stdout.

@michaelpj you could place out links in a tmp directory and readlink them.

If you only care about getting stuff on stdout, and not the out links, path-info enables a pretty simple wrapper:

nbuild() {
  nix build --no-link "$@"
  nix path-info "$@"
}

Of course this evaluates expressions twice as many times....

Is #2423 all we need, or do we want to change the default? Personally, I'm only ever using the symlink or the stdout, not both, so #2423 is enough for me.

It seems a bit weird to link it to the out-link flag - they seem orthogonal to me.

Theoretically orthogonal, but they are two possible answers to «how do you want to get the result», so wanting a single one (either of the two) is way more typical than both or neither

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pjotrp picture pjotrp  Â·  37Comments

LisannaAtHome picture LisannaAtHome  Â·  42Comments

lilyball picture lilyball  Â·  67Comments

taktoa picture taktoa  Â·  35Comments

ryanbooker picture ryanbooker  Â·  34Comments