elixirasdf-vm

How to get full PATH with asdf


I'm developing an LSP for the Elixir language.

The way it works at a high level is that it spawns a VM to build the user project, and I need to find the user's elixir executable to ensure the VM that gets spawned uses the same elixir and erlang versions that the user is using to develop their project.

The user's elixir and erlang versions might be managed by ASDF, so I need to get the PATH that ASDF uses for that project's directory.

I tried using asdf env elixir, but that gives me a path that only includes the asdf installation for elixir, leaving out erlang or any other asdf managed program.

The main issue this causes is that when we spawn the VM using that elixir installation, it will crash due to erl being missing(Elixir uses Erlang's vm):

/Users/dorgan/.asdf/installs/elixir/1.17.0/bin/elixir: line 248: exec: erl: not found

I can sort of mitigate this by running asdf env erlang and merging both PATHs, but we also need any other asdf managed program to be included in that path. For example, if the user is using libraries like rustler or zigler we also need the rust and zig installations to be included in the path, and it's not realistic for the LSP implementation to run asdf env * for every possible program the user might need.

Another thing I tried was to add /Users/dorgan/.asdf/shims to the PATH returned by asdf env elixir, but if the user has a local erlang(or any other program) version set in their project's .tool-versions, it will only load the globally configured one and ignore the local ones.

I'd like to know if there's a way to get ASDF to return a PATH that includes every installation for a particular directory


Solution

  • The solution I found here is to open an interactive shell in the target directory, and grab the PATH from there. Afterwards I can call :os.find_executable(~c"elixir", path):

    shell = System.get_env("SHELL")
    
    {path, 0} = System.cmd(shell, ["-i", "-l", "-c", "cd #{project_path} && echo $PATH"])
    elixir_executable = :os.find_executable(~c"elixir", to_charlist(path))