Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: introduce binPath #67392

Closed
wants to merge 7 commits into from
Closed

lib: introduce binPath #67392

wants to merge 7 commits into from

Conversation

zimbatm
Copy link
Member

@zimbatm zimbatm commented Aug 24, 2019

A lot of derivations have a main executable. For example pkgs.curl has
bin/curl, pkgs.bash has bin/bash. Writing those can be repetitive:

"${lib.getBin pkgs.bash}/bin/bash"

Introduce a new lib.binPath function that can be used to infer a
default binary path for all packages.

"${lib.binPath pkgs.bash}"

By default the binary is at $out/bin/$pname. For the package where that
doesn't match it's possible to provide a meta.binPath attribute that
contains the relative path to the binary.

Motivation for this change
Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nix-review --run "nix-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Ensured that relevant documentation is up to date
  • Fits CONTRIBUTING.md.
Notify maintainers

cc @

@zimbatm
Copy link
Member Author

zimbatm commented Aug 24, 2019

hmm, maybe only use builtins.parseDrvName to infer the binary name.

nix-repl> pkgs.lib.pkgBin pkgs.terraform.full 
"/nix/store/44gjizfr1v5lf9yhq9jvhvynsk9j8g5i-terraform-0.11.14/bin/terraform-with-plugins"

@zimbatm
Copy link
Member Author

zimbatm commented Aug 24, 2019

One idea is that if nixpkgs is consistently mapped, it will make it easy to build single-program containers with docker / firejail / ...

@zimbatm
Copy link
Member Author

zimbatm commented Aug 24, 2019

It would be nice to also be able to annotate which packages don't have a default executable so they can fail during evaluation.

@zimbatm
Copy link
Member Author

zimbatm commented Aug 24, 2019

renamed lib.pkgBin to lib.binPath so that there is only one term to learn.

@gloaming
Copy link
Contributor

binPath sounds like it would be bin/... That could be confusing for someone seeing it for the first time. MaybemainBin so it does what it says?

@gloaming
Copy link
Contributor

hmm, maybe only use builtins.parseDrvName to infer the binary name.

nix-repl> pkgs.lib.pkgBin pkgs.terraform.full 
"/nix/store/44gjizfr1v5lf9yhq9jvhvynsk9j8g5i-terraform-0.11.14/bin/terraform-with-plugins"

When wouldn't they return the same thing?

nix-repl> builtins.parseDrvName terraform.full.name
{ name = "terraform-with-plugins"; version = "0.11.14"; }

@gloaming
Copy link
Contributor

gloaming commented Aug 25, 2019

I was actually thinking about this recently in relation to NixOS modules :)

One concern I had is that a user might override a package with a new pname, and calls to the package would then fail. I don't see a way to solve this without adding the attribute to meta from mkDerivation, which would be a bit annoying.

However, I'm not sure to what extent anyone actually cares about being able to override the pname.

@@ -63,6 +63,9 @@ rec {
# Pointless to do this on a remote machine.
preferLocalBuild = true;
allowSubstitutes = false;
meta = {
binPath = destination;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe only for executables?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While working on this PR I discovered that there is already an executables (plural) attribute. I have no idea what it's for.

$ rg "executables = \["
pkgs/os-specific/linux/autofs/default.nix
45:    executables = [ "automount" ];

pkgs/tools/text/patchutils/generic.nix
23:    executables = [ "combinediff" "dehtmldiff" "editdiff" "espdiff"

pkgs/tools/backup/dirvish/default.nix
13:  executables = [ "dirvish" "dirvish-runall" "dirvish-expire" "dirvish-locate" ];

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

summoning @winpat who added dirvish

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quick review suggests those are used only for build process, so probably not a subject for this PR

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zimbatm What @danbst said.

Copy link
Contributor

@danbst danbst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good! Can you also add some real usages inside NixOS or Nixpkgs? Though I understand it's main purpose is to be used externally (by update bots most likely)

@danbst
Copy link
Contributor

danbst commented Aug 26, 2019

loosely related NixOS/nix#1049

@danbst
Copy link
Contributor

danbst commented Aug 26, 2019

also, loosely related https://github.com/NixOS/nixpkgs/pull/861/files. The idea is to force create /bin/foo symlinks if package attribute name is called foo, to minimize surprises.

With this PR, it could be inversed (as a NixOS module) - autocreate "/bin" symlinks based on pname and meta.binPath.

@zimbatm
Copy link
Member Author

zimbatm commented Aug 26, 2019

Good! Can you also add some real usages inside NixOS or Nixpkgs? Though I understand it's main purpose is to be used externally (by update bots most likely)

I will convert the code inside of nixpkgs once the naming has stabilized. Most calls to "${lib.getBin thepackage}/bin/thepackage" can be simplified to lib.mainBIn thepackage.

Once the API is stable I also think that tools like nix-bundle and dockerTools.buildImage can be adapted to work 99% of the time. nix-bundle nixpkgs.hello => get a distributable image

@domenkozar
Copy link
Member

domenkozar commented Aug 26, 2019

  • I think the name could be more descriptive like lib.getDefaultExecutable or maybe just lib.getExecutable

  • This function is going to fail a lot of times due to the missing file, it's seems like a slippery slope. It would be better to build another derivation that asserts the path really exists and is executable. A bit more development work with less overhead is to extend stdenv to assert drv.defaultExecutable exists at build time, so then only those packages that define that attribute can use the shortcut.

@gloaming
Copy link
Contributor

This could potentially benefit NixOS modules, see NixOS/rfcs#42 (comment)

@gloaming
Copy link
Contributor

I think the name could be more descriptive like lib.getDefaultExecutable or maybe just lib.getExecutable

Ehh, it's a bit long...

This function is going to fail a lot of times due to the missing file, it's seems like a slippery slope.

Well, the function can't fail, but I get what you mean. I'm not sure that it's much worse than doing it manually, but I guess it is akin to a partial function in some sense.

extend stdenv to assert drv.defaultExecutable exists at build time, so then only those packages that define that attribute can use the shortcut.

👍 I like this. Then we can, for example, require ExecStart to be defined iff there is no default binary for the options.package.

Copy link
Member

@FRidh FRidh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think packages should instead declare that variable in their passthru. E.g., for Python we have
python3.interpreter which is the path to the Python executable (python3.executable).

Don't we also somewhere have an attribute set which a bunch of these executables?

@matthewbauer
Copy link
Member

Once the API is stable I also think that tools like nix-bundle and dockerTools.buildImage can be adapted to work 99% of the time. nix-bundle nixpkgs.hello => get a distributable image

Yeah! That would be really nice. I had an old issue about this a while back:

NixOS/nix#2154

@edolstra wants to use the "defaultApp" in Flakes to accomplish this (NixOS/nix#2909), but we may be able to have some way to put this on plain derivations.

@zimbatm
Copy link
Member Author

zimbatm commented Nov 3, 2019

I'm not sure how to move this forward. @domenkozar has a good point that bad paths wouldn't be detected automatically. On the other hand adding a derivation per derivation is also a lot of overhead.

A lot of derivations have a *main* executable. For example pkgs.curl has
bin/curl, pkgs.bash has bin/bash. Writing those can be repetitive:

   "${lib.getBin pkgs.bash}/bin/bash"

Introduce a new `lib.binPath` function that can be used to infer a
default binary path for all packages.

   "${lib.binPath pkgs.bash}"

By default the binary is at $out/bin/$pname. For the package where that
doesn't match it's possible to provide a `meta.binPath` attribute that
contains the relative path to the binary.
Support the lib.binPath interface

    nix-repl> pkgs = import ./. {}
    nix-repl> pkg = pkgs.writeScript "foo" "hohoho"
    nix-repl> pkgs.lib.pkgBin pkg
    "/nix/store/v9xjci3rz9ck1amyfndh6wjz2f4d5v1l-foo"
    nix-repl> pkg2 = pkgs.writeScriptBin "foo" "hahaha"
    nix-repl> pkgs.lib.pkgBin pkg2
    "/nix/store/0zp2hj619874rh2g1v8n62958f6scp6f-foo/bin/foo"
@zimbatm zimbatm changed the title lib: introduce pkgBin lib: introduce binPath Jan 12, 2020
@zimbatm
Copy link
Member Author

zimbatm commented Mar 28, 2020

flakes are introducing a similar idea so maybe it's worth resurrecting this.

{ drv, name ? drv.pname or drv.name, exePath ? "/bin/${name}" }:
{
   type = "app";
   program = "${drv}${exePath}";
}

@zimbatm zimbatm mentioned this pull request Aug 16, 2020
10 tasks
@zimbatm
Copy link
Member Author

zimbatm commented Aug 16, 2020

replaced with #95615 which mimics the heuristic of nix run

@zimbatm zimbatm closed this Aug 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants