From d0119c18adff184c5c75f7ec59b6f12b301d268d Mon Sep 17 00:00:00 2001 From: William Boman Date: Mon, 11 Sep 2023 00:37:05 +0200 Subject: refactor!: consolidate Lua registry sources and the Package API (#1498) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **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.
To handle these breaking changes in plugins, leverage the `mason.version` module, for example: ```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 ```
---
This change also introduces breaking changes for Lua registry sources, by consolidating the package schema with the registry. 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", }, } ```
--- lua/mason-core/package/init.lua | 144 ++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 93 deletions(-) (limited to 'lua/mason-core/package/init.lua') 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 +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? ---@field opt table? ----@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, {})) - - ---@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 +---@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 + +---@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 +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 -- cgit v1.2.3-70-g09d2