diff options
| author | William Boman <william@redwill.se> | 2022-07-08 18:34:38 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-07-08 18:34:38 +0200 |
| commit | 976aa4fbee8a070f362cab6f6ec84e9251a90cf9 (patch) | |
| tree | 5e8d9c9c59444a25c7801b8f39763c4ba6e1f76d /lua/mason-core/managers/cargo/init.lua | |
| parent | feat: add gotests, gomodifytags, impl (#28) (diff) | |
| download | mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar.gz mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar.bz2 mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar.lz mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar.xz mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.tar.zst mason-976aa4fbee8a070f362cab6f6ec84e9251a90cf9.zip | |
refactor: add mason-schemas and mason-core modules (#29)
* refactor: add mason-schemas and move generated filetype map to mason-lspconfig
* refactor: add mason-core module
Diffstat (limited to 'lua/mason-core/managers/cargo/init.lua')
| -rw-r--r-- | lua/mason-core/managers/cargo/init.lua | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/lua/mason-core/managers/cargo/init.lua b/lua/mason-core/managers/cargo/init.lua new file mode 100644 index 00000000..5b87667c --- /dev/null +++ b/lua/mason-core/managers/cargo/init.lua @@ -0,0 +1,140 @@ +local process = require "mason-core.process" +local path = require "mason-core.path" +local platform = require "mason-core.platform" +local spawn = require "mason-core.spawn" +local a = require "mason-core.async" +local Optional = require "mason-core.optional" +local installer = require "mason-core.installer" +local client = require "mason-core.managers.cargo.client" +local _ = require "mason-core.functional" + +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: boolean | string, features: string|nil, bin: string[] | nil } | nil +function M.crate(crate, opts) + return function() + M.install(crate, opts).with_receipt() + end +end + +---@async +---@param crate string The crate to install. +---@param opts {git: boolean | string, features: string|nil, bin: string[] | nil } | nil +function M.install(crate, opts) + local ctx = installer.context() + opts = opts or {} + ctx.requested_version:if_present(function() + assert(not opts.git, "Providing a version when installing a git crate is not allowed.") + end) + + local final_crate = crate + + if opts.git then + final_crate = { "--git" } + if type(opts.git) == "string" then + table.insert(final_crate, opts.git) + end + table.insert(final_crate, crate) + end + + ctx.spawn.cargo { + "install", + "--root", + ".", + "--locked", + ctx.requested_version + :map(function(version) + return { "--version", version } + end) + :or_else(vim.NIL), + opts.features and { "--features", opts.features } or vim.NIL, + final_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 + +---@param output string @The `cargo install --list` output. +---@return table<string, string> @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 name, version = line:match "^(.+)%s+v([.%S]+)[%s:]" + if name and version then + installed_crates[name] = version + end + end + return installed_crates +end + +---@async +---@param receipt InstallReceipt +---@param install_dir string +function M.check_outdated_primary_package(receipt, install_dir) + return M.get_installed_primary_package_version(receipt, install_dir):map_catching(function(installed_version) + ---@type CrateResponse + local crate_response = client.fetch_crate(receipt.primary_source.package):get_or_throw() + if installed_version ~= crate_response.crate.max_stable_version then + return { + name = receipt.primary_source.package, + current_version = installed_version, + latest_version = crate_response.crate.max_stable_version, + } + else + error "Primary package is not outdated." + end + end) +end + +---@async +---@param receipt InstallReceipt +---@param install_dir string +function M.get_installed_primary_package_version(receipt, install_dir) + return spawn + .cargo({ + "install", + "--list", + "--root", + ".", + cwd = install_dir, + }) + :map_catching(function(result) + local installed_crates = M.parse_installed_crates(result.stdout) + if vim.in_fast_event() then + a.scheduler() -- needed because vim.fn.* call + end + local pkg = vim.fn.fnamemodify(receipt.primary_source.package, ":t") + return Optional.of_nilable(installed_crates[pkg]):or_else_throw "Failed to find cargo package version." + end) +end + +---@param install_dir string +function M.env(install_dir) + return { + PATH = process.extend_path { path.concat { install_dir, "bin" } }, + } +end + +return M |
