spack / spack

A flexible package manager that supports multiple versions, configurations, platforms, and compilers.
https://spack.io
Other
4.21k stars 2.24k forks source link

command not found: complete on zsh shell #20551

Open Nischay-Pro opened 3 years ago

Nischay-Pro commented 3 years ago

I created a script /etc/profile.d/spack.sh to auto load spack on starting a shell across all users. Some of my users use zsh as their default shell. I've noticed that users who use zsh are getting the command not found: complete

Steps to reproduce the issue

  1. Create environment script /etc/profile.d/spack.sh
    export SPACK_ROOT=/opt/spack
    . $SPACK_ROOT/share/spack/setup-env.sh
  2. Change shell to zsh
  3. Logout and relogin to your user account.

Error Message

/opt/spack/share/spack/spack-completion.bash:318: command not found: complete
/opt/spack/share/spack/spack-completion.bash:321: command not found: complete

Information on your system

Additional information

trws commented 3 years ago

Interesting, I am having trouble reproducing this exactly as noted, but it looks like this is what happens if both of these things happen together:

  1. zsh is initialized without either compinit, bashcompinit or both
  2. user sources spack-completion.bash in an emulation mode other than zsh

One way to repro, non-interactive shell in sh emulation mode: zsh -c 'emulate sh ; source share/spack/setup-env.sh'

Try this alternate block at the top of spack-completion.bash:

  if test -n "${ZSH_VERSION:-}" ; then
    _spack_zsh_completion_init() {
      emulate -L zsh
      if test -n "${SPACK_ROOT:-}" ; then
        SELF="${SPACK_ROOT}/share/spack/spack-completion.bash"
      else
        # try to get self from zsh, $0:A doesn't work in a function
        SELF="${(%):-%x}"
      fi
      # ensure base completion support is enabled, ignore insecure directories
      autoload -U +X compinit && compinit -i
      # ensure bash compatible completion support is enabled
      autoload -U +X bashcompinit && bashcompinit
      emulate sh -c "source '$SELF'"
    }
    if ! typeset -f complete > /dev/null ; then
      _spack_zsh_completion_init "$(emulate)"
      return # stop interpreting file
    fi
  fi

It works for all the cases I can identify, but since I wasn't able to directly reproduce your issue I'd like to know if it covers your case as well.

Nischay-Pro commented 3 years ago

@trws Looks like your code snippet did the trick. I'm no longer getting the error message.

NicolasDerumigny commented 3 years ago

My bad, this was #20253, now resolved. I leave here the original comment as I believe it may give some idea for another fix for #20555. ------ I'm not sure whether this is the same issue or not, but I've remarked that I did not have autocomplete on zsh, even with bashcompinit in my .zshrc. A (partial) way to make this work is:

  1. add this piece of code after the if block sourcing spack-completion.bash:
    # Add programmable tab completion for zsh
    #
    if [ "$_sp_shell" = zsh ] && [ "$(type -w complete)" = "complete: function" ]; then
    source $_sp_share_dir/spack-completion.bash
    fi
  2. Replace in spack-completion.bash the block:
    if [[ "$(type -t $subfunction)" == "function" ]]
    then
        $subfunction
        COMPREPLY=($(compgen -W "$SPACK_COMPREPLY" -- "$cur"))
    fi

    by

        # Make sure function exists before calling it
    # bash version
    if [[ "$_sp_shell" = "bash" ]] && [[ "$(type -t $subfunction)" == "function" ]]
    then
        $subfunction
        COMPREPLY=($(compgen -W "$SPACK_COMPREPLY" -- "$cur"))
    fi
    # zsh-compatibility version
    if [[ "$_sp_shell" = "zsh" ]] && [[ "$(type -w $subfunction)" == "$subfunction: function" ]]
    then
        $subfunction
        COMPREPLY=($(compgen -W "$SPACK_COMPREPLY" -- "$cur"))
    fi

But:

Maybe a fix similar to 2) may be apply to check that complete is defined, and solve the original issue?

Additional information

dmd commented 1 year ago

What is the correct way to solve this at this point? I (a zsh user) am still getting this issue, and nothing above seems to help.

When I log in, I see:

/cm/shared/apps/spack/share/spack/spack-completion.bash:322: command not found: complete
/cm/shared/apps/spack/share/spack/spack-completion.bash:325: command not found: complete

However, if I then, at my shell prompt, run:

. /cm/shared/apps/spack/share/spack/spack-completion.bash

I get no errors and the completion for spack starts working fine.

trws commented 1 year ago

This issue is fixed for zsh shells running in zsh mode, none of the workarounds should be necessary anymore for that case. My best guess is that you're running zsh, but when you load the completion script at login you're running in an emulation mode other than zsh for some reason, then it's restored for the interactive prompt. An easy thing to try would be to use the following:

emulate zsh -c '. /cm/shared/apps/spack/share/spack/spack-completion.bash'

Which doesn't actually run a subshell but temporarily enters full normal zsh mode while sourcing the spack completion script.

Yorkking commented 2 months ago

I encountered this bug too, the reason is: I use zsh, when executing the script of spack/share/spack/spack-completion.bash, which should be interpreting by bash, the code syntax of it may be not correct for zsh.

My solution is modifying the setup-env.sh in line: 390-394, which original is:

# Add programmable tab completion for Bash
#
if test "$_sp_shell" = bash || test -n "${ZSH_VERSION:-}"; then
    source $_sp_share_dir/spack-completion.bash
fi

Do not execute the spack-completion.bash in zsh, so the modified code is:

# When using zsh, we don't need to do anything here.
if test "$_sp_shell" = bash ; then
    source $_sp_share_dir/spack-completion.bash
fi