null-ls.nvim icon indicating copy to clipboard operation
null-ls.nvim copied to clipboard

Running tools inside containers

Open WhyNotHugo opened this issue 3 years ago • 6 comments

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.

WhyNotHugo avatar Apr 28 '22 23:04 WhyNotHugo

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:

  1. How can you launch a container via Neovim (I assume jobs?)
  2. Can you interact with containers via stdio? If I'm running, say, Prettier in a container, is there a command I can drop into cat file | prettier?

jose-elias-alvarez avatar Apr 29 '22 02:04 jose-elias-alvarez

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,
    }),
})

ranebrown avatar May 05 '22 15:05 ranebrown

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).

WhyNotHugo avatar May 05 '22 15:05 WhyNotHugo

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.

bpinto avatar May 05 '22 17:05 bpinto

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.

jose-elias-alvarez avatar May 06 '22 02:05 jose-elias-alvarez

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.

bpinto avatar May 06 '22 07:05 bpinto

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.

jose-elias-alvarez avatar Sep 06 '22 19:09 jose-elias-alvarez