aboutsummaryrefslogtreecommitdiffstats
path: root/lua/mason-core/installer/managers/std.lua
diff options
context:
space:
mode:
authorWilliam Boman <william@redwill.se>2023-03-12 08:21:15 +0100
committerGitHub <noreply@github.com>2023-03-12 08:21:15 +0100
commita01d02ad7f680aec98a1e2ec35b04cedd307cfa8 (patch)
tree1a09e274a1f2a4da85b911abcbb182a211035501 /lua/mason-core/installer/managers/std.lua
parentfeat(golangci-lint): support linux_arm64 (#1089) (diff)
downloadmason-a01d02ad7f680aec98a1e2ec35b04cedd307cfa8.tar
mason-a01d02ad7f680aec98a1e2ec35b04cedd307cfa8.tar.gz
mason-a01d02ad7f680aec98a1e2ec35b04cedd307cfa8.tar.bz2
mason-a01d02ad7f680aec98a1e2ec35b04cedd307cfa8.tar.lz
mason-a01d02ad7f680aec98a1e2ec35b04cedd307cfa8.tar.xz
mason-a01d02ad7f680aec98a1e2ec35b04cedd307cfa8.tar.zst
mason-a01d02ad7f680aec98a1e2ec35b04cedd307cfa8.zip
feat: add github registry source capabilities (#1091)
Diffstat (limited to 'lua/mason-core/installer/managers/std.lua')
-rw-r--r--lua/mason-core/installer/managers/std.lua241
1 files changed, 241 insertions, 0 deletions
diff --git a/lua/mason-core/installer/managers/std.lua b/lua/mason-core/installer/managers/std.lua
new file mode 100644
index 00000000..4ae3fc7b
--- /dev/null
+++ b/lua/mason-core/installer/managers/std.lua
@@ -0,0 +1,241 @@
+local _ = require "mason-core.functional"
+local installer = require "mason-core.installer"
+local fetch = require "mason-core.fetch"
+local path = require "mason-core.path"
+local platform = require "mason-core.platform"
+local powershell = require "mason-core.managers.powershell"
+local Result = require "mason-core.result"
+local log = require "mason-core.log"
+
+local M = {}
+
+---@async
+---@param rel_path string
+---@nodiscard
+local function unpack_7z(rel_path)
+ log.fmt_debug("std: unpack_7z %s", rel_path)
+ local ctx = installer.context()
+ return ctx.spawn["7z"] { "x", "-y", "-r", rel_path }
+end
+
+---@async
+---@param rel_path string
+---@nodiscard
+local function unpack_peazip(rel_path)
+ log.fmt_debug("std: unpack_peazip %s", rel_path)
+ local ctx = installer.context()
+ return ctx.spawn.peazip { "-ext2here", path.concat { ctx.cwd:get(), rel_path } } -- peazip requires absolute paths
+end
+
+---@async
+---@param rel_path string
+---@nodiscard
+local function wzunzip(rel_path)
+ log.fmt_debug("std: wzunzip %s", rel_path)
+ local ctx = installer.context()
+ return ctx.spawn.wzunzip { rel_path }
+end
+
+---@async
+---@param rel_path string
+---@nodiscard
+local function unpack_winrar(rel_path)
+ log.fmt_debug("std: unpack_winrar %s", rel_path)
+ local ctx = installer.context()
+ return ctx.spawn.winrar { "e", rel_path }
+end
+
+---@async
+---@param rel_path string
+---@nodiscard
+local function gunzip_unix(rel_path)
+ log.fmt_debug("std: gunzip_unix %s", rel_path)
+ local ctx = installer.context()
+ return ctx.spawn.gzip { "-d", rel_path }
+end
+
+---@async
+---@param rel_path string
+---@nodiscard
+local function unpack_arc(rel_path)
+ log.fmt_debug("std: unpack_arc %s", rel_path)
+ local ctx = installer.context()
+ return ctx.spawn.arc { "unarchive", rel_path }
+end
+
+---@param rel_path string
+---@return Result
+local function win_decompress(rel_path)
+ local ctx = installer.context()
+ return gunzip_unix(rel_path)
+ :or_else(function()
+ return unpack_7z(rel_path)
+ end)
+ :or_else(function()
+ return unpack_peazip(rel_path)
+ end)
+ :or_else(function()
+ return wzunzip(rel_path)
+ end)
+ :or_else(function()
+ return unpack_winrar(rel_path)
+ end)
+ :on_success(function()
+ pcall(function()
+ ctx.fs:unlink(rel_path)
+ end)
+ end)
+end
+
+---@async
+---@param url string
+---@param out_file string
+---@nodiscard
+function M.download_file(url, out_file)
+ log.fmt_debug("std: downloading file %s", url, out_file)
+ local ctx = installer.context()
+ ctx.stdio_sink.stdout(("Downloading file %q...\n"):format(url))
+ return fetch(url, {
+ out_file = path.concat { ctx.cwd:get(), out_file },
+ }):map_err(function(err)
+ return ("%s\nFailed to download file %q."):format(err, url)
+ end)
+end
+
+---@async
+---@param rel_path string
+---@nodiscard
+local function untar(rel_path)
+ log.fmt_debug("std: untar %s", rel_path)
+ local ctx = installer.context()
+ return ctx.spawn.tar({ "--no-same-owner", "-xvf", rel_path }):on_success(function()
+ pcall(function()
+ ctx.fs:unlink(rel_path)
+ end)
+ end)
+end
+
+---@async
+---@param rel_path string
+---@nodiscard
+local function unzip(rel_path)
+ log.fmt_debug("std: unzip %s", rel_path)
+ local ctx = installer.context()
+ return platform.when {
+ unix = function()
+ return ctx.spawn.unzip({ "-d", ".", rel_path }):on_success(function()
+ pcall(function()
+ ctx.fs:unlink(rel_path)
+ end)
+ end)
+ end,
+ win = function()
+ return Result.pcall(function()
+ -- Expand-Archive seems to be hard-coded to only allow .zip extensions. Bit weird but ok.
+ if not _.matches("%.zip$", rel_path) then
+ local zip_file = ("%s.zip"):format(rel_path)
+ ctx.fs:rename(rel_path, zip_file)
+ return zip_file
+ end
+ return rel_path
+ end):and_then(function(zip_file)
+ return powershell
+ .command(
+ ("Microsoft.PowerShell.Archive\\Expand-Archive -Path %q -DestinationPath ."):format(zip_file),
+ {},
+ ctx.spawn
+ )
+ :on_success(function()
+ pcall(function()
+ ctx.fs:unlink(zip_file)
+ end)
+ end)
+ end)
+ end,
+ }
+end
+
+---@async
+---@param rel_path string
+---@nodiscard
+local function gunzip(rel_path)
+ log.fmt_debug("std: gunzip %s", rel_path)
+ return platform.when {
+ unix = function()
+ return gunzip_unix(rel_path)
+ end,
+ win = function()
+ return win_decompress(rel_path)
+ end,
+ }
+end
+
+---@async
+---@param rel_path string
+---@return Result
+---@nodiscard
+local function untar_compressed(rel_path)
+ log.fmt_debug("std: untar_compressed %s", rel_path)
+ return platform.when {
+ unix = function()
+ return untar(rel_path)
+ end,
+ win = function()
+ return win_decompress(rel_path)
+ :and_then(function()
+ return untar(_.gsub("%.tar%..*$", ".tar", rel_path))
+ end)
+ :or_else(function()
+ -- arc both decompresses and unpacks tar in one go
+ return unpack_arc(rel_path)
+ end)
+ end,
+ }
+end
+
+-- Order is important.
+local unpack_by_filename = _.cond {
+ { _.matches "%.tar$", untar },
+ { _.matches "%.tar%.gz$", untar },
+ { _.matches "%.tar%.bz2$", untar },
+ { _.matches "%.tar%.xz$", untar_compressed },
+ { _.matches "%.tar%.zst$", untar_compressed },
+ { _.matches "%.zip$", unzip },
+ { _.matches "%.vsix$", unzip },
+ { _.matches "%.gz$", gunzip },
+ { _.T, _.compose(Result.success, _.format "%q doesn't need unpacking.") },
+}
+
+---@async
+---@param rel_path string The relative path to the file to unpack.
+---@nodiscard
+function M.unpack(rel_path)
+ log.fmt_debug("std: unpack %s", rel_path)
+ return unpack_by_filename(rel_path)
+end
+
+---@async
+---@param git_url string
+---@param opts? { rev?: string, recursive?: boolean }
+---@nodiscard
+function M.clone(git_url, opts)
+ opts = opts or {}
+ log.fmt_debug("std: clone %s %s", git_url, opts)
+ local ctx = installer.context()
+ return Result.try(function(try)
+ try(ctx.spawn.git {
+ "clone",
+ "--depth",
+ "1",
+ opts.recursive and "--recursive" or vim.NIL,
+ git_url,
+ ".",
+ })
+ if opts.rev then
+ try(ctx.spawn.git { "fetch", "--depth", "1", "origin", opts.rev })
+ try(ctx.spawn.git { "checkout", "FETCH_HEAD" })
+ end
+ end)
+end
+
+return M