aboutsummaryrefslogtreecommitdiffstats
path: root/lua/mason-core
diff options
context:
space:
mode:
authorWilliam Boman <william@redwill.se>2022-10-30 17:43:46 +0100
committerGitHub <noreply@github.com>2022-10-30 17:43:46 +0100
commit37c745fa73b983c86904132efb30ef2a4a76df5e (patch)
treec55fe52b7c5c20ed4fdbb3ee073519fd0ccbe6b2 /lua/mason-core
parentchore: update generated code (#608) (diff)
downloadmason-37c745fa73b983c86904132efb30ef2a4a76df5e.tar
mason-37c745fa73b983c86904132efb30ef2a4a76df5e.tar.gz
mason-37c745fa73b983c86904132efb30ef2a4a76df5e.tar.bz2
mason-37c745fa73b983c86904132efb30ef2a4a76df5e.tar.lz
mason-37c745fa73b983c86904132efb30ef2a4a76df5e.tar.xz
mason-37c745fa73b983c86904132efb30ef2a4a76df5e.tar.zst
mason-37c745fa73b983c86904132efb30ef2a4a76df5e.zip
feat: add provider interface (#601)
Diffstat (limited to 'lua/mason-core')
-rw-r--r--lua/mason-core/functional/function.lua5
-rw-r--r--lua/mason-core/functional/init.lua3
-rw-r--r--lua/mason-core/functional/list.lua7
-rw-r--r--lua/mason-core/functional/string.lua4
-rw-r--r--lua/mason-core/managers/github/client.lua13
-rw-r--r--lua/mason-core/managers/npm/init.lua4
-rw-r--r--lua/mason-core/managers/pip3/init.lua48
-rw-r--r--lua/mason-core/optional.lua8
-rw-r--r--lua/mason-core/providers/init.lua77
-rw-r--r--lua/mason-core/spawn.lua2
10 files changed, 128 insertions, 43 deletions
diff --git a/lua/mason-core/functional/function.lua b/lua/mason-core/functional/function.lua
index c6d460a5..f1475229 100644
--- a/lua/mason-core/functional/function.lua
+++ b/lua/mason-core/functional/function.lua
@@ -89,4 +89,9 @@ _.lazy = function(fn)
end
end
+_.tap = _.curryN(function(fn, value)
+ fn(value)
+ return value
+end, 2)
+
return _
diff --git a/lua/mason-core/functional/init.lua b/lua/mason-core/functional/init.lua
index ed502a4b..04ef1534 100644
--- a/lua/mason-core/functional/init.lua
+++ b/lua/mason-core/functional/init.lua
@@ -27,6 +27,7 @@ _.T = fun.T
_.F = fun.F
_.memoize = fun.memoize
_.lazy = fun.lazy
+_.tap = fun.tap
---@module "mason-core.functional.list"
local list = lazy_require "mason-core.functional.list"
@@ -45,6 +46,7 @@ _.prepend = list.prepend
_.zip_table = list.zip_table
_.nth = list.nth
_.head = list.head
+_.last = list.last
_.length = list.length
_.flatten = list.flatten
_.sort_by = list.sort_by
@@ -80,6 +82,7 @@ _.dec = number.dec
---@module "mason-core.functional.string"
local string = lazy_require "mason-core.functional.string"
_.matches = string.matches
+_.match = string.match
_.format = string.format
_.split = string.split
_.gsub = string.gsub
diff --git a/lua/mason-core/functional/list.lua b/lua/mason-core/functional/list.lua
index 31b631b8..2a5378fe 100644
--- a/lua/mason-core/functional/list.lua
+++ b/lua/mason-core/functional/list.lua
@@ -148,6 +148,13 @@ end, 2)
_.head = _.nth(1)
+---@generic T
+---@param list T[]
+---@return T?
+_.last = function(list)
+ return list[#list]
+end
+
---@param value string|any[]
_.length = function(value)
return #value
diff --git a/lua/mason-core/functional/string.lua b/lua/mason-core/functional/string.lua
index 7726c8e1..9b7da979 100644
--- a/lua/mason-core/functional/string.lua
+++ b/lua/mason-core/functional/string.lua
@@ -8,6 +8,10 @@ _.matches = fun.curryN(function(pattern, str)
return str:match(pattern) ~= nil
end, 2)
+_.match = fun.curryN(function(pattern, str)
+ return { str:match(pattern) }
+end, 2)
+
---@param template string
---@param str string
_.format = fun.curryN(function(template, str)
diff --git a/lua/mason-core/managers/github/client.lua b/lua/mason-core/managers/github/client.lua
index 3ef307c1..699e3fa4 100644
--- a/lua/mason-core/managers/github/client.lua
+++ b/lua/mason-core/managers/github/client.lua
@@ -2,13 +2,10 @@ local _ = require "mason-core.functional"
local log = require "mason-core.log"
local fetch = require "mason-core.fetch"
local spawn = require "mason-core.spawn"
-local api = require "mason-registry.api"
+local providers = require "mason-core.providers"
local M = {}
----@alias GitHubReleaseAsset {url: string, id: integer, name: string, browser_download_url: string, created_at: string, updated_at: string, size: integer, download_count: integer}
----@alias GitHubRelease {tag_name: string, prerelease: boolean, draft: boolean, assets:GitHubReleaseAsset[]}
----@alias GitHubTag {name: string}
---@alias GitHubCommit {sha: string}
local stringify_params = _.compose(_.join "&", _.map(_.join "="), _.sort_by(_.head), _.to_pairs)
@@ -66,11 +63,7 @@ end
---@return Result # Result<GitHubRelease>
function M.fetch_latest_release(repo, opts)
opts = opts or { include_prerelease = false }
- return api.repo.releases.latest({ repo = repo }, {
- params = {
- include_prerelease = opts.include_prerelease and "true" or "false",
- },
- })
+ return providers.github.get_latest_release(repo, { include_prerelease = opts.include_prerelease })
end
---@async
@@ -87,7 +80,7 @@ end
---@param repo string The GitHub repo ("username/repo").
---@return Result # Result<string> The latest tag name.
function M.fetch_latest_tag(repo)
- return api.repo.tags.latest({ repo = repo }):map(_.prop "tag")
+ return providers.github.get_latest_tag(repo):map(_.prop "tag")
end
---@async
diff --git a/lua/mason-core/managers/npm/init.lua b/lua/mason-core/managers/npm/init.lua
index 61ee4042..96571420 100644
--- a/lua/mason-core/managers/npm/init.lua
+++ b/lua/mason-core/managers/npm/init.lua
@@ -4,7 +4,7 @@ local Result = require "mason-core.result"
local path = require "mason-core.path"
local _ = require "mason-core.functional"
local platform = require "mason-core.platform"
-local api = require "mason-registry.api"
+local providers = require "mason-core.providers"
local list_copy = _.list_copy
@@ -112,7 +112,7 @@ function M.check_outdated_primary_package(receipt, install_dir)
local primary_package = receipt.primary_source.package
return M.get_installed_primary_package_version(receipt, install_dir)
:and_then(function(installed_version)
- return api.npm.versions.latest({ package = primary_package }):map(function(response)
+ return providers.npm.get_latest_version(primary_package):map(function(response)
return {
installed = installed_version,
latest = response.version,
diff --git a/lua/mason-core/managers/pip3/init.lua b/lua/mason-core/managers/pip3/init.lua
index 4581bc0b..67f70a89 100644
--- a/lua/mason-core/managers/pip3/init.lua
+++ b/lua/mason-core/managers/pip3/init.lua
@@ -7,6 +7,7 @@ local Optional = require "mason-core.optional"
local installer = require "mason-core.installer"
local Result = require "mason-core.result"
local spawn = require "mason-core.spawn"
+local providers = require "mason-core.providers"
local VENV_DIR = "venv"
@@ -103,36 +104,27 @@ function M.check_outdated_primary_package(receipt, install_dir)
return Result.failure "Receipt does not have a primary source of type pip3"
end
local normalized_package = M.normalize_package(receipt.primary_source.package)
- return spawn
- .python({
- "-m",
- "pip",
- "list",
- "--outdated",
- "--format=json",
- cwd = install_dir,
- with_paths = { M.venv_path(install_dir) },
- })
- :map_catching(function(result)
- ---@alias PipOutdatedPackage {name: string, version: string, latest_version: string}
- ---@type PipOutdatedPackage[]
- local packages = vim.json.decode(result.stdout)
-
- local outdated_primary_package = _.find_first(function(outdated_package)
- return outdated_package.name == normalized_package
- and outdated_package.version ~= outdated_package.latest_version
- end, packages)
-
- return Optional.of_nilable(outdated_primary_package)
- :map(function(pkg)
- return {
+ return M.get_installed_primary_package_version(receipt, install_dir):and_then(function(installed_version)
+ return providers.pypi
+ .get_latest_version(normalized_package)
+ :map(function(latest)
+ return {
+ current = installed_version,
+ latest = latest.version,
+ }
+ end)
+ :and_then(function(versions)
+ if versions.current ~= versions.latest then
+ return Result.success {
name = normalized_package,
- current_version = assert(pkg.version, "missing current pip3 package version"),
- latest_version = assert(pkg.latest_version, "missing latest pip3 package version"),
+ current_version = versions.current,
+ latest_version = versions.latest,
}
- end)
- :or_else_throw "Primary package is not outdated."
- end)
+ else
+ return Result.failure "Primary package is not outdated."
+ end
+ end)
+ end)
end
---@async
diff --git a/lua/mason-core/optional.lua b/lua/mason-core/optional.lua
index 6eb0719e..cc40da77 100644
--- a/lua/mason-core/optional.lua
+++ b/lua/mason-core/optional.lua
@@ -105,13 +105,17 @@ function Optional:is_present()
return self._value ~= nil
end
----@param err fun(): any
+---@param err (fun(): any)|string
function Optional:ok_or(err)
local Result = require "mason-core.result"
if self:is_present() then
return Result.success(self:get())
else
- return Result.failure(err())
+ if type(err) == "string" then
+ return Result.failure(err)
+ else
+ return Result.failure(err())
+ end
end
end
diff --git a/lua/mason-core/providers/init.lua b/lua/mason-core/providers/init.lua
new file mode 100644
index 00000000..76bd431b
--- /dev/null
+++ b/lua/mason-core/providers/init.lua
@@ -0,0 +1,77 @@
+local settings = require "mason.settings"
+local log = require "mason-core.log"
+local Result = require "mason-core.result"
+
+---@alias GitHubReleaseAsset {url: string, id: integer, name: string, browser_download_url: string, created_at: string, updated_at: string, size: integer, download_count: integer}
+---@alias GitHubRelease { tag_name: string, prerelease: boolean, draft: boolean, assets:GitHubReleaseAsset[] }
+---@alias GitHubTag { name: string }
+
+---@class GitHubProvider
+---@field get_latest_release? async fun(repo: string, opts?: { include_prerelease?: boolean }): 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.
+
+---@class Provider
+---@field github? GitHubProvider
+---@field npm? NpmProvider
+---@field pypi? PyPiProvider
+
+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 found 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
diff --git a/lua/mason-core/spawn.lua b/lua/mason-core/spawn.lua
index fd01c97a..814ef8f7 100644
--- a/lua/mason-core/spawn.lua
+++ b/lua/mason-core/spawn.lua
@@ -5,7 +5,7 @@ local process = require "mason-core.process"
local platform = require "mason-core.platform"
local log = require "mason-core.log"
----@alias JobSpawn table<string, async fun(opts: JobSpawnOpts): Result>
+---@alias JobSpawn table<string, async fun(opts: SpawnArgs): Result>
---@type JobSpawn
local spawn = {
_aliases = {