Skip to content

Commit

Permalink
feat: more competent platform detection (#436)
Browse files Browse the repository at this point in the history
  • Loading branch information
williamboman authored Sep 17, 2022
1 parent ac70755 commit d7eb2ee
Show file tree
Hide file tree
Showing 21 changed files with 164 additions and 127 deletions.
2 changes: 1 addition & 1 deletion lua/mason-core/fetch.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ local function fetch(url, opts)

local platform_specific = Result.failure()

if platform.is_win then
if platform.is.win then
local header_entries = _.join(
", ",
_.map(function(pair)
Expand Down
2 changes: 1 addition & 1 deletion lua/mason-core/installer/context.lua
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ function InstallContext:promote_cwd()
-- 1. Unlink any existing installation
self.handle.package:unlink()
-- 2. Prepare for renaming cwd to destination
if platform.is_unix then
if platform.is.unix then
-- Some Unix systems will raise an error when renaming a directory to a destination that does not already exist.
fs.async.mkdir(install_path)
end
Expand Down
8 changes: 4 additions & 4 deletions lua/mason-core/managers/github/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ function M.release_file(opts)
end
if not asset_file then
error(
("Could not find which release file to download.\nMost likely the current operating system, architecture (%s), or libc (%s) is not supported."):format(
platform.arch,
platform.get_libc()
),
(
"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
Expand Down
2 changes: 1 addition & 1 deletion lua/mason-core/managers/go/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ function M.get_installed_primary_package_version(receipt, install_dir)
.go({
"version",
"-m",
platform.is_win and ("%s.exe"):format(executable) or executable,
platform.is.win and ("%s.exe"):format(executable) or executable,
cwd = install_dir,
})
:map_catching(function(result)
Expand Down
6 changes: 3 additions & 3 deletions lua/mason-core/managers/pip3/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ 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" })
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[]
Expand Down Expand Up @@ -44,7 +44,7 @@ function M.install(packages)
pkgs[1] = ("%s==%s"):format(pkgs[1], version)
end)

local executables = platform.is_win and _.list_not_nil(vim.g.python3_host_prog, "python", "python3")
local executables = platform.is.win and _.list_not_nil(vim.g.python3_host_prog, "python", "python3")
or _.list_not_nil(vim.g.python3_host_prog, "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.
Expand Down Expand Up @@ -161,7 +161,7 @@ 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" }
return path.concat { install_dir, VENV_DIR, platform.is.win and "Scripts" or "bin" }
end

return M
2 changes: 1 addition & 1 deletion lua/mason-core/managers/std/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ end
---@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
if platform.is.unix then
local ctx = installer.context()
ctx.spawn.chmod { flags, files }
end
Expand Down
110 changes: 73 additions & 37 deletions lua/mason-core/platform.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local fun = require "mason-core.functional.function"
local _ = require "mason-core.functional"

local M = {}

Expand All @@ -21,28 +21,83 @@ local arch_aliases = {
}

M.arch = arch_aliases[uname.machine] or uname.machine
M.sysname = uname.sysname

M.is_win = vim.fn.has "win32" == 1
M.is_unix = vim.fn.has "unix" == 1
M.is_mac = vim.fn.has "mac" == 1
M.is_linux = not M.is_mac and M.is_unix
M.is_headless = #vim.api.nvim_list_uis() == 0

-- PATH separator
M.path_sep = M.is_win and ";" or ":"
-- @return string @The libc found on the system, musl or glibc (glibc if ldd is not found)
local get_libc = _.lazy(function()
local _, _, libc_exit_code = os.execute "ldd --version 2>&1 | grep -q musl"
if libc_exit_code == 0 then
return "musl"
else
return "glibc"
end
end)

M.is_headless = #vim.api.nvim_list_uis() == 0
-- Most of the code that calls into these functions executes outside of the main event loop, where API/fn functions are
-- disabled. We evaluate these immediately here to avoid issues with main loop synchronization.
local cached_features = {
["win"] = vim.fn.has "win32",
["win32"] = vim.fn.has "win32",
["win64"] = vim.fn.has "win64",
["mac"] = vim.fn.has "mac",
["unix"] = vim.fn.has "unix",
["linux"] = vim.fn.has "linux",
}

---@type fun(env: string): boolean
local check_env = _.memoize(_.cond {
{
_.equals "musl",
function()
return get_libc() == "musl"
end,
},
{
_.equals "gnu",
function()
return get_libc() == "glibc"
end,
},
{ _.equals "openbsd", _.always(uname.sysname == "OpenBSD") },
{ _.T, _.F },
})

---Table that allows for checking whether the provided targets apply to the current system.
---Each key is a target tuple consisting of at most 3 targets, in the following order:
--- 1) OS (e.g. linux, unix, mac, win) - Mandatory
--- 2) Architecture (e.g. arm64, x64) - Optional
--- 3) Environment (e.g. gnu, musl, openbsd) - Optional
---Each target is separated by a "_" character, like so: "linux_x64_musl".
---@type table<string, boolean>
M.is = setmetatable({}, {
__index = function(__, key)
local os, arch, env = unpack(vim.split(key, "_", { plain = true }))
if not cached_features[os] or cached_features[os] ~= 1 then
return false
end
if arch and arch ~= M.arch then
return false
end
if env and not check_env(env) then
return false
end
return true
end,
})

---@generic T
---@param platform_table table<Platform, T>
---@return T
local function get_by_platform(platform_table)
if M.is_mac then
if M.is.mac then
return platform_table.mac or platform_table.unix
elseif M.is_linux then
elseif M.is.linux then
return platform_table.linux or platform_table.unix
elseif M.is_unix then
elseif M.is.unix then
return platform_table.unix
elseif M.is_win then
elseif M.is.win then
return platform_table.win
else
return nil
Expand All @@ -59,7 +114,7 @@ function M.when(cases)
end

---@type async fun(): table
M.os_distribution = fun.lazy(function()
M.os_distribution = _.lazy(function()
local Result = require "mason-core.result"

---Parses the provided contents of an /etc/\*-release file and identifies the Linux distribution.
Expand Down Expand Up @@ -122,8 +177,8 @@ M.os_distribution = fun.lazy(function()
end)

---@type async fun(): Result<string>
M.get_homebrew_prefix = fun.lazy(function()
assert(M.is_mac, "Can only locate Homebrew installation on Mac systems.")
M.get_homebrew_prefix = _.lazy(function()
assert(M.is.mac, "Can only locate Homebrew installation on Mac systems.")
local spawn = require "mason-core.spawn"
return spawn
.brew({ "--prefix" })
Expand All @@ -135,31 +190,9 @@ M.get_homebrew_prefix = fun.lazy(function()
end)
end)

-- @return string @The libc found on the system, musl or glibc (glibc if ldd is not found)
M.get_libc = fun.lazy(function()
local _, _, libc_exit_code = os.execute "ldd --version 2>&1 | grep -q musl"
if libc_exit_code == 0 then
return "musl"
else
return "glibc"
end
end)

---@type table<string, boolean>
M.is = setmetatable({}, {
__index = function(_, key)
local platform, arch = unpack(vim.split(key, "_", { plain = true }))
if arch and M.arch ~= arch then
return false
end
return M["is_" .. platform] == true
end,
})

---@async
function M.get_node_version()
local spawn = require "mason-core.spawn"
local _ = require "mason-core.functional"

return spawn.node({ "--version" }):map(function(result)
-- Parses output such as "v16.3.1" into major, minor, patch
Expand All @@ -168,4 +201,7 @@ function M.get_node_version()
end)
end

-- PATH separator
M.path_sep = M.is.win and ";" or ":"

return M
12 changes: 6 additions & 6 deletions lua/mason-core/spawn.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ local log = require "mason-core.log"
---@type JobSpawn
local spawn = {
_aliases = {
npm = platform.is_win and "npm.cmd" or "npm",
gem = platform.is_win and "gem.cmd" or "gem",
composer = platform.is_win and "composer.bat" or "composer",
gradlew = platform.is_win and "gradlew.bat" or "gradlew",
npm = platform.is.win and "npm.cmd" or "npm",
gem = platform.is.win and "gem.cmd" or "gem",
composer = platform.is.win and "composer.bat" or "composer",
gradlew = platform.is.win and "gradlew.bat" or "gradlew",
-- for hererocks installations
luarocks = (platform.is_win and vim.fn.executable "luarocks.bat" == 1) and "luarocks.bat" or "luarocks",
rebar3 = platform.is_win and "rebar3.cmd" or "rebar3",
luarocks = (platform.is.win and vim.fn.executable "luarocks.bat" == 1) and "luarocks.bat" or "luarocks",
rebar3 = platform.is.win and "rebar3.cmd" or "rebar3",
},
_flatten_cmd_args = _.compose(_.filter(_.complement(_.equals(vim.NIL))), _.flatten),
}
Expand Down
11 changes: 2 additions & 9 deletions lua/mason-registry/cbfmt/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,10 @@ return Pkg.new {
---@async
---@param ctx InstallContext
install = function(ctx)
local libc = platform.get_libc()

local asset_file = coalesce(
when(platform.is.mac, "cbfmt_macos-x86_64_%s.tar.gz"),
when(
platform.is.linux_x64,
coalesce(
when(libc == "glibc", "cbfmt_linux-x86_64_%s.tar.gz"),
when(libc == "musl", "cbfmt_linux-x86_64-musl_%s.tar.gz")
)
),
when(platform.is.linux_x64_gnu, "cbfmt_linux-x86_64_%s.tar.gz"),
when(platform.is.linux_x64_musl, "cbfmt_linux-x86_64-musl_%s.tar.gz"),
when(platform.is.win_x64, "cbfmt_windows-x86_64-msvc_%s.zip")
)

Expand Down
9 changes: 3 additions & 6 deletions lua/mason-registry/clojure-lsp/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,10 @@ return Pkg.new {
asset_file = coalesce(
when(platform.is.mac_arm64, "clojure-lsp-native-macos-aarch64.zip"),
when(platform.is.mac_x64, "clojure-lsp-native-macos-amd64.zip"),
when(
platform.is.linux_x64 and platform.get_libc() == "musl",
"clojure-lsp-native-static-linux-amd64.zip"
),
when(platform.is.linux_x64 and platform.get_libc() == "glibc", "clojure-lsp-native-linux-amd64.zip"),
when(platform.is.linux_x64_musl, "clojure-lsp-native-static-linux-amd64.zip"),
when(platform.is.linux_x64_gnu, "clojure-lsp-native-linux-amd64.zip"),
when(platform.is.linux_arm64, "clojure-lsp-native-linux-aarch64.zip"),
when(platform.is_win, "clojure-lsp-native-windows-amd64.zip")
when(platform.is.win_x64, "clojure-lsp-native-windows-amd64.zip")
),
})
.with_receipt()
Expand Down
2 changes: 2 additions & 0 deletions lua/mason-registry/editorconfig-checker/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ return Pkg.new {
asset_file = coalesce(
when(platform.is.mac_arm64, "ec-darwin-arm64.tar.gz"),
when(platform.is.mac_x64, "ec-darwin-amd64.tar.gz"),
when(platform.is.linux_x64_openbsd, "ec-openbsd-amd64.tar.gz"),
when(platform.is.linux_arm64_openbsd, "ec-openbsd-arm64.tar.gz"),
when(platform.is.linux_arm64, "ec-linux-arm64.tar.gz"),
when(platform.is.linux_x64, "ec-linux-amd64.tar.gz"),
when(platform.is.win_x86, "ec-windows-386.tar.gz"),
Expand Down
2 changes: 1 addition & 1 deletion lua/mason-registry/erlang-ls/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ local github = require "mason-core.managers.github"
local Optional = require "mason-core.optional"
local path = require "mason-core.path"

local rebar3 = platform.is_win and "rebar3.cmd" or "rebar3"
local rebar3 = platform.is.win and "rebar3.cmd" or "rebar3"

return Pkg.new {
name = "erlang-ls",
Expand Down
9 changes: 5 additions & 4 deletions lua/mason-registry/ltex-ls/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,19 @@ local function download_platform_dependent()
repo = repo,
asset_file = function(version)
local target = coalesce(
when(platform.is_mac, "ltex-ls-%s-mac-x64.tar.gz"),
when(platform.is_linux, "ltex-ls-%s-linux-x64.tar.gz")
when(platform.is.mac, "ltex-ls-%s-mac-x64.tar.gz"),
when(platform.is.linux_x64, "ltex-ls-%s-linux-x64.tar.gz")
)
return target:format(version)
return target and target:format(version)
end,
}
end,
win = function()
return github.unzip_release_file {
repo = repo,
asset_file = function(version)
return ("ltex-ls-%s-windows-x64.zip"):format(version)
local target = coalesce(when(platform.is.win_x64, "ltex-ls-%s-windows-x64.zip"))
return target and target:format(version)
end,
}
end,
Expand Down
8 changes: 4 additions & 4 deletions lua/mason-registry/prosemd-lsp/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ return Pkg.new {
github
.download_release_file({
repo = "kitten/prosemd-lsp",
out_file = platform.is_win and "prosemd-lsp.exe" or "prosemd-lsp",
out_file = platform.is.win and "prosemd-lsp.exe" or "prosemd-lsp",
asset_file = coalesce(
when(platform.is_mac, "prosemd-lsp-macos"),
when(platform.is_linux and platform.arch == "x64", "prosemd-lsp-linux"),
when(platform.is_win and platform.arch == "x64", "prosemd-lsp-windows.exe")
when(platform.is.mac, "prosemd-lsp-macos"),
when(platform.is.linux_x64_gnu, "prosemd-lsp-linux"),
when(platform.is.win_x64, "prosemd-lsp-windows.exe")
),
})
.with_receipt()
Expand Down
21 changes: 3 additions & 18 deletions lua/mason-registry/rust-analyzer/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,12 @@ return Pkg.new {
---@async
---@param ctx InstallContext
install = function(ctx)
local libc = platform.get_libc()

local asset_file = coalesce(
when(platform.is.mac_arm64, "rust-analyzer-aarch64-apple-darwin.gz"),
when(platform.is.mac_x64, "rust-analyzer-x86_64-apple-darwin.gz"),
when(
platform.is.linux,
coalesce(
when(
libc == "glibc",
coalesce(
when(platform.arch == "arm64", "rust-analyzer-aarch64-unknown-linux-gnu.gz"),
when(platform.arch == "x64", "rust-analyzer-x86_64-unknown-linux-gnu.gz")
)
),
when(
libc == "musl",
coalesce(when(platform.arch == "x64", "rust-analyzer-x86_64-unknown-linux-musl.gz"))
)
)
),
when(platform.is.linux_x64_gnu, "rust-analyzer-x86_64-unknown-linux-gnu.gz"),
when(platform.is.linux_arm64_gnu, "rust-analyzer-aarch64-unknown-linux-gnu.gz"),
when(platform.is.linux_x64_musl, "rust-analyzer-x86_64-unknown-linux-musl.gz"),
when(platform.is.win_arm64, "rust-analyzer-aarch64-pc-windows-msvc.gz"),
when(platform.is.win_x64, "rust-analyzer-x86_64-pc-windows-msvc.gz")
)
Expand Down
2 changes: 1 addition & 1 deletion lua/mason-registry/solidity/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ return Pkg.new {
github
.download_release_file({
repo = "ethereum/solidity",
out_file = platform.is_win and "solc.exe" or "solc",
out_file = platform.is.win and "solc.exe" or "solc",
asset_file = coalesce(
when(platform.is.mac, "solc-macos"),
when(platform.is.linux, "solc-static-linux"),
Expand Down
Loading

0 comments on commit d7eb2ee

Please sign in to comment.