NixOS / nix

Nix, the purely functional package manager
https://nixos.org/
GNU Lesser General Public License v2.1
11.93k stars 1.46k forks source link

Unified profile script that detects single-user vs multi-user #3630

Open lilyball opened 4 years ago

lilyball commented 4 years ago

Is your feature request related to a problem? Please describe. A problem I have when writing tooling that wants to use Nix outside the context of a terminal is making it support both single-user and multi-user Nix installs. The problem is that a different profile script needs to be sourced for single-user vs multi-user in order to set up the environment for accessing Nix-installed stuff.

Describe the solution you'd like I'd really like a single profile script I can source that detects whether it's a single-user or a multi-user install. This could replace both existing scripts, or it could just source whichever one is correct; the latter is more appropriate if the test for single-user vs multi-user isn't sufficiently cheap.

This also requires having some official way to tell the difference between the two prior to sourcing any scripts. This mechanism should not be "check for the existence of nixbld1" or anything like that as rm -rf /nix doesn't clear that up; ideally it's some defined path in /nix that only exists for multi-user installs, preferably something stable that external tooling can use too without worrying about it changing in a later release.

Describe alternatives you've considered If Nix just provides the official "here's how you detect a multi-user install outside of a bash login shell" then I can pick the profile script to source myself, but simplifying it by having a script that does that already would be very convenient.

LnL7 commented 4 years ago

Before nix autodetected the daemon there was a snippet in nixpkgs that checked whether /nix/var/nix/db is writable and would set NIX_REMOTE accordingly. That's still what nix uses internally to resolve --store auto AFAIK.

lilyball commented 4 years ago

A concern I have with that is I believe /nix/var/nix/db is owned and writable by root, right? (I'm on a single-user install right now so I can't verify this on a non-NixOS system, but the install scripts suggest this is the case). So root is still supposed to source nix-daemon.sh. But in my external tooling, if it's running as root then using test -w /nix/var/nix/db would tell me it's single-user. This test may work for determining whether it's okay to manipulate the store, but using it would result in setting up the wrong env vars (e.g. the single-user install doesn't put /nix/var/nix/profiles/default into the PATH).

To be fair, I'm not expecting my tooling to be run as root, but it would be great to have a solution that works. And I don't want my tooling to run a bash interactive shell because I don't want per-user configuration to screw with it. I suppose I could source /etc/bashrc and then check if Nix has been set up, and if not then source the single-user profile script, but that still seems awkward, and it risks other system-wide configuration being weird (for example on macOS if the var TERM_PROGRAM exists then /etc/bashrc sets up a bunch of session saving/restoration stuff; that var shouldn't exist for my external tooling but it's an example of how /etc/bashrc is liable to assume that we're running from a terminal).

Looking at /nix/var/nix right now my NixOS machine has /nix/var/nix/daemon-socket and my single-user macOS install doesn't; if this exists on all multi-user installs (not just NixOS) then it's a candidate for detection. But I don't like the idea of rolling my own detection because without being officially sanctioned by Nix it runs the risk of breaking, just like how I have a script right now that checked NIX_REMOTE except that's no longer set for multi-user installs >_<

LnL7 commented 4 years ago

Yeah both the user and and write access where tested.

https://github.com/NixOS/nixpkgs/blob/4e0d6a5ff8157e6aacb1ef0b948d0b7dca36341f/nixos/modules/services/misc/nix-daemon.nix#L465-L469

lilyball commented 4 years ago

The test there was "if user isn't root OR /nix/var/nix/db isn't writable". This is the nix-daemon.sh script so it's already assuming it's multi-user. The ! -w /nix/var/nix/db test was introduced because

In NixOS containers, root doesn't have write permission to /nix/var/nix/db, so it has to use the daemon.

lilyball commented 4 years ago

I've just realized that in a multi-user scenario you don't use ~/.nix-profile/etc/profile.d/* at all, so a unified script actually doesn't help as there wouldn't be a unified path (unless it's at a constant path within the nix store itself). So perhaps just focusing on an officially-supported and documented way to test if we're in a single-user vs multi-user install would be best.

lilyball commented 4 years ago

I guess a unified script would actually work after all, because I could then just do something like

if test -e ~/.nix-profile/etc/profile.d/unified-nix.sh; then
  . ~/.nix-profile/etc/profile.d/unified-nix.sh
elif test -e /nix/var/nix/profiles/default/etc/profile.d/unified-nix.sh; then
  . /nix/var/nix/profiles/default/etc/profile.d/unified-nix.sh
fi
lilyball commented 3 years ago

It occurs to me the simplest solution may be to just have the installer write a file somewhere in /nix that sources the appropriate path based on install type. For single-user it would want to silently do nothing if the user's profile script path doesn't exist (so it can be sourced from other users and not throw an error). The downside of course is existing installs won't have it.

nixos-discourse commented 3 years ago

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/what-is-the-simplest-way-if-one-has-single-or-multi-user-nix-installed/13882/2

stale[bot] commented 2 years ago

I marked this as stale due to inactivity. → More info