diff --git a/apps/expert/lib/expert/port.ex b/apps/expert/lib/expert/port.ex index 62f564f4..877339a7 100644 --- a/apps/expert/lib/expert/port.ex +++ b/apps/expert/lib/expert/port.ex @@ -34,14 +34,8 @@ defmodule Expert.Port do def elixir_executable(%Project{} = project) do root_path = Project.root_path(project) - # We run a shell in interactive mode to populate the PATH with the right value - # at the project root. Otherwise, we either can't find an elixir executable, - # we use the wrong version if the user uses a version manager like asdf/mise, - # or we get an incomplete PATH not including erl or any other version manager - # managed programs. shell = System.get_env("SHELL") - - {path, 0} = System.cmd(shell, ["-i", "-l", "-c", "cd #{root_path} && echo $PATH"]) + path = path_env_at_directory(root_path, shell) case :os.find_executable(~c"elixir", to_charlist(path)) do false -> @@ -63,6 +57,31 @@ defmodule Expert.Port do end end + defp path_env_at_directory(directory, shell) do + # We run a shell in interactive mode to populate the PATH with the right value + # at the project root. Otherwise, we either can't find an elixir executable, + # we use the wrong version if the user uses a version manager like asdf/mise, + # or we get an incomplete PATH not including erl or any other version manager + # managed programs. + + case Path.basename(shell) do + # Ideally, it should contain the path to shell (e.g. `/usr/bin/fish`), + # but it might contain only the name of the shell (e.g. `fish`). + "fish" -> + # Fish uses space-separated PATH, so we use the built-in `string join` command + # to join the entries with colons and have a standard colon-separated PATH output + # as in bash, which is expected by `:os.find_executable/2`. + {path, 0} = + System.cmd(shell, ["-i", "-l", "-c", "cd #{directory} && string join ':' $PATH"]) + + path + + _ -> + {path, 0} = System.cmd(shell, ["-i", "-l", "-c", "cd #{directory} && echo $PATH"]) + path + end + end + @doc """ Launches an executable in the project context via a port. """