zdharma-continuum / zinit

🌻 Flexible and fast ZSH plugin manager
MIT License
2.9k stars 125 forks source link

[bug]: `mv` ice does not rename file on initial run #129

Open OrbitalHustler opened 2 years ago

OrbitalHustler commented 2 years ago

Issue description

When starting zinit for the first time, using the direnv hook given in zinit wiki:

# Direnv hook into zsh
# https://zdharma.github.io/zinit/wiki/Direnv-explanation/
zinit from"gh-r" as"program" mv"direnv* -> direnv" \
    atclone'./direnv hook zsh > zhook.zsh' atpull'%atclone' \
    pick"direnv" src="zhook.zsh" for \
        direnv/direnv

The renaming (direnv* to direnv) does not happen: ziextract: Successfully extracted and assigned +x chmod to the file:direnv.linux-amd64'.`

The file direnv.linux-amd64 isn't renamed to direnv.

If however I then rm -rf ~/.local/share/zinit/plugins/direnv---direnv and start zsh again, I get:

ziextract: Successfully extracted and assigned +x chmod to the file:direnv.linux-amd64'. renamed 'direnv.linux-amd64' -> 'direnv'`

So it seems to only happen during the very first time zinit is setup.

zinit config

if [[ ! -f "$ZINIT_DIR/zinit.zsh" ]]; then
    echo -e "y" | sh -c "$(curl -fsSL https://git.io/zinit-install)"
fi

source "$ZINIT_DIR/zinit.zsh"
autoload -Uz _zinit
(( ${+_comps} )) && _comps[zinit]=_zinit

# Load a few important annexes, without Turbo
# (this is currently required for annexes)
zinit light-mode for \
    zdharma-continuum/z-a-rust \
    zdharma-continuum/z-a-as-monitor \
    zdharma-continuum/z-a-patch-dl \
    zdharma-continuum/z-a-bin-gem-node

### End of Zinit's installer chunk

zinit ice wait lucid
zinit snippet OMZ::plugins/colored-man-pages
zinit ice wait lucid
zinit snippet OMZ::plugins/colorize
zinit ice wait lucid
zinit snippet OMZ::plugins/command-not-found
zinit ice wait lucid
zinit snippet OMZ::plugins/copydir
zinit ice wait lucid
zinit snippet OMZ::plugins/copyfile
zinit ice wait lucid
zinit snippet OMZ::plugins/cp
zinit ice wait lucid
zinit snippet OMZ::plugins/debian
zinit ice wait lucid
zinit snippet OMZ::plugins/dircycle
zinit ice wait lucid
zinit snippet OMZ::plugins/extract
zinit ice wait lucid
zinit snippet OMZ::plugins/jump
zinit ice wait lucid
zinit snippet OMZ::plugins/mercurial
zinit ice wait lucid
zinit snippet OMZ::plugins/rsync
zinit ice wait lucid
zinit snippet OMZ::plugins/safe-paste

# # Bundles from external repos
zinit ice wait lucid
zinit load Tarrasch/zsh-bd
zinit ice wait lucid
zinit load djui/alias-tips
zinit ice wait lucid
zinit load hlissner/zsh-autopair
zinit ice wait lucid
zinit load mdumitru/fancy-ctrl-z
zinit ice wait lucid
zinit load rutchkiwi/copyzshell
zinit ice wait lucid
zinit load wfxr/forgit
zinit ice wait lucid
zinit load redxtech/zsh-show-path
# zinit load kutsan/zsh-system-clipboard
zinit ice wait lucid
zinit load zsh-users/zsh-completions

# Do not turbo mode (ice wait) these packages
zinit load jeffreytse/zsh-vi-mode # problems with fzf Ctrl+R, Ctrl+Z, Ctrl+T bindings if turbo
zinit ice svn pick"tmux.plugin.zsh"
zinit snippet OMZ::plugins/tmux
zinit load Aloxaf/fzf-tab
zinit snippet OMZ::plugins/fzf # after fzf-tab
zinit load davidde/git
zinit snippet OMZ::plugins/common-aliases # if turbo, replaces my aliases
unalias zi
zinit snippet OMZ::plugins/zoxide # so the function "zi" replaces the "zinit" alias "zi" properly

# Direnv hook into zsh
# https://zdharma.github.io/zinit/wiki/Direnv-explanation/
zinit from"gh-r" as"program" mv"direnv* -> direnv" \
    atclone'./direnv hook zsh > zhook.zsh' atpull'%atclone' \
    pick"direnv" src="zhook.zsh" for \
        direnv/direnv

# LS_COLORS managed by zinit
# https://zdharma.github.io/zinit/wiki/LS_COLORS-explanation/
#
zinit ice atclone"dircolors -b LS_COLORS > clrs.zsh" \
    atpull'%atclone' pick"clrs.zsh" nocompile'!' \
    atload'zstyle ":completion:*" list-colors β€œ${(s.:.)LS_COLORS}”'
zinit light trapd00r/LS_COLORS

# # # Order important
zinit ice wait"1" lucid
zinit load zsh-users/zsh-syntax-highlighting # last

zicompinit; zicdreplay

# # # Theme
zinit ice depth="1"
zinit load romkatv/powerlevel10k

zinit version or commit ID

e8058a8c8d77bb2b1940658eec3cbd809603fcb7

zsh version

5.8

host info

OSTYPE=linux-gnu CPUTYPE=x86_64 MACHTYPE=x86_64 5.10.60.1-microsoft-standard-WSL2 VERSION="11 (bullseye)" ID=debian

pschmitt commented 2 years ago

Can you please share the output of setopt? I wonder if it may be an extendedglob kinda thing.

OrbitalHustler commented 2 years ago

setopt gives:

alwaystoend
autocd
nobeep
correct
extendedglob
extendedhistory
histexpiredupsfirst
histfindnodups
histignorealldups
histignoredups
histignorespace
histsavenodups
histverify
interactive
monitor
nonomatch
promptsubst
sharehistory
shinstdin
zle
OrbitalHustler commented 2 years ago

Actually that is setopt in the case where it works. When it doesn't work, it is

interactive
monitor
shinstdin
zle

I see that there is no extendedglob there, could that be the cause in your opinion?

How should it be fixed? Should the zinit user be expected to set it correctly before calling zinit?

OrbitalHustler commented 2 years ago

Actually, even if I call setopt extendedglob before calling the first zinit install/plugins update, the direnv renaming doesn't happen.

More details to help pin it down:

If I run rm ~/.local/share/zinit/plugins && exec zsh, zinit plugins get reinstalled and direnv mv is done correctly.

If I run rm ~/.local/share/zinit/ && exec zsh, then zinit & its plugins get reinstalled and the direnv mv isn't done correctly (the bug happens)

pschmitt commented 2 years ago

How should it be fixed? Should the zinit user be expected to set it correctly before calling zinit?

No user-config should be mandatory, it's zinit's job to set zsh opts in the functions where it's behavior depends on the value of those. We will fix this in zinit ;)

jankatins commented 2 years ago

In #199 I had some fun trying to figure out why mv/atclone/... are not run after I deleted the whole `~/.zinit/plugins/* dir and I found one codepath which resulted in no hooks getting registered, effectively not running any ices:

When zinit.zsh is sourced, one of the last things is actually checking and ensuring that the plugins dir is correctly initialized (recreating it if not) and then afterwards registering all the ice hooks. An xtrace revealed that the registering never happens when I delete my plugin dir. Following the last call in the source zinit.zsh line, it's basically .zinit-prepare-home (zinit.zsh#L3055) -> rebuilds the plugin dir and in the last line of that block calls .zinit-compinit &>/dev/null (zinit.zsh#L1207-L1219) -> .zinit-compinit does as a first thing check something in OPTS (zinit-install.zsh#L611-L612) but this fails with the following error when I remove the redirect to dev null:

+.zinit-compinit:2> [[.zinit-compinit:2: bad math expression: operand expected at `/Users/jan...'
 -n '' ]]

The redirect to dev null hides the error but the error still results in not finishing the sourcing of the zinit.zsh file, so the hooks are not registered.

I did the following change and it seems to fix the problem but to be honest I do not understand that code at all so I do not know what side effects this might have:

--- a/zinit-install.zsh
+++ b/zinit-install.zsh
@@ -609,7 +609,7 @@ builtin source "${ZINIT[BIN_DIR]}/zinit-side.zsh" || {
 #
 # No arguments.
 .zinit-compinit() {
-    [[ -n ${OPTS[opt_-p,--parallel]} && $1 != 1 ]] && return
+    [[ -n $OPTS && -n ${OPTS[opt_-p,--parallel]} && $1 != 1 ]] && return

     emulate -LR zsh
     builtin setopt nullglob extendedglob warncreateglobal typesetsilent

Maybe interesting for @Percee to try out?

jankatins commented 2 years ago

I opened https://github.com/zdharma-continuum/zinit/pull/241 for the above idea.

OrbitalHustler commented 2 years ago

@jankatins I'm currently redoing my config and I didn't add zinit back in yet. I'll try it when I get there tho. Thanks very much!

vladdoster commented 2 years ago

@Percee

You shouldn't delete only the plugins directory, ever. If you want to delete plugins, run:

zinit delete --all

You break zinit when you delete the plugins directory since it holds _local---zinit

Regardless of the answer above, this brings up the issue of deleting zinit directories. As I've said before @jankatins, this is not how you should delete plugins.

Screen Shot 2022-05-02 at 01 55 51

Use zinit delete --all I would assume this edge-case is handled in the delete command since it deletes subdirectories and not the actual $ZINIT[PLUGINS_DIR] directory. So, is this needed or just not using the proper method of deleting plugins?

Link to my previous comment

Indeed, it avoids this issue altogether.

Screen Shot 2022-05-02 at 02 06 52

Originally posted by @vladdoster in https://github.com/zdharma-continuum/zinit/issues/241#issuecomment-1114558918

vladdoster commented 2 years ago

@Percee, Same idea for deleting a single plugin via rm -rf.

Instead, it should be deleted via:

zinit delete direnv---direnv

vladdoster commented 2 years ago

I'm unable to replicate this issue

[INFO]:  darwin20.2.0 (arm64) detected
[INFO]: downloading zinit
Cloning into '/Users/null/.local/share/zsh/zinit/zinit.git'...
remote: Enumerating objects: 19225, done.
remote: Counting objects: 100% (81/81), done.
remote: Compressing objects: 100% (53/53), done.
remote: Total 19225 (delta 45), reused 48 (delta 24), pack-reused 19144
Receiving objects: 100% (19225/19225), 11.12 MiB | 21.99 MiB/s, done.
Resolving deltas: 100% (12024/12024), done.
[INFO]: setting up zinit
[INFO]: sucessfully installed zinit

Downloading romkatv/zsh-bin…
Cloning into '/Users/null/.local/share/zsh/zinit/plugins/romkatv---zsh-bin'...
β Ό β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ OBJ: 100, PACK: 18/18, COMPR: 100%, REC: 100%, RES: 100%
===> installing Zsh 5.8 to /Users/null/.local
===> fetching zsh-5.8-darwin-arm64.tar.gz
===> verifying archive integrity
===> sha256 signature matches
===> md5 signature matches
===> extracting files

Installed Zsh 5.8 to /Users/null/.local

To start Zsh, type:

  export PATH="/Users/null/.local/bin:$PATH"
  zsh

Downloading direnv/direnv…
gh-r:removed deb packages
gh-r:removed rpm packages
(Requesting `direnv.darwin-arm64'…)
########################################################################################################################################################### 100.0%
ziextract: Successfully extracted and assigned +x chmod to the file: `direnv.darwin-arm64'.
direnv.darwin-arm64 -> direnv
direnv: loading ~/.envrc
wezen%

Config:

#=== HELPER METHODS ===================================[[[
function error() { print -P "%F{red}[ERROR]%f: %F{yellow}$1%f" && return 1 }
function info() { print -P "%F{blue}[INFO]%f: %F{cyan}$1%f"; }
# ]]]
#=== ZINIT ============================================[[[
typeset -gAH ZINIT;
ZINIT[HOME_DIR]=$XDG_DATA_HOME/zsh/zinit  ZPFX=$ZINIT[HOME_DIR]/polaris
ZINIT[BIN_DIR]=$ZINIT[HOME_DIR]/zinit.git ZINIT[OPTIMIZE_OUT_DISK_ACCESSES]=1
ZINIT[COMPLETIONS_DIR]=$ZINIT[HOME_DIR]/completions ZINIT[SNIPPETS_DIR]=$ZINIT[HOME_DIR]/snippets
ZINIT[ZCOMPDUMP_PATH]=$ZINIT[HOME_DIR]/zcompdump    ZINIT[PLUGINS_DIR]=$ZINIT[HOME_DIR]/plugins
ZI_FORK='vladdoster'; ZI_REPO='zdharma-continuum'; GH_RAW_URL='https://raw.githubusercontent.com'
if [[ ! -e $ZINIT[BIN_DIR] ]]; then
  info 'downloading zinit' \
  && command git clone \
    https://github.com/$ZI_REPO/zinit.git \
    $ZINIT[BIN_DIR] \
  || error 'failed to clone zinit repository' \
  && info 'setting up zinit' \
  && command chmod g-rwX $ZINIT[HOME_DIR] \
  && zcompile $ZINIT[BIN_DIR]/zinit.zsh \
  && info 'sucessfully installed zinit'
fi
if [[ -e $ZINIT[BIN_DIR]/zinit.zsh ]]; then
  source $ZINIT[BIN_DIR]/zinit.zsh \
    && autoload -Uz _zinit \
    && (( ${+_comps} )) \
    && _comps[zinit]=_zinit
else error "unable to find 'zinit.zsh'" && return 1
fi
# ]]]
#=== STATIC ZSH BINARY =======================================[[[
zi for atpull"%atclone" depth"1" lucid nocompile nocompletions as"null" \
    atclone"./install -e no -d ~/.local" atinit"export PATH=$HOME/.local/bin:$PATH" \
  @romkatv/zsh-bin
# ]]]
#=== PROMPT ===========================================[[[
zi light-mode for \
  compile'(pure|async).zsh' multisrc'(pure|async).zsh' atinit"
    PURE_GIT_DOWN_ARROW='↓'; PURE_GIT_UP_ARROW='↑'
    PURE_PROMPT_SYMBOL='ᐳ'; PURE_PROMPT_VICMD_SYMBOL='ᐸ'
    zstyle ':prompt:pure:git:action' color 'yellow'
    zstyle ':prompt:pure:git:branch' color 'blue'
    zstyle ':prompt:pure:git:dirty' color 'red'
    zstyle ':prompt:pure:path' color 'cyan'
    zstyle ':prompt:pure:prompt:success' color 'green'" \
  sindresorhus/pure
# ]]]
# # === zsh-vim-mode cursor configuration [[[
MODE_CURSOR_VICMD="green block";              MODE_CURSOR_VIINS="#20d08a blinking bar"
MODE_INDICATOR_REPLACE='%F{9}%F{1}REPLACE%f'; MODE_INDICATOR_VISUAL='%F{12}%F{4}VISUAL%f'
MODE_INDICATOR_VIINS='%F{15}%F{8}INSERT%f';   MODE_INDICATOR_VICMD='%F{10}%F{2}NORMAL%f'
MODE_INDICATOR_VLINE='%F{12}%F{4}V-LINE%f';   MODE_CURSOR_SEARCH="#ff00ff blinking underline"
setopt PROMPT_SUBST;  export KEYTIMEOUT=1 export LANG=en_US.UTF-8; export LC_ALL="en_US.UTF-8";
export LC_COLLATE='C' export LESS='-RMs'; export PAGER=less;       export VISUAL=vi
RPS1='${MODE_INDICATOR_PROMPT} ${vcs_info_msg_0_}'
# ]]]
# #=== ANNEXES ==========================================[[[
zi light-mode for "$ZI_REPO"/zinit-annex-{'bin-gem-node','binary-symlink','patch-dl','submods'}
# ]]]

zinit for \
    atclone'./direnv* hook zsh > zhook.zsh' \
    from"gh-r" \
    load \
    nocompile \
    src"zhook.zsh" \
    mv'direnv* -> direnv' \
  direnv/direnv

# vim:ft=zsh:sw=2:sts=2:et:foldmarker=[[[,]]]:foldmethod=marker
jankatins commented 2 years ago

Just commenting on the "don't run rm": While I agree that one "shouldn't do it", it's nice if a program is forgiving about user errors. .zinit-prepare-home is actually forgiving (after #241), as it explicitly handles this situation on every sourcing, e.g. for the _local---zinit folder:

https://github.com/zdharma-continuum/zinit/blob/bad7af3ae2d8aab18feb11a0251987fe3c08c31b/zinit.zsh#L1217-L1230

Nice :-)

vladdoster commented 1 year ago

@jankatins, did your PR (i.e, escaping exclamation marks) happen to fix this issue?

jankatins commented 1 year ago

@vladdoster As far as my understanding here goes, https://github.com/zdharma-continuum/zinit/pull/241 should have fixed this.

vladdoster commented 1 year ago

@vladdoster As far as my understanding here goes, https://github.com/zdharma-continuum/zinit/pull/241 should have fixed this.

@jankatins, Thanks for confirmation. I'll double check before closing this issue.

vladdoster commented 1 year ago

@Percee,

I can confirm this seems to be fixed and completion still works as expected πŸ‘πŸ».

Screenshot 2022-10-31 at 06 37 54

Note +1 for work done by @jankatins

jankatins commented 1 year ago

My understanding was that the original issue was about creating direnv right after installing zinit. That would match the problem in #241, which would fail if some default folders would not be there during sourcing of zinit. See this comment:

More details to help pin it down: If I run rm ~/.local/share/zinit/plugins && exec zsh, zinit plugins get reinstalled and direnv mv is done correctly. If I run rm ~/.local/share/zinit/ && exec zsh, then zinit & its plugins get reinstalled and the direnv mv isn't done correctly (the bug happens)

jankatins commented 1 year ago

I think the easiest to test all of this would be to add a final ZINIT_INITIALIZED=true to the last line of the sourced script and then torture the script by deleting various parts of the zinit folder... The original problem seems to have been a redirected error which hid the problem...

github-actions[bot] commented 1 year ago

:tada: This issue has been resolved in version 3.8.0 :tada:

The release is available on GitHub release

Your semantic-release bot :package::rocket: