From e21e289c970323767a897d5a949035c7a870c13d Mon Sep 17 00:00:00 2001 From: "Travis A. Everett" Date: Wed, 11 Oct 2023 19:29:49 -0500 Subject: [PATCH 1/2] install-darwin: work around zshrc overwrites macOS updates have been overwriting /etc/zshrc for a while. This evicts the Nix shell hook, causing quite a few support threads (and inevitabling harming people's impression of the project). This workaround *is* cursed :) --- scripts/install-darwin-multi-user.sh | 29 +++++++++++++++ scripts/install-multi-user.sh | 52 +++++++++++++++++---------- scripts/install-systemd-multi-user.sh | 4 +++ 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/scripts/install-darwin-multi-user.sh b/scripts/install-darwin-multi-user.sh index 0326d34150e..cd343a8ba6c 100644 --- a/scripts/install-darwin-multi-user.sh +++ b/scripts/install-darwin-multi-user.sh @@ -222,3 +222,32 @@ EOF failure "This script needs a /nix volume with global permissions! This may require running sudo /usr/sbin/diskutil enableOwnership /nix." fi } + +# appended to shell init +poly_extra_init_for_zshenv() { + cat <<'EOF' + +# wrap path_helper to keep it from pushing nix rightwards +/usr/libexec/path_helper() { + case "$1" in + "-c") + # don't interfere if this gets invoked with -c + command /usr/libexec/path_helper "$@" + ;; + *) + ( + # subshell to see what path_helper would do to PATH. inject a + # separator for splitting (saving previous PATH can duplicate + # entries, and people tend to see that as a smell) + eval "$(PATH="nixpathsep:$PATH" command /usr/libexec/path_helper "$@")" + local prefixed="${PATH%%:nixpathsep:*}" pushed_back="${PATH##*:nixpathsep:}" + + # re-emit what path_helper would; remove function to avoid rerunning + echo "PATH=\"${pushed_back}:${prefixed}\"; export PATH; unset -f /usr/libexec/path_helper;" + ) + ;; + esac +} + +EOF +} diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh index a08f62333dc..3d27f6c7a87 100644 --- a/scripts/install-multi-user.sh +++ b/scripts/install-multi-user.sh @@ -33,7 +33,7 @@ NIX_BUILD_USER_NAME_TEMPLATE="nixbld%d" readonly NIX_ROOT="/nix" readonly NIX_EXTRA_CONF=${NIX_EXTRA_CONF:-} -readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc" "/etc/bash.bashrc" "/etc/zsh/zshrc") +readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshenv" "/etc/bash.bashrc" "/etc/zsh/zshrc") readonly PROFILE_BACKUP_SUFFIX=".backup-before-nix" readonly PROFILE_NIX_FILE="$NIX_ROOT/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" @@ -845,6 +845,16 @@ EOF ) } +extra_shell_init() { + case "$1" in + /etc/zshenv) + poly_extra_init_for_zshenv;; + *) + ;; + esac +} + +# $1 == file we're generating for shell_source_lines() { cat < Date: Wed, 25 Oct 2023 21:07:10 -0500 Subject: [PATCH 2/2] nix-profile*.sh.in: append PATHs idempotently When people source the Nix profile scripts more than once, they can cause appended PATH variables to grow longer each time. This is somewhat benign, but it does spook people and cause support load. --- scripts/nix-profile-daemon.sh.in | 11 +++++++++-- scripts/nix-profile.sh.in | 23 +++++++++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/scripts/nix-profile-daemon.sh.in b/scripts/nix-profile-daemon.sh.in index 8cfd3149ee8..98adf46f768 100644 --- a/scripts/nix-profile-daemon.sh.in +++ b/scripts/nix-profile-daemon.sh.in @@ -1,6 +1,6 @@ # Only execute this file once per shell. if [ -n "${__ETC_PROFILE_NIX_SOURCED:-}" ]; then return; fi -__ETC_PROFILE_NIX_SOURCED=1 +export __ETC_PROFILE_NIX_SOURCED=1 NIX_LINK=$HOME/.nix-profile if [ -n "${XDG_STATE_HOME-}" ]; then @@ -60,5 +60,12 @@ else unset -f check_nix_profiles fi -export PATH="$NIX_LINK/bin:@localstatedir@/nix/profiles/default/bin:$PATH" +# only append once +case ":$PATH:" in + *:"$NIX_LINK/bin:@localstatedir@/nix/profiles/default/bin":*) + ;; + *) + export PATH="$NIX_LINK/bin:@localstatedir@/nix/profiles/default/bin:$PATH" + ;; +esac unset NIX_LINK diff --git a/scripts/nix-profile.sh.in b/scripts/nix-profile.sh.in index c4d60cf376a..b41437e536d 100644 --- a/scripts/nix-profile.sh.in +++ b/scripts/nix-profile.sh.in @@ -1,3 +1,7 @@ +# Only execute this file once per shell. +if [ -n "${__ETC_PROFILE_NIX_SOURCED:-}" ]; then return; fi +export __ETC_PROFILE_NIX_SOURCED=1 + if [ -n "$HOME" ] && [ -n "$USER" ]; then # Set up the per-user profile. @@ -51,9 +55,24 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then # pick up `.nix-profile/share/man` because is it close to `.nix-profile/bin` # which is in the $PATH. For more info, run `manpath -d`. if [ -n "${MANPATH-}" ]; then - export MANPATH="$NIX_LINK/share/man:$MANPATH" + # only append once + case ":$MANPATH:" in + *:"$NIX_LINK/share/man":*) + ;; + *) + export MANPATH="$NIX_LINK/share/man:$MANPATH" + ;; + esac fi - export PATH="$NIX_LINK/bin:$PATH" + # only append once + case ":$PATH:" in + *:"$NIX_LINK/bin":*) + ;; + *) + export PATH="$NIX_LINK/bin:$PATH" + ;; + esac + unset NIX_LINK NIX_LINK_NEW fi