From 8240d7da6b2800aaacb0bec71a268cba62130814 Mon Sep 17 00:00:00 2001 From: William Boman Date: Wed, 21 Dec 2022 11:51:36 +0100 Subject: [PATCH] fix(powershell): use pwsh if available (#782) --- README.md | 2 +- doc/mason.txt | 4 +- lua/mason-core/managers/powershell/init.lua | 6 +- lua/mason/health/init.lua | 12 ++- tests/mason-core/managers/powershell_spec.lua | 97 +++++++++++++++++++ 5 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 tests/mason-core/managers/powershell_spec.lua diff --git a/README.md b/README.md index 1ff650747..29f3eff3a 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ The _minimum_ recommended requirements are: - neovim `>= 0.7.0` - For Unix systems: `git(1)`, `curl(1)` or `wget(1)`, `unzip(1)`, `tar(1)`, `gzip(1)` -- For Windows systems: powershell, git, tar, and [7zip][7zip] or [peazip][peazip] or [archiver][archiver] or [winzip][winzip] or [WinRAR][winrar] +- For Windows systems: pwsh or powershell, git, tar, and [7zip][7zip] or [peazip][peazip] or [archiver][archiver] or [winzip][winzip] or [WinRAR][winrar] Note that `mason.nvim` will regularly shell out to external package managers, such as `cargo` and `npm`. Depending on your personal usage, some of these will also need to be installed. Refer to `:checkhealth mason` for a full list. diff --git a/doc/mason.txt b/doc/mason.txt index 44ca83df0..5a5c9bdad 100644 --- a/doc/mason.txt +++ b/doc/mason.txt @@ -56,8 +56,8 @@ perfect substitutes). The _minimum_ recommended requirements are: - neovim `>= 0.7.0` - For Unix systems: `git(1)`, `curl(1)` or `wget(1)`, `unzip(1)`, `tar(1)`, `gzip(1)` -- For Windows systems: powershell, git, tar, and 7zip or peazip or archiver - or winzip or WinRAR +- For Windows systems: pwsh or powershell, git, tar, and 7zip or peazip or + archiver or winzip or WinRAR Note that Mason will regularly shell out to external package managers, such as `cargo` and `npm`. Depending on your personal usage, some of these diff --git a/lua/mason-core/managers/powershell/init.lua b/lua/mason-core/managers/powershell/init.lua index 5cc5e21d2..161ee4b2c 100644 --- a/lua/mason-core/managers/powershell/init.lua +++ b/lua/mason-core/managers/powershell/init.lua @@ -8,6 +8,8 @@ local PWSHOPT = { security_protocol = [[ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; ]], } +local powershell = vim.fn.executable "pwsh" == 1 and "pwsh" or "powershell" + ---@param script string ---@param opts JobSpawnOpts? ---@param custom_spawn JobSpawn? @@ -15,7 +17,7 @@ function M.script(script, opts, custom_spawn) opts = opts or {} ---@type JobSpawn local spawner = custom_spawn or spawn - return spawner.powershell(vim.tbl_extend("keep", { + return spawner[powershell](vim.tbl_extend("keep", { "-NoProfile", on_spawn = function(_, stdio) local stdin = stdio[1] @@ -35,7 +37,7 @@ function M.command(command, opts, custom_spawn) opts = opts or {} ---@type JobSpawn local spawner = custom_spawn or spawn - return spawner.powershell(vim.tbl_extend("keep", { + return spawner[powershell](vim.tbl_extend("keep", { "-NoProfile", "-Command", PWSHOPT.progress_preference .. PWSHOPT.security_protocol .. command, diff --git a/lua/mason/health/init.lua b/lua/mason/health/init.lua index 5003bb0ae..0e33911de 100644 --- a/lua/mason/health/init.lua +++ b/lua/mason/health/init.lua @@ -221,8 +221,16 @@ function M.check() relaxed = platform.is.win, }, check { cmd = "tar", args = { "--version" }, name = "tar" }, - -- when(platform.is.win, check { cmd = "powershell.exe", args = { "-Version" }, name = "PowerShell" }), -- TODO fix me - -- when(platform.is.win, check { cmd = "cmd.exe", args = { "-Version" }, name = "cmd" }) -- TODO fix me + check { + cmd = "pwsh", + args = { + "-NoProfile", + "-Command", + [[$PSVersionTable.PSVersion, $PSVersionTable.OS, $PSVersionTable.Platform -join " "]], + }, + name = "pwsh", + relaxed = not platform.is.win, + }, } if platform.is.unix then diff --git a/tests/mason-core/managers/powershell_spec.lua b/tests/mason-core/managers/powershell_spec.lua new file mode 100644 index 000000000..3cc78e5e9 --- /dev/null +++ b/tests/mason-core/managers/powershell_spec.lua @@ -0,0 +1,97 @@ +local stub = require "luassert.stub" +local spy = require "luassert.spy" +local match = require "luassert.match" +local mock = require "luassert.mock" +local spawn = require "mason-core.spawn" + +describe("powershell manager", function() + local function powershell() + package.loaded["mason-core.managers.powershell"] = nil + return require "mason-core.managers.powershell" + end + + it("should use pwsh if available", function() + stub(spawn, "pwsh", function() end) + stub(spawn, "powershell", function() end) + stub(vim.fn, "executable") + vim.fn.executable.on_call_with("pwsh").returns(1) + + powershell().command "echo 'Is this bash?'" + + assert.spy(spawn.pwsh).was_called(1) + assert.spy(spawn.powershell).was_called(0) + end) + + it( + "should use powershell if pwsh is not availble", + async_test(function() + stub(spawn, "pwsh", function() end) + stub(spawn, "powershell", function() end) + stub(vim.fn, "executable") + vim.fn.executable.on_call_with("pwsh").returns(0) + + powershell().command "echo 'Is this bash?'" + + assert.spy(spawn.pwsh).was_called(0) + assert.spy(spawn.powershell).was_called(1) + end) + ) + + it("should use the provided spawner for commands", function() + spy.on(spawn, "pwsh") + local custom_spawn = mock.new { pwsh = mockx.just_runs } + stub(vim.fn, "executable") + vim.fn.executable.on_call_with("pwsh").returns(1) + powershell().command("echo 'Is this bash?'", {}, custom_spawn) + + assert.spy(spawn.pwsh).was_called(0) + assert.spy(custom_spawn.pwsh).was_called(1) + end) + + it("should use the provided spawner scripts", function() + spy.on(spawn, "pwsh") + local custom_spawn = mock.new { pwsh = mockx.just_runs } + stub(vim.fn, "executable") + vim.fn.executable.on_call_with("pwsh").returns(1) + powershell().script("echo 'Is this bash?'", {}, custom_spawn) + + assert.spy(spawn.pwsh).was_called(0) + assert.spy(custom_spawn.pwsh).was_called(1) + end) + + it("should provide default powershell options via script stdin", function() + local stdin = mock.new { write = mockx.just_runs, close = mockx.just_runs } + stub(spawn, "pwsh", function(args) + args.on_spawn(nil, { stdin }) + end) + stub(vim.fn, "executable") + vim.fn.executable.on_call_with("pwsh").returns(1) + + powershell().script "echo 'Is this bash?'" + + assert.spy(spawn.pwsh).was_called(1) + assert.spy(stdin.write).was_called(3) + assert.spy(stdin.write).was_called_with(match.is_ref(stdin), " $ProgressPreference = 'SilentlyContinue'; ") + assert + .spy(stdin.write) + .was_called_with(match.is_ref(stdin), " [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; ") + assert.spy(stdin.write).was_called_with(match.is_ref(stdin), "echo 'Is this bash?'") + assert.spy(stdin.close).was_called(1) + end) + + it("should provide default powershell options via command interface", function() + stub(spawn, "pwsh", function() end) + stub(vim.fn, "executable") + vim.fn.executable.on_call_with("pwsh").returns(1) + + powershell().command "echo 'Is this bash?'" + + assert.spy(spawn.pwsh).was_called(1) + vim.pretty_print(spawn.pwsh) + assert.spy(spawn.pwsh).was_called_with(match.tbl_containing { + "-NoProfile", + "-Command", + " $ProgressPreference = 'SilentlyContinue'; [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; echo 'Is this bash?'", + }) + end) +end)