diff options
Diffstat (limited to 'lua/mason-core/package/init.lua')
| -rw-r--r-- | lua/mason-core/package/init.lua | 132 |
1 files changed, 112 insertions, 20 deletions
diff --git a/lua/mason-core/package/init.lua b/lua/mason-core/package/init.lua index 88e89c41..16250ead 100644 --- a/lua/mason-core/package/init.lua +++ b/lua/mason-core/package/init.lua @@ -6,10 +6,16 @@ local log = require "mason-core.log" local EventEmitter = require "mason-core.EventEmitter" local fs = require "mason-core.fs" local path = require "mason-core.path" +local Result = require "mason-core.result" +local Purl = require "mason-core.purl" + +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 PackageSpec +---@field spec RegistryPackageSpec | PackageSpec ---@field private handle InstallHandle The currently associated handle. local Package = setmetatable({}, { __index = EventEmitter }) @@ -50,16 +56,52 @@ local PackageMt = { __index = Package } ---@field languages PackageLanguage[] ---@field install async fun(ctx: InstallContext) ----@param spec PackageSpec +---@class RegistryPackageSourceVersionOverride : RegistryPackageSource +---@field constraint string + +---@class RegistryPackageSource +---@field id string PURL-compliant identifier. +---@field version_overrides? RegistryPackageSourceVersionOverride[] + +---@class RegistryPackageSpec +---@field schema '"registry+v1"' +---@field name string +---@field description string +---@field homepage string +---@field licenses string[] +---@field languages string[] +---@field categories string[] +---@field source RegistryPackageSource +---@field bin table<string, string>? +---@field share table<string, string>? +---@field opt table<string, string>? + +---@param spec PackageSpec | RegistryPackageSpec function Package.new(spec) - vim.validate { - name = { spec.name, "s" }, - desc = { spec.desc, "s" }, - homepage = { spec.homepage, "s" }, - categories = { spec.categories, "t" }, - languages = { spec.languages, "t" }, - install = { spec.install, "f" }, - } + if is_registry_spec(spec) then + vim.validate { + name = { spec.name, "s" }, + description = { spec.description, "s" }, + homepage = { spec.homepage, "s" }, + licenses = { spec.licenses, "t" }, + categories = { spec.categories, "t" }, + languages = { spec.languages, "t" }, + source = { spec.source, "t" }, + bin = { spec.bin, { "t", "nil" } }, + share = { spec.share, { "t", "nil" } }, + } + -- XXX: this is for compatibilty with the PackageSpec structure + spec.desc = spec.description + else + vim.validate { + name = { spec.name, "s" }, + desc = { spec.desc, "s" }, + homepage = { spec.homepage, "s" }, + categories = { spec.categories, "t" }, + languages = { spec.languages, "t" }, + install = { spec.install, "f" }, + } + end return EventEmitter.init(setmetatable({ name = spec.name, -- for convenient access @@ -190,20 +232,65 @@ end ---@param callback fun(success: boolean, version_or_err: string) function Package:get_installed_version(callback) - 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_installed_version(receipt, self:get_install_path()):get_or_throw() - end, callback) + self:get_receipt() + :if_present( + ---@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 + end + ) + :if_not_present(function() + callback(false, "Unable to get receipt.") + end) end ---@param callback fun(success: boolean, result_or_err: NewPackageVersion) function Package:check_new_version(callback) - 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) + if self:is_registry_spec() then + self:get_installed_version(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 end function Package:get_lsp_settings_schema() @@ -214,6 +301,11 @@ function Package:get_lsp_settings_schema() return Optional.of(schema) 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 |
