There were some breaking changes in Fish 3.0.0, that result in asdf adding duplicated (and broken) paths for nested fish shells. This happens on both asdf 0.6.3 and latest master.
How to reproduce:
Start new fish >= v3.0.0 shell and write:
$ echo $fish_user_paths
/home/kossak/.asdf/bin /home/kossak/.asdf/shims
$ fish
$ echo $fish_user_paths
/home/kossak/.asdf/bin /home/kossak/.asdf/shims /home/kossak/.asdf/bin /home/kossak/.asdf/shims
Result:
In last output line variable $fish_user_paths (in result $PATH too!) contains duplicated directories (2 bins and 2 shims)
Expected Result
Variable $fish_user_paths should have only 2 different directories for asdf (like before starting second fish shell).
The asdf code adding paths is:
https://github.com/asdf-vm/asdf/blob/65aa5abe4e9858efdf798bc44f645b2b59f134ef/asdf.fish#L11-L15
The reason for duplicated paths is fish doesn't treat $fish_user_paths as array variable by default, so the check if directory already exists in it fails. Additionally, based on information I managed to gather from https://github.com/fish-shell/fish-shell/issues/5594#issuecomment-458889967, $fish_user_paths shouldn't be actually a global (nor exported) variable, but unviersal one (also that's how it is treated in fish tutorial). Is there any reason asdf makes it global? We can either make it universal one (set once, during installation, not in config.fish) or if for some reason we want it global - at least not export it (so the paths won't be duplicated). What do you think?
This seems related, not sure if it would fix this issue though: https://github.com/asdf-vm/asdf/pull/455
This seems related, not sure if it would fix this issue though: #455
For me it doesn't fix mangled paths in fish 3.0.0. Using this new asdf.fish results in:
First (not nested) shell:
$ for p in $PATH; echo $p; end
/home/kossak/.poetry/bin
/home/kossak/.local/bin
/home/kossak/.dotfiles.local/bin
/home/kossak/.dotfiles/bin
/home/kossak/.asdf/bin
/home/kossak/.asdf/shims
/usr/local/bin
/usr/bin
/bin
/usr/local/sbin
/usr/lib/jvm/default/bin
/usr/bin/site_perl
/usr/bin/vendor_perl
/usr/bin/core_perl
I have proper paths above, but when I run nested shell:
$ fish
$ for p in $PATH; echo $p; end
/home/kossak/.poetry/bin /home/kossak/.local/bin /home/kossak/.dotfiles.local/bin /home/kossak/.dotfiles/bin /home/kossak/.asdf/bin /home/kossak/.asdf/shims
/home/kossak/.poetry/bin
/home/kossak/.local/bin
/home/kossak/.dotfiles.local/bin
/home/kossak/.dotfiles/bin
/home/kossak/.asdf/bin
/home/kossak/.asdf/shims
/usr/local/bin
/usr/bin
/bin
/usr/local/sbin
/usr/lib/jvm/default/bin
/usr/bin/site_perl
/usr/bin/vendor_perl
/usr/bin/core_perl
What's wrong: first path in $PATH is broken - it is string containing multiple paths concatenated by space.
For me the fix is to use universal $fish_user_paths variable (as it is intended to be used according to fish developers). So I run once:
set -U fish_user_paths \
$HOME/.poetry/bin \
$HOME/.local/bin \
$HOME/.dotfiles.local/bin \
$HOME/.dotfiles/bin \
$HOME/.asdf/bin \
$HOME/.asdf/shims
And remove most of the lines from asdf.fish so whole file looks like this:
#!/usr/bin/env fish
set -x ASDF_DIR (dirname (status -f))
and everything works correctly:
$ for f in $fish_user_paths; echo $f; end
/home/kossak/.poetry/bin
/home/kossak/.local/bin
/home/kossak/.dotfiles.local/bin
/home/kossak/.dotfiles/bin
/home/kossak/.asdf/bin
/home/kossak/.asdf/shims
$聽for p in $PATH; echo $p; end
/home/kossak/.poetry/bin
/home/kossak/.local/bin
/home/kossak/.dotfiles.local/bin
/home/kossak/.dotfiles/bin
/home/kossak/.asdf/bin
/home/kossak/.asdf/shims
/usr/local/bin
/usr/bin
/bin
/usr/local/sbin
/usr/lib/jvm/default/bin
/usr/bin/site_perl
/usr/bin/vendor_perl
/usr/bin/core_perl
$ fish
$ for f in $fish_user_paths; echo $f; end
/home/kossak/.poetry/bin
/home/kossak/.local/bin
/home/kossak/.dotfiles.local/bin
/home/kossak/.dotfiles/bin
/home/kossak/.asdf/bin
/home/kossak/.asdf/shims
$ for p in $PATH; echo $p; end
/home/kossak/.poetry/bin
/home/kossak/.local/bin
/home/kossak/.dotfiles.local/bin
/home/kossak/.dotfiles/bin
/home/kossak/.asdf/bin
/home/kossak/.asdf/shims
/usr/local/bin
/usr/bin
/bin
/usr/local/sbin
/usr/lib/jvm/default/bin
/usr/bin/site_perl
/usr/bin/vendor_perl
/usr/bin/core_perl
@tkossak I've had similar issues dealing with asdf and fish 3.0. I've made the following change in my local asdf.fish and it works for me.
I just changed
set -gx fish_user_paths $fish_user_paths $x
to
set -U fish_user_paths $fish_user_paths $x
See the change in context here.
When doing this, you're not going to get the asdf paths added multiple times to the universal variable because a check is in place preventing it. This change allows the user to set a universal version of $fish_user_paths (as recommended by fish tutorial) for their own paths and not have them shadowed/overridden by a global definition of the variable every time asdf.fish is sourced.
You should try to apply this change to your asdf.fish, then clear your fish variables with
rm ~/.config/fish/fish_variables # Note, will also clear other universal variables you've set
exit # Make sure you close all fish sessions
Then after starting a new session apply your personal paths with this
set -U fish_user_paths \
$HOME/.poetry/bin \
$HOME/.local/bin \
$HOME/.dotfiles.local/bin \
$HOME/.dotfiles/bin \
$fish_user_paths
@tkossak Let me know if this fixes your issue too and I will create a PR.
As a side note, in my personal dotfiles I update my $fish_user_paths. I got the idea from the asdf source code to loop over $fish_user_paths to see if a given path is in there already before adding it. That works and If you wanted you could do this in your own config.fish on startup, but I found it works well in a script that I manually run.
@dtcristo Yes, this solution works for me too, even without clearing any fish variables (just set set -U instead of set -gx in asdf.fish).
Issue fixed in https://github.com/asdf-vm/asdf/pull/455
Most helpful comment
@tkossak I've had similar issues dealing with asdf and fish 3.0. I've made the following change in my local
asdf.fishand it works for me.I just changed
to
See the change in context here.
When doing this, you're not going to get the asdf paths added multiple times to the universal variable because a check is in place preventing it. This change allows the user to set a universal version of
$fish_user_paths(as recommended by fish tutorial) for their own paths and not have them shadowed/overridden by a global definition of the variable every timeasdf.fishis sourced.You should try to apply this change to your
asdf.fish, then clear your fish variables withThen after starting a new session apply your personal paths with this
@tkossak Let me know if this fixes your issue too and I will create a PR.
As a side note, in my personal dotfiles I update my
$fish_user_paths. I got the idea from the asdf source code to loop over$fish_user_pathsto see if a given path is in there already before adding it. That works and If you wanted you could do this in your ownconfig.fishon startup, but I found it works well in a script that I manually run.