diff options
| author | William Boman <william@redwill.se> | 2023-08-26 00:03:13 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-08-26 00:03:13 +0200 |
| commit | 85440397264a31208721e4501c93b23a4940b27e (patch) | |
| tree | 2026821ac8f1e63d5a34f2f52f40ac50eac84f3f /lua | |
| parent | chore: decrease log level (#1467) (diff) | |
| download | mason-85440397264a31208721e4501c93b23a4940b27e.tar mason-85440397264a31208721e4501c93b23a4940b27e.tar.gz mason-85440397264a31208721e4501c93b23a4940b27e.tar.bz2 mason-85440397264a31208721e4501c93b23a4940b27e.tar.lz mason-85440397264a31208721e4501c93b23a4940b27e.tar.xz mason-85440397264a31208721e4501c93b23a4940b27e.tar.zst mason-85440397264a31208721e4501c93b23a4940b27e.zip | |
feat(registry): add file: source protocol (#1457)
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/mason-registry/sources/file.lua | 152 | ||||
| -rw-r--r-- | lua/mason-registry/sources/github.lua | 45 | ||||
| -rw-r--r-- | lua/mason-registry/sources/init.lua | 7 | ||||
| -rw-r--r-- | lua/mason-registry/sources/util.lua | 40 | ||||
| -rw-r--r-- | lua/mason/api/command.lua | 2 |
5 files changed, 205 insertions, 41 deletions
diff --git a/lua/mason-registry/sources/file.lua b/lua/mason-registry/sources/file.lua new file mode 100644 index 00000000..8d881c03 --- /dev/null +++ b/lua/mason-registry/sources/file.lua @@ -0,0 +1,152 @@ +local Optional = require "mason-core.optional" +local Result = require "mason-core.result" +local _ = require "mason-core.functional" +local a = require "mason-core.async" +local async_control = require "mason-core.async.control" +local async_uv = require "mason-core.async.uv" +local fs = require "mason-core.fs" +local log = require "mason-core.log" +local path = require "mason-core.path" +local spawn = require "mason-core.spawn" +local util = require "mason-registry.sources.util" + +local Channel = async_control.Channel + +---@class FileRegistrySourceSpec +---@field path string + +---@class FileRegistrySource : RegistrySource +---@field spec FileRegistrySourceSpec +---@field root_dir string +---@field buffer { specs: RegistryPackageSpec[], instances: table<string, Package> }? +local FileRegistrySource = {} +FileRegistrySource.__index = FileRegistrySource + +---@param spec FileRegistrySourceSpec +function FileRegistrySource.new(spec) + return setmetatable({ + spec = spec, + }, FileRegistrySource) +end + +function FileRegistrySource:is_installed() + return self.buffer ~= nil +end + +---@return RegistryPackageSpec[] +function FileRegistrySource:get_all_package_specs() + return _.filter_map(util.map_registry_spec, self:get_buffer().specs) +end + +function FileRegistrySource:reload() + if not self:is_installed() then + return + end + self.buffer.instances = _.compose( + _.index_by(_.prop "name"), + _.map(util.hydrate_package(self.buffer.instances or {})) + )(self:get_all_package_specs()) + return self.buffer +end + +function FileRegistrySource:get_buffer() + return self.buffer or { + specs = {}, + instances = {}, + } +end + +---@param pkg_name string +---@return Package? +function FileRegistrySource:get_package(pkg_name) + return self:get_buffer().instances[pkg_name] +end + +function FileRegistrySource:get_all_package_names() + return _.map(_.prop "name", self:get_all_package_specs()) +end + +function FileRegistrySource:get_installer() + return Optional.of(_.partial(self.install, self)) +end + +---@async +function FileRegistrySource:install() + return Result.try(function(try) + if vim.fn.executable "yq" ~= 1 then + return Result.failure "yq is not installed." + end + local yq = vim.fn.exepath "yq" + + local registry_dir = vim.fn.expand(self.spec.path) --[[@as string]] + local packages_dir = path.concat { registry_dir, "packages" } + if not fs.async.dir_exists(registry_dir) then + return Result.failure(("Directory %s does not exist."):format(registry_dir)) + end + + if not fs.async.dir_exists(packages_dir) then + return Result.failure "packages/ directory is missing." + end + + ---@type ReaddirEntry[] + local entries = _.filter(_.prop_eq("type", "directory"), fs.async.readdir(packages_dir)) + + local channel = Channel.new() + a.run(function() + for _, entry in ipairs(entries) do + channel:send(path.concat { packages_dir, entry.name, "package.yaml" }) + end + channel:close() + end, function() end) + + local CONSUMERS_COUNT = 10 + local consumers = {} + for _ = 1, CONSUMERS_COUNT do + table.insert(consumers, function() + local specs = {} + for package_file in channel:iter() do + local yaml_spec = fs.async.read_file(package_file) + local spec = vim.json.decode(spawn + [yq]({ + "-o", + "json", + on_spawn = a.scope(function(_, stdio) + local stdin = stdio[1] + async_uv.write(stdin, yaml_spec) + async_uv.shutdown(stdin) + async_uv.close(stdin) + end), + }) + :get_or_throw(("Failed to parse %s."):format(package_file)).stdout) + + specs[#specs + 1] = spec + end + return specs + end) + end + + local specs = _.reduce(vim.list_extend, {}, _.table_pack(a.wait_all(consumers))) + return specs + end) + :on_success(function(specs) + self.buffer = _.assoc("specs", specs, self.buffer or {}) + self:reload() + end) + :on_failure(function(err) + log.fmt_error("Failed to install registry %s. %s", self, err) + end) +end + +function FileRegistrySource:get_display_name() + if self:is_installed() then + return ("local: %s"):format(self.spec.path) + else + return ("local: %s [uninstalled]"):format(self.spec.path) + end +end + +function FileRegistrySource:__tostring() + return ("FileRegistrySource(path=%s)"):format(self.spec.path) +end + +return FileRegistrySource diff --git a/lua/mason-registry/sources/github.lua b/lua/mason-registry/sources/github.lua index 833c5ba1..fce5077f 100644 --- a/lua/mason-registry/sources/github.lua +++ b/lua/mason-registry/sources/github.lua @@ -1,5 +1,4 @@ local Optional = require "mason-core.optional" -local Pkg = require "mason-core.package" local Result = require "mason-core.result" local _ = require "mason-core.functional" local fetch = require "mason-core.fetch" @@ -7,8 +6,8 @@ local fs = require "mason-core.fs" local log = require "mason-core.log" local path = require "mason-core.path" local providers = require "mason-core.providers" -local registry_installer = require "mason-core.installer.registry" local settings = require "mason.settings" +local util = require "mason-registry.sources.util" -- Parse sha256sum text output to a table<filename: string, sha256sum: string> structure local parse_checksums = _.compose(_.from_pairs, _.map(_.compose(_.reverse, _.split " ")), _.split "\n", _.trim) @@ -52,50 +51,16 @@ function GitHubRegistrySource:get_all_package_specs() return {} end local data = vim.json.decode(fs.sync.read_file(self.data_file)) --[[@as RegistryPackageSpec[] ]] - return _.filter_map( - ---@param spec RegistryPackageSpec - function(spec) - -- registry+v1 specifications doesn't include a schema property, so infer it - spec.schema = spec.schema or "registry+v1" - - if not registry_installer.SCHEMA_CAP[spec.schema] then - log.fmt_debug("Excluding package=%s with unsupported schema_version=%s", spec.name, spec.schema) - return Optional.empty() - end - - -- XXX: this is for compatibilty with the PackageSpec structure - spec.desc = spec.description - return Optional.of(spec) - end, - data - ) + return _.filter_map(util.map_registry_spec, data) end function GitHubRegistrySource:reload() if not self:is_installed() then return end - self.buffer = _.compose( - _.index_by(_.prop "name"), - _.map( - ---@param spec RegistryPackageSpec - function(spec) - -- hydrate Pkg.Lang index - _.each(function(lang) - local _ = Pkg.Lang[lang] - end, spec.languages) - - local pkg = self.buffer and self.buffer[spec.name] - if pkg then - -- Apply spec to the existing Package instance. This is important as to not have lingering package - -- instances. - pkg.spec = spec - return pkg - end - return Pkg.new(spec) - end - ) - )(self:get_all_package_specs()) + self.buffer = _.compose(_.index_by(_.prop "name"), _.map(util.hydrate_package(self.buffer or {})))( + self:get_all_package_specs() + ) return self.buffer end diff --git a/lua/mason-registry/sources/init.lua b/lua/mason-registry/sources/init.lua index 0739f40b..e849fb84 100644 --- a/lua/mason-registry/sources/init.lua +++ b/lua/mason-registry/sources/init.lua @@ -30,6 +30,13 @@ local function parse(registry_id) mod = id, } end + elseif type == "file" then + return function() + local FileRegistrySource = require "mason-registry.sources.file" + return FileRegistrySource.new { + path = id, + } + end elseif type ~= nil then error(("Unknown registry type %q: %q."):format(type, registry_id), 0) end diff --git a/lua/mason-registry/sources/util.lua b/lua/mason-registry/sources/util.lua new file mode 100644 index 00000000..262cbef2 --- /dev/null +++ b/lua/mason-registry/sources/util.lua @@ -0,0 +1,40 @@ +local Optional = require "mason-core.optional" +local Pkg = require "mason-core.package" +local _ = require "mason-core.functional" +local log = require "mason-core.log" +local registry_installer = require "mason-core.installer.registry" + +local M = {} + +---@param spec RegistryPackageSpec +function M.map_registry_spec(spec) + spec.schema = spec.schema or "registry+v1" + + if not registry_installer.SCHEMA_CAP[spec.schema] then + log.fmt_debug("Excluding package=%s with unsupported schema_version=%s", spec.name, spec.schema) + return Optional.empty() + end + + -- XXX: this is for compatibilty with the PackageSpec structure + spec.desc = spec.description + return Optional.of(spec) +end + +---@param buffer table<string, Package> +---@param spec RegistryPackageSpec +M.hydrate_package = _.curryN(function(buffer, spec) + -- hydrate Pkg.Lang index + _.each(function(lang) + local _ = Pkg.Lang[lang] + end, spec.languages) + + local pkg = buffer[spec.name] + if pkg then + -- Apply spec to the existing Package instance. This is important as to not have lingering package instances. + pkg.spec = spec + return pkg + end + return Pkg.new(spec) +end, 2) + +return M diff --git a/lua/mason/api/command.lua b/lua/mason/api/command.lua index 0c2e3e9b..65c1ee84 100644 --- a/lua/mason/api/command.lua +++ b/lua/mason/api/command.lua @@ -149,7 +149,7 @@ end, { ---@param arg_lead string complete = function(arg_lead) local registry = require "mason-registry" - + registry.refresh() if _.starts_with("--", arg_lead) then return _.filter(_.starts_with(arg_lead), { "--debug", |
