aboutsummaryrefslogtreecommitdiffstats
path: root/lua
diff options
context:
space:
mode:
authorWilliam Boman <william@redwill.se>2023-09-11 00:05:44 +0200
committerWilliam Boman <william@redwill.se>2025-02-16 09:32:29 +0100
commit2275067747a118d6002f421cb54f28affbc0ef98 (patch)
tree79bc1c2580ba96cc1b19e71f2b31f7c4c8ab490c /lua
parentchore(main): release 1.11.0 (#1658) (diff)
downloadmason-2275067747a118d6002f421cb54f28affbc0ef98.tar
mason-2275067747a118d6002f421cb54f28affbc0ef98.tar.gz
mason-2275067747a118d6002f421cb54f28affbc0ef98.tar.bz2
mason-2275067747a118d6002f421cb54f28affbc0ef98.tar.lz
mason-2275067747a118d6002f421cb54f28affbc0ef98.tar.xz
mason-2275067747a118d6002f421cb54f28affbc0ef98.tar.zst
mason-2275067747a118d6002f421cb54f28affbc0ef98.zip
refactor!: remove old managers (#1497)
Diffstat (limited to 'lua')
-rw-r--r--lua/mason-core/fetch.lua2
-rw-r--r--lua/mason-core/installer/context.lua9
-rw-r--r--lua/mason-core/installer/managers/common.lua2
-rw-r--r--lua/mason-core/installer/managers/powershell.lua (renamed from lua/mason-core/managers/powershell/init.lua)0
-rw-r--r--lua/mason-core/installer/managers/pypi.lua8
-rw-r--r--lua/mason-core/installer/managers/std.lua2
-rw-r--r--lua/mason-core/managers/cargo/client.lua18
-rw-r--r--lua/mason-core/managers/cargo/init.lua199
-rw-r--r--lua/mason-core/managers/composer/init.lua127
-rw-r--r--lua/mason-core/managers/dotnet/init.lua56
-rw-r--r--lua/mason-core/managers/gem/init.lua162
-rw-r--r--lua/mason-core/managers/git/init.lua76
-rw-r--r--lua/mason-core/managers/github/client.lua84
-rw-r--r--lua/mason-core/managers/github/init.lua208
-rw-r--r--lua/mason-core/managers/go/init.lua167
-rw-r--r--lua/mason-core/managers/luarocks/init.lua137
-rw-r--r--lua/mason-core/managers/npm/init.lua136
-rw-r--r--lua/mason-core/managers/opam/init.lua62
-rw-r--r--lua/mason-core/managers/pip3/init.lua173
-rw-r--r--lua/mason-core/managers/std/init.lua196
20 files changed, 15 insertions, 1809 deletions
diff --git a/lua/mason-core/fetch.lua b/lua/mason-core/fetch.lua
index c8a8591c..26ddb0f7 100644
--- a/lua/mason-core/fetch.lua
+++ b/lua/mason-core/fetch.lua
@@ -4,7 +4,7 @@ local a = require "mason-core.async"
local async_uv = require "mason-core.async.uv"
local log = require "mason-core.log"
local platform = require "mason-core.platform"
-local powershell = require "mason-core.managers.powershell"
+local powershell = require "mason-core.installer.managers.powershell"
local spawn = require "mason-core.spawn"
local version = require "mason.version"
diff --git a/lua/mason-core/installer/context.lua b/lua/mason-core/installer/context.lua
index 7637209f..21c9c26f 100644
--- a/lua/mason-core/installer/context.lua
+++ b/lua/mason-core/installer/context.lua
@@ -303,10 +303,10 @@ end
---@param new_executable_rel_path string Relative path to the executable file to create.
---@param module string The python module to call.
function InstallContext:write_pyvenv_exec_wrapper(new_executable_rel_path, module)
- local pip3 = require "mason-core.managers.pip3"
+ local pypi = require "mason-core.installer.managers.pypi"
local module_exists, module_err = pcall(function()
local result =
- self.spawn.python { "-c", ("import %s"):format(module), with_paths = { pip3.venv_path(self.cwd:get()) } }
+ self.spawn.python { "-c", ("import %s"):format(module), with_paths = { pypi.venv_path(self.cwd:get()) } }
if not self.spawn.strict_mode then
result:get_or_throw()
end
@@ -319,7 +319,7 @@ function InstallContext:write_pyvenv_exec_wrapper(new_executable_rel_path, modul
new_executable_rel_path,
("%q -m %s"):format(
path.concat {
- pip3.venv_path(self.package:get_install_path()),
+ pypi.venv_path(self.package:get_install_path()),
"python",
},
module
@@ -367,14 +367,13 @@ function InstallContext:write_shell_exec_wrapper(new_executable_rel_path, comman
end
return platform.when {
unix = function()
- local std = require "mason-core.managers.std"
local formatted_envs = _.map(function(pair)
local var, value = pair[1], pair[2]
return ("export %s=%q"):format(var, value)
end, _.to_pairs(env or {}))
self.fs:write_file(new_executable_rel_path, BASH_TEMPLATE:format(_.join("\n", formatted_envs), command))
- std.chmod("+x", { new_executable_rel_path })
+ self.fs:chmod_exec(new_executable_rel_path)
return new_executable_rel_path
end,
win = function()
diff --git a/lua/mason-core/installer/managers/common.lua b/lua/mason-core/installer/managers/common.lua
index c730a3aa..c13d3bff 100644
--- a/lua/mason-core/installer/managers/common.lua
+++ b/lua/mason-core/installer/managers/common.lua
@@ -5,7 +5,7 @@ local async_uv = require "mason-core.async.uv"
local installer = require "mason-core.installer"
local log = require "mason-core.log"
local platform = require "mason-core.platform"
-local powershell = require "mason-core.managers.powershell"
+local powershell = require "mason-core.installer.managers.powershell"
local std = require "mason-core.installer.managers.std"
local M = {}
diff --git a/lua/mason-core/managers/powershell/init.lua b/lua/mason-core/installer/managers/powershell.lua
index 0e7f4145..0e7f4145 100644
--- a/lua/mason-core/managers/powershell/init.lua
+++ b/lua/mason-core/installer/managers/powershell.lua
diff --git a/lua/mason-core/installer/managers/pypi.lua b/lua/mason-core/installer/managers/pypi.lua
index f60a8ede..d5368bc8 100644
--- a/lua/mason-core/installer/managers/pypi.lua
+++ b/lua/mason-core/installer/managers/pypi.lua
@@ -15,6 +15,14 @@ local M = {}
local VENV_DIR = "venv"
+function M.venv_path(dir)
+ return path.concat {
+ dir,
+ VENV_DIR,
+ platform.is.win and "Scripts" or "bin",
+ }
+end
+
---@async
---@param candidates string[]
local function resolve_python3(candidates)
diff --git a/lua/mason-core/installer/managers/std.lua b/lua/mason-core/installer/managers/std.lua
index 6e1a0d9e..b4eb11ab 100644
--- a/lua/mason-core/installer/managers/std.lua
+++ b/lua/mason-core/installer/managers/std.lua
@@ -6,7 +6,7 @@ local installer = require "mason-core.installer"
local log = require "mason-core.log"
local path = require "mason-core.path"
local platform = require "mason-core.platform"
-local powershell = require "mason-core.managers.powershell"
+local powershell = require "mason-core.installer.managers.powershell"
local M = {}
diff --git a/lua/mason-core/managers/cargo/client.lua b/lua/mason-core/managers/cargo/client.lua
deleted file mode 100644
index 82dc85aa..00000000
--- a/lua/mason-core/managers/cargo/client.lua
+++ /dev/null
@@ -1,18 +0,0 @@
-local fetch = require "mason-core.fetch"
-
-local M = {}
-
----@alias CrateResponse {crate: {id: string, max_stable_version: string, max_version: string, newest_version: string}}
-
----@async
----@param crate string
----@return Result # Result<CrateResponse>
-function M.fetch_crate(crate)
- return fetch(("https://crates.io/api/v1/crates/%s"):format(crate), {
- headers = {
- Accept = "application/json",
- },
- }):map_catching(vim.json.decode)
-end
-
-return M
diff --git a/lua/mason-core/managers/cargo/init.lua b/lua/mason-core/managers/cargo/init.lua
deleted file mode 100644
index 49a5841a..00000000
--- a/lua/mason-core/managers/cargo/init.lua
+++ /dev/null
@@ -1,199 +0,0 @@
-local Optional = require "mason-core.optional"
-local _ = require "mason-core.functional"
-local a = require "mason-core.async"
-local client = require "mason-core.managers.cargo.client"
-local github = require "mason-core.managers.github"
-local github_client = require "mason-core.managers.github.client"
-local installer = require "mason-core.installer"
-local path = require "mason-core.path"
-local platform = require "mason-core.platform"
-local spawn = require "mason-core.spawn"
-
-local get_bin_path = _.compose(path.concat, function(executable)
- return _.append(executable, { "bin" })
-end, _.if_else(_.always(platform.is.win), _.format "%s.exe", _.identity))
-
----@param crate string
-local function with_receipt(crate)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source(ctx.receipt.cargo(crate))
- end
-end
-
-local M = {}
-
----@async
----@param crate string The crate to install.
----@param opts { git: { url: string, tag: boolean? }, features: string?, bin: string[]? }?
-function M.crate(crate, opts)
- return function()
- if opts and opts.git and opts.git.tag then
- local ctx = installer.context()
- local repo = assert(opts.git.url:match "^https://github%.com/(.+)$", "git url needs to be github.com")
- local source = github.tag { repo = repo }
- source.with_receipt()
- ctx.requested_version = Optional.of(source.tag)
- M.install(crate, opts)
- else
- M.install(crate, opts).with_receipt()
- end
- end
-end
-
----@async
----@param crate string The crate to install.
----@param opts { git: { url: string, tag: boolean? }, features: string?, bin: string[]? }?
-function M.install(crate, opts)
- local ctx = installer.context()
- opts = opts or {}
-
- local version
-
- if opts.git then
- if opts.git.tag then
- assert(ctx.requested_version:is_present(), "version is required when installing tagged git crate.")
- end
- version = ctx.requested_version
- :map(function(version)
- if opts.git.tag then
- return { "--tag", version }
- else
- return { "--rev", version }
- end
- end)
- :or_else(vim.NIL)
- else
- version = ctx.requested_version
- :map(function(version)
- return { "--version", version }
- end)
- :or_else(vim.NIL)
- end
-
- ctx.spawn.cargo {
- "install",
- "--root",
- ".",
- "--locked",
- version,
- opts.git and { "--git", opts.git.url } or vim.NIL,
- opts.features and { "--features", opts.features } or vim.NIL,
- crate,
- }
-
- if opts.bin then
- _.each(function(bin)
- ctx:link_bin(bin, get_bin_path(bin))
- end, opts.bin)
- end
-
- return {
- with_receipt = with_receipt(crate),
- }
-end
-
----@alias InstalledCrate { name: string, version: string, github_ref: { owner: string, repo: string, ref: string }? }
-
----@param line string
----@return InstalledCrate? crate
-local function parse_installed_crate(line)
- local name, version, context = line:match "^(.+)%s+v([^%s:]+) ?(.*):$"
- if context then
- local owner, repo, ref = context:match "^%(https://github%.com/(.+)/([^?]+).*#(.+)%)$"
- if ref then
- return { name = name, version = ref, github_ref = { owner = owner, repo = repo, ref = ref } }
- end
- end
- if name and version then
- return { name = name, version = version }
- end
-end
-
----@param output string The `cargo install --list` output.
----@return table<string, InstalledCrate> # Key is the crate name, value is its version.
-function M.parse_installed_crates(output)
- local installed_crates = {}
- for _, line in ipairs(vim.split(output, "\n")) do
- local installed_crate = parse_installed_crate(line)
- if installed_crate then
- installed_crates[installed_crate.name] = installed_crate
- end
- end
- return installed_crates
-end
-
----@async
----@param install_dir string
----@return Result # Result<table<string, InstalledCrate>>
-local function get_installed_crates(install_dir)
- return spawn
- .cargo({
- "install",
- "--list",
- "--root",
- ".",
- cwd = install_dir,
- })
- :map_catching(function(result)
- return M.parse_installed_crates(result.stdout)
- end)
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.check_outdated_primary_package(receipt, install_dir)
- a.scheduler()
- local crate_name = vim.fn.fnamemodify(receipt.primary_source.package, ":t")
- return get_installed_crates(install_dir)
- :ok()
- :map(_.prop(crate_name))
- :map(
- ---@param installed_crate InstalledCrate
- function(installed_crate)
- if installed_crate.github_ref then
- ---@type GitHubCommit
- local latest_commit = github_client
- .fetch_commits(
- ("%s/%s"):format(installed_crate.github_ref.owner, installed_crate.github_ref.repo),
- { page = 1, per_page = 1 }
- )
- :get_or_throw("Failed to fetch latest commits.")[1]
- if not vim.startswith(latest_commit.sha, installed_crate.github_ref.ref) then
- return {
- name = receipt.primary_source.package,
- current_version = installed_crate.github_ref.ref,
- latest_version = latest_commit.sha,
- }
- end
- else
- ---@type CrateResponse
- local crate_response = client.fetch_crate(crate_name):get_or_throw()
- if installed_crate.version ~= crate_response.crate.max_stable_version then
- return {
- name = receipt.primary_source.package,
- current_version = installed_crate.version,
- latest_version = crate_response.crate.max_stable_version,
- }
- end
- end
- end
- )
- :ok_or(_.always "Primary package is not outdated.")
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.get_installed_primary_package_version(receipt, install_dir)
- a.scheduler()
- local crate_name = vim.fn.fnamemodify(receipt.primary_source.package, ":t")
- return get_installed_crates(install_dir)
- :ok()
- :map(_.prop(crate_name))
- :map(_.prop "version")
- :ok_or(_.always "Failed to find cargo package version.")
-end
-
-return M
diff --git a/lua/mason-core/managers/composer/init.lua b/lua/mason-core/managers/composer/init.lua
deleted file mode 100644
index 274e2bcb..00000000
--- a/lua/mason-core/managers/composer/init.lua
+++ /dev/null
@@ -1,127 +0,0 @@
-local Optional = require "mason-core.optional"
-local Result = require "mason-core.result"
-local _ = require "mason-core.functional"
-local installer = require "mason-core.installer"
-local path = require "mason-core.path"
-local platform = require "mason-core.platform"
-local spawn = require "mason-core.spawn"
-
-local M = {}
-
-local create_bin_path = _.compose(path.concat, function(executable)
- return _.append(executable, { "vendor", "bin" })
-end, _.if_else(_.always(platform.is.win), _.format "%s.bat", _.identity))
-
----@param packages string[]
-local function with_receipt(packages)
- return function()
- local ctx = installer.context()
-
- ctx.receipt:with_primary_source(ctx.receipt.composer(packages[1]))
- for i = 2, #packages do
- ctx.receipt:with_secondary_source(ctx.receipt.composer(packages[i]))
- end
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The composer packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.packages(packages)
- return function()
- return M.require(packages).with_receipt()
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The composer packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.require(packages)
- local ctx = installer.context()
- local pkgs = _.list_copy(packages)
-
- if not ctx.fs:file_exists "composer.json" then
- ctx.spawn.composer { "init", "--no-interaction", "--stability=stable" }
- end
-
- ctx.requested_version:if_present(function(version)
- pkgs[1] = ("%s:%s"):format(pkgs[1], version)
- end)
-
- ctx.spawn.composer { "require", pkgs }
-
- if packages.bin then
- _.each(function(executable)
- ctx:link_bin(executable, create_bin_path(executable))
- end, packages.bin)
- end
-
- return {
- with_receipt = with_receipt(packages),
- }
-end
-
----@async
-function M.install()
- local ctx = installer.context()
- ctx.spawn.composer {
- "install",
- "--no-interaction",
- "--no-dev",
- "--optimize-autoloader",
- "--classmap-authoritative",
- }
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.check_outdated_primary_package(receipt, install_dir)
- if receipt.primary_source.type ~= "composer" then
- return Result.failure "Receipt does not have a primary source of type composer"
- end
- return spawn
- .composer({
- "outdated",
- "--no-interaction",
- "--format=json",
- cwd = install_dir,
- })
- :map_catching(function(result)
- local outdated_packages = vim.json.decode(result.stdout)
- local outdated_package = _.find_first(function(pkg)
- return pkg.name == receipt.primary_source.package
- end, outdated_packages.installed)
- return Optional.of_nilable(outdated_package)
- :map(function(pkg)
- if pkg.version ~= pkg.latest then
- return {
- name = pkg.name,
- current_version = pkg.version,
- latest_version = pkg.latest,
- }
- end
- end)
- :or_else_throw "Primary package is not outdated."
- end)
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.get_installed_primary_package_version(receipt, install_dir)
- if receipt.primary_source.type ~= "composer" then
- return Result.failure "Receipt does not have a primary source of type composer"
- end
- return spawn
- .composer({
- "info",
- "--format=json",
- receipt.primary_source.package,
- cwd = install_dir,
- })
- :map_catching(function(result)
- local info = vim.json.decode(result.stdout)
- return info.versions[1]
- end)
-end
-
-return M
diff --git a/lua/mason-core/managers/dotnet/init.lua b/lua/mason-core/managers/dotnet/init.lua
deleted file mode 100644
index 984b2463..00000000
--- a/lua/mason-core/managers/dotnet/init.lua
+++ /dev/null
@@ -1,56 +0,0 @@
-local _ = require "mason-core.functional"
-local installer = require "mason-core.installer"
-local platform = require "mason-core.platform"
-
-local M = {}
-
-local create_bin_path = _.if_else(_.always(platform.is.win), _.format "%s.exe", _.identity)
-
----@param package string
-local function with_receipt(package)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source(ctx.receipt.dotnet(package))
- end
-end
-
----@async
----@param pkg string
----@param opt { bin: string[]? }?
-function M.package(pkg, opt)
- return function()
- return M.install(pkg, opt).with_receipt()
- end
-end
-
----@async
----@param pkg string
----@param opt { bin: string[]? }?
-function M.install(pkg, opt)
- local ctx = installer.context()
- ctx.spawn.dotnet {
- "tool",
- "update",
- "--ignore-failed-sources",
- "--tool-path",
- ".",
- ctx.requested_version
- :map(function(version)
- return { "--version", version }
- end)
- :or_else(vim.NIL),
- pkg,
- }
-
- if opt and opt.bin then
- _.each(function(executable)
- ctx:link_bin(executable, create_bin_path(executable))
- end, opt.bin)
- end
-
- return {
- with_receipt = with_receipt(pkg),
- }
-end
-
-return M
diff --git a/lua/mason-core/managers/gem/init.lua b/lua/mason-core/managers/gem/init.lua
deleted file mode 100644
index dc7448bf..00000000
--- a/lua/mason-core/managers/gem/init.lua
+++ /dev/null
@@ -1,162 +0,0 @@
-local Optional = require "mason-core.optional"
-local Result = require "mason-core.result"
-local _ = require "mason-core.functional"
-local installer = require "mason-core.installer"
-local path = require "mason-core.path"
-local platform = require "mason-core.platform"
-local process = require "mason-core.process"
-local providers = require "mason-core.providers"
-local spawn = require "mason-core.spawn"
-
-local M = {}
-
----@param install_dir string
-local function env(install_dir)
- return {
- GEM_HOME = install_dir,
- GEM_PATH = install_dir,
- PATH = process.extend_path { path.concat { install_dir, "bin" } },
- }
-end
-
-local create_bin_path = _.compose(path.concat, function(executable)
- return _.append(executable, { "bin" })
-end, _.if_else(_.always(platform.is.win), _.format "%s.bat", _.identity))
-
----@async
----@param executable string
-local function link_executable(executable)
- local ctx = installer.context()
- local bin_path = create_bin_path(executable)
- if not ctx.fs:file_exists(bin_path) then
- error(("Cannot link Gem executable %q because it doesn't exist in %q."):format(executable, bin_path), 0)
- end
- ctx:link_bin(
- executable,
- ctx:write_shell_exec_wrapper(executable, path.concat { ctx.package:get_install_path(), bin_path }, {
- GEM_PATH = platform.when {
- unix = function()
- return ("%s:$GEM_PATH"):format(ctx.package:get_install_path())
- end,
- win = function()
- return ("%s;%%GEM_PATH%%"):format(ctx.package:get_install_path())
- end,
- },
- })
- )
-end
-
----@param packages string[]
-local function with_receipt(packages)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source(ctx.receipt.gem(packages[1]))
- for i = 2, #packages do
- ctx.receipt:with_secondary_source(ctx.receipt.gem(packages[i]))
- end
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The Gem packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.packages(packages)
- return function()
- return M.install(packages).with_receipt()
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The Gem packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.install(packages)
- local ctx = installer.context()
- local pkgs = _.list_copy(packages or {})
-
- ctx.requested_version:if_present(function(version)
- pkgs[1] = ("%s:%s"):format(pkgs[1], version)
- end)
-
- ctx.spawn.gem {
- "install",
- "--no-user-install",
- "--no-format-executable",
- "--install-dir=.",
- "--bindir=bin",
- "--no-document",
- pkgs,
- env = {
- GEM_HOME = ctx.cwd:get(),
- },
- }
-
- if packages.bin then
- _.each(link_executable, packages.bin)
- end
-
- return {
- with_receipt = with_receipt(packages),
- }
-end
-
----@alias GemOutdatedPackage {name:string, current_version: string, latest_version: string}
-
----Parses the stdout of the `gem list` command into a table<package_name, version>
----@param output string
-function M.parse_gem_list_output(output)
- ---@type table<string, string>
- local gem_versions = {}
- for _, line in ipairs(vim.split(output, "\n")) do
- local gem_package, version = line:match "^(%S+) %((%S+)%)$"
- if gem_package and version then
- gem_versions[gem_package] = version
- end
- end
- return gem_versions
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.check_outdated_primary_package(receipt, install_dir)
- if receipt.primary_source.type ~= "gem" then
- return Result.failure "Receipt does not have a primary source of type gem"
- end
- return M.get_installed_primary_package_version(receipt, install_dir)
- :and_then(function(installed_version)
- return providers.rubygems.get_latest_version(receipt.primary_source.package):map(function(latest)
- return {
- installed = installed_version,
- latest = latest.version,
- }
- end)
- end)
- :and_then(function(versions)
- if versions.installed ~= versions.latest then
- return Result.success {
- name = receipt.primary_source.package,
- current_version = versions.installed,
- latest_version = versions.latest,
- }
- else
- return Result.failure "Primary package is not outdated."
- end
- end)
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.get_installed_primary_package_version(receipt, install_dir)
- return spawn
- .gem({
- "list",
- cwd = install_dir,
- env = env(install_dir),
- })
- :map_catching(function(result)
- local gems = M.parse_gem_list_output(result.stdout)
- return Optional.of_nilable(gems[receipt.primary_source.package])
- :or_else_throw "Failed to find gem package version."
- end)
-end
-
-return M
diff --git a/lua/mason-core/managers/git/init.lua b/lua/mason-core/managers/git/init.lua
deleted file mode 100644
index 099ea6c2..00000000
--- a/lua/mason-core/managers/git/init.lua
+++ /dev/null
@@ -1,76 +0,0 @@
-local Result = require "mason-core.result"
-local _ = require "mason-core.functional"
-local installer = require "mason-core.installer"
-local spawn = require "mason-core.spawn"
-
-local M = {}
-
----@param repo string
-local function with_receipt(repo)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source(ctx.receipt.git_remote(repo))
- end
-end
-
----@async
----@param opts {[1]: string, recursive: boolean, version: Optional?} The first item in the table is the repository to clone.
-function M.clone(opts)
- local ctx = installer.context()
- local repo = assert(opts[1], "No git URL provided.")
- ctx.spawn.git {
- "clone",
- "--depth",
- "1",
- opts.recursive and "--recursive" or vim.NIL,
- repo,
- ".",
- }
- _.coalesce(opts.version, ctx.requested_version):if_present(function(version)
- ctx.spawn.git { "fetch", "--depth", "1", "origin", version }
- ctx.spawn.git { "checkout", "FETCH_HEAD" }
- end)
-
- return {
- with_receipt = with_receipt(repo),
- }
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.check_outdated_git_clone(receipt, install_dir)
- if receipt.primary_source.type ~= "git" then
- return Result.failure "Receipt does not have a primary source of type git"
- end
- return spawn.git({ "fetch", "origin", "HEAD", cwd = install_dir }):map_catching(function()
- local result = spawn.git({ "rev-parse", "FETCH_HEAD", "HEAD", cwd = install_dir }):get_or_throw()
- local remote_head, local_head = unpack(vim.split(result.stdout, "\n"))
- if remote_head == local_head then
- error("Git clone is up to date.", 2)
- end
- return {
- name = receipt.primary_source.remote,
- current_version = assert(local_head, "no local HEAD"),
- latest_version = assert(remote_head, "no remote HEAD"),
- }
- end)
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.get_installed_revision(receipt, install_dir)
- return spawn
- .git({
- "rev-parse",
- "--short",
- "HEAD",
- cwd = install_dir,
- })
- :map_catching(function(result)
- return assert(vim.trim(result.stdout))
- end)
-end
-
-return M
diff --git a/lua/mason-core/managers/github/client.lua b/lua/mason-core/managers/github/client.lua
deleted file mode 100644
index e8301f72..00000000
--- a/lua/mason-core/managers/github/client.lua
+++ /dev/null
@@ -1,84 +0,0 @@
-local _ = require "mason-core.functional"
-local fetch = require "mason-core.fetch"
-local spawn = require "mason-core.spawn"
-
-local M = {}
-
----@alias GitHubCommit { sha: string }
----@alias GitHubRef { ref: string }
-
-local stringify_params = _.compose(_.join "&", _.map(_.join "="), _.sort_by(_.head), _.to_pairs)
-
----@param path string
----@param opts { params: table<string, any>? }?
----@return Result # JSON decoded response.
-local function gh_api_call(path, opts)
- if opts and opts.params then
- local params = stringify_params(opts.params)
- path = ("%s?%s"):format(path, params)
- end
- return spawn
- .gh({ "api", path, env = { CLICOLOR_FORCE = 0 } })
- :map(_.prop "stdout")
- :or_else(function()
- return fetch(("https://api.github.com/%s"):format(path), {
- headers = {
- Accept = "application/vnd.github.v3+json; q=1.0, application/json; q=0.8",
- },
- })
- end)
- :map_catching(vim.json.decode)
-end
-
-M.api_call = gh_api_call
-
----@async
----@param repo string The GitHub repo ("username/repo").
----@return Result # Result<GitHubRelease>
-function M.fetch_latest_release(repo)
- local path = ("repos/%s/releases/latest"):format(repo)
- return gh_api_call(path)
-end
-
----@async
----@param repo string The GitHub repo ("username/repo").
----@return Result # Result<GitHubRelease[]>
-function M.fetch_all_releases(repo)
- local path = ("repos/%s/releases"):format(repo)
- return gh_api_call(path)
-end
-
----@async
----@param repo string The GitHub repo ("username/repo").
----@return Result # Result<GitHubRef[]>
-function M.fetch_all_tags(repo)
- local path = ("repos/%s/git/matching-refs/tags"):format(repo)
- return gh_api_call(path)
-end
-
----@async
----@param repo string The GitHub repo ("username/repo").
----@param opts { page: integer?, per_page: integer? }?
----@return Result # Result<GitHubCommit[]>
-function M.fetch_commits(repo, opts)
- local path = ("repos/%s/commits"):format(repo)
- return gh_api_call(path, {
- params = {
- page = opts and opts.page or 1,
- per_page = opts and opts.per_page or 30,
- },
- }):map_err(function()
- return ("Failed to fetch commits for GitHub repository %s."):format(repo)
- end)
-end
-
----@alias GitHubRateLimit {limit: integer, remaining: integer, reset: integer, used: integer}
----@alias GitHubRateLimitResponse {resources: { core: GitHubRateLimit }}
-
----@async
----@return Result # Result<GitHubRateLimitResponse>
-function M.fetch_rate_limit()
- return gh_api_call "rate_limit"
-end
-
-return M
diff --git a/lua/mason-core/managers/github/init.lua b/lua/mason-core/managers/github/init.lua
deleted file mode 100644
index 2d593790..00000000
--- a/lua/mason-core/managers/github/init.lua
+++ /dev/null
@@ -1,208 +0,0 @@
-local Result = require "mason-core.result"
-local _ = require "mason-core.functional"
-local installer = require "mason-core.installer"
-local platform = require "mason-core.platform"
-local providers = require "mason-core.providers"
-local settings = require "mason.settings"
-local std = require "mason-core.managers.std"
-
-local M = {}
-
----@class InstallReceiptGitHubReleaseFileSource
----@field type '"github_release_file"'
----@field repo string
----@field file string
----@field release string
-
----@param repo string
----@param asset_file string
----@param release string
-local function with_release_file_receipt(repo, asset_file, release)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source {
- type = "github_release_file",
- repo = repo,
- file = asset_file,
- release = release,
- }
- end
-end
-
----@class InstallReceiptGitHubTagSource
----@field type '"github_tag"'
----@field repo string
----@field tag string
-
----@param repo string
----@param tag string
-local function with_tag_receipt(repo, tag)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source {
- type = "github_tag",
- repo = repo,
- tag = tag,
- }
- end
-end
-
----@async
----@param opts {repo: string, version: Optional?}
-function M.release_version(opts)
- local ctx = installer.context()
- ---@type string
- local release = _.coalesce(opts.version, ctx.requested_version):or_else_get(function()
- return providers.github
- .get_latest_release(opts.repo)
- :map(_.prop "tag_name")
- :get_or_throw "Failed to fetch latest release from GitHub API. Refer to :h mason-provider-errors for more information."
- end)
-
- return {
- with_receipt = function()
- ctx.receipt:with_primary_source {
- type = "github_release",
- repo = opts.repo,
- release = release,
- }
- end,
- release = release,
- }
-end
-
----@async
----@param opts {repo: string, version: Optional?, asset_file: string|fun(release: string):string}
-function M.release_file(opts)
- local source = M.release_version(opts)
- ---@type string
- local asset_file
- if type(opts.asset_file) == "function" then
- asset_file = opts.asset_file(source.release)
- elseif type(opts.asset_file) == "string" then
- asset_file = opts.asset_file --[[@as string]]
- end
- if not asset_file then
- error(
- (
- "Could not find which release file to download.\n"
- .. "Most likely the current operating system or architecture is not supported (%s_%s)."
- ):format(platform.sysname, platform.arch),
- 0
- )
- end
- local download_url = settings.current.github.download_url_template:format(opts.repo, source.release, asset_file)
- return {
- release = source.release,
- download_url = download_url,
- asset_file = asset_file,
- with_receipt = with_release_file_receipt(opts.repo, download_url, source.release),
- }
-end
-
----@async
----@param opts {repo: string, version: Optional?}
-function M.tag(opts)
- local ctx = installer.context()
- local tag = _.coalesce(opts.version, ctx.requested_version):or_else_get(function()
- return providers.github
- .get_latest_tag(opts.repo)
- :map(_.prop "tag")
- :get_or_throw "Failed to fetch latest tag from GitHub API."
- end)
-
- return {
- tag = tag,
- with_receipt = with_tag_receipt(opts.repo, tag),
- }
-end
-
----@param filename string
----@param processor async fun(opts: table)
-local function release_file_processor(filename, processor)
- ---@async
- ---@param opts {repo: string, version: Optional|nil, asset_file: string|fun(release: string):string}
- return function(opts)
- local release_file_source = M.release_file(opts)
- std.download_file(release_file_source.download_url, filename)
- processor(opts)
- return release_file_source
- end
-end
-
-M.unzip_release_file = release_file_processor("archive.zip", function()
- std.unzip("archive.zip", ".")
-end)
-
-M.untarzst_release_file = release_file_processor("archive.tar.zst", function(opts)
- std.untarzst("archive.tar.zst", { strip_components = opts.strip_components })
-end)
-
-M.untarxz_release_file = release_file_processor("archive.tar.xz", function(opts)
- std.untarxz("archive.tar.xz", { strip_components = opts.strip_components })
-end)
-
-M.untargz_release_file = release_file_processor("archive.tar.gz", function(opts)
- std.untar("archive.tar.gz", { strip_components = opts.strip_components })
-end)
-
----@async
----@param opts {repo: string, out_file:string, asset_file: string|fun(release: string):string}
-function M.download_release_file(opts)
- local release_file_source = M.release_file(opts)
- std.download_file(release_file_source.download_url, assert(opts.out_file, "out_file is required"))
- return release_file_source
-end
-
----@async
----@param opts {repo: string, out_file:string, asset_file: string|fun(release: string):string}
-function M.gunzip_release_file(opts)
- local release_file_source = M.release_file(opts)
- local gzipped_file = ("%s.gz"):format(assert(opts.out_file, "out_file must be specified"))
- std.download_file(release_file_source.download_url, gzipped_file)
- std.gunzip(gzipped_file)
- return release_file_source
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptGitHubReleaseFileSource>
-function M.check_outdated_primary_package_release(receipt)
- local source = receipt.primary_source
- if source.type ~= "github_release" and source.type ~= "github_release_file" then
- return Result.failure "Receipt does not have a primary source of type (github_release|github_release_file)."
- end
- return providers.github.get_latest_release(source.repo):map_catching(
- ---@param latest_release GitHubRelease
- function(latest_release)
- if source.release ~= latest_release.tag_name then
- return {
- name = source.repo,
- current_version = source.release,
- latest_version = latest_release.tag_name,
- }
- end
- error "Primary package is not outdated."
- end
- )
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptGitHubTagSource>
-function M.check_outdated_primary_package_tag(receipt)
- local source = receipt.primary_source
- if source.type ~= "github_tag" then
- return Result.failure "Receipt does not have a primary source of type github_tag."
- end
- return providers.github.get_latest_tag(source.repo):map(_.prop "tag"):map_catching(function(latest_tag)
- if source.tag ~= latest_tag then
- return {
- name = source.repo,
- current_version = source.tag,
- latest_version = latest_tag,
- }
- end
- error "Primary package is not outdated."
- end)
-end
-
-return M
diff --git a/lua/mason-core/managers/go/init.lua b/lua/mason-core/managers/go/init.lua
deleted file mode 100644
index 0452400d..00000000
--- a/lua/mason-core/managers/go/init.lua
+++ /dev/null
@@ -1,167 +0,0 @@
-local Optional = require "mason-core.optional"
-local _ = require "mason-core.functional"
-local a = require "mason-core.async"
-local installer = require "mason-core.installer"
-local platform = require "mason-core.platform"
-local spawn = require "mason-core.spawn"
-
-local M = {}
-
-local create_bin_path = _.if_else(_.always(platform.is.win), _.format "%s.exe", _.identity)
-
----@param packages string[]
-local function with_receipt(packages)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source(ctx.receipt.go(packages[1]))
- -- Install secondary packages
- for i = 2, #packages do
- local pkg = packages[i]
- ctx.receipt:with_secondary_source(ctx.receipt.go(pkg))
- end
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The go packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.packages(packages)
- return function()
- M.install(packages).with_receipt()
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The go packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.install(packages)
- local ctx = installer.context()
- local env = {
- GOBIN = ctx.cwd:get(),
- }
- -- Install the head package
- do
- local head_package = packages[1]
- local version = ctx.requested_version:or_else "latest"
- ctx.spawn.go {
- "install",
- "-v",
- ("%s@%s"):format(head_package, version),
- env = env,
- }
- end
-
- -- Install secondary packages
- for i = 2, #packages do
- ctx.spawn.go { "install", "-v", ("%s@latest"):format(packages[i]), env = env }
- end
-
- if packages.bin then
- _.each(function(executable)
- ctx:link_bin(executable, create_bin_path(executable))
- end, packages.bin)
- end
-
- return {
- with_receipt = with_receipt(packages),
- }
-end
-
----@param output string The output from `go version -m` command.
-function M.parse_mod_version_output(output)
- ---@type {path: string[], mod: string[], dep: string[], build: string[]}
- local result = {}
- local lines = vim.split(output, "\n")
- for _, line in ipairs { unpack(lines, 2) } do
- local type, id, value = unpack(vim.split(line, "%s+", { trimempty = true }))
- if type and id then
- result[type] = result[type] or {}
- result[type][id] = value or ""
- end
- end
- return result
-end
-
-local trim_wildcard_suffix = _.gsub("/%.%.%.$", "")
-
----@param pkg string
-function M.parse_package_mod(pkg)
- if _.starts_with("github.com", pkg) then
- local components = _.split("/", pkg)
- return trim_wildcard_suffix(_.join("/", {
- components[1], -- github.com
- components[2], -- owner
- components[3], -- repo
- }))
- elseif _.starts_with("golang.org", pkg) then
- local components = _.split("/", pkg)
- return trim_wildcard_suffix(_.join("/", {
- components[1], -- golang.org
- components[2], -- x
- components[3], -- owner
- components[4], -- repo
- }))
- else
- -- selene: allow(if_same_then_else)
- local components = _.split("/", pkg)
- return trim_wildcard_suffix(_.join("/", {
- components[1],
- components[2],
- components[3],
- }))
- end
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.get_installed_primary_package_version(receipt, install_dir)
- a.scheduler()
- local normalized_pkg_name = trim_wildcard_suffix(receipt.primary_source.package)
- -- trims e.g. golang.org/x/tools/gopls to gopls
- local executable = vim.fn.fnamemodify(normalized_pkg_name, ":t")
- return spawn
- .go({
- "version",
- "-m",
- platform.is.win and ("%s.exe"):format(executable) or executable,
- cwd = install_dir,
- })
- :map_catching(function(result)
- local parsed_output = M.parse_mod_version_output(result.stdout)
- return Optional.of_nilable(parsed_output.mod[M.parse_package_mod(receipt.primary_source.package)])
- :or_else_throw "Failed to parse mod version"
- end)
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.check_outdated_primary_package(receipt, install_dir)
- local normalized_pkg_name = M.parse_package_mod(receipt.primary_source.package)
- return spawn
- .go({
- "list",
- "-json",
- "-m",
- ("%s@latest"):format(normalized_pkg_name),
- cwd = install_dir,
- })
- :map_catching(function(result)
- ---@type {Path: string, Version: string}
- local output = vim.json.decode(result.stdout)
- return Optional.of_nilable(output.Version)
- :map(function(latest_version)
- local installed_version = M.get_installed_primary_package_version(receipt, install_dir)
- :get_or_throw()
- if installed_version ~= latest_version then
- return {
- name = normalized_pkg_name,
- current_version = assert(installed_version, "missing installed_version"),
- latest_version = assert(latest_version, "missing latest_version"),
- }
- end
- end)
- :or_else_throw "Primary package is not outdated."
- end)
-end
-
-return M
diff --git a/lua/mason-core/managers/luarocks/init.lua b/lua/mason-core/managers/luarocks/init.lua
deleted file mode 100644
index 321346f9..00000000
--- a/lua/mason-core/managers/luarocks/init.lua
+++ /dev/null
@@ -1,137 +0,0 @@
-local Optional = require "mason-core.optional"
-local Result = require "mason-core.result"
-local _ = require "mason-core.functional"
-local installer = require "mason-core.installer"
-local path = require "mason-core.path"
-local platform = require "mason-core.platform"
-local spawn = require "mason-core.spawn"
-
-local M = {}
-
-local create_bin_path = _.compose(path.concat, function(executable)
- return _.append(executable, { "bin" })
-end, _.if_else(_.always(platform.is.win), _.format "%s.bat", _.identity))
-
----@param package string
-local function with_receipt(package)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source(ctx.receipt.luarocks(package))
- end
-end
-
----@param package string The luarock package to install.
----@param opts { dev: boolean?, server: string?, bin: string[]? }?
-function M.package(package, opts)
- return function()
- return M.install(package, opts).with_receipt()
- end
-end
-
----@async
----@param pkg string: The luarock package to install.
----@param opts { dev: boolean?, server: string?, bin: string[]? }?
-function M.install(pkg, opts)
- opts = opts or {}
- local ctx = installer.context()
- ctx:promote_cwd()
- ctx.spawn.luarocks {
- "install",
- "--tree",
- ctx.cwd:get(),
- opts.dev and "--dev" or vim.NIL,
- opts.server and ("--server=%s"):format(opts.server) or vim.NIL,
- pkg,
- ctx.requested_version:or_else(vim.NIL),
- }
- if opts.bin then
- _.each(function(executable)
- ctx:link_bin(executable, create_bin_path(executable))
- end, opts.bin)
- end
- return {
- with_receipt = with_receipt(pkg),
- }
-end
-
----@alias InstalledLuarock {package: string, version: string, arch: string, nrepo: string, namespace: string}
-
----@type fun(output: string): InstalledLuarock[]
-M.parse_installed_rocks = _.compose(
- _.map(_.compose(
- -- https://github.com/luarocks/luarocks/blob/fbd3566a312e647cde57b5d774533731e1aa844d/src/luarocks/search.lua#L317
- _.zip_table { "package", "version", "arch", "nrepo", "namespace" },
- _.split "\t"
- )),
- _.split "\n"
-)
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.get_installed_primary_package_version(receipt, install_dir)
- if receipt.primary_source.type ~= "luarocks" then
- return Result.failure "Receipt does not have a primary source of type luarocks"
- end
- local primary_package = receipt.primary_source.package
- return spawn
- .luarocks({
- "list",
- "--tree",
- install_dir,
- "--porcelain",
- })
- :map_catching(function(result)
- local luarocks = M.parse_installed_rocks(result.stdout)
- return Optional.of_nilable(_.find_first(_.prop_eq("package", primary_package), luarocks))
- :map(_.prop "version")
- :or_else_throw()
- end)
-end
-
----@alias OutdatedLuarock {name: string, installed: string, available: string, repo: string}
-
----@type fun(output: string): OutdatedLuarock[]
-M.parse_outdated_rocks = _.compose(
- _.map(_.compose(
- -- https://github.com/luarocks/luarocks/blob/fbd3566a312e647cde57b5d774533731e1aa844d/src/luarocks/cmd/list.lua#L59
- _.zip_table { "name", "installed", "available", "repo" },
- _.split "\t"
- )),
- _.split "\n"
-)
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.check_outdated_primary_package(receipt, install_dir)
- if receipt.primary_source.type ~= "luarocks" then
- return Result.failure "Receipt does not have a primary source of type luarocks"
- end
- local primary_package = receipt.primary_source.package
- return spawn
- .luarocks({
- "list",
- "--outdated",
- "--tree",
- install_dir,
- "--porcelain",
- })
- :map_catching(function(result)
- local outdated_rocks = M.parse_outdated_rocks(result.stdout)
- return Optional.of_nilable(_.find_first(_.prop_eq("name", primary_package), outdated_rocks))
- :map(
- ---@param outdated_rock OutdatedLuarock
- function(outdated_rock)
- return {
- name = outdated_rock.name,
- current_version = assert(outdated_rock.installed, "missing installed luarock version"),
- latest_version = assert(outdated_rock.available, "missing available luarock version"),
- }
- end
- )
- :or_else_throw()
- end)
-end
-
-return M
diff --git a/lua/mason-core/managers/npm/init.lua b/lua/mason-core/managers/npm/init.lua
deleted file mode 100644
index bcefb55d..00000000
--- a/lua/mason-core/managers/npm/init.lua
+++ /dev/null
@@ -1,136 +0,0 @@
-local Result = require "mason-core.result"
-local _ = require "mason-core.functional"
-local installer = require "mason-core.installer"
-local path = require "mason-core.path"
-local platform = require "mason-core.platform"
-local providers = require "mason-core.providers"
-local spawn = require "mason-core.spawn"
-
-local list_copy = _.list_copy
-
-local M = {}
-
-local create_bin_path = _.compose(path.concat, function(executable)
- return _.append(executable, { "node_modules", ".bin" })
-end, _.if_else(_.always(platform.is.win), _.format "%s.cmd", _.identity))
-
----@async
----@param ctx InstallContext
-local function ensure_npm_root(ctx)
- if not (ctx.fs:dir_exists "node_modules" or ctx.fs:file_exists "package.json") then
- -- Create a package.json to set a boundary for where npm installs packages.
- ctx.spawn.npm { "init", "--yes", "--scope=mason" }
- ctx.stdio_sink.stdout "Initialized npm root\n"
- end
-end
-
----@param packages string[]
-local function with_receipt(packages)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source(ctx.receipt.npm(packages[1]))
- for i = 2, #packages do
- ctx.receipt:with_secondary_source(ctx.receipt.npm(packages[i]))
- end
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The npm packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.packages(packages)
- return function()
- return M.install(packages).with_receipt()
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The npm packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.install(packages)
- local ctx = installer.context()
- local pkgs = list_copy(packages)
- ctx.requested_version:if_present(function(version)
- pkgs[1] = ("%s@%s"):format(pkgs[1], version)
- end)
-
- -- Use global-style. The reasons for this are:
- -- a) To avoid polluting the executables (aka bin-links) that npm creates.
- -- b) The installation is, after all, more similar to a "global" installation. We don't really gain
- -- any of the benefits of not using global style (e.g., deduping the dependency tree).
- --
- -- We write to .npmrc manually instead of going through npm because managing a local .npmrc file
- -- is a bit unreliable across npm versions (especially <7), so we take extra measures to avoid
- -- inadvertently polluting global npm config.
- ctx.fs:append_file(".npmrc", "global-style=true")
-
- ensure_npm_root(ctx)
- ctx.spawn.npm { "install", pkgs }
-
- if packages.bin then
- _.each(function(executable)
- ctx:link_bin(executable, create_bin_path(executable))
- end, packages.bin)
- end
-
- return {
- with_receipt = with_receipt(packages),
- }
-end
-
----@async
----@param exec_args string[] The arguments to pass to npm exec.
-function M.exec(exec_args)
- local ctx = installer.context()
- ctx.spawn.npm { "exec", "--yes", "--", exec_args }
-end
-
----@async
----@param script string The npm script to run.
-function M.run(script)
- local ctx = installer.context()
- ctx.spawn.npm { "run", script }
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.get_installed_primary_package_version(receipt, install_dir)
- if receipt.primary_source.type ~= "npm" then
- return Result.failure "Receipt does not have a primary source of type npm"
- end
- return spawn.npm({ "ls", "--json", cwd = install_dir }):map_catching(function(result)
- local npm_packages = vim.json.decode(result.stdout)
- return npm_packages.dependencies[receipt.primary_source.package].version
- end)
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.check_outdated_primary_package(receipt, install_dir)
- if receipt.primary_source.type ~= "npm" then
- return Result.failure "Receipt does not have a primary source of type npm"
- end
- local primary_package = receipt.primary_source.package
- return M.get_installed_primary_package_version(receipt, install_dir)
- :and_then(function(installed_version)
- return providers.npm.get_latest_version(primary_package):map(function(response)
- return {
- installed = installed_version,
- latest = response.version,
- }
- end)
- end)
- :and_then(function(versions)
- if versions.installed ~= versions.latest then
- return Result.success {
- name = primary_package,
- current_version = versions.installed,
- latest_version = versions.latest,
- }
- else
- return Result.failure "Primary package is not outdated."
- end
- end)
-end
-
-return M
diff --git a/lua/mason-core/managers/opam/init.lua b/lua/mason-core/managers/opam/init.lua
deleted file mode 100644
index ae742510..00000000
--- a/lua/mason-core/managers/opam/init.lua
+++ /dev/null
@@ -1,62 +0,0 @@
-local _ = require "mason-core.functional"
-local installer = require "mason-core.installer"
-local path = require "mason-core.path"
-local platform = require "mason-core.platform"
-
-local M = {}
-
-local list_copy = _.list_copy
-
-local create_bin_path = _.compose(path.concat, function(executable)
- return _.append(executable, { "bin" })
-end, _.if_else(_.always(platform.is.win), _.format "%s.exe", _.identity))
-
----@param packages string[]
-local function with_receipt(packages)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source(ctx.receipt.opam(packages[1]))
- for i = 2, #packages do
- ctx.receipt:with_secondary_source(ctx.receipt.opam(packages[i]))
- end
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The opam packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.packages(packages)
- return function()
- return M.install(packages).with_receipt()
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The opam packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.install(packages)
- local ctx = installer.context()
- local pkgs = list_copy(packages)
-
- ctx.requested_version:if_present(function(version)
- pkgs[1] = ("%s.%s"):format(pkgs[1], version)
- end)
-
- ctx.spawn.opam {
- "install",
- "--destdir=.",
- "--yes",
- "--verbose",
- pkgs,
- }
-
- if packages.bin then
- _.each(function(executable)
- ctx:link_bin(executable, create_bin_path(executable))
- end, packages.bin)
- end
-
- return {
- with_receipt = with_receipt(packages),
- }
-end
-
-return M
diff --git a/lua/mason-core/managers/pip3/init.lua b/lua/mason-core/managers/pip3/init.lua
deleted file mode 100644
index 813bc9ea..00000000
--- a/lua/mason-core/managers/pip3/init.lua
+++ /dev/null
@@ -1,173 +0,0 @@
-local Optional = require "mason-core.optional"
-local Result = require "mason-core.result"
-local _ = require "mason-core.functional"
-local a = require "mason-core.async"
-local installer = require "mason-core.installer"
-local path = require "mason-core.path"
-local platform = require "mason-core.platform"
-local providers = require "mason-core.providers"
-local settings = require "mason.settings"
-local spawn = require "mason-core.spawn"
-
-local VENV_DIR = "venv"
-
-local M = {}
-
-local create_bin_path = _.compose(path.concat, function(executable)
- return _.append(executable, { VENV_DIR, platform.is.win and "Scripts" or "bin" })
-end, _.if_else(_.always(platform.is.win), _.format "%s.exe", _.identity))
-
----@param packages string[]
-local function with_receipt(packages)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source(ctx.receipt.pip3(packages[1]))
- for i = 2, #packages do
- ctx.receipt:with_secondary_source(ctx.receipt.pip3(packages[i]))
- end
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The pip packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.packages(packages)
- return function()
- return M.install(packages).with_receipt()
- end
-end
-
----@async
----@param packages { [number]: string, bin: string[]? } The pip packages to install. The first item in this list will be the recipient of the requested version, if set.
-function M.install(packages)
- local ctx = installer.context()
- local pkgs = _.list_copy(packages)
-
- ctx.requested_version:if_present(function(version)
- pkgs[1] = ("%s==%s"):format(pkgs[1], version)
- end)
-
- a.scheduler()
-
- local executables = platform.is.win and { "python", "python3" } or { "python3", "python" }
-
- -- pip3 will hardcode the full path to venv executables, so we need to promote cwd to make sure pip uses the final destination path.
- ctx:promote_cwd()
-
- -- Find first executable that manages to create venv
- local executable = _.find_first(function(executable)
- return pcall(ctx.spawn[executable], { "-m", "venv", VENV_DIR })
- end, executables)
-
- Optional.of_nilable(executable)
- :if_present(function()
- if settings.current.pip.upgrade_pip then
- ctx.spawn.python {
- "-m",
- "pip",
- "--disable-pip-version-check",
- "install",
- "-U",
- settings.current.pip.install_args,
- "pip",
- with_paths = { M.venv_path(ctx.cwd:get()) },
- }
- end
- ctx.spawn.python {
- "-m",
- "pip",
- "--disable-pip-version-check",
- "install",
- "-U",
- settings.current.pip.install_args,
- pkgs,
- with_paths = { M.venv_path(ctx.cwd:get()) },
- }
- end)
- :or_else_throw "Unable to create python3 venv environment."
-
- if packages.bin then
- _.each(function(bin)
- ctx:link_bin(bin, create_bin_path(bin))
- end, packages.bin)
- end
-
- return {
- with_receipt = with_receipt(packages),
- }
-end
-
----@param pkg string
----@return string
-function M.normalize_package(pkg)
- -- https://stackoverflow.com/a/60307740
- local s = pkg:gsub("%[.*%]", "")
- return s
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.check_outdated_primary_package(receipt, install_dir)
- if receipt.primary_source.type ~= "pip3" then
- return Result.failure "Receipt does not have a primary source of type pip3"
- end
- local normalized_package = M.normalize_package(receipt.primary_source.package)
- return M.get_installed_primary_package_version(receipt, install_dir):and_then(function(installed_version)
- return providers.pypi
- .get_latest_version(normalized_package)
- :map(function(latest)
- return {
- current = installed_version,
- latest = latest.version,
- }
- end)
- :and_then(function(versions)
- if versions.current ~= versions.latest then
- return Result.success {
- name = normalized_package,
- current_version = versions.current,
- latest_version = versions.latest,
- }
- else
- return Result.failure "Primary package is not outdated."
- end
- end)
- end)
-end
-
----@async
----@param receipt InstallReceipt<InstallReceiptPackageSource>
----@param install_dir string
-function M.get_installed_primary_package_version(receipt, install_dir)
- if receipt.primary_source.type ~= "pip3" then
- return Result.failure "Receipt does not have a primary source of type pip3"
- end
- return spawn
- .python({
- "-m",
- "pip",
- "list",
- "--format=json",
- cwd = install_dir,
- with_paths = { M.venv_path(install_dir) },
- })
- :map_catching(function(result)
- local pip_packages = vim.json.decode(result.stdout)
- local normalized_pip_package = M.normalize_package(receipt.primary_source.package)
- local pip_package = _.find_first(function(pkg)
- return pkg.name == normalized_pip_package
- end, pip_packages)
- return Optional.of_nilable(pip_package)
- :map(function(pkg)
- return pkg.version
- end)
- :or_else_throw "Unable to find pip package."
- end)
-end
-
----@param install_dir string
-function M.venv_path(install_dir)
- return path.concat { install_dir, VENV_DIR, platform.is.win and "Scripts" or "bin" }
-end
-
-return M
diff --git a/lua/mason-core/managers/std/init.lua b/lua/mason-core/managers/std/init.lua
deleted file mode 100644
index b3116d7a..00000000
--- a/lua/mason-core/managers/std/init.lua
+++ /dev/null
@@ -1,196 +0,0 @@
-local Result = require "mason-core.result"
-local a = require "mason-core.async"
-local fetch = require "mason-core.fetch"
-local installer = require "mason-core.installer"
-local path = require "mason-core.path"
-local platform = require "mason-core.platform"
-local powershell = require "mason-core.managers.powershell"
-
-local M = {}
-
-local function with_system_executable_receipt(executable)
- return function()
- local ctx = installer.context()
- ctx.receipt:with_primary_source(ctx.receipt.system(executable))
- end
-end
-
----@async
----@param executable string
----@param opts {help_url:string?}?
-function M.ensure_executable(executable, opts)
- local ctx = installer.context()
- opts = opts or {}
- a.scheduler()
- if vim.fn.executable(executable) ~= 1 then
- ctx.stdio_sink.stderr(("%s was not found in path.\n"):format(executable))
- if opts.help_url then
- ctx.stdio_sink.stderr(("See %s for installation instructions.\n"):format(opts.help_url))
- end
- error("Installation failed: system executable was not found.", 0)
- end
-
- return {
- with_receipt = with_system_executable_receipt(executable),
- }
-end
-
----@async
----@param url string
----@param out_file string
-function M.download_file(url, out_file)
- local ctx = installer.context()
- ctx.stdio_sink.stdout(("Downloading file %q…\n"):format(url))
- fetch(url, {
- out_file = path.concat { ctx.cwd:get(), out_file },
- })
- :map_err(function(err)
- return ("Failed to download file %q.\n%s"):format(url, err)
- end)
- :get_or_throw()
-end
-
----@async
----@param file string
----@param dest string
-function M.unzip(file, dest)
- local ctx = installer.context()
- platform.when {
- unix = function()
- ctx.spawn.unzip { "-d", dest, file }
- end,
- win = function()
- powershell.command(
- ("Microsoft.PowerShell.Archive\\Expand-Archive -Path %q -DestinationPath %q"):format(file, dest),
- {},
- ctx.spawn
- )
- end,
- }
- pcall(function()
- -- make sure the .zip archive doesn't linger
- ctx.fs:unlink(file)
- end)
-end
-
----@param file string
-local function win_decompress(file)
- local ctx = installer.context()
- Result.run_catching(function()
- ctx.spawn.gzip { "-d", file }
- end)
- :recover_catching(function()
- ctx.spawn["7z"] { "x", "-y", "-r", file }
- end)
- :recover_catching(function()
- ctx.spawn.peazip { "-ext2here", path.concat { ctx.cwd:get(), file } } -- peazip requires absolute paths
- end)
- :recover_catching(function()
- ctx.spawn.wzunzip { file }
- end)
- :recover_catching(function()
- ctx.spawn.winrar { "e", file }
- end)
- :get_or_throw(("Unable to unpack %s."):format(file))
-end
-
----@async
----@param file string
----@param opts { strip_components?: integer }?
-function M.untar(file, opts)
- opts = opts or {}
- local ctx = installer.context()
- ctx.spawn.tar {
- opts.strip_components and { "--strip-components", opts.strip_components } or vim.NIL,
- "--no-same-owner",
- "-xvf",
- file,
- }
- pcall(function()
- ctx.fs:unlink(file)
- end)
-end
-
----@async
----@param file string
----@param opts { strip_components?: integer }?
-function M.untarzst(file, opts)
- opts = opts or {}
- platform.when {
- unix = function()
- M.untar(file, opts)
- end,
- win = function()
- local ctx = installer.context()
- local uncompressed_tar = file:gsub("%.zst$", "")
- ctx.spawn.zstd { "-dfo", uncompressed_tar, file }
- M.untar(uncompressed_tar, opts)
- end,
- }
-end
-
----@async
----@param file string
----@param opts { strip_components?: integer }?
-function M.untarxz(file, opts)
- opts = opts or {}
- local ctx = installer.context()
- platform.when {
- unix = function()
- M.untar(file, opts)
- end,
- win = function()
- Result.run_catching(function()
- win_decompress(file) -- unpack .tar.xz to .tar
- local uncompressed_tar = file:gsub("%.xz$", "")
- M.untar(uncompressed_tar, opts)
- end):recover(function()
- ctx.spawn.arc {
- "unarchive",
- opts.strip_components and { "--strip-components", opts.strip_components } or vim.NIL,
- file,
- }
- pcall(function()
- ctx.fs:unlink(file)
- end)
- end)
- end,
- }
-end
-
----@async
----@param file string
-function M.gunzip(file)
- platform.when {
- unix = function()
- local ctx = installer.context()
- ctx.spawn.gzip { "-d", file }
- end,
- win = function()
- win_decompress(file)
- end,
- }
-end
-
----@async
----@param flags string The chmod flag to apply.
----@param files string[] A list of relative paths to apply the chmod on.
-function M.chmod(flags, files)
- if platform.is.unix then
- local ctx = installer.context()
- ctx.spawn.chmod { flags, files }
- end
-end
-
----@async
----Wrapper around vim.ui.select.
----@param items table
----@params opts
-function M.select(items, opts)
- assert(not platform.is_headless, "Tried to prompt for user input while in headless mode.")
- a.scheduler()
- local async_select = a.promisify(vim.ui.select)
- return async_select(items, opts)
-end
-
-return M