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
|