null-ls.nvim
null-ls.nvim copied to clipboard
Running tools inside containers
Issues
- [X] I have checked existing issues and there are no existing ones with the same request.
Feature description
I'd like to run most of the invoked tools inside containers. I prefer not to rely on a system-wide node, python, etc.
One one side, some projects require specific version. I already handle running them via containers, so running tooling via containers makes perfect sense.
I'm also running other LSPs using containers via https://github.com/lspcontainers/lspcontainers.nvim.
I'd find a single flag to run all tools in containers.
Help
Yes, but I don't know how to start. I would need guidance
Implementation help
I'll try and make container images, for example, for things like shellcheck or prettier
Maybe a container_image_url field would be a good place to keep references to known-to-work defaults?
E.g.:
diff --git a/lua/null-ls/builtins/diagnostics/shellcheck.lua b/lua/null-ls/builtins/diagnostics/shellcheck.lua
index d6013a7..dba02dc 100644
--- a/lua/null-ls/builtins/diagnostics/shellcheck.lua
+++ b/lua/null-ls/builtins/diagnostics/shellcheck.lua
@@ -9,6 +9,7 @@ return h.make_builtin({
filetypes = { "sh" },
generator_opts = {
command = "shellcheck",
+ container_image_url = "docker.io/koalaman/shellcheck-alpine/",
args = { "--format", "json1", "--source-path=$DIRNAME", "--external-sources", "-" },
to_stdin = true,
format = "json",
The entire feature would be optional, of course. I'm sure there's those who'd rather stick to the current approach.
I have never worked with and know absolutely nothing about containers, but I think this would be a cool feature and would be happy to provide support if you're up for implementing it. Depending on the amount of work required, I wonder if this might make sense as a separate plugin that integrates with null-ls vs. an addition to the core.
My preliminary and very ignorant questions to try to gauge feasibility:
- How can you launch a container via Neovim (I assume jobs?)
- Can you interact with containers via
stdio? If I'm running, say, Prettier in a container, is there a command I can drop intocat file | prettier?
I've been using this to run a tool inside a container (tested with clang-format and black). It does require the container to be already running.
null_ls.register({
method = null_ls.methods.FORMATTING,
filetypes = { "cpp", "c" },
generator = helpers.formatter_factory({
command = "docker",
args = {
"exec",
"-i",
"devcontainer",
"clang-format",
"-style=file",
"-",
},
to_stdin = true,
check_exit_code = function(code)
if code ~= 0 then
vim.schedule(function()
vim.notify(
"Failed to run formatter. Is Docker container running?",
vim.log.levels.ERROR
)
end)
return false
else
return true
end
end,
}),
})
I like the approach taken in lspcontainers.nvim a bit more. Each tool has its own dedicated image, and the container is spawned by the plugin itself.
Having to build a local, dedicated container with all the tools in one place can be a lot of work an not easily reusable by others.
Also, manually managing the container can be a bit of a drag -- especially given that it needs at least one process to stay alive, but there's nothing to run when it's not doing anything (I guess sleep infinity should work, but that's... odd).
My 2 cents: I don't think you want to open this can of worms of officially supporting containers.
Longer version:
Not all tools can be executed with a dedicated container, for instance, eslint supports plugins, and one needs to have the plugins packages installed for it to run correctly (and the correct versions). For that reason, I cannot imagine lspcontainers supporting eslint.
For eslint, again, I imagine you would have an image locally with eslint and its plugins installed, so I think @ranebrown solution would be preferred.
In the end, containers are a little beast on their own and trying to support it seems like a huge task.
I see, so actually running tools from containers is pretty straightforward but managing the containers is the tricky part. I think this might be better suited for a companion plugin that integrates with null-ls, then.
Yes, that's my opinion, the problem is usually not on running the containers themselves.
As an example, I have aliased "npm", "eslint", "prettier", and others to a command that will invoke the same command through docker if im inside a repo with a Dockerfile.
That means I can use containers with null-ls without changing any of the builtins.
I think the conclusion here was that this wouldn't be appropriate for inclusion in null-ls core, so I'm going to close the issue, but I'm happy to provide support for anybody who wants to work on a companion plugin.