Skip to content

Commit 2384d36

Browse files
balsoftthufschmitttimfenneypasqui23Artturin
committed
A setting to follow XDG Base Directory standard
XDG Base Directory is a standard for locations for storing various files. Nix has a few files which seem to fit in the standard, but currently use a custom location directly in the user's ~, polluting it: - ~/.nix-profile - ~/.nix-defexpr - ~/.nix-channels This commit adds a config option (use-xdg-base-directories) to follow the XDG spec and instead use the following locations: - $XDG_STATE_HOME/nix/profile - $XDG_STATE_HOME/nix/defexpr - $XDG_STATE_HOME/nix/channels If $XDG_STATE_HOME is not set, it is assumed to be ~/.local/state. Co-authored-by: Théophane Hufschmitt <7226587+thufschmitt@users.noreply.github.com> Co-authored-by: Tim Fenney <kodekata@gmail.com> Co-authored-by: pasqui23 <pasqui23@users.noreply.github.com> Co-authored-by: Artturin <Artturin@artturin.com> Co-authored-by: John Ericson <Ericson2314@Yahoo.com>
1 parent a31d7d4 commit 2384d36

16 files changed

Lines changed: 153 additions & 20 deletions

File tree

doc/manual/src/command-ref/env-common.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,16 @@ Most Nix commands interpret the following environment variables:
9191
variable sets the initial size of the heap in bytes. It defaults to
9292
384 MiB. Setting it to a low value reduces memory consumption, but
9393
will increase runtime due to the overhead of garbage collection.
94+
95+
## XDG Base Directory
96+
97+
New Nix commands conform to the [XDG Base Directory Specification], and use the following environment variables to determine locations of various state and configuration files:
98+
99+
- [`XDG_CONFIG_HOME`]{#env-XDG_CONFIG_HOME} (default `~/.config`)
100+
- [`XDG_STATE_HOME`]{#env-XDG_STATE_HOME} (default `~/.local/state`)
101+
- [`XDG_CACHE_HOME`]{#env-XDG_CACHE_HOME} (default `~/.cache`)
102+
103+
Classic Nix commands can also be made to follow this standard using the [`use-xdg-base-directories`] configuration option.
104+
105+
[XDG Base Directory Specification]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
106+
[`use-xdg-base-directories`]: ../command-ref/conf-file.md#conf-use-xdg-base-directories

scripts/install-multi-user.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ EOF
136136
cat <<EOF
137137
$step. Delete the files Nix added to your system:
138138
139-
sudo rm -rf /etc/nix $NIX_ROOT $ROOT_HOME/.nix-profile $ROOT_HOME/.nix-defexpr $ROOT_HOME/.nix-channels $HOME/.nix-profile $HOME/.nix-defexpr $HOME/.nix-channels
139+
sudo rm -rf "/etc/nix" "$NIX_ROOT" "$ROOT_HOME/.nix-profile" "$ROOT_HOME/.nix-defexpr" "$ROOT_HOME/.nix-channels" "$ROOT_HOME/.local/state/nix" "$ROOT_HOME/.cache/nix" "$HOME/.nix-profile" "$HOME/.nix-defexpr" "$HOME/.nix-channels" "$HOME/.local/state/nix" "$HOME/.cache/nix"
140140
141141
and that is it.
142142

scripts/install-nix-from-closure.sh

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ fi
188188
# shellcheck source=./nix-profile.sh.in
189189
. "$nix/etc/profile.d/nix.sh"
190190

191+
NIX_LINK="$HOME/.nix-profile"
192+
191193
if ! "$nix/bin/nix-env" -i "$nix"; then
192194
echo "$0: unable to install Nix into your default profile" >&2
193195
exit 1
@@ -196,7 +198,7 @@ fi
196198
# Install an SSL certificate bundle.
197199
if [ -z "$NIX_SSL_CERT_FILE" ] || ! [ -f "$NIX_SSL_CERT_FILE" ]; then
198200
"$nix/bin/nix-env" -i "$cacert"
199-
export NIX_SSL_CERT_FILE="$HOME/.nix-profile/etc/ssl/certs/ca-bundle.crt"
201+
export NIX_SSL_CERT_FILE="$NIX_LINK/etc/ssl/certs/ca-bundle.crt"
200202
fi
201203

202204
# Subscribe the user to the Nixpkgs channel and fetch it.
@@ -214,8 +216,8 @@ fi
214216

215217
added=
216218
p=
217-
p_sh=$HOME/.nix-profile/etc/profile.d/nix.sh
218-
p_fish=$HOME/.nix-profile/etc/profile.d/nix.fish
219+
p_sh=$NIX_LINK/etc/profile.d/nix.sh
220+
p_fish=$NIX_LINK/etc/profile.d/nix.fish
219221
if [ -z "$NIX_INSTALLER_NO_MODIFY_PROFILE" ]; then
220222
# Make the shell source nix.sh during login.
221223
for i in .bash_profile .bash_login .profile; do

scripts/nix-profile-daemon.sh.in

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,33 @@
22
if [ -n "${__ETC_PROFILE_NIX_SOURCED:-}" ]; then return; fi
33
__ETC_PROFILE_NIX_SOURCED=1
44

5-
export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"
5+
NIX_LINK=$HOME/.nix-profile
6+
if [ -n "$XDG_STATE_HOME" ]; then
7+
NIX_LINK_NEW="$XDG_STATE_HOME/nix/profile"
8+
else
9+
NIX_LINK_NEW=$HOME/.local/state/nix/profile
10+
fi
11+
if ! [ -e "$NIX_LINK" ]; then
12+
NIX_LINK="$NIX_LINK_NEW"
13+
else
14+
if [ -t 2 ] && [ -e "$NIX_LINK_NEW" ]; then
15+
warning="\033[1;35mwarning:\033[0m"
16+
printf "$warning Both %s and legacy %s exist; using the latter.\n" "$NIX_LINK_NEW" "$NIX_LINK" 1>&2
17+
if [ "$(realpath "$NIX_LINK")" = "$(realpath "$NIX_LINK_NEW")" ]; then
18+
printf " Since the profiles match, you can safely delete either of them.\n" 1>&2
19+
else
20+
# This should be an exceptionally rare occasion: the only way to get it would be to
21+
# 1. Update to newer Nix;
22+
# 2. Remove .nix-profile;
23+
# 3. Set the $NIX_LINK_NEW to something other than the default user profile;
24+
# 4. Roll back to older Nix.
25+
# If someone did all that, they can probably figure out how to migrate the profile.
26+
printf "$warning Profiles do not match. You should manually migrate from %s to %s.\n" "$NIX_LINK" "$NIX_LINK_NEW" 1>&2
27+
fi
28+
fi
29+
fi
30+
31+
export NIX_PROFILES="@localstatedir@/nix/profiles/default $NIX_LINK"
632

733
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
834
if [ -n "${NIX_SSL_CERT_FILE:-}" ]; then
@@ -34,4 +60,5 @@ else
3460
unset -f check_nix_profiles
3561
fi
3662

37-
export PATH="$HOME/.nix-profile/bin:@localstatedir@/nix/profiles/default/bin:$PATH"
63+
export PATH="$NIX_LINK/bin:@localstatedir@/nix/profiles/default/bin:$PATH"
64+
unset NIX_LINK

scripts/nix-profile.sh.in

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,35 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
22

33
# Set up the per-user profile.
44

5-
NIX_LINK=$HOME/.nix-profile
5+
NIX_LINK="$HOME/.nix-profile"
6+
if [ -n "$XDG_STATE_HOME" ]; then
7+
NIX_LINK_NEW="$XDG_STATE_HOME/nix/profile"
8+
else
9+
NIX_LINK_NEW="$HOME/.local/state/nix/profile"
10+
fi
11+
if ! [ -e "$NIX_LINK" ]; then
12+
NIX_LINK="$NIX_LINK_NEW"
13+
else
14+
if [ -t 2 ] && [ -e "$NIX_LINK_NEW" ]; then
15+
warning="\033[1;35mwarning:\033[0m"
16+
printf "$warning Both %s and legacy %s exist; using the latter.\n" "$NIX_LINK_NEW" "$NIX_LINK" 1>&2
17+
if [ "$(realpath "$NIX_LINK")" = "$(realpath "$NIX_LINK_NEW")" ]; then
18+
printf " Since the profiles match, you can safely delete either of them.\n" 1>&2
19+
else
20+
# This should be an exceptionally rare occasion: the only way to get it would be to
21+
# 1. Update to newer Nix;
22+
# 2. Remove .nix-profile;
23+
# 3. Set the $NIX_LINK_NEW to something other than the default user profile;
24+
# 4. Roll back to older Nix.
25+
# If someone did all that, they can probably figure out how to migrate the profile.
26+
printf "$warning Profiles do not match. You should manually migrate from %s to %s.\n" "$NIX_LINK" "$NIX_LINK_NEW" 1>&2
27+
fi
28+
fi
29+
fi
630

731
# Set up environment.
832
# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix
9-
export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"
33+
export NIX_PROFILES="@localstatedir@/nix/profiles/default $NIX_LINK"
1034

1135
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
1236
if [ -e /etc/ssl/certs/ca-certificates.crt ]; then # NixOS, Ubuntu, Debian, Gentoo, Arch
@@ -31,5 +55,5 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
3155
fi
3256

3357
export PATH="$NIX_LINK/bin:$PATH"
34-
unset NIX_LINK
58+
unset NIX_LINK NIX_LINK_NEW
3559
fi

src/libexpr/eval.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2496,7 +2496,7 @@ Strings EvalSettings::getDefaultNixPath()
24962496
res.push_back(s ? *s + "=" + p : p);
24972497
};
24982498

2499-
add(getHome() + "/.nix-defexpr/channels");
2499+
add(settings.useXDGBaseDirectories ? getStateDir() + "/nix/defexpr/channels" : getHome() + "/.nix-defexpr/channels");
25002500
add(settings.nixStateDir + "/profiles/per-user/root/channels/nixpkgs", "nixpkgs");
25012501
add(settings.nixStateDir + "/profiles/per-user/root/channels");
25022502

src/libstore/globals.hh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,27 @@ public:
975975
resolves to a different location from that of the build machine. You
976976
can enable this setting if you are sure you're not going to do that.
977977
)"};
978+
979+
Setting<bool> useXDGBaseDirectories{
980+
this, false, "use-xdg-base-directories",
981+
R"(
982+
If set to `true`, Nix will conform to the [XDG Base Directory Specification] for files in `$HOME`.
983+
The environment variables used to implement this are documented in the [Environment Variables section](@docroot@/installation/env-variables.md).
984+
985+
[XDG Base Directory Specification]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
986+
987+
> **Warning**
988+
> This changes the location of some well-known symlinks that Nix creates, which might break tools that rely on the old, non-XDG-conformant locations.
989+
990+
In particular, the following locations change:
991+
992+
| Old | New |
993+
|-------------------|--------------------------------|
994+
| `~/.nix-profile` | `$XDG_STATE_HOME/nix/profile` |
995+
| `~/.nix-defexpr` | `$XDG_STATE_HOME/nix/defexpr` |
996+
| `~/.nix-channels` | `$XDG_STATE_HOME/nix/channels` |
997+
)"
998+
};
978999
};
9791000

9801001

src/libstore/profiles.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,15 +282,15 @@ std::string optimisticLockProfile(const Path & profile)
282282

283283
Path profilesDir()
284284
{
285-
auto profileRoot = getDataDir() + "/nix/profiles";
285+
auto profileRoot = createNixStateDir() + "/profiles";
286286
createDirs(profileRoot);
287287
return profileRoot;
288288
}
289289

290290

291291
Path getDefaultProfile()
292292
{
293-
Path profileLink = getHome() + "/.nix-profile";
293+
Path profileLink = settings.useXDGBaseDirectories ? createNixStateDir() + "/profile" : getHome() + "/.nix-profile";
294294
try {
295295
auto profile =
296296
getuid() == 0

src/libstore/profiles.hh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ std::string optimisticLockProfile(const Path & profile);
7272
profiles. */
7373
Path profilesDir();
7474

75-
/* Resolve ~/.nix-profile. If ~/.nix-profile doesn't exist yet, create
76-
it. */
75+
/* Resolve the default profile (~/.nix-profile by default, $XDG_STATE_HOME/
76+
nix/profile if XDG Base Directory Support is enabled), and create if doesn't
77+
exist */
7778
Path getDefaultProfile();
7879

7980
}

src/libutil/util.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,19 @@ Path getDataDir()
608608
return dataDir ? *dataDir : getHome() + "/.local/share";
609609
}
610610

611+
Path getStateDir()
612+
{
613+
auto stateDir = getEnv("XDG_STATE_HOME");
614+
return stateDir ? *stateDir : getHome() + "/.local/state";
615+
}
616+
617+
Path createNixStateDir()
618+
{
619+
Path dir = getStateDir() + "/nix";
620+
createDirs(dir);
621+
return dir;
622+
}
623+
611624

612625
std::optional<Path> getSelfExe()
613626
{

0 commit comments

Comments
 (0)