home-manager icon indicating copy to clipboard operation
home-manager copied to clipboard

bug: environment variables are unavailable in ZSH since #2708 was merged

Open berbiche opened this issue 3 years ago • 40 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Issue description

Context: https://github.com/nix-community/home-manager/commit/2116fe6b50a5118d56f1f443cccf024abee9de40#r67122011

Maintainer CC

No response

System information

So far, this occurs on Darwin only.

berbiche avatar Feb 22 '22 18:02 berbiche

This is an issue for at least PROMPT on NixOS: https://github.com/nix-community/home-manager/pull/2708#issuecomment-1047520943

Maybe we should have an explicit setting for prompt init in home-manager to make it less fragile against stuff like this...

clhodapp avatar Feb 22 '22 18:02 clhodapp

It does seem that all of my settings do get set, including the PROMPT, it just doesn't have an effect:

johnw@Vulcan> env | grep PROMPT                                                                   ~
PROMPT=%m %~ $
PROMPT_DIRTRIM=2
RPROMPT=
johnw@Vulcan> echo $PROMPT                                                                        ~
%B%(?..[%?] )%b%n@%U%m%u>
johnw@Vulcan> export PROMPT='%m %~ $ '                                                            ~
Vulcan ~ $                                                                                        ~

jwiegley avatar Feb 22 '22 21:02 jwiegley

@jwiegley

As I posted in https://github.com/nix-community/home-manager/commit/2116fe6b50a5118d56f1f443cccf024abee9de40#r67162926 , I think the reason for your output is that:

  1. you export PROMPT in your .zshenv,
  2. PS1 or PROMPT is set in /etc/zshrc but not exported,
  3. env only prints exported variables.

I can reproduce your output:

$ setopt interactivecomments
$ export PROMPT="exported_prompt> " # set by your .zshenv
exported_prompt> PS1="not_exported_prompt> " # set in /etc/zshrc. PS1 and PROMPT are the same, they use PS1 IIRC
not_exported_prompt> env | grep PROMPT
PROMPT=exported_prompt> 
not_exported_prompt> echo $PROMPT 
not_exported_prompt> 
not_exported_prompt> export PROMPT="exported_prompt> "
exported_prompt>

Can you post content related to PROMPT or PS1 in your /etc/zshrc and .zshrc to confirm my guess?

If my guess is true, then it's not a bug, it a wrong user config.

PROMPT should not be exported since different shells have different syntax for it and will set it during initialization. Also, as I said before, PROMPT should be set in .zshrc to override what /etc/zshrc sets and doing so will fix your issue.

It does seem that all of my settings do get set, including the PROMPT, it just doesn't have an effect:

@berbiche Seems like this issue is only about PROMPT, maybe the title should be changed to something like "PROMPT in ZSH doesn't take effect since #2708 was merged "

jian-lin avatar Feb 23 '22 08:02 jian-lin

There is also my issue where some variables (e.g. EDITOR) are overridden by /etc/zprofile.

chvp avatar Feb 23 '22 08:02 chvp

There is also my issue where some variables (e.g. EDITOR) are overridden by /etc/zprofile.

Can you post your /etc/zprofile?

jian-lin avatar Feb 23 '22 08:02 jian-lin

https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/shells/zsh/default.nix#L59 (which eventually sources set-environment, which contains lines like export EDITOR=nano.

chvp avatar Feb 23 '22 08:02 chvp

I mean your actual /etc/zprofile. I cannot reproduce your issue because my /etc/zprofile doesn't contain these lines (https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/shells/zsh/default.nix#L59) and these lines are not sourced on my system.

Can you provide a way to reproduce your issue?

jian-lin avatar Feb 23 '22 09:02 jian-lin

That is my actual /etc/zprofile (or rather, I don't have an /etc/zprofile at the root). I don't have programs.zsh.enable at the nixos level (because there should be no need to configure it at that level). That file sources /etc/profile, which contains

# /etc/profile: DO NOT EDIT -- this file has been generated automatically.
# This file is read for login shells.

# Only execute this file once per shell.
if [ -n "$__ETC_PROFILE_SOURCED" ]; then return; fi
__ETC_PROFILE_SOURCED=1

# Prevent this file from being sourced by interactive non-login child shells.
export __ETC_PROFILE_DONE=1

if [ -z "$__NIXOS_SET_ENVIRONMENT_DONE" ]; then
    . /nix/store/qwazca3pvvr2pijvy8jciypj8yy7hx22-set-environment
fi





# Read system-wide modifications.
if test -f /etc/profile.local; then
    . /etc/profile.local
fi

if [ -n "${BASH_VERSION:-}" ]; then
    . /etc/bashrc
fi

Where /nix/store/qwazca3pvvr2pijvy8jciypj8yy7hx22-set-environment contains

# DO NOT EDIT -- this file has been generated automatically.

# Prevent this file from being sourced by child shells.
export __NIXOS_SET_ENVIRONMENT_DONE=1

export EDITOR="nano"
export GIO_EXTRA_MODULES="/nix/store/2anfhzjz6d4n5xx5k5bfc9png6bjxis6-dconf-0.40.0-lib/lib/gio/modules"
export GTK_PATH="$HOME/.nix-profile/lib/gtk-2.0:$HOME/.nix-profile/lib/gtk-3.0:/etc/profiles/per-user/$USER/lib/gtk-2.0:/etc/profiles/per-user/$USER/lib/gtk-3.0:/nix/var/nix/profiles/default/lib/gtk-2.0:/nix/var/nix/profiles/default/lib/gtk-3.0:/run/current-system/sw/lib/gtk-2.0:/run/current-system/sw/lib/gtk-3.0"
export GTK_USE_PORTAL="1"
export INFOPATH="$HOME/.nix-profile/info:$HOME/.nix-profile/share/info:/etc/profiles/per-user/$USER/info:/etc/profiles/per-user/$USER/share/info:/nix/var/nix/profiles/default/info:/nix/var/nix/profiles/default/share/info:/run/current-system/sw/info:/run/current-system/sw/share/info"
export KDEDIRS="$HOME/.nix-profile:/etc/profiles/per-user/$USER:/nix/var/nix/profiles/default:/run/current-system/sw"
export LANG="en_IE.UTF-8"
export LC_TIME="en_GB.UTF-8"
export LD_LIBRARY_PATH="/nix/store/7j2n3xsdnhzy2f0lyszxpsdpr9pb40xb-pipewire-0.3.45-jack/lib"
export LESSKEYIN_SYSTEM="/nix/store/l907b9hlvg710sx9q8zsdjanaw3nlmf1-lessconfig"
export LESSOPEN="|/nix/store/v86yp3qqpl0j4kvfkniik0ayn6a0aqjr-lesspipe-1.85/bin/lesspipe.sh %s"
export LIBEXEC_PATH="$HOME/.nix-profile/lib/libexec:/etc/profiles/per-user/$USER/lib/libexec:/nix/var/nix/profiles/default/lib/libexec:/run/current-system/sw/lib/libexec"
export LOCALE_ARCHIVE="/run/current-system/sw/lib/locale/locale-archive"
export MOZ_PLUGIN_PATH="$HOME/.nix-profile/lib/mozilla/plugins:/etc/profiles/per-user/$USER/lib/mozilla/plugins:/nix/var/nix/profiles/default/lib/mozilla/plugins:/run/current-system/sw/lib/mozilla/plugins"
export NIXPKGS_CONFIG="/etc/nix/nixpkgs-config.nix"
export NIX_PATH="/etc/channels"
export NO_AT_BRIDGE="1"
export PAGER="less"
export PATH="$HOME/.nix-profile/bin:/etc/profiles/per-user/$USER/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin"
export QTWEBKIT_PLUGIN_PATH="$HOME/.nix-profile/lib/mozilla/plugins/:/etc/profiles/per-user/$USER/lib/mozilla/plugins/:/nix/var/nix/profiles/default/lib/mozilla/plugins/:/run/current-system/sw/lib/mozilla/plugins/"
export QT_PLUGIN_PATH="$HOME/.nix-profile/lib/qt4/plugins:$HOME/.nix-profile/lib/kde4/plugins:/etc/profiles/per-user/$USER/lib/qt4/plugins:/etc/profiles/per-user/$USER/lib/kde4/plugins:/nix/var/nix/profiles/default/lib/qt4/plugins:/nix/var/nix/profiles/default/lib/kde4/plugins:/run/current-system/sw/lib/qt4/plugins:/run/current-system/sw/lib/kde4/plugins"
export SSH_ASKPASS=""
export TERMINFO_DIRS="$HOME/.nix-profile/share/terminfo:/etc/profiles/per-user/$USER/share/terminfo:/nix/var/nix/profiles/default/share/terminfo:/run/current-system/sw/share/terminfo"
export TZDIR="/etc/zoneinfo"
export XCURSOR_PATH="$HOME/.icons:$HOME/.local/share/icons:$HOME/.nix-profile/share/icons:$HOME/.nix-profile/share/pixmaps:/etc/profiles/per-user/$USER/share/icons:/etc/profiles/per-user/$USER/share/pixmaps:/nix/var/nix/profiles/default/share/icons:/nix/var/nix/profiles/default/share/pixmaps:/run/current-system/sw/share/icons:/run/current-system/sw/share/pixmaps"
export XDG_CONFIG_DIRS="/etc/xdg:$HOME/.nix-profile/etc/xdg:/etc/profiles/per-user/$USER/etc/xdg:/nix/var/nix/profiles/default/etc/xdg:/run/current-system/sw/etc/xdg"
export XDG_DATA_DIRS="/nix/store/3yiqbc66573m1m0z2jk1hl28ri2qciqj-desktops/share:$HOME/.nix-profile/share:/etc/profiles/per-user/$USER/share:/nix/var/nix/profiles/default/share:/run/current-system/sw/share"
export XDG_DESKTOP_PORTAL_DIR="/nix/store/acaj431c40is6y5vv65j4825sgk4m3pw-xdg-portals/share/xdg-desktop-portal/portals"

if [ -e "$HOME/.nix-defexpr/channels" ]; then
  export NIX_PATH="$HOME/.nix-defexpr/channels${NIX_PATH:+:$NIX_PATH}"
fi

# Wrappers override other bin directories.
export PATH="/run/wrappers/bin:$PATH"


unset ASPELL_CONF
for i in /run/current-system/sw /nix/var/nix/profiles/default /etc/profiles/per-user/$USER $HOME/.nix-profile ; do
  if [ -d "$i/lib/aspell" ]; then
    export ASPELL_CONF="dict-dir $i/lib/aspell"
  fi
done

export NIX_USER_PROFILE_DIR="/nix/var/nix/profiles/per-user/$USER"
export NIX_PROFILES="/run/current-system/sw /nix/var/nix/profiles/default /etc/profiles/per-user/$USER $HOME/.nix-profile"


# reset TERM with new TERMINFO available (if any)
export TERM=$TERM

chvp avatar Feb 23 '22 09:02 chvp

I can reproduce your issue. The key to reproduce is to not use a graphic environment because display managers will source /etc/profile and /etc/profile will not be sourced again later so your issue will not appear in a graphic environment.

Additionally, I can confirm that your linked code will run if and only if it's a login shell.

I think setting the nixos option programs.zsh.enable to true is a reasonable workaround, in which case /etc/zprofile will be sourced instead of /etc/profile and /nix/store/hash-set-environment will be sourced in /etc/zshenv.

jian-lin avatar Feb 23 '22 11:02 jian-lin

@chvp Sorry, I made a mistake in my last comment. I have corrected it.

I still think the proper way to fix your issue is to change the behavior of zsh from nixpkgs.

jian-lin avatar Feb 23 '22 18:02 jian-lin

Yeah, I'm pretty sure I agree that this is something that should be fixed in nixpkgs. I did enable programs.zsh.enable as a workaround. (Something I did not realize is that the set-environment script is sourced in /etc/zshenv in that case, which is definitely the more proper zsh way to do things.)

chvp avatar Feb 23 '22 18:02 chvp

I've also noticed that after this change, none of standard bindkey mappings works. For example, I used to have in my shell (without any modifications) the following:

"^E" end-of-line
"^F" forward-char

After the change I have:

"^E"-"^F" self-insert

knl avatar Feb 23 '22 22:02 knl

@knl I don't think this commit cause your issue since it only move session variables.

Anyway, can you provide a minimal working example to reproduce your issue?

jian-lin avatar Feb 24 '22 07:02 jian-lin

@knl I don't think this commit cause your issue since it only move session variables.

Anyway, can you provide a minimal working example to reproduce your issue?

I did a bisect, and this commit was the first one that broke the expected behavior. By bisect, I mean I re-deployed my home-manager configuration with different versions of home-manager, and then checking the output of bindkey in a newly opened shell. I'll try to provide the minimal working example in the next 24h. Also, I'll open a new issue, just not to pollute this one (unless it's ok to keep the whole discussion here)?

knl avatar Feb 24 '22 12:02 knl

One thing that strikes me is that the relToDotDir ".zshenv" file is concatenated/merged ~three~ four times within the mkMerge list.

Considering order matters quite a bit when initializing a shell, I'm wondering if the additions from #2708 would be appended to the resulting file after the value of envExtra? In general, I find the mkMerge usage here to be somewhat less-than-explicit (but let's also leave room for my own lack of understanding here 😅).

https://github.com/nix-community/home-manager/blob/afe96e7433c513bf82375d41473c57d1f66b4e68/modules/programs/zsh.nix#L408-L410

https://github.com/nix-community/home-manager/blob/afe96e7433c513bf82375d41473c57d1f66b4e68/modules/programs/zsh.nix#L424-L429

https://github.com/nix-community/home-manager/blob/afe96e7433c513bf82375d41473c57d1f66b4e68/modules/programs/zsh.nix#L431-L434

https://github.com/nix-community/home-manager/blob/afe96e7433c513bf82375d41473c57d1f66b4e68/modules/programs/zsh.nix#L445-L456

In which order will these be applied to the resulting file?

Would the following change to the third section (and corresponding removal of the existing examples) potentially result in the expected behavior?

{
  home.file."${relToDotDir ".zshenv"}".text = ''
    ${optionalString (cfg.dotDir != null) "ZDOTDIR=${zdotdir}"} 

    ${optionalString (cfg.oh-my-zsh.enable) '' 
      ZSH="${pkgs.oh-my-zsh}/share/oh-my-zsh"; 
      ZSH_CACHE_DIR="${config.xdg.cacheHome}/oh-my-zsh"; 
    ''} 

    # Environment variables
    . "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh"

    # Only source this once
    if [[ -z "$__HM_ZSH_SESS_VARS_SOURCED" ]]; then
      export __HM_ZSH_SESS_VARS_SOURCED=1
      ${envVarsStr}
    fi

    ### Move the `envExtra` value here ###
    ${optionalString (cfg.envExtra != "") cfg.envExtra}
  '';
}

montchr avatar Mar 11 '22 04:03 montchr

Can confirm NixOS setting programs.zsh.enable = true; works for getting my EDITOR setting back on NixOS.

austinbutler avatar Mar 11 '22 18:03 austinbutler

@montchr

LGTM. I don't use oh-my-zsh though. Not sure about that part.

I think PR is welcome.

jian-lin avatar Mar 11 '22 20:03 jian-lin

I don't use oh-my-zsh though. Not sure about that part.

@jian-lin Same, though based on the variables it touches, it seemed like the sort of low-level change that belongs close to the top of the file.

I opened #2787, which also adds a programs.zsh.envExtraFirst option along the lines of programs.zsh.initExtraFirst.

@knl @jwiegley et al. if you're open to testing #2787, I'm curious to know whether it addresses the issues that prompted this ticket.

montchr avatar Mar 11 '22 21:03 montchr

For what it's worth, I tried the change from #2787 in my own repo https://github.com/akanter/nix-config in https://github.com/akanter/nix-config/blob/ee86b34c24f524ab158f48ff7e11e1e4b579164b/darwin-configuration.nix and my $EDITOR was still broken. The only way I was able to fix this was to revert #2708.

akanter avatar Mar 12 '22 19:03 akanter

Some advice on debugging:

  1. echo $__HM_ZSH_SESS_VARS_SOURCED to see if .zshenv is sourced. Let's assume it is sourced.
  2. unset __HM_ZSH_SESS_VARS_SOURCED && zsh -c 'echo $EDITOR' to see if EDITOR is overridden in .zshenv
  3. unset __HM_ZSH_SESS_VARS_SOURCED && zsh -i -c 'echo $EDITOR' to see if EDITOR is overridden by /etc/zshrc or .zshrc
  4. unset __HM_ZSH_SESS_VARS_SOURCED && zsh -l -c 'echo $EDITOR' to see if EDITOR is overridden by /etc/zprofile or .zprofile.

jian-lin avatar Mar 12 '22 19:03 jian-lin

Using montchr/home-manager/tree/zsh-env-section-order

>echo $__HM_ZSH_SESS_VARS_SOURCED
1
>unset __HM_ZSH_SESS_VARS_SOURCED && zsh -c 'echo $EDITOR'                                                                                                                                 
nano
>unset __HM_ZSH_SESS_VARS_SOURCED && zsh -i -c 'echo $EDITOR'
nano
>unset __HM_ZSH_SESS_VARS_SOURCED && zsh -l -c 'echo $EDITOR'
nano
>cat ~/.zshenv
# Environment variables
. "/Users/ak/.nix-profile/etc/profile.d/hm-session-vars.sh"

# Only source this once
if [[ -z "$__HM_ZSH_SESS_VARS_SOURCED" ]]; then
  export __HM_ZSH_SESS_VARS_SOURCED=1

fi



#
# Defines environment variables.
#
# Authors:
#   Sorin Ionescu <[email protected]>
#

# Ensure that a non-login, non-interactive shell has a defined environment.
if [[ ( "$SHLVL" -eq 1 && ! -o LOGIN ) && -s "${ZDOTDIR:-$HOME}/.zprofile" ]]; then
  source "${ZDOTDIR:-$HOME}/.zprofile"
fi

Not sure what's going on but I hope this can assist you!

akanter avatar Mar 12 '22 20:03 akanter

My bad. I misread. Actually, you set EDITOR in home.sessionVariables instead of programs.zsh.sessionVariables. So the guard variable __HM_ZSH_SESS_VARS_SOURCED should be changed to __HM_SESS_VARS_SOURCED.

 #
 # Defines environment variables.
 #
 # Authors:
 #   Sorin Ionescu <[email protected]>
 #
 
 # Ensure that a non-login, non-interactive shell has a defined environment.
 if [[ ( "$SHLVL" -eq 1 && ! -o LOGIN ) && -s "${ZDOTDIR:-$HOME}/.zprofile" ]]; then
   source "${ZDOTDIR:-$HOME}/.zprofile"
 fi

But I cannot find this in your home manager config. That should not exist since your .zshenv is generated by home manager. Also, it is not needed as it is taken care of by the zsh module.

Could you remove that and redo the test with __HM_SESS_VARS_SOURCED?

jian-lin avatar Mar 12 '22 20:03 jian-lin

Ah, that comes from zsh-prezto.

Ah, I think I find the cause of your issue: zsh-prezto also sets some variables like EDITOR in .zprofile, which overridden the ones we set in .zshenv.

jian-lin avatar Mar 12 '22 20:03 jian-lin

I skim through prezto's zsh settings and think that prezto can be improved.

@akanter For your issue, prezto should set variables like EDTIOR in .zprofile only if they are not set. Maybe you can make a PR for prezto?

Not sure if there are more incompatibilities between our zsh module and prezto.

jian-lin avatar Mar 12 '22 21:03 jian-lin

https://github.com/sorin-ionescu/prezto/pull/1992 fixed this problem, just needs an update.

pinpox avatar Apr 01 '22 08:04 pinpox

Thank you for your contribution! I marked this issue as stale due to inactivity. Please be considerate of people watching this issue and receiving notifications before commenting 'I have this issue too'. We welcome additional information that will help resolve this issue. Please read the relevant sections below before commenting.

If you are the original author of the issue

  • If this is resolved, please consider closing it so that the maintainers know not to focus on this.
  • If this might still be an issue, but you are not interested in promoting its resolution, please consider closing it while encouraging others to take over and reopen an issue if they care enough.
  • If you know how to solve the issue, please consider submitting a Pull Request that addresses this issue.
If you are not the original author of the issue

  • If you are also experiencing this issue, please add details of your situation to help with the debugging process.
  • If you know how to solve the issue, please consider submitting a Pull Request that addresses this issue.
Memorandum on closing issues

Don't be afraid to manually close an issue, even if it holds valuable information. Closed issues stay in the system for people to search, read, cross-reference, or even reopen – nothing is lost! Closing obsolete issues is an important way to help maintainers focus their time and effort.

stale[bot] avatar Jul 01 '22 07:07 stale[bot]

I am having similar issues but I am not using prezto. If I add:

    programs.zsh = {
      enable = true;
      sessionVariables = {
        ASD = "asdasd";
      };
    ...
   };

And then edit /etc/profiles/per-user/dbarroso/etc/profile.d/hm-session-vars.sh and change it to:

# Only source this once.
echo 1 # <-------
if [ -n "$__HM_SESS_VARS_SOURCED" ]; then return; fi
echo 2 # <------
export __HM_SESS_VARS_SOURCED=1

export EDITOR="nvim":w

When I open a new shell I see 1 twice but never 2 so I am not sure who/where that var is being set but the contents of .zshenv are never fully loaded due to the the gate:

. "/etc/profiles/per-user/dbarroso/etc/profile.d/hm-session-vars.sh"

# Only source this once
if [[ -z "$__HM_ZSH_SESS_VARS_SOURCED" ]]; then
  export __HM_ZSH_SESS_VARS_SOURCED=1
  export ASD="asdasd"
fi

dbarrosop avatar Jul 22 '22 09:07 dbarrosop

Disregard, in my case I figured the issue was due to the fact I am using nix-darwin + home-manager and I had zsh enabled in both in which case there are bad interactions in there.

dbarrosop avatar Jul 22 '22 10:07 dbarrosop

Thank you for your contribution! I marked this issue as stale due to inactivity. Please be considerate of people watching this issue and receiving notifications before commenting 'I have this issue too'. We welcome additional information that will help resolve this issue. Please read the relevant sections below before commenting.

If you are the original author of the issue

  • If this is resolved, please consider closing it so that the maintainers know not to focus on this.
  • If this might still be an issue, but you are not interested in promoting its resolution, please consider closing it while encouraging others to take over and reopen an issue if they care enough.
  • If you know how to solve the issue, please consider submitting a Pull Request that addresses this issue.
If you are not the original author of the issue

  • If you are also experiencing this issue, please add details of your situation to help with the debugging process.
  • If you know how to solve the issue, please consider submitting a Pull Request that addresses this issue.
Memorandum on closing issues

Don't be afraid to manually close an issue, even if it holds valuable information. Closed issues stay in the system for people to search, read, cross-reference, or even reopen – nothing is lost! Closing obsolete issues is an important way to help maintainers focus their time and effort.

stale[bot] avatar Oct 20 '22 16:10 stale[bot]

FYI, I created a pr to let you disable the system-level programs.zsh.enable option. https://github.com/NixOS/nixpkgs/pull/217205

jian-lin avatar Feb 21 '23 20:02 jian-lin