aboutsummaryrefslogtreecommitdiffstats
path: root/lua
diff options
context:
space:
mode:
authorWilliam Boman <william@redwill.se>2023-08-26 00:03:13 +0200
committerGitHub <noreply@github.com>2023-08-26 00:03:13 +0200
commit85440397264a31208721e4501c93b23a4940b27e (patch)
tree2026821ac8f1e63d5a34f2f52f40ac50eac84f3f /lua
parentchore: decrease log level (#1467) (diff)
downloadmason-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.lua152
-rw-r--r--lua/mason-registry/sources/github.lua45
-rw-r--r--lua/mason-registry/sources/init.lua7
-rw-r--r--lua/mason-registry/sources/util.lua40
-rw-r--r--lua/mason/api/command.lua2
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",