From e3d469e7712b81b752cb63813fc7c79e18df279d Mon Sep 17 00:00:00 2001 From: William Boman Date: Mon, 26 Dec 2022 17:38:44 +0100 Subject: [PATCH] feat(powershell): set $ErrorActionPreference = "Stop"; (#807) Also write to stdin pipe asynchronously. --- lua/mason-core/managers/powershell/init.lua | 26 ++++++++++-------- tests/mason-core/managers/powershell_spec.lua | 27 ++++++++++++------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/lua/mason-core/managers/powershell/init.lua b/lua/mason-core/managers/powershell/init.lua index 161ee4b2c..786645dbb 100644 --- a/lua/mason-core/managers/powershell/init.lua +++ b/lua/mason-core/managers/powershell/init.lua @@ -1,3 +1,4 @@ +local a = require "mason-core.async" local spawn = require "mason-core.spawn" local process = require "mason-core.process" @@ -6,12 +7,13 @@ local M = {} local PWSHOPT = { progress_preference = [[ $ProgressPreference = 'SilentlyContinue'; ]], -- https://stackoverflow.com/a/63301751 security_protocol = [[ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; ]], + error_action_preference = [[ $ErrorActionPreference = "Stop"; ]], } local powershell = vim.fn.executable "pwsh" == 1 and "pwsh" or "powershell" ---@param script string ----@param opts JobSpawnOpts? +---@param opts SpawnArgs? ---@param custom_spawn JobSpawn? function M.script(script, opts, custom_spawn) opts = opts or {} @@ -19,19 +21,21 @@ function M.script(script, opts, custom_spawn) local spawner = custom_spawn or spawn return spawner[powershell](vim.tbl_extend("keep", { "-NoProfile", - on_spawn = function(_, stdio) + on_spawn = a.scope(function(_, stdio) local stdin = stdio[1] - stdin:write(PWSHOPT.progress_preference) - stdin:write(PWSHOPT.security_protocol) - stdin:write(script) - stdin:close() - end, + local write = a.promisify(vim.loop.write) + write(stdin, PWSHOPT.error_action_preference) + write(stdin, PWSHOPT.progress_preference) + write(stdin, PWSHOPT.security_protocol) + write(stdin, script) + stdin:shutdown() + end), env_raw = process.graft_env(opts.env or {}, { "PSMODULEPATH" }), - }, opts) --[[@as JobSpawnOpts]]) + }, opts)) end ---@param command string ----@param opts JobSpawnOpts? +---@param opts SpawnArgs? ---@param custom_spawn JobSpawn? function M.command(command, opts, custom_spawn) opts = opts or {} @@ -40,9 +44,9 @@ function M.command(command, opts, custom_spawn) return spawner[powershell](vim.tbl_extend("keep", { "-NoProfile", "-Command", - PWSHOPT.progress_preference .. PWSHOPT.security_protocol .. command, + PWSHOPT.error_action_preference .. PWSHOPT.progress_preference .. PWSHOPT.security_protocol .. command, env_raw = process.graft_env(opts.env or {}, { "PSMODULEPATH" }), - }, opts) --[[@as JobSpawnOpts]]) + }, opts)) end return M diff --git a/tests/mason-core/managers/powershell_spec.lua b/tests/mason-core/managers/powershell_spec.lua index 3cc78e5e9..0d6851d1c 100644 --- a/tests/mason-core/managers/powershell_spec.lua +++ b/tests/mason-core/managers/powershell_spec.lua @@ -60,23 +60,33 @@ describe("powershell manager", function() end) it("should provide default powershell options via script stdin", function() - local stdin = mock.new { write = mockx.just_runs, close = mockx.just_runs } + local stdin = mock.new { shutdown = mockx.just_runs } stub(spawn, "pwsh", function(args) args.on_spawn(nil, { stdin }) end) stub(vim.fn, "executable") + stub(vim.loop, "write", function(_, _, callback) + callback() + end) 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(vim.loop.write).was_called(4) + assert + .spy(vim.loop.write) + .was_called_with(match.is_ref(stdin), [[ $ErrorActionPreference = "Stop"; ]], match.is_function()) 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) + .spy(vim.loop.write) + .was_called_with(match.is_ref(stdin), " $ProgressPreference = 'SilentlyContinue'; ", match.is_function()) + assert.spy(vim.loop.write).was_called_with( + match.is_ref(stdin), + " [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; ", + match.is_function() + ) + assert.spy(vim.loop.write).was_called_with(match.is_ref(stdin), "echo 'Is this bash?'", match.is_function()) + assert.spy(stdin.shutdown).was_called(1) end) it("should provide default powershell options via command interface", function() @@ -87,11 +97,10 @@ describe("powershell manager", function() 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?'", + [[ $ErrorActionPreference = "Stop"; $ProgressPreference = 'SilentlyContinue'; [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; echo 'Is this bash?']], }) end) end)