diff --git a/doc/manual/rl-next/profile-flags.md b/doc/manual/rl-next/profile-flags.md new file mode 100644 index 00000000000..1491a2fc2d5 --- /dev/null +++ b/doc/manual/rl-next/profile-flags.md @@ -0,0 +1,7 @@ +--- +synopsis: Profile Flags +prs: 8531 +--- + +Commands acting on profiles now have `--global-profile` and `--user-profile` flags as a short hand for these default profiles. +This makes explicit the differences between root and non-root, which could only be described obliquely before. diff --git a/doc/manual/src/command-ref/files/channels.md b/doc/manual/src/command-ref/files/channels.md index 7b1f271280b..599429cfd5a 100644 --- a/doc/manual/src/command-ref/files/channels.md +++ b/doc/manual/src/command-ref/files/channels.md @@ -1,13 +1,25 @@ ## Channels -A directory containing symlinks to Nix channels, managed by [`nix-channel`]: +A directory containing symlinks to Nix channels, managed by [`nix-channel`]. -- `$XDG_STATE_HOME/nix/profiles/channels` for regular users -- `$NIX_STATE_DIR/profiles/per-user/root/channels` for `root` - -[`nix-channel`] uses a [profile](@docroot@/command-ref/files/profiles.md) to store channels. +The channels directory is a [profile](@docroot@/command-ref/files/profiles.md), so as to allow easy management of multiple versions and switching between them. This profile contains symlinks to the contents of those channels. +### User-specific and global channels + +Channels are managed either for a specific user, or for all users globally on the system to share. +This matches the [user-specific vs global conventions](@docroot@/command-ref/files/profiles.md#user-specific-and-global-profiles) of profiles themselves. + +- [User-specific channels]{#user-channels} are stored in: + ``` + $XDG_STATE_HOME/nix/profiles/channels + ``` + +- [Global channels]{#global-channels} are stored in + ``` + $NIX_STATE_DIR/profiles/per-user/root/channels + ``` + ## Subscribed channels The list of subscribed channels is stored in diff --git a/doc/manual/src/command-ref/files/default-nix-expression.md b/doc/manual/src/command-ref/files/default-nix-expression.md index 620f7035c58..d4a0c2f4580 100644 --- a/doc/manual/src/command-ref/files/default-nix-expression.md +++ b/doc/manual/src/command-ref/files/default-nix-expression.md @@ -42,8 +42,8 @@ A symlink that ensures that [`nix-env`] can find your channels: This symlink points to: -- `$XDG_STATE_HOME/profiles/channels` for regular users -- `$NIX_STATE_DIR/profiles/per-user/root/channels` for `root` +- The [user-specific channels](@docroot@/command-ref/files/profiles.md#user-channels) (`$XDG_STATE_HOME/profiles/channels`) for regular users +- The [global channels](@docroot@/command-ref/files/profiles.md#global-channels) (`$NIX_STATE_DIR/profiles/per-user/root/channels`) for `root` In a multi-user installation, you may also have `~/.nix-defexpr/channels_root`, which links to the channels of the root user.[`nix-env`]: ../nix-env.md diff --git a/doc/manual/src/command-ref/files/profiles.md b/doc/manual/src/command-ref/files/profiles.md index b5c7378800f..31c467479ce 100644 --- a/doc/manual/src/command-ref/files/profiles.md +++ b/doc/manual/src/command-ref/files/profiles.md @@ -1,11 +1,32 @@ ## Profiles -A directory that contains links to profiles managed by [`nix-env`] and [`nix profile`]: +A directory that contains links to profiles managed by [`nix-env`] and [`nix profile`]. -- `$XDG_STATE_HOME/nix/profiles` for regular users -- `$NIX_STATE_DIR/profiles/per-user/root` if the user is `root` +### [User-specific and global profiles]{#user-specific-and-global-profiles} -A profile is a directory of symlinks to files in the Nix store. +Profiles can be placed in any directory, but by default, different locations are used depending on whether the profile is intended to be used by a single user, or shared globally by all users. + +- The default directory for user-specific profiles is: + ``` + $XDG_STATE_HOME/nix/profiles + ``` + + Within it, the [default user profile]{#default-user-profile} is: + ``` + $XDG_STATE_HOME/nix/profiles/profile + ``` + +- The default directory for global profiles is + ``` + $NIX_STATE_DIR/profiles + ``` + + Within it, the [default global profile]{#default-global-profile} is + ``` + $NIX_STATE_DIR/profiles/default + ``` + +Nix command will default to the default user profile for regular users, and the default global profiles for root, but often provide flags to override this behavior. ### Filesystem layout @@ -63,8 +84,8 @@ A symbolic link to the user's current profile: By default, this symlink points to: -- `$XDG_STATE_HOME/nix/profiles/profile` for regular users -- `$NIX_STATE_DIR/profiles/per-user/root/profile` for `root` +- The [default user profile](#default-user-profile) (`$XDG_STATE_HOME/nix/profiles/profile`) for regular users +- The [default global profile](#default-global-profile) (`$NIX_STATE_DIR/profiles/per-user/root/profile`) for `root` The `PATH` environment variable should include `/bin` subdirectory of the profile link (e.g. `~/.nix-profile/bin`) for the user environment to be visible to the user. The [installer](@docroot@/installation/installing-binary.md) sets this up by default, unless you enable [`use-xdg-base-directories`]. diff --git a/doc/manual/src/command-ref/nix-channel.md b/doc/manual/src/command-ref/nix-channel.md index cebbc7b00d0..0bbf43047aa 100644 --- a/doc/manual/src/command-ref/nix-channel.md +++ b/doc/manual/src/command-ref/nix-channel.md @@ -62,6 +62,16 @@ This command has the following operations: Revert channels to the state before the last call to `nix-channel --update`. Optionally, you can specify a specific channel *generation* number to restore. +It also has the following flags, which affect all operations: + + - `--global-profile`\ + Operate on the [global channels](@docroot@/command-ref/files/channels.md#global-channels), i.e. the channels shared by all users. + + - `--user-profile`\ + Operate on the [user channels](@docroot@/command-ref/files/channels.md#user-channels), i.e. the channels just for the current user. + +The list of subscribed channels is stored in `~/.nix-channels`. + {{#include ./opt-common.md}} {{#include ./env-common.md}} diff --git a/doc/manual/src/command-ref/nix-env.md b/doc/manual/src/command-ref/nix-env.md index c6f627365a5..f3f0e5024dd 100644 --- a/doc/manual/src/command-ref/nix-env.md +++ b/doc/manual/src/command-ref/nix-env.md @@ -9,7 +9,7 @@ [`--arg` *name* *value*] [`--argstr` *name* *value*] [{`--file` | `-f`} *path*] - [{`--profile` | `-p`} *path*] + [{`--profile` | `-p`} *path* | `--global-profile` | `--user-profile`] [`--system-filter` *system*] [`--dry-run`] diff --git a/doc/manual/src/command-ref/nix-env/opt-common.md b/doc/manual/src/command-ref/nix-env/opt-common.md index 636281b6d36..27626f78e61 100644 --- a/doc/manual/src/command-ref/nix-env/opt-common.md +++ b/doc/manual/src/command-ref/nix-env/opt-common.md @@ -19,6 +19,16 @@ The following options are allowed for all `nix-env` operations, but may not alwa sequence of user environments called *generations*, one of which is the *current generation*. + - `--user-profile`\ + Specifies the profile as the [default user profile](@docroot@/command-ref/files/profiles.md#default-user-profile) private to this user. + This is a shorthand for passing `--profile` and the path to that default profile. + This is default if the current user is not root. + + - `--global-profile`\ + Specifies the profile as the [default global profile](@docroot@/command-ref/files/profiles.md#default-global-profile) shared between all users. + A shorthand instead of passing `--profile` and the path to that default profile. + This is default if the current user is root. + - `--dry-run`\ For the `--install`, `--upgrade`, `--uninstall`, `--switch-generation`, `--delete-generations` and `--rollback` diff --git a/doc/manual/src/contributing/config-guideline.md b/doc/manual/src/contributing/config-guideline.md new file mode 100644 index 00000000000..ebcaa510f67 --- /dev/null +++ b/doc/manual/src/contributing/config-guideline.md @@ -0,0 +1,47 @@ +# Configuration guidelines + +## Don't just autodetect the environment + +Nix can be run in a variety of different ways with different permissions. +Regular users and the super user ("root") can run Nix. +Nix can be be run inside other tool's sandboxes too. + +It can be tempting to try to "make Nix work" by changing what it does based on what permissions we have. +E.g. if there is some operation we don't think will work as a regular user, we might skip it as `getuid() != 0`. + +The problem with just doing this, however, is that it creates more uncertainty for the user. +Nix operations are supposed to be reproducible, but if we start "bending the rules" based on how Nix is run, it gets increasingly likely that an operation would succeed with different results. + +The compromise is as follows: + +1. Whenever one wants to condition some operation on an expression like `getuid() != 0`, instead condition it on a boolean setting. + +2. Make the setting's default value the condition one would have used. + +This still provides the convenience of trying to make things work, but it congregates those suspect impure conditionals in just a select few places, namely where the settings re defined. +This makes it easy to, at glance, see all the ways the current environment influences what is being done. + +> In the future we plan on making the default expressions (e.g. not just the values they might happen to evaluate to, like just `true` or `false`) show up in the docs for the settings, so finding all such settings as described above is in fact easy. +> Consulting the source code to get this information should not be necessary. + +It also makes it easy to ensure that things like `getuid()` cannot matter, by explicitly forcing all those options with conditional defaults one way or the other. + +### Examples + +- The default profile + + The default profile is a user-specific one for regular users, but the global one for root. + Rather than just having a conditional method when looking up its path, instead be able to (unconditionally) look up either a per-user or global profile. + Expose both options, but if neither is explicitly chosen, only then make the choice of which option based on `getuid() == 0`. + +- [`require-drop-supplementary-groups`](@docroot@/command-ref/conf-file.md#conf-require-drop-supplementary-groups) + + We always want to drop as many permissions as possible when performing builds, to prevent the derivation being built from doing things we do not expect and do not want it to do. + Part of this is dropping "supplementary groups", which are groups in addition to a user's "primary group". + For non-root users we do not expect this to succeed, because special privilages are required to do this (see the setting for details). + For root users so do expect this to succeed, but inside Linux user namespaces the "fake" root we have may still fail. + + Rather than conditionally attempt this operation on whether we are root, we always attempt it, and conditionally abort the build if we get a permission error. + (Other non-permission errors are still abort the build unconditionally.) + Furthermore the condition to ignore the permission failure here is not directly based on `getuid() == 0`, but instead `require-drop-supplementary-groups`. + Rather, that setting is defaulted based upon `getuid() == 0`. diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 543250da3ac..ceb22c142c9 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -283,7 +283,24 @@ void MixProfile::updateProfile(const BuiltPaths & buildables) MixDefaultProfile::MixDefaultProfile() { - profile = getDefaultProfile(); + + addFlag({ + .longName = "user-profile", + .description = "Act on the profile for this current user", + .handler = {[this]() { + profile = getDefaultProfile(DefaultProfileKind::User); + }} + }); + + addFlag({ + .longName = "global-profile", + .description = "Act on the global profile shared between all default users", + .handler = {[this]() { + profile = getDefaultProfile(DefaultProfileKind::Global); + }} + }); + + profile = getDefaultProfile(defaultDefaultProfileKind()); } MixEnvironment::MixEnvironment() : ignoreEnvironment(false) diff --git a/src/libexpr/eval-settings.cc b/src/libexpr/eval-settings.cc index 2ccbe327fad..86cd8c03301 100644 --- a/src/libexpr/eval-settings.cc +++ b/src/libexpr/eval-settings.cc @@ -1,6 +1,7 @@ #include "users.hh" #include "globals.hh" #include "profiles.hh" +#include "profiles/channels.hh" #include "eval.hh" #include "eval-settings.hh" @@ -65,8 +66,8 @@ Strings EvalSettings::getDefaultNixPath() if (!evalSettings.restrictEval && !evalSettings.pureEval) { add(getNixDefExpr() + "/channels"); - add(rootChannelsDir() + "/nixpkgs", "nixpkgs"); - add(rootChannelsDir()); + add(globalChannelsDir() + "/nixpkgs", "nixpkgs"); + add(globalChannelsDir()); } return res; diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc index d0da9626213..07acbed091d 100644 --- a/src/libstore/profiles.cc +++ b/src/libstore/profiles.cc @@ -73,6 +73,9 @@ static Path makeName(const Path & profile, GenerationNumber num) Path createGeneration(LocalFSStore & store, Path profile, StorePath outPath) { + /* Make sure the directory for this profile exists. */ + createDirs(dirOf(profile)); + /* The new generation number should be higher than old the previous ones. */ auto [gens, dummy] = findGenerations(profile); @@ -305,36 +308,95 @@ std::string optimisticLockProfile(const Path & profile) } -Path profilesDir() +Path userProfilesDir() { - auto profileRoot = - isRootUser() - ? rootProfilesDir() - : createNixStateDir() + "/profiles"; + auto profileRoot = createNixStateDir() + "/profiles"; createDirs(profileRoot); return profileRoot; } -Path rootProfilesDir() +/** + * Return the path to the global profile directory (but don't try creating it) + * + * Just used for the global profile and the global channels, but those + * go in different subdirs, so we do not expose this. + */ +static Path globalProfilesDir() +{ + return settings.nixStateDir + "/profiles"; +} + +/** + * The other directory used for global profiles + */ +static Path perUsersRootDir() { - return settings.nixStateDir + "/profiles/per-user/root"; + return globalProfilesDir() + "/per-user/root/"; } +std::vector globalProfilesDirs() +{ + return { + globalProfilesDir(), + perUsersRootDir(), + }; +} -Path getDefaultProfile() +/** + * The default per-user profile. + */ +static Path getDefaultUserProfile() { - Path profileLink = settings.useXDGBaseDirectories ? createNixStateDir() + "/profile" : getHome() + "/.nix-profile"; + return userProfilesDir() + "/profile"; +} + +/** + * The default global profile. + */ +static Path getDefaultGlobalProfile() +{ + return globalProfilesDir() + "/default"; +} + +DefaultProfileKind defaultDefaultProfileKind() +{ + return isRootUser() + ? DefaultProfileKind::Global + : DefaultProfileKind::User; +} + +Path defaultProfileLink() +{ + return settings.useXDGBaseDirectories ? createNixStateDir() + "/profile" : getHome() + "/.nix-profile"; +} + +std::optional tryGetDefaultProfile() +{ + Path profileLink = defaultProfileLink(); + if (pathExists(profileLink)) + return absPath(readLink(profileLink), dirOf(profileLink)); + else + return std::nullopt; +} + +Path getDefaultProfile(DefaultProfileKind profileKind) +{ + Path profileLink = defaultProfileLink(); try { - auto profile = profilesDir() + "/profile"; if (!pathExists(profileLink)) { + Path profile; + switch (profileKind) { + case DefaultProfileKind::Global: + profile = getDefaultGlobalProfile(); + break; + case DefaultProfileKind::User: + profile = getDefaultUserProfile(); + break; + default: + assert(false); + } replaceSymlink(profile, profileLink); } - // Backwards compatibiliy measure: Make root's profile available as - // `.../default` as it's what NixOS and most of the init scripts expect - Path globalProfileLink = settings.nixStateDir + "/profiles/default"; - if (isRootUser() && !pathExists(globalProfileLink)) { - replaceSymlink(profile, globalProfileLink); - } return absPath(readLink(profileLink), dirOf(profileLink)); } catch (Error &) { return profileLink; @@ -343,14 +405,17 @@ Path getDefaultProfile() } } -Path defaultChannelsDir() +Path userChannelsDir() { - return profilesDir() + "/channels"; + return userProfilesDir() + "/channels"; } -Path rootChannelsDir() +Path globalChannelsDir() { - return rootProfilesDir() + "/channels"; + /* "per-user" might seem like a weird thing to include in the path + to the "global" channels dir; it is done this way for + back-compat. */ + return perUsersRootDir() + "/channels"; } } diff --git a/src/libstore/profiles.hh b/src/libstore/profiles.hh index b10a72330b4..0522e23e578 100644 --- a/src/libstore/profiles.hh +++ b/src/libstore/profiles.hh @@ -211,28 +211,60 @@ std::string optimisticLockProfile(const Path & profile); * Create and return the path to a directory suitable for storing the user’s * profiles. */ -Path profilesDir(); +Path userProfilesDir(); /** - * Return the path to the profile directory for root (but don't try creating it) + * Create and return the paths to the directories use for storing the + * global profiles. There are multiple for backwards compatibility + * reasons. */ -Path rootProfilesDir(); +std::vector globalProfilesDirs(); /** - * Create and return the path to the file used for storing the users's channels + * We have two types of default profiles: + * + * - User, just for the current user (read/write). + * + * - Global, shared (read-only) by all users. + */ +enum class DefaultProfileKind +{ + User, + Global, +}; + +/** + * Returns the default kind of default profile. + * + * For regular users, this is `DefaultProfileKind::User`, but for root it is `DefaultProfileKind::Global`. */ -Path defaultChannelsDir(); +DefaultProfileKind defaultDefaultProfileKind(); /** - * Return the path to the channel directory for root (but don't try creating it) + * The path to the link (itself, not its target) defining the default profile. + * + * It is `~/.nix-profile` by default, `$XDG_STATE_HOME/nix/profile` if + * XDG Base Directory Support is enabled). + */ +Path defaultProfileLink(); + +/** + * Resolve the default profile (as indicated by `defaultProfileLink()`). + * + * If it doesn't exist, return `std::nullopt`. */ -Path rootChannelsDir(); +std::optional tryGetDefaultProfile(); /** - * Resolve the default profile (~/.nix-profile by default, - * $XDG_STATE_HOME/nix/profile if XDG Base Directory Support is enabled), - * and create if doesn't exist + * Resolve the default profile (just `tryGetDefaultProfile()`), + * but also create if doesn't exist. + * + * If something goes wrong, just return the path to the link itself. + * + * @todo Why do squelch failures this way? + * + * @param kind Just used if the profile doesn't exist. */ -Path getDefaultProfile(); +Path getDefaultProfile(DefaultProfileKind kind); } diff --git a/src/libstore/profiles/channels.hh b/src/libstore/profiles/channels.hh new file mode 100644 index 00000000000..b01c5decefa --- /dev/null +++ b/src/libstore/profiles/channels.hh @@ -0,0 +1,17 @@ +#pragma once + +#include "types.hh" + +namespace nix { + +/** + * Create and return the path to the file used for storing the user's channels + */ +Path userChannelsDir(); + +/** + * Return the path to the global channel directory (but don't try creating it) + */ +Path globalChannelsDir(); + +} diff --git a/src/nix-channel/nix-channel.cc b/src/nix-channel/nix-channel.cc index 9f7f557b59d..558f7df1b3a 100644 --- a/src/nix-channel/nix-channel.cc +++ b/src/nix-channel/nix-channel.cc @@ -1,4 +1,5 @@ #include "profiles.hh" +#include "profiles/channels.hh" #include "shared.hh" #include "globals.hh" #include "filetransfer.hh" @@ -168,10 +169,6 @@ static int main_nix_channel(int argc, char ** argv) channelsList = settings.useXDGBaseDirectories ? createNixStateDir() + "/channels" : home + "/.nix-channels"; nixDefExpr = getNixDefExpr(); - // Figure out the name of the channels profile. - profile = profilesDir() + "/channels"; - createDirs(dirOf(profile)); - enum { cNone, cAdd, @@ -181,6 +178,9 @@ static int main_nix_channel(int argc, char ** argv) cListGenerations, cRollback } cmd = cNone; + + DefaultProfileKind profileKind = defaultDefaultProfileKind(); + std::vector args; parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { if (*arg == "--help") { @@ -199,6 +199,10 @@ static int main_nix_channel(int argc, char ** argv) cmd = cListGenerations; } else if (*arg == "--rollback") { cmd = cRollback; + } else if (*arg == "--user-profile") { + profileKind = DefaultProfileKind::User; + } else if (*arg == "--global-profile") { + profileKind = DefaultProfileKind::Global; } else { if (hasPrefix(*arg, "-")) throw UsageError("unsupported argument '%s'", *arg); @@ -207,6 +211,19 @@ static int main_nix_channel(int argc, char ** argv) return true; }); + // Figure out the name of the channels profile. + switch (profileKind) { + case DefaultProfileKind::User: + profile = userChannelsDir(); + break; + case DefaultProfileKind::Global: + profile = globalChannelsDir(); + break; + default: + assert(false); + }; + createDirs(dirOf(profile)); + switch (cmd) { case cNone: throw UsageError("no command specified"); diff --git a/src/nix-collect-garbage/nix-collect-garbage.cc b/src/nix-collect-garbage/nix-collect-garbage.cc index 91209c97898..16206c8e48e 100644 --- a/src/nix-collect-garbage/nix-collect-garbage.cc +++ b/src/nix-collect-garbage/nix-collect-garbage.cc @@ -82,7 +82,12 @@ static int main_nix_collect_garbage(int argc, char * * argv) if (removeOld) { std::set dirsToClean = { - profilesDir(), settings.nixStateDir + "/profiles", dirOf(getDefaultProfile())}; + userProfilesDir(), + }; + if (auto optProfile = tryGetDefaultProfile()) + dirsToClean.insert(dirOf(*optProfile)); + for (auto && dir : globalProfilesDirs()) + dirsToClean.insert(std::move(dir)); for (auto & dir : dirsToClean) removeOldGenerations(dir); } diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index b5e13cc2308..94899778fb5 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -7,6 +7,7 @@ #include "globals.hh" #include "names.hh" #include "profiles.hh" +#include "profiles/channels.hh" #include "path-with-outputs.hh" #include "shared.hh" #include "store-api.hh" @@ -56,6 +57,7 @@ struct InstallSourceInfo struct Globals { InstallSourceInfo instSource; + std::optional profileKind; Path profile; std::shared_ptr state; bool dryRun; @@ -1296,7 +1298,7 @@ static void opSwitchProfile(Globals & globals, Strings opFlags, Strings opArgs) throw UsageError("exactly one argument expected"); Path profile = absPath(opArgs.front()); - Path profileLink = settings.useXDGBaseDirectories ? createNixStateDir() + "/profile" : getHome() + "/.nix-profile"; + Path profileLink = defaultProfileLink(); switchLink(profileLink, profile); } @@ -1409,29 +1411,13 @@ static int main_nix_env(int argc, char * * argv) Globals globals; - globals.instSource.type = srcUnknown; - globals.instSource.systemFilter = "*"; - - Path nixExprPath = getNixDefExpr(); - - if (!pathExists(nixExprPath)) { - try { - createDirs(nixExprPath); - replaceSymlink( - defaultChannelsDir(), - nixExprPath + "/channels"); - if (!isRootUser()) - replaceSymlink( - rootChannelsDir(), - nixExprPath + "/channels_root"); - } catch (Error &) { } - } - globals.dryRun = false; globals.preserveInstalled = false; globals.removeAll = false; globals.prebuiltOnly = false; + globals.profileKind = { defaultDefaultProfileKind() }; + struct MyArgs : LegacyArgs, MixEvalArgs { using LegacyArgs::LegacyArgs; @@ -1470,8 +1456,18 @@ static int main_nix_env(int argc, char * * argv) op = opQuery; opName = "-query"; } - else if (*arg == "--profile" || *arg == "-p") + else if (*arg == "--user-profile") { + globals.profileKind = DefaultProfileKind::User; + globals.profile = ""; + } + else if (*arg == "--global-profile") { + globals.profileKind = DefaultProfileKind::Global; + globals.profile = ""; + } + else if (*arg == "--profile" || *arg == "-p") { + globals.profileKind = std::nullopt; globals.profile = absPath(getArg(*arg, arg, end)); + } else if (*arg == "--file" || *arg == "-f") file = getArg(*arg, arg, end); else if (*arg == "--switch-profile" || *arg == "-S") { @@ -1523,8 +1519,39 @@ static int main_nix_env(int argc, char * * argv) if (showHelp) showManPage("nix-env" + opName); if (!op) throw UsageError("no operation specified"); + // Store layer concerns + auto store = openStore(); + // Profiles layer concerns + + if (globals.profile == "") + globals.profile = getEnv("NIX_PROFILE").value_or(""); + + if (globals.profile == "") { + assert(globals.profileKind); + globals.profile = getDefaultProfile(*globals.profileKind); + } + + // Eval layer concerns + + globals.instSource.type = srcUnknown; + globals.instSource.systemFilter = "*"; + + Path nixExprPath = getNixDefExpr(); + + if (!pathExists(nixExprPath)) { + try { + createDirs(nixExprPath); + replaceSymlink( + userChannelsDir(), + nixExprPath + "/channels"); + replaceSymlink( + globalChannelsDir(), + nixExprPath + "/channels_root"); + } catch (Error &) { } + } + globals.state = std::shared_ptr(new EvalState(myArgs.lookupPath, store)); globals.state->repair = myArgs.repair; @@ -1535,11 +1562,7 @@ static int main_nix_env(int argc, char * * argv) globals.instSource.autoArgs = myArgs.getAutoArgs(*globals.state); - if (globals.profile == "") - globals.profile = getEnv("NIX_PROFILE").value_or(""); - - if (globals.profile == "") - globals.profile = getDefaultProfile(); + // Do the operation op(globals, std::move(opFlags), std::move(opArgs)); diff --git a/tests/functional/common/vars-and-functions.sh.in b/tests/functional/common/vars-and-functions.sh.in index cb1f0d56616..3f1a2d9a627 100644 --- a/tests/functional/common/vars-and-functions.sh.in +++ b/tests/functional/common/vars-and-functions.sh.in @@ -68,8 +68,11 @@ readLink() { } clearProfiles() { - profiles="$HOME"/.local/state/nix/profiles - rm -rf "$profiles" + local localProfilesDir="$HOME"/.local/state/nix/profiles + local globalProfilesDir="$NIX_STATE_DIR/profiles" + rm -rf "$localProfilesDir" "$globalProfilesDir" + # Tests expect this + profiles="$localProfilesDir" } clearStore() { diff --git a/tests/functional/nix-collect-garbage-d.sh b/tests/functional/nix-collect-garbage-d.sh index bf30f893860..2e952d2ad28 100644 --- a/tests/functional/nix-collect-garbage-d.sh +++ b/tests/functional/nix-collect-garbage-d.sh @@ -38,3 +38,7 @@ testCollectGarbageD # Regression test for #8294 rm ~/.nix-profile testCollectGarbageD --profile "$NIX_STATE_DIR/profiles/per-user/me" + +# Test shortcuts for these default profiles +testCollectGarbageD --global-profile +testCollectGarbageD --user-profile