williamboman / mason.nvim

Portable package manager for Neovim that runs everywhere Neovim runs. Easily install and manage LSP servers, DAP servers, linters, and formatters.
Apache License 2.0
7.51k stars 264 forks source link

Support linking executables using relative symlinks #1156

Open rs-loves-bugs opened 1 year ago

rs-loves-bugs commented 1 year ago

I've searched open issues for similar requests

Yes

Is your feature request related to a problem? Please describe.

Idealy I would like to be able to just copy a nvim setup with mason to a different machine and it should just work.

Currently the symlinks mason creates for executables in bin/ are not relative. This makes it hard to make a portable neovim setup as most of the times the path will be different on other machines.

[rs@arch bin]$ ls -l
total 16
lrwxrwxrwx 1 rs rs 47 mar 30 16:23 jq -> /home/rs/.local/share/nvim/mason/packages/jq/jq
lrwxrwxrwx 1 rs rs 81 mar 30 15:24 lua-language-server -> /home/rs/.local/share/nvim/mason/packages/lua-language-server/lua-language-server
lrwxrwxrwx 1 rs rs 77 mar 30 16:20 prettier -> /home/rs/.local/share/nvim/mason/packages/prettier/node_modules/.bin/prettier

Describe the solution you'd like

The symlinks should be relative to the bin/ directory.

[rs@arch bin]$ ls -l
total 16
lrwxrwxrwx 1 rs rs 47 mar 30 16:23 jq -> ../packages/jq/jq
lrwxrwxrwx 1 rs rs 81 mar 30 15:24 lua-language-server -> ../packages/lua-language-server/lua-language-server
lrwxrwxrwx 1 rs rs 77 mar 30 16:20 prettier -> ../packages/prettier/node_modules/.bin/prettier

Describe potential alternatives you've considered

No response

Additional context

No response

williamboman commented 1 year ago

Just ACKing this, absolute paths are not by design but more due to limited abilities of working with paths in Lua without custom lib code. There seems to have been some basic util functions added to core Neovim recently (under vim.fs), not sure if they are sufficient for the kinds of operations needed to achieve correct path resolution. ~Either way, these util functions need to be vendored (or written from scratch) in Mason for backwards compatibility.~

Another thing that complicates this is that paths aren't really standardized/normalized internally, and may appear with DOS-like components (\ and C:\) at different stages on Windows, or even a mix of DOS components and POSIX components (/), this will need to be kept in mind when working on this.

I'd really like this to be fixed, but there are other things above this in the backlog. PRs would be accepted and appreciated. A good starting point would be to start expanding mason-core.path with additional util functions that 1) normalize paths, 2) resolves relative paths (i.e. path.relative("/mason/bin/typescript-language-server", "/mason/packages/typescript-language-server/.bin/typescript-language-server") == "../typescript-language-server/.bin/typescript-language-server").

botbotty commented 10 months ago

There is another issue apart from this one if you want to make a portable neovim setup: some package scripts will have absolute path in their shebang. Not sure if it should be addressed in mason or upstream though.

$ cd ~/.local/share/nvim/
$ grep "^#\!$(realpath ~)" . -r -l
./mason/packages/debugpy/venv/bin/pip3.10
./mason/packages/debugpy/venv/bin/pip3
./mason/packages/debugpy/venv/bin/pip
./mason/packages/ruff-lsp/venv/bin/ruff-lsp
./mason/packages/ruff-lsp/venv/bin/pip3.10
./mason/packages/ruff-lsp/venv/bin/pip3
./mason/packages/ruff-lsp/venv/bin/pip
./mason/packages/isort/venv/bin/pip3.10
./mason/packages/isort/venv/bin/pip3
./mason/packages/isort/venv/bin/pip
./mason/packages/isort/venv/bin/isort
./mason/packages/isort/venv/bin/isort-identify-imports
./mason/packages/black/venv/bin/pip3.10
./mason/packages/black/venv/bin/pip3
./mason/packages/black/venv/bin/pip
./mason/packages/black/venv/bin/blackd
./mason/packages/black/venv/bin/black
doctoromer commented 10 months ago

Hey, I would really like to see that implemented, because I copy my neovim config to air-gapped network. I think most of the language server can be symlinked with relative paths, but everything based on virtualenv can't. I tried to solve it myself multiple times and failed.

If anyone can think of a good solution for the venvs, I will gladly implement it.

henry-hsieh commented 8 months ago

Hi @williamboman,

I have done some tests on v2.x branch on relative symlinks. The symbolic links are work as expected. The environment is Docker of Ubuntu:latest & nvim 0.9.4. Here is my log:

lrwxrwxrwx 1 henry henry   71 Dec 28 21:19 bash-language-server -> ../packages/bash-language-server/node_modules/.bin/bash-language-server*
lrwxrwxrwx 1 henry henry   43 Dec 28 21:20 clangd -> ../packages/clangd/clangd_17.0.3/bin/clangd*
lrwxrwxrwx 1 henry henry   47 Dec 28 21:22 ltex-cli -> ../packages/ltex-ls/ltex-ls-16.0.0/bin/ltex-cli*
lrwxrwxrwx 1 henry henry   46 Dec 28 21:22 ltex-ls -> ../packages/ltex-ls/ltex-ls-16.0.0/bin/ltex-ls*
lrwxrwxrwx 1 henry henry   51 Dec 28 21:19 lua-language-server -> ../packages/lua-language-server/lua-language-server*
lrwxrwxrwx 1 henry henry   45 Dec 28 21:19 pyright -> ../packages/pyright/node_modules/.bin/pyright*
lrwxrwxrwx 1 henry henry   56 Dec 28 21:19 pyright-langserver -> ../packages/pyright/node_modules/.bin/pyright-langserver*
lrwxrwxrwx 1 henry henry   55 Dec 28 21:19 svlangserver -> ../packages/svlangserver/node_modules/.bin/svlangserver*
lrwxrwxrwx 1 henry henry   83 Dec 28 21:19 typescript-language-server -> ../packages/typescript-language-server/node_modules/.bin/typescript-language-server*
lrwxrwxrwx 1 henry henry   69 Dec 28 21:19 vim-language-server -> ../packages/vim-language-server/node_modules/.bin/vim-language-server*

However, it seems that expand_bin() doesn't use the relative path. Following is the lua-language-server bash command created by mason.nvim:

#!/usr/bin/env bash

exec "/setup/build/.local/share/nvim/mason/packages/lua-language-server/libexec/bin/lua-language-server" "$@"

/setup/build/ is my $HOME inside the docker. Following is my partial mason.log with DEBUG log level:

[DEBUG Thu Dec 28 13:19:45 2023] ...zy/mason.nvim/lua/mason-core/installer/InstallRunner.lua:205: Acquiring permit for Package(name=lua-language-server)
[DEBUG Thu Dec 28 13:19:45 2023] ...zy/mason.nvim/lua/mason-core/installer/InstallRunner.lua:223: Activating handle InstallHandle(package=Package(name=lua-language-server), state=QUEUED)
[DEBUG Thu Dec 28 13:19:45 2023] ...zy/mason.nvim/lua/mason-core/installer/InstallRunner.lua:186: Attempting to lock package Package(name=lua-language-server)
[DEBUG Thu Dec 28 13:19:45 2023] ...zy/mason.nvim/lua/mason-core/installer/InstallRunner.lua:198: Wrote lockfile Package(name=lua-language-server)
[DEBUG Thu Dec 28 13:19:45 2023] .../.local/share/nvim/lazy/mason.nvim/lua/mason-core/fs.lua:71: fs: mkdirp /setup/build/.local/share/nvim/mason/staging/lua-language-server
[DEBUG Thu Dec 28 13:19:45 2023] ...zy/mason.nvim/lua/mason-core/installer/compiler/init.lua:147: Compiling installer. lua-language-server {
  debug = false,
  force = false,
  reinstall_subpackages = true,
  strict = false
}
[DEBUG Thu Dec 28 13:19:45 2023] .../.local/share/nvim/lazy/mason.nvim/lua/mason-core/fs.lua:71: fs: mkdirp /setup/build/.local/share/nvim/mason/staging/lua-language-server/libexec
[DEBUG Thu Dec 28 13:19:45 2023] ...azy/mason.nvim/lua/mason-core/installer/managers/std.lua:96: std: downloading file "https://github.com/luals/lua-language-server/releases/download/3.7.3/lua-language-server-3.7.3-linux-x64.tar.gz"
[DEBUG Thu Dec 28 13:19:45 2023] ...ocal/share/nvim/lazy/mason.nvim/lua/mason-core/fetch.lua:37: Fetching URL "https://github.com/luals/lua-language-server/releases/download/3.7.3/lua-language-server-3.7.3-linux-x64.tar.gz"
[DEBUG Thu Dec 28 13:19:45 2023] ...al/share/nvim/lazy/mason.nvim/lua/mason-core/process.lua:116: Spawning cmd="curl", spawn_opts={
  args = { "-H", "User-Agent: mason.nvim v1.8.2 (+https://github.com/williamboman/mason.nvim)", "-fsSL", "-X", "GET", "-o", "/setup/build/.local/share/nvim/mason/staging/lua-language-server/libexec/lua-language-server-3.7.3-linux-x64.tar.gz", "--connect-timeout", 30, "https://github.com/luals/lua-language-server/releases/download/3.7.3/lua-language-server-3.7.3-linux-x64.tar.gz" }
}
[DEBUG Thu Dec 28 13:19:45 2023] ...al/share/nvim/lazy/mason.nvim/lua/mason-core/process.lua:162: Spawned with pid 2281
[DEBUG Thu Dec 28 13:19:56 2023] ...al/share/nvim/lazy/mason.nvim/lua/mason-core/process.lua:148: Job pid=2281 exited with exit_code=0, signal=0
[DEBUG Thu Dec 28 13:19:56 2023] ...azy/mason.nvim/lua/mason-core/installer/managers/std.lua:235: std: unpack "lua-language-server-3.7.3-linux-x64.tar.gz"
[DEBUG Thu Dec 28 13:19:56 2023] ...azy/mason.nvim/lua/mason-core/installer/managers/std.lua:110: std: untar "lua-language-server-3.7.3-linux-x64.tar.gz"
[DEBUG Thu Dec 28 13:19:56 2023] ...al/share/nvim/lazy/mason.nvim/lua/mason-core/process.lua:116: Spawning cmd="tar", spawn_opts={
  args = { "--no-same-owner", "-xvf", "lua-language-server-3.7.3-linux-x64.tar.gz" },
  cwd = "/setup/build/.local/share/nvim/mason/staging/lua-language-server/libexec"
}
[DEBUG Thu Dec 28 13:19:56 2023] ...al/share/nvim/lazy/mason.nvim/lua/mason-core/process.lua:162: Spawned with pid 2527
[DEBUG Thu Dec 28 13:19:56 2023] ...al/share/nvim/lazy/mason.nvim/lua/mason-core/process.lua:148: Job pid=2527 exited with exit_code=0, signal=0
[DEBUG Thu Dec 28 13:19:56 2023] .../.local/share/nvim/lazy/mason.nvim/lua/mason-core/fs.lua:59: fs: unlink /setup/build/.local/share/nvim/mason/staging/lua-language-server/libexec/lua-language-server-3.7.3-linux-x64.tar.gz
[DEBUG Thu Dec 28 13:19:56 2023] ...mason.nvim/lua/mason-core/installer/compiler/schemas.lua:52: schemas: download Package(name=lua-language-server) {
  lsp = "vscode:https://raw.githubusercontent.com/LuaLS/vscode-lua/master/package.json"
}
[DEBUG Thu Dec 28 13:19:56 2023] .../.local/share/nvim/lazy/mason.nvim/lua/mason-core/fs.lua:65: fs: mkdir /setup/build/.local/share/nvim/mason/staging/lua-language-server/mason-schemas
[DEBUG Thu Dec 28 13:19:56 2023] ...ocal/share/nvim/lazy/mason.nvim/lua/mason-core/fetch.lua:37: Fetching URL "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/package.json"
[DEBUG Thu Dec 28 13:19:56 2023] ...al/share/nvim/lazy/mason.nvim/lua/mason-core/process.lua:116: Spawning cmd="curl", spawn_opts={
  args = { "-H", "User-Agent: mason.nvim v1.8.2 (+https://github.com/williamboman/mason.nvim)", "-fsSL", "-X", "GET", "--connect-timeout", 30, "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/package.json" }
}
[DEBUG Thu Dec 28 13:19:56 2023] ...al/share/nvim/lazy/mason.nvim/lua/mason-core/process.lua:162: Spawned with pid 2529
[DEBUG Thu Dec 28 13:19:56 2023] ...al/share/nvim/lazy/mason.nvim/lua/mason-core/process.lua:148: Job pid=2529 exited with exit_code=0, signal=0
[DEBUG Thu Dec 28 13:19:56 2023] ...zy/mason.nvim/lua/mason-core/installer/compiler/link.lua:139: Registering bin links Package(name=lua-language-server) {
  ["lua-language-server"] = "{{source.asset.bin}}"
}
[DEBUG Thu Dec 28 13:19:56 2023] ...im/lua/mason-core/installer/context/InstallContextFs.lua:94: Setting exec flags on file "lua-language-server" 100644 -> 100755
[DEBUG Thu Dec 28 13:19:56 2023] ...zy/mason.nvim/lua/mason-core/installer/compiler/link.lua:166: Expanded bin link "lua-language-server" -> "lua-language-server"
[DEBUG Thu Dec 28 13:19:56 2023] ...azy/mason.nvim/lua/mason-core/installer/context/init.lua:112: Promoting cwd "/setup/build/.local/share/nvim/mason/staging/lua-language-server" to "/setup/build/.local/share/nvim/mason/packages/lua-language-server"
[DEBUG Thu Dec 28 13:19:56 2023] .../.local/share/nvim/lazy/mason.nvim/lua/mason-core/fs.lua:65: fs: mkdir /setup/build/.local/share/nvim/mason/packages/lua-language-server
[DEBUG Thu Dec 28 13:19:56 2023] .../.local/share/nvim/lazy/mason.nvim/lua/mason-core/fs.lua:84: fs: rename /setup/build/.local/share/nvim/mason/staging/lua-language-server /setup/build/.local/share/nvim/mason/packages/lua-language-server
[DEBUG Thu Dec 28 13:19:56 2023] ...nvim/lazy/mason.nvim/lua/mason-core/installer/linker.lua:162: Linking Package(name=lua-language-server)
[DEBUG Thu Dec 28 13:19:56 2023] ...azy/mason.nvim/lua/mason-core/installer/context/init.lua:341: Building receipt for Package(name=lua-language-server)
[DEBUG Thu Dec 28 13:19:56 2023] .../.local/share/nvim/lazy/mason.nvim/lua/mason-core/fs.lua:59: fs: unlink /setup/build/.local/share/nvim/mason/staging/lua-language-server.lock
[INFO  Thu Dec 28 13:19:56 2023] ...zy/mason.nvim/lua/mason-core/installer/InstallRunner.lua:89: Installation succeeded for Package(name=lua-language-server)
williamboman commented 7 months ago

Thanks for testing @henry-hsieh, will look into it.

henry-hsieh commented 5 months ago

Hi @williamboman,

I have further looked into it. The "npm:typescript-language-server"-like expressions will create a bash (unix) or a batch (win) script to call the target binary or script. The main problem is that the path of target is concatenated by the full installation path of the package and its relative executable path (in InstallContext:write_exec_wrapper().)

Instead of using full installation path, we can use the path relative to the bash or batch script. Take lua-language-server as an example, following path is equivalent to the full path in bash script. $(dirname $0)/../packages/lua-language-server/libexec/bin/lua-language-server

The path.concat can be moved into InstallContext:write_shell_exec_wrapper() for platform-dependent script path. I'll open a PR to resolve the issue.