aboutsummaryrefslogtreecommitdiffstats
path: root/lua/mason-core/providers/init.lua
blob: 15e8081c28a855635f0ff00f7b8be56641e73721 (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
local Result = require "mason-core.result"
local log = require "mason-core.log"
local settings = require "mason.settings"

---@alias GitHubRelease { tag_name: string, prerelease: boolean, draft: boolean, assets: table[] }
---@alias GitHubTag { name: string }

---@class GitHubProvider
---@field get_latest_release? async fun(repo: string): Result # Result<GitHubRelease>
---@field get_all_release_versions? async fun(repo: string): Result # Result<string[]>
---@field get_latest_tag? async fun(repo: string): Result # Result<GitHubTag>
---@field get_all_tags? async fun(repo: string): Result # Result<string[]>

---@alias NpmPackage { name: string, version: string }

---@class NpmProvider
---@field get_latest_version? async fun(pkg: string): Result # Result<NpmPackage>
---@field get_all_versions? async fun(pkg: string): Result # Result<string[]>

---@alias PyPiPackage { name: string, version: string }

---@class PyPiProvider
---@field get_latest_version? async fun(pkg: string): Result # Result<PyPiPackage>
---@field get_all_versions? async fun(pkg: string): Result # Result<string[]> # Sorting should not be relied upon due to "proprietary" sorting algo in pip that is difficult to replicate in mason-registry-api.

---@alias RubyGem { name: string, version: string }

---@class RubyGemsProvider
---@field get_latest_version? async fun(gem: string): Result # Result<RubyGem>
---@field get_all_versions? async fun(gem: string): Result # Result<string[]>

---@alias PackagistPackage { name: string, version: string }

---@class PackagistProvider
---@field get_latest_version? async fun(pkg: string): Result # Result<PackagistPackage>
---@field get_all_versions? async fun(pkg: string): Result # Result<string[]>

---@alias Crate { name: string, version: string }

---@class CratesProvider
---@field get_latest_version? async fun(crate: string): Result # Result<Crate>
---@field get_all_versions? async fun(crate: string): Result # Result<string[]>

---@class GolangProvider
---@field get_all_versions? async fun(pkg: string): Result # Result<string[]>

---@class Provider
---@field github?     GitHubProvider
---@field npm?        NpmProvider
---@field pypi?       PyPiProvider
---@field rubygems?   RubyGemsProvider
---@field packagist?  PackagistProvider
---@field crates?     CratesProvider
---@field golang?     GolangProvider

local function service_mt(service)
    return setmetatable({}, {
        __index = function(_, method)
            return function(...)
                if #settings.current.providers < 1 then
                    log.error "No providers configured."
                    return Result.failure "1 or more providers are required."
                end
                for _, provider_module in ipairs(settings.current.providers) do
                    local ok, provider = pcall(require, provider_module)
                    if ok and provider then
                        local impl = provider[service] and provider[service][method]
                        if impl then
                            ---@type boolean, Result
                            local ok, result = pcall(impl, ...)
                            if ok and result:is_success() then
                                return result
                            else
                                if getmetatable(result) == Result then
                                    log.fmt_error("Provider %s %s failed: %s", service, method, result:err_or_nil())
                                else
                                    log.fmt_error("Provider %s %s errored: %s", service, method, result)
                                end
                            end
                        end
                    else
                        log.fmt_error("Unable to find provider %s is not registered. %s", provider_module, provider)
                    end
                end
                local err = ("No provider implementation succeeded for %s.%s"):format(service, method)
                log.error(err)
                return Result.failure(err)
            end
        end,
    })
end

---@type Provider
local providers = setmetatable({}, {
    __index = function(tbl, service)
        tbl[service] = service_mt(service)
        return tbl[service]
    end,
})

return providers