From 38bfbb297c380f8b07d8a20ffdeb72da71c1567c Mon Sep 17 00:00:00 2001 From: Noam Yorav-Raphael Date: Wed, 11 Sep 2024 13:36:46 +0300 Subject: [PATCH] Use envvars NIX_CACHE_HOME, NIX_CONFIG_HOME, NIX_DATA_HOME, NIX_STATE_HOME if defined (#11351) --- doc/manual/rl-next/add-nix-state-home.md | 14 ++++++ doc/manual/src/command-ref/env-common.md | 15 ++++++- scripts/nix-profile.sh.in | 46 ++++++++++--------- src/libcmd/repl.cc | 2 +- src/libexpr/eval-cache.cc | 2 +- src/libexpr/eval-settings.cc | 2 +- src/libfetchers/cache.cc | 2 +- src/libfetchers/git-utils.cc | 2 +- src/libfetchers/git.cc | 2 +- src/libfetchers/mercurial.cc | 2 +- src/libfetchers/registry.cc | 4 +- src/libflake/flake/config.cc | 2 +- src/libstore/globals.cc | 2 +- src/libstore/nar-info-disk-cache.cc | 2 +- src/libstore/store-api.cc | 2 +- src/libutil/users.cc | 57 ++++++++++++++++++++---- src/libutil/users.hh | 8 ++-- 17 files changed, 118 insertions(+), 48 deletions(-) create mode 100644 doc/manual/rl-next/add-nix-state-home.md diff --git a/doc/manual/rl-next/add-nix-state-home.md b/doc/manual/rl-next/add-nix-state-home.md new file mode 100644 index 000000000..bbfdd5d38 --- /dev/null +++ b/doc/manual/rl-next/add-nix-state-home.md @@ -0,0 +1,14 @@ +--- +synopsis: Use envvars NIX_CACHE_HOME, NIX_CONFIG_HOME, NIX_DATA_HOME, NIX_STATE_HOME if defined +prs: [11351] +--- + +Added new environment variables: + +- `NIX_CACHE_HOME` +- `NIX_CONFIG_HOME` +- `NIX_DATA_HOME` +- `NIX_STATE_HOME` + +Each, if defined, takes precedence over the corresponding [XDG environment variable](@docroot@/command-ref/env-common.md#xdg-base-directories). +This provides more fine-grained control over where Nix looks for files, and allows to have a stand-alone Nix environment, which only uses files in a specific directory, and doesn't interfere with the user environment. diff --git a/doc/manual/src/command-ref/env-common.md b/doc/manual/src/command-ref/env-common.md index 0b5017882..ee3995111 100644 --- a/doc/manual/src/command-ref/env-common.md +++ b/doc/manual/src/command-ref/env-common.md @@ -138,6 +138,19 @@ The following environment variables are used to determine locations of various s - [`XDG_STATE_HOME`]{#env-XDG_STATE_HOME} (default `~/.local/state`) - [`XDG_CACHE_HOME`]{#env-XDG_CACHE_HOME} (default `~/.cache`) - [XDG Base Directory Specification]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html [`use-xdg-base-directories`]: @docroot@/command-ref/conf-file.md#conf-use-xdg-base-directories + +In addition, setting the following environment variables overrides the XDG base directories: + +- [`NIX_CONFIG_HOME`]{#env-NIX_CONFIG_HOME} (default `$XDG_CONFIG_HOME/nix`) +- [`NIX_STATE_HOME`]{#env-NIX_STATE_HOME} (default `$XDG_STATE_HOME/nix`) +- [`NIX_CACHE_HOME`]{#env-NIX_CACHE_HOME} (default `$XDG_CACHE_HOME/nix`) + +When [`use-xdg-base-directories`] is enabled, the configuration directory is: + +1. `$NIX_CONFIG_HOME`, if it is defined +2. Otherwise, `$XDG_CONFIG_HOME/nix`, if `XDG_CONFIG_HOME` is defined +3. Otherwise, `~/.config/nix`. + +Likewise for the state and cache directories. diff --git a/scripts/nix-profile.sh.in b/scripts/nix-profile.sh.in index e868399b1..3d0e498f4 100644 --- a/scripts/nix-profile.sh.in +++ b/scripts/nix-profile.sh.in @@ -3,29 +3,33 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then # Set up the per-user profile. - NIX_LINK="$HOME/.nix-profile" - if [ -n "${XDG_STATE_HOME-}" ]; then - NIX_LINK_NEW="$XDG_STATE_HOME/nix/profile" + if [ -n "$NIX_STATE_HOME" ]; then + NIX_LINK="$NIX_STATE_HOME/profile" else - NIX_LINK_NEW="$HOME/.local/state/nix/profile" - fi - if [ -e "$NIX_LINK_NEW" ]; then - if [ -t 2 ] && [ -e "$NIX_LINK" ]; then - warning="\033[1;35mwarning:\033[0m" - printf "$warning Both %s and legacy %s exist; using the former.\n" "$NIX_LINK_NEW" "$NIX_LINK" 1>&2 - if [ "$(realpath "$NIX_LINK")" = "$(realpath "$NIX_LINK_NEW")" ]; then - printf " Since the profiles match, you can safely delete either of them.\n" 1>&2 - else - # This should be an exceptionally rare occasion: the only way to get it would be to - # 1. Update to newer Nix; - # 2. Remove .nix-profile; - # 3. Set the $NIX_LINK_NEW to something other than the default user profile; - # 4. Roll back to older Nix. - # If someone did all that, they can probably figure out how to migrate the profile. - printf "$warning Profiles do not match. You should manually migrate from %s to %s.\n" "$NIX_LINK" "$NIX_LINK_NEW" 1>&2 - fi + NIX_LINK="$HOME/.nix-profile" + if [ -n "${XDG_STATE_HOME-}" ]; then + NIX_LINK_NEW="$XDG_STATE_HOME/nix/profile" + else + NIX_LINK_NEW="$HOME/.local/state/nix/profile" + fi + if [ -e "$NIX_LINK_NEW" ]; then + if [ -t 2 ] && [ -e "$NIX_LINK" ]; then + warning="\033[1;35mwarning:\033[0m" + printf "$warning Both %s and legacy %s exist; using the former.\n" "$NIX_LINK_NEW" "$NIX_LINK" 1>&2 + if [ "$(realpath "$NIX_LINK")" = "$(realpath "$NIX_LINK_NEW")" ]; then + printf " Since the profiles match, you can safely delete either of them.\n" 1>&2 + else + # This should be an exceptionally rare occasion: the only way to get it would be to + # 1. Update to newer Nix; + # 2. Remove .nix-profile; + # 3. Set the $NIX_LINK_NEW to something other than the default user profile; + # 4. Roll back to older Nix. + # If someone did all that, they can probably figure out how to migrate the profile. + printf "$warning Profiles do not match. You should manually migrate from %s to %s.\n" "$NIX_LINK" "$NIX_LINK_NEW" 1>&2 + fi + fi + NIX_LINK="$NIX_LINK_NEW" fi - NIX_LINK="$NIX_LINK_NEW" fi # Set up environment. diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 63f6c1bdd..b09ae3d09 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -134,7 +134,7 @@ NixRepl::NixRepl(const LookupPath & lookupPath, nix::ref store, refstaticBaseEnv.get())) , runNixPtr{runNix} - , interacter(make_unique(getDataDir() + "/nix/repl-history")) + , interacter(make_unique(getDataDir() + "/repl-history")) { } diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index 9019edc1f..c407cc89a 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -69,7 +69,7 @@ struct AttrDb { auto state(_state->lock()); - Path cacheDir = getCacheDir() + "/nix/eval-cache-v5"; + Path cacheDir = getCacheDir() + "/eval-cache-v5"; createDirs(cacheDir); Path dbPath = cacheDir + "/" + fingerprint.to_string(HashFormat::Base16, false) + ".sqlite"; diff --git a/src/libexpr/eval-settings.cc b/src/libexpr/eval-settings.cc index 2846eccbc..4cbcb39b9 100644 --- a/src/libexpr/eval-settings.cc +++ b/src/libexpr/eval-settings.cc @@ -99,7 +99,7 @@ const std::string & EvalSettings::getCurrentSystem() const Path getNixDefExpr() { return settings.useXDGBaseDirectories - ? getStateDir() + "/nix/defexpr" + ? getStateDir() + "/defexpr" : getHome() + "/.nix-defexpr"; } diff --git a/src/libfetchers/cache.cc b/src/libfetchers/cache.cc index 7019b0325..b0b6cb887 100644 --- a/src/libfetchers/cache.cc +++ b/src/libfetchers/cache.cc @@ -36,7 +36,7 @@ struct CacheImpl : Cache { auto state(_state.lock()); - auto dbPath = getCacheDir() + "/nix/fetcher-cache-v2.sqlite"; + auto dbPath = getCacheDir() + "/fetcher-cache-v2.sqlite"; createDirs(dirOf(dbPath)); state->db = SQLite(dbPath); diff --git a/src/libfetchers/git-utils.cc b/src/libfetchers/git-utils.cc index 114aa4ec0..31c42008f 100644 --- a/src/libfetchers/git-utils.cc +++ b/src/libfetchers/git-utils.cc @@ -1083,7 +1083,7 @@ std::vector> GitRepoImpl::getSubmodules ref getTarballCache() { - static auto repoDir = std::filesystem::path(getCacheDir()) / "nix" / "tarball-cache"; + static auto repoDir = std::filesystem::path(getCacheDir()) / "tarball-cache"; return GitRepo::openRepo(repoDir, true, true); } diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index 076c757c5..13682231d 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -44,7 +44,7 @@ bool isCacheFileWithinTtl(time_t now, const struct stat & st) Path getCachePath(std::string_view key, bool shallow) { return getCacheDir() - + "/nix/gitv3/" + + "/gitv3/" + hashString(HashAlgorithm::SHA256, key).to_string(HashFormat::Nix32, false) + (shallow ? "-shallow" : ""); } diff --git a/src/libfetchers/mercurial.cc b/src/libfetchers/mercurial.cc index 3feb3cb19..2c987f79d 100644 --- a/src/libfetchers/mercurial.cc +++ b/src/libfetchers/mercurial.cc @@ -263,7 +263,7 @@ struct MercurialInputScheme : InputScheme return makeResult(res->value, res->storePath); } - Path cacheDir = fmt("%s/nix/hg/%s", getCacheDir(), hashString(HashAlgorithm::SHA256, actualUrl).to_string(HashFormat::Nix32, false)); + Path cacheDir = fmt("%s/hg/%s", getCacheDir(), hashString(HashAlgorithm::SHA256, actualUrl).to_string(HashFormat::Nix32, false)); /* If this is a commit hash that we already have, we don't have to pull again. */ diff --git a/src/libfetchers/registry.cc b/src/libfetchers/registry.cc index 3c893c8ea..7f7a09053 100644 --- a/src/libfetchers/registry.cc +++ b/src/libfetchers/registry.cc @@ -116,7 +116,7 @@ static std::shared_ptr getSystemRegistry(const Settings & settings) Path getUserRegistryPath() { - return getConfigDir() + "/nix/registry.json"; + return getConfigDir() + "/registry.json"; } std::shared_ptr getUserRegistry(const Settings & settings) @@ -159,7 +159,7 @@ static std::shared_ptr getGlobalRegistry(const Settings & settings, re if (!hasPrefix(path, "/")) { auto storePath = downloadFile(store, path, "flake-registry.json").storePath; if (auto store2 = store.dynamic_pointer_cast()) - store2->addPermRoot(storePath, getCacheDir() + "/nix/flake-registry.json"); + store2->addPermRoot(storePath, getCacheDir() + "/flake-registry.json"); path = store->toRealPath(storePath); } diff --git a/src/libflake/flake/config.cc b/src/libflake/flake/config.cc index e526cdddf..4879de463 100644 --- a/src/libflake/flake/config.cc +++ b/src/libflake/flake/config.cc @@ -12,7 +12,7 @@ typedef std::map> TrustedList; Path trustedListPath() { - return getDataDir() + "/nix/trusted-settings.json"; + return getDataDir() + "/trusted-settings.json"; } static TrustedList readTrustedList() diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 52ab35b4c..8958e6997 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -135,7 +135,7 @@ std::vector getUserConfigFiles() std::vector files; auto dirs = getConfigDirs(); for (auto & dir : dirs) { - files.insert(files.end(), dir + "/nix/nix.conf"); + files.insert(files.end(), dir + "/nix.conf"); } return files; } diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc index 83e63794e..80e8d3414 100644 --- a/src/libstore/nar-info-disk-cache.cc +++ b/src/libstore/nar-info-disk-cache.cc @@ -87,7 +87,7 @@ public: Sync _state; - NarInfoDiskCacheImpl(Path dbPath = getCacheDir() + "/nix/binary-cache-v6.sqlite") + NarInfoDiskCacheImpl(Path dbPath = getCacheDir() + "/binary-cache-v6.sqlite") { auto state(_state.lock()); diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index fc8d51c39..426a69ae2 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -1315,7 +1315,7 @@ ref openStore(StoreReference && storeURI) /* If /nix doesn't exist, there is no daemon socket, and we're not root, then automatically set up a chroot store in ~/.local/share/nix/root. */ - auto chrootStore = getDataDir() + "/nix/root"; + auto chrootStore = getDataDir() + "/root"; if (!pathExists(chrootStore)) { try { createDirs(chrootStore); diff --git a/src/libutil/users.cc b/src/libutil/users.cc index d546e364f..b4bc67cbc 100644 --- a/src/libutil/users.cc +++ b/src/libutil/users.cc @@ -7,15 +7,33 @@ namespace nix { Path getCacheDir() { - auto cacheDir = getEnv("XDG_CACHE_HOME"); - return cacheDir ? *cacheDir : getHome() + "/.cache"; + auto dir = getEnv("NIX_CACHE_HOME"); + if (dir) { + return *dir; + } else { + auto xdgDir = getEnv("XDG_CACHE_HOME"); + if (xdgDir) { + return *xdgDir + "/nix"; + } else { + return getHome() + "/.cache/nix"; + } + } } Path getConfigDir() { - auto configDir = getEnv("XDG_CONFIG_HOME"); - return configDir ? *configDir : getHome() + "/.config"; + auto dir = getEnv("NIX_CONFIG_HOME"); + if (dir) { + return *dir; + } else { + auto xdgDir = getEnv("XDG_CONFIG_HOME"); + if (xdgDir) { + return *xdgDir + "/nix"; + } else { + return getHome() + "/.config/nix"; + } + } } std::vector getConfigDirs() @@ -23,6 +41,9 @@ std::vector getConfigDirs() Path configHome = getConfigDir(); auto configDirs = getEnv("XDG_CONFIG_DIRS").value_or("/etc/xdg"); std::vector result = tokenizeString>(configDirs, ":"); + for (auto& p : result) { + p += "/nix"; + } result.insert(result.begin(), configHome); return result; } @@ -30,19 +51,37 @@ std::vector getConfigDirs() Path getDataDir() { - auto dataDir = getEnv("XDG_DATA_HOME"); - return dataDir ? *dataDir : getHome() + "/.local/share"; + auto dir = getEnv("NIX_DATA_HOME"); + if (dir) { + return *dir; + } else { + auto xdgDir = getEnv("XDG_DATA_HOME"); + if (xdgDir) { + return *xdgDir + "/nix"; + } else { + return getHome() + "/.local/share/nix"; + } + } } Path getStateDir() { - auto stateDir = getEnv("XDG_STATE_HOME"); - return stateDir ? *stateDir : getHome() + "/.local/state"; + auto dir = getEnv("NIX_STATE_HOME"); + if (dir) { + return *dir; + } else { + auto xdgDir = getEnv("XDG_STATE_HOME"); + if (xdgDir) { + return *xdgDir + "/nix"; + } else { + return getHome() + "/.local/state/nix"; + } + } } Path createNixStateDir() { - Path dir = getStateDir() + "/nix"; + Path dir = getStateDir(); createDirs(dir); return dir; } diff --git a/src/libutil/users.hh b/src/libutil/users.hh index 153cc73fd..d22c3311d 100644 --- a/src/libutil/users.hh +++ b/src/libutil/users.hh @@ -24,12 +24,12 @@ Path getHomeOf(uid_t userId); Path getHome(); /** - * @return $XDG_CACHE_HOME or $HOME/.cache. + * @return $NIX_CACHE_HOME or $XDG_CACHE_HOME/nix or $HOME/.cache/nix. */ Path getCacheDir(); /** - * @return $XDG_CONFIG_HOME or $HOME/.config. + * @return $NIX_CONFIG_HOME or $XDG_CONFIG_HOME/nix or $HOME/.config/nix. */ Path getConfigDir(); @@ -39,12 +39,12 @@ Path getConfigDir(); std::vector getConfigDirs(); /** - * @return $XDG_DATA_HOME or $HOME/.local/share. + * @return $NIX_DATA_HOME or $XDG_DATA_HOME/nix or $HOME/.local/share/nix. */ Path getDataDir(); /** - * @return $XDG_STATE_HOME or $HOME/.local/state. + * @return $NIX_STATE_HOME or $XDG_STATE_HOME/nix or $HOME/.local/state/nix. */ Path getStateDir();