diff --git a/asdf.sh b/asdf.sh index aadb43f3..1f8d2b56 100644 --- a/asdf.sh +++ b/asdf.sh @@ -59,6 +59,60 @@ fi _asdf_bin="$ASDF_DIR/bin" _asdf_shims="${ASDF_DATA_DIR:-$HOME/.asdf}/shims" +_asdf_should_prepend=no +if [ -n "${ASDF_FORCE_PREPEND+x}" ]; then + _asdf_should_prepend=$ASDF_FORCE_PREPEND +else + # If ASDF_FORCE_PREPEND is not set, then prepend by default on macOS + # to workaround `path_helper`. + if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then + # shellcheck disable=SC3028 + case $OSTYPE in + darwin*) _asdf_should_prepend=yes ;; + esac + else + if ! _asdf_output=$(uname); then + printf "%s\n" "asdf: Error: Failed to execute 'uname'" >&2 + return 1 + fi + if [ "$_asdf_output" = 'Darwin' ]; then + _asdf_should_prepend=yes + fi + unset -v _asdf_output + fi +fi + +# If prepending is enabled, remove any existing instances of asdf from PATH so +# the prepending done after is always at the frontmost part of the PATH. +if [ "$_asdf_should_prepend" = 'yes' ]; then + if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then + # shellcheck disable=SC3060 + case ":$PATH:" in + *":${_asdf_bin}:"*) PATH=${PATH//$_asdf_bin:/} ;; + esac + # shellcheck disable=SC3060 + case ":$PATH:" in + *":${_asdf_shims}:"*) PATH=${PATH//$_asdf_shims:/} ;; + esac + else + _path=${PATH}: + _new_path= + while [ -n "$_path" ]; do + _part=${_path%%:*} + _path=${_path#*:} + + if [ "$_part" = "$_asdf_bin" ] || [ "$_part" = "$_asdf_shims" ]; then + continue + fi + + _new_path="$_new_path${_new_path:+:}$_part" + done + PATH=$_new_path + unset -v _path _new_path _part + fi +fi +unset -v _asdf_should_prepend + case ":$PATH:" in *":$_asdf_bin:"*) : ;; *) PATH="$_asdf_bin:$PATH" ;; diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md index 38d679c1..f6e91b93 100644 --- a/docs/guide/getting-started.md +++ b/docs/guide/getting-started.md @@ -51,7 +51,9 @@ We highly recommend using the official `git` method. ## 3. Install asdf -There are many different combinations of Shells, OSs & Installation methods all of which affect the configuration here. Expand the selection below that best matches your system: +There are many different combinations of Shells, OSs & Installation methods all of which affect the configuration here. Expand the selection below that best matches your system. + +**macOS users, be sure to read the warning about `path_helper` at the end of this section.** ::: details Bash & Git @@ -359,6 +361,10 @@ export ASDF_DIR="/opt/asdf-vm" `asdf` scripts need to be sourced **after** you have set your `$PATH` and **after** you have sourced your framework (oh-my-zsh etc). +::: warning +On macOS, starting a Bash or Zsh shell automatically calls a utility called `path_helper`. `path_helper` can rearrange items in `PATH` (and `MANPATH`), causing inconsistent behavior for tools that require specific ordering. To workaround this, `asdf` on macOS defaults to forcily adding its `PATH`-entries to the front (taking highest priority). This is controllable with the `ASDF_FORCE_PREPEND` variable.`. +::: + Restart your shell so that `PATH` changes take effect. Opening a new terminal tab will usually do it. ## Core Installation Complete! diff --git a/docs/manage/configuration.md b/docs/manage/configuration.md index 225a49c4..1ec7d83e 100644 --- a/docs/manage/configuration.md +++ b/docs/manage/configuration.md @@ -188,6 +188,15 @@ Number of cores to use when compiling the source code. If set, this value takes - If Unset: the asdf config `concurrency` value is used. - Usage: `export ASDF_CONCURRENCY=32` +### `ASDF_FORCE_PREPEND` + +Whether or not to prepend the `asdf` shims and path directories to the front-most (highest-priority) part of the `PATH`. + +- If Unset: On macOS, defaults to `yes`; but on other systems, defaults to `no` +- If `yes`: Force `asdf` directories to the front of the `PATH` +- If set to any string _other_ than `yes`: Do _not_ force `asdf` directories to the front of the `PATH` +- Usage: `ASDF_FORCE_PREPEND=no . "/asdf.sh"` + ## Full Configuration Example Following a simple asdf setup with: