Skip to content

Commit

Permalink
Revert "fix(spawn): always expand cmd if PATH is not modified (#773)" (
Browse files Browse the repository at this point in the history
…#783)

This reverts commit dd04b41.
  • Loading branch information
williamboman committed Dec 21, 2022
1 parent 8240d7d commit 28408c8
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 66 deletions.
40 changes: 21 additions & 19 deletions lua/mason-core/spawn.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ local log = require "mason-core.log"
---@alias JobSpawn table<string, async fun(opts: SpawnArgs): Result>
---@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",
-- 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",
},
_flatten_cmd_args = _.compose(_.filter(_.complement(_.equals(vim.NIL))), _.flatten),
}

Expand All @@ -24,16 +33,11 @@ local function Failure(err, cmd)
}))
end

local exepath = _.memoize(function(cmd)
local is_executable = _.memoize(function(cmd)
if vim.in_fast_event() then
a.scheduler()
end
local exepath = vim.fn.exepath(cmd)
if exepath == "" then
return nil
else
return exepath
end
return vim.fn.executable(cmd) == 1
end, _.identity)

---@class SpawnArgs
Expand All @@ -43,10 +47,11 @@ end, _.identity)
---@field stdio_sink StdioSink? If provided, will be used to write to stdout and stderr.
---@field cwd string?
---@field on_spawn (fun(handle: luv_handle, stdio: luv_pipe[], pid: integer))? Will be called when the process successfully spawns.
---@field check_executable boolean? Whether to check if the provided command is executable (defaults to true).

setmetatable(spawn, {
---@param cmd string
__index = function(self, cmd)
---@param normalized_cmd string
__index = function(self, normalized_cmd)
---@param args SpawnArgs
return function(args)
local cmd_args = self._flatten_cmd_args(args)
Expand All @@ -71,16 +76,13 @@ setmetatable(spawn, {
spawn_args.stdio_sink = stdio.sink
end

-- Ensure that the cmd is executable (only if PATH is not modified).
if (env and env.PATH) == nil then
local expanded_cmd = exepath(cmd)
if expanded_cmd == nil then
log.fmt_debug("%s is not executable", cmd)
return Failure({
stderr = ("%s is not executable"):format(cmd),
}, cmd)
end
cmd = expanded_cmd
local cmd = self._aliases[normalized_cmd] or normalized_cmd

if (env and env.PATH) == nil and args.check_executable ~= false and not is_executable(cmd) then
log.fmt_debug("%s is not executable", cmd)
return Failure({
stderr = ("%s is not executable"):format(cmd),
}, cmd)
end

local _, exit_code, signal = a.wait(function(resolve)
Expand Down
62 changes: 15 additions & 47 deletions tests/mason-core/spawn_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe("async spawn", function()
assert.equals("", result:get_or_nil().stderr)
assert.spy(process.spawn).was_called(1)
assert.spy(process.spawn).was_called_with(
match.matches "bash$",
"bash",
match.tbl_containing {
stdio_sink = match.tbl_containing {
stdout = match.is_function(),
Expand Down Expand Up @@ -139,8 +139,7 @@ describe("async spawn", function()
callback(false)
end)

local result = spawn.bash {}
assert.spy(process.spawn).was_called(1)
local result = spawn.my_cmd {}
assert.is_true(result:is_failure())
assert.is_nil(result:err_or_nil().exit_code)
end)
Expand All @@ -156,40 +155,33 @@ describe("async spawn", function()

local result = spawn.bash {}
assert.is_true(result:is_failure())
assert.is_true(
match.matches "spawn: .+bash failed with exit code 127 and signal %-%. This is an error message for .+bash!"(
tostring(result:err_or_nil())
)
assert.equals(
"spawn: bash failed with exit code 127 and signal -. This is an error message for bash!",
tostring(result:err_or_nil())
)
end)
)

it(
"should fail if unable to expand command",
"should check whether command is executable",
async_test(function()
spy.on(process, "spawn")
stub(vim.fn, "exepath", function()
return ""
end)

local result = spawn.unexpand_cmd {}
local result = spawn.my_cmd {}
assert.is_true(result:is_failure())
assert.is_true(
match.matches "spawn: unexpand_cmd failed with exit code %- and signal %-%. unexpand_cmd is not executable"(
tostring(result:err_or_nil())
)
assert.equals(
"spawn: my_cmd failed with exit code - and signal -. my_cmd is not executable",
tostring(result:err_or_nil())
)
end)
)

it(
"should not expand cmd if custom PATH is used",
"should skip checking whether command is executable",
async_test(function()
stub(process, "spawn", function(_, _, callback)
callback(false, 127)
end)

local result = spawn.my_cmd { "arg1", env = { PATH = "/bin" } }
local result = spawn.my_cmd { "arg1", check_executable = false }
assert.is_true(result:is_failure())
assert.spy(process.spawn).was_called(1)
assert.spy(process.spawn).was_called_with(
Expand All @@ -203,46 +195,22 @@ describe("async spawn", function()
)

it(
"should skip expanding command if with_paths is provided",
"should skip checking whether command is executable if with_paths is provided",
async_test(function()
stub(process, "spawn", function(_, _, callback)
callback(false, 127)
end)

local result = spawn.custom_path { "arg1", with_paths = {} }
local result = spawn.my_cmd { "arg1", with_paths = {} }
assert.is_true(result:is_failure())
assert.spy(process.spawn).was_called(1)
assert.spy(process.spawn).was_called_with(
"custom_path",
"my_cmd",
match.tbl_containing {
args = match.same { "arg1" },
},
match.is_function()
)
end)
)

it(
"should use expanded command path",
async_test(function()
stub(vim.fn, "exepath", function()
return "/abs/path/to/cmd"
end)
stub(process, "spawn", function(_, _, callback)
callback(false)
end)

spawn.the_command { "arg1", "arg2" }
assert.spy(vim.fn.exepath).was_called(1)
assert.spy(vim.fn.exepath).was_called_with "the_command"
assert.spy(process.spawn).was_called(1)
assert.spy(process.spawn).was_called_with(
"/abs/path/to/cmd",
match.tbl_containing {
args = match.same { "arg1", "arg2" },
},
match.is_function()
)
end)
)
end)

0 comments on commit 28408c8

Please sign in to comment.