summaryrefslogtreecommitdiffstats
path: root/lua/mason-core/package
diff options
context:
space:
mode:
authorWilliam Boman <william@redwill.se>2023-09-11 00:37:05 +0200
committerWilliam Boman <william@redwill.se>2025-02-16 09:48:59 +0100
commitd0119c18adff184c5c75f7ec59b6f12b301d268d (patch)
tree3f196ef7cdde464392c0680edcd57fc6fe47825a /lua/mason-core/package
parentrefactor!: remove old managers (#1497) (diff)
downloadmason-d0119c18adff184c5c75f7ec59b6f12b301d268d.tar
mason-d0119c18adff184c5c75f7ec59b6f12b301d268d.tar.gz
mason-d0119c18adff184c5c75f7ec59b6f12b301d268d.tar.bz2
mason-d0119c18adff184c5c75f7ec59b6f12b301d268d.tar.lz
mason-d0119c18adff184c5c75f7ec59b6f12b301d268d.tar.xz
mason-d0119c18adff184c5c75f7ec59b6f12b301d268d.tar.zst
mason-d0119c18adff184c5c75f7ec59b6f12b301d268d.zip
refactor!: consolidate Lua registry sources and the Package API (#1498)
**This removes the following APIs:** - `Package:check_new_version()`. Instead use the new `Package:get_latest_version()`. **This has a breaking change in the following APIs:** - `Package:get_installed_version()` now no longer takes a callback but instead returns the installed version or `nil` if not installed. <details> <summary>To handle these breaking changes in plugins, leverage the `mason.version` module, for example:</summary> ```lua local mason_version = require("mason.version") local registry = require("mason-registry") local pkg = registry.get_package("rust-analyzer") if mason_version.MAJOR_VERSION < 2 then -- before pkg:check_new_version(function (success, new_version) -- … end) pkg:get_installed_version(function (success, installed_version) -- … end) else -- after local new_version = pkg:get_latest_version() local installed_version = pkg:get_installed_version() fi ``` </details> --- <details> <summary>This change also introduces breaking changes for Lua registry sources, by consolidating the package schema with the registry.</summary> The following is an example of a package defined in a Lua registry, following the new schema: ```lua local Pkg = require("mason-core.package") return Pkg.new { schema = "registry+v1", name = "ripgrep", description = "ripgrep recursively searches directories for a regex pattern while respecting your gitignore.", homepage = "https://github.com/BurntSushi/ripgrep", licenses = { Pkg.License.MIT }, languages = {}, categories = {}, source = { id = "pkg:mason/ripgrep@13.0.0", ---@param ctx InstallContext ---@param purl Purl install = function(ctx, purl) -- Arbitrary installation code. end, }, bin = { rg = "./bin/rg", }, } ``` </details>
Diffstat (limited to 'lua/mason-core/package')
-rw-r--r--lua/mason-core/package/init.lua142
-rw-r--r--lua/mason-core/package/version-check.lua80
2 files changed, 50 insertions, 172 deletions
diff --git a/lua/mason-core/package/init.lua b/lua/mason-core/package/init.lua
index 899370fa..4a7f3d70 100644
--- a/lua/mason-core/package/init.lua
+++ b/lua/mason-core/package/init.lua
@@ -10,13 +10,9 @@ local path = require "mason-core.path"
local platform = require "mason-core.platform"
local registry = require "mason-registry"
-local is_not_nil = _.complement(_.is_nil)
-local is_registry_schema_id = _.matches "^registry%+v[1-9]+$"
-local is_registry_spec = _.prop_satisfies(_.all_pass { is_not_nil, is_registry_schema_id }, "schema")
-
---@class Package : EventEmitter
---@field name string
----@field spec RegistryPackageSpec | PackageSpec
+---@field spec RegistryPackageSpec
---@field private handle InstallHandle The currently associated handle.
local Package = setmetatable({}, { __index = EventEmitter })
@@ -47,15 +43,17 @@ Package.Cat = {
Formatter = "Formatter",
}
-local PackageMt = { __index = Package }
+---@alias PackageLicense string
----@class PackageSpec
----@field name string
----@field desc string
----@field homepage string
----@field categories PackageCategory[]
----@field languages PackageLanguage[]
----@field install async fun(ctx: InstallContext)
+---@type table<PackageLicense, PackageLicense>
+Package.License = setmetatable({}, {
+ __index = function(s, license)
+ s[license] = license
+ return s[license]
+ end,
+})
+
+local PackageMt = { __index = Package }
---@class RegistryPackageSourceVersionOverride : RegistryPackageSource
---@field constraint string
@@ -86,32 +84,24 @@ local PackageMt = { __index = Package }
---@field share table<string, string>?
---@field opt table<string, string>?
----@param spec PackageSpec | RegistryPackageSpec
+---@param spec RegistryPackageSpec
local function validate_spec(spec)
if platform.cached_features["nvim-0.11"] ~= 1 then
return
end
- if is_registry_spec(spec) then
- vim.validate("name", spec.name, "string")
- vim.validate("description", spec.description, "string")
- vim.validate("homepage", spec.homepage, "string")
- vim.validate("licenses", spec.licenses, "table")
- vim.validate("categories", spec.categories, "table")
- vim.validate("languages", spec.languages, "table")
- vim.validate("source", spec.source, "table")
- vim.validate("bin", spec.bin, { "table", "nil" })
- vim.validate("share", spec.share, { "table", "nil" })
- else
- vim.validate("name", spec.name, "string")
- vim.validate("desc", spec.desc, "string")
- vim.validate("homepage", spec.homepage, "string")
- vim.validate("categories", spec.categories, "table")
- vim.validate("languages", spec.languages, "table")
- vim.validate("install", spec.install, "function")
- end
+ vim.validate("schema", spec.schema, _.equals "registry+v1", "registry+v1")
+ vim.validate("name", spec.name, "string")
+ vim.validate("description", spec.description, "string")
+ vim.validate("homepage", spec.homepage, "string")
+ vim.validate("licenses", spec.licenses, "table")
+ vim.validate("categories", spec.categories, "table")
+ vim.validate("languages", spec.languages, "table")
+ vim.validate("source", spec.source, "table")
+ vim.validate("bin", spec.bin, { "table", "nil" })
+ vim.validate("share", spec.share, { "table", "nil" })
end
----@param spec PackageSpec | RegistryPackageSpec
+---@param spec RegistryPackageSpec
function Package.new(spec)
validate_spec(spec)
return EventEmitter.init(setmetatable({
@@ -241,67 +231,40 @@ function Package:get_receipt()
return Optional.empty()
end
----@param callback fun(success: boolean, version_or_err: string)
-function Package:get_installed_version(callback)
- self:get_receipt()
- :if_present(
+---@return string?
+function Package:get_installed_version()
+ return self:get_receipt()
+ :and_then(
---@param receipt InstallReceipt
function(receipt)
- if is_registry_schema_id(receipt.primary_source.type) then
- local resolve = _.curryN(callback, 2)
- Purl.parse(receipt.primary_source.id)
- :map(_.prop "version")
- :on_success(resolve(true))
- :on_failure(resolve(false))
- else
- a.run(function()
- local version_checks = require "mason-core.package.version-check"
- return version_checks.get_installed_version(receipt, self:get_install_path()):get_or_throw()
- end, callback)
- end
+ return Purl.parse(receipt.primary_source.id):map(_.prop "version"):ok()
end
)
- :if_not_present(function()
- callback(false, "Unable to get receipt.")
- end)
+ :or_else(nil)
end
----@param callback fun(success: boolean, result_or_err: NewPackageVersion)
-function Package:check_new_version(callback)
- if self:is_registry_spec() then
- self:get_installed_version(_.scheduler_wrap(function(success, installed_version)
- if not success then
- return callback(false, installed_version)
- end
- local resolve = _.curryN(callback, 2)
- Result.try(function(try)
- -- This is a bit goofy, but it's done to verify that a new version is supported by the
- -- current platform (parse fails if it's not). We don't want to surface new versions that
- -- are unsupported.
- try(require("mason-core.installer.registry").parse(self.spec, {}))
+---@return string
+function Package:get_latest_version()
+ return Purl.parse(self.spec.source.id)
+ :map(_.prop "version")
+ :get_or_throw(("Unable to retrieve version from malformed purl: %s."):format(self.spec.source.id))
+end
- ---@type Purl
- local purl = try(Purl.parse(self.spec.source.id))
- if purl.version and installed_version ~= purl.version then
- return {
- name = purl.name,
- current_version = installed_version,
- latest_version = purl.version,
- }
- else
- return Result.failure "Package is not outdated."
- end
- end)
- :on_success(resolve(true))
- :on_failure(resolve(false))
- end))
- else
- a.run(function()
- local receipt = self:get_receipt():or_else_throw "Unable to get receipt."
- local version_checks = require "mason-core.package.version-check"
- return version_checks.get_new_version(receipt, self:get_install_path()):get_or_throw()
- end, callback)
- end
+---@param opts? PackageInstallOpts
+function Package:is_installable(opts)
+ return require("mason-core.installer.registry").parse(self.spec, opts or {}):is_success()
+end
+
+---@return Result # Result<string[]>
+function Package:get_all_versions()
+ local registry_installer = require "mason-core.installer.registry"
+ return Result.try(function(try)
+ ---@type Purl
+ local purl = try(Purl.parse(self.spec.source.id))
+ ---@type InstallerProvider
+ local provider = try(registry_installer.get_provider(purl))
+ return provider.get_versions(purl, self.spec.source)
+ end)
end
function Package:get_lsp_settings_schema()
@@ -314,11 +277,6 @@ function Package:get_lsp_settings_schema()
return Optional.empty()
end
----@return boolean
-function Package:is_registry_spec()
- return is_registry_spec(self.spec)
-end
-
function PackageMt.__tostring(self)
return ("Package(name=%s)"):format(self.name)
end
diff --git a/lua/mason-core/package/version-check.lua b/lua/mason-core/package/version-check.lua
deleted file mode 100644
index 66d9ad13..00000000
--- a/lua/mason-core/package/version-check.lua
+++ /dev/null
@@ -1,80 +0,0 @@
-local Result = require "mason-core.result"
-local cargo = require "mason-core.managers.cargo"
-local composer = require "mason-core.managers.composer"
-local gem = require "mason-core.managers.gem"
-local git = require "mason-core.managers.git"
-local github = require "mason-core.managers.github"
-local go = require "mason-core.managers.go"
-local log = require "mason-core.log"
-local luarocks = require "mason-core.managers.luarocks"
-local npm = require "mason-core.managers.npm"
-local pip3 = require "mason-core.managers.pip3"
-
----@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
-
----@type table<InstallReceiptSourceType, async fun(receipt: InstallReceipt, install_dir: string): Result>
-local get_installed_version_by_type = {
- ["npm"] = npm.get_installed_primary_package_version,
- ["pip3"] = pip3.get_installed_primary_package_version,
- ["gem"] = gem.get_installed_primary_package_version,
- ["cargo"] = cargo.get_installed_primary_package_version,
- ["composer"] = composer.get_installed_primary_package_version,
- ["git"] = git.get_installed_revision,
- ["go"] = go.get_installed_primary_package_version,
- ["luarocks"] = luarocks.get_installed_primary_package_version,
- ["github_release_file"] = version_in_receipt "release",
- ["github_release"] = version_in_receipt "release",
- ["github_tag"] = version_in_receipt "tag",
-}
-
----@class NewPackageVersion
----@field name string
----@field current_version string
----@field latest_version string
-
-local get_new_version_by_type = {
- ["npm"] = npm.check_outdated_primary_package,
- ["pip3"] = pip3.check_outdated_primary_package,
- ["git"] = git.check_outdated_git_clone,
- ["cargo"] = cargo.check_outdated_primary_package,
- ["composer"] = composer.check_outdated_primary_package,
- ["gem"] = gem.check_outdated_primary_package,
- ["go"] = go.check_outdated_primary_package,
- ["luarocks"] = luarocks.check_outdated_primary_package,
- ["github_release_file"] = github.check_outdated_primary_package_release,
- ["github_release"] = github.check_outdated_primary_package_release,
- ["github_tag"] = github.check_outdated_primary_package_tag,
-}
-
----@param provider_mapping table<string, async fun(receipt: InstallReceipt, install_dir: string): Result>
-local function version_check(provider_mapping)
- ---@param receipt InstallReceipt
- ---@param install_dir string
- return function(receipt, install_dir)
- local check = provider_mapping[receipt.primary_source.type]
- if not check then
- return Result.failure(
- ("Packages installed via %s does not yet support version check."):format(receipt.primary_source.type)
- )
- end
- return check(receipt, install_dir)
- :on_success(function(version)
- log.debug("Version check", version)
- end)
- :on_failure(function(failure)
- log.debug("Version check failed", tostring(failure))
- end)
- end
-end
-
-return {
- get_installed_version = version_check(get_installed_version_by_type),
- get_new_version = version_check(get_new_version_by_type),
-}