aboutsummaryrefslogtreecommitdiffstats
path: root/lua/nvim-lsp-installer/jobs/version-check/init.lua
blob: da33ea9d47f934a76a389b3aac34a1c033d7ee71 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
local a = require "nvim-lsp-installer.core.async"
local Result = require "nvim-lsp-installer.core.result"
local process = require "nvim-lsp-installer.process"
local pip3 = require "nvim-lsp-installer.installers.pip3"
local gem = require "nvim-lsp-installer.installers.gem"
local cargo_check = require "nvim-lsp-installer.jobs.outdated-servers.cargo"
local gem_check = require "nvim-lsp-installer.jobs.outdated-servers.gem"
local pip3_check = require "nvim-lsp-installer.jobs.outdated-servers.pip3"
local spawn = require "nvim-lsp-installer.core.async.spawn"

local M = {}

local ServerVersion = {}
ServerVersion.__index = ServerVersion

---@param field_name string
local function version_in_receipt(field_name)
    ---@param receipt InstallReceipt
    ---@return Result
    return function(_, receipt)
        return Result.success(receipt.primary_source[field_name])
    end
end

local function noop()
    return Result.failure "Unable to detect version."
end

---@type Record<InstallReceiptSourceType, fun(server: Server, receipt: InstallReceipt): Result>
local version_checker = {
    ["npm"] = function(server, receipt)
        return spawn.npm({
            "ls",
            "--json",
            cwd = server.root_dir,
        }):map_catching(function(result)
            local npm_packages = vim.json.decode(result.stdout)
            return npm_packages.dependencies[receipt.primary_source.package].version
        end)
    end,
    ["pip3"] = function(server, receipt)
        return spawn.python3({
            "-m",
            "pip",
            "list",
            "--format",
            "json",
            cwd = server.root_dir,
            env = process.graft_env(pip3.env(server.root_dir)),
        }):map_catching(function(result)
            local pip_packages = vim.json.decode(result.stdout)
            local normalized_pip_package = pip3_check.normalize_package(receipt.primary_source.package)
            for _, pip_package in ipairs(pip_packages) do
                if pip_package.name == normalized_pip_package then
                    return pip_package.version
                end
            end
            error "Unable to find pip package."
        end)
    end,
    ["gem"] = function(server, receipt)
        return spawn.gem({
            "list",
            cwd = server.root_dir,
            env = process.graft_env(gem.env(server.root_dir)),
        }):map_catching(function(result)
            local gems = gem_check.parse_gem_list_output(result.stdout)
            if gems[receipt.primary_source.package] then
                return gems[receipt.primary_source.package]
            else
                error "Failed to find gem package version."
            end
        end)
    end,
    ["cargo"] = function(server, receipt)
        return spawn.cargo({
            "install",
            "--list",
            "--root",
            server.root_dir,
            cwd = server.root_dir,
        }):map_catching(function(result)
            local crates = cargo_check.parse_installed_crates(result.stdout)
            a.scheduler() -- needed because vim.fn.* call
            local package = vim.fn.fnamemodify(receipt.primary_source.package, ":t")
            if crates[package] then
                return crates[package]
            else
                error "Failed to find cargo package version."
            end
        end)
    end,
    ["git"] = function(server)
        return spawn.git({
            "rev-parse",
            "--short",
            "HEAD",
            cwd = server.root_dir,
        }):map_catching(function(result)
            return vim.trim(result.stdout)
        end)
    end,
    ["opam"] = noop,
    ["dotnet"] = noop,
    ["r_package"] = noop,
    ["github_release_file"] = version_in_receipt "release",
    ["github_tag"] = version_in_receipt "tag",
    ["jdtls"] = version_in_receipt "version",
}

--- Async function.
---@param server Server
---@return Result
function M.check_server_version(server)
    local receipt = server:get_receipt()
    if not receipt then
        return Result.failure "Unable to retrieve installation receipt."
    end
    local version_check = version_checker[receipt.primary_source.type] or noop
    local ok, result = pcall(version_check, server, receipt)
    if ok then
        return result
    else
        return Result.failure(result)
    end
end

return M