Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(pypi): support MSYS2 virtual environments on Windows #1547

Merged
merged 3 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 26 additions & 17 deletions lua/mason-core/installer/managers/pypi.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,32 @@ local function create_venv(py_executables)
end, py_executables)):ok_or "Failed to create python3 virtual environment."
end

---@param ctx InstallContext
---@param executable string
local function find_venv_executable(ctx, executable)
local candidates = _.filter(_.identity, {
platform.is.unix and path.concat { VENV_DIR, "bin", executable },
-- MSYS2
platform.is.win and path.concat { VENV_DIR, "bin", ("%s.exe"):format(executable) },
-- Stock Windows
platform.is.win and path.concat { VENV_DIR, "Scripts", ("%s.exe"):format(executable) },
})

for _, candidate in ipairs(candidates) do
if ctx.fs:file_exists(candidate) then
return Result.success(candidate)
end
end
return Result.failure(("Failed to find executable %q in Python virtual environment."):format(executable))
end

---@async
---@param args SpawnArgs
local function venv_python(args)
local ctx = installer.context()
local python_path = path.concat {
ctx.cwd:get(),
VENV_DIR,
platform.is.win and "Scripts" or "bin",
platform.is.win and "python.exe" or "python",
}
return ctx.spawn[python_path](args)
return find_venv_executable(ctx, "python"):and_then(function(python_path)
return ctx.spawn[path.concat { ctx.cwd:get(), python_path }](args)
end)
end

---@async
Expand Down Expand Up @@ -93,16 +108,10 @@ function M.install(pkg, version, opts)
}, opts.install_extra_args)
end

---@param exec string
function M.bin_path(exec)
return Result.pcall(platform.when, {
unix = function()
return path.concat { "venv", "bin", exec }
end,
win = function()
return path.concat { "venv", "Scripts", ("%s.exe"):format(exec) }
end,
})
---@param executable string
function M.bin_path(executable)
local ctx = installer.context()
return find_venv_executable(ctx, executable)
end

return M
13 changes: 13 additions & 0 deletions tests/mason-core/installer/managers/pypi_spec.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local installer = require "mason-core.installer"
local match = require "luassert.match"
local path = require "mason-core.path"
local pypi = require "mason-core.installer.managers.pypi"
local spy = require "luassert.spy"
Expand Down Expand Up @@ -35,6 +36,9 @@ describe("pypi manager", function()
it("should init venv and upgrade pip", function()
local ctx = create_dummy_context()
stub(ctx, "promote_cwd")
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.ref(ctx.fs), "venv/bin/python").returns(true)

installer.exec_in_context(ctx, function()
pypi.init { upgrade_pip = true, install_extra_args = { "--proxy", "http://localhost" } }
end)
Expand All @@ -60,6 +64,8 @@ describe("pypi manager", function()

it("should install", function()
local ctx = create_dummy_context()
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.ref(ctx.fs), "venv/bin/python").returns(true)
installer.exec_in_context(ctx, function()
pypi.install("pypi-package", "1.0.0")
end)
Expand All @@ -81,6 +87,8 @@ describe("pypi manager", function()

it("should write output", function()
local ctx = create_dummy_context()
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.ref(ctx.fs), "venv/bin/python").returns(true)
spy.on(ctx.stdio_sink, "stdout")

installer.exec_in_context(ctx, function()
Expand All @@ -92,6 +100,9 @@ describe("pypi manager", function()

it("should install extra specifier", function()
local ctx = create_dummy_context()
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.ref(ctx.fs), "venv/bin/python").returns(true)

installer.exec_in_context(ctx, function()
pypi.install("pypi-package", "1.0.0", {
extra = "lsp",
Expand All @@ -115,6 +126,8 @@ describe("pypi manager", function()

it("should install extra packages", function()
local ctx = create_dummy_context()
stub(ctx.fs, "file_exists")
ctx.fs.file_exists.on_call_with(match.ref(ctx.fs), "venv/bin/python").returns(true)
installer.exec_in_context(ctx, function()
pypi.install("pypi-package", "1.0.0", {
extra_packages = { "extra-package" },
Expand Down
2 changes: 1 addition & 1 deletion tests/mason-core/installer/registry/link_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ describe("registry linker", function()
["npm:executable"] = "node_modules/.bin/executable",
["nuget:executable"] = "executable",
["opam:executable"] = "bin/executable",
["pypi:executable"] = "venv/bin/executable",
-- ["pypi:executable"] = "venv/bin/executable",
}

for bin, path in pairs(matrix) do
Expand Down
Loading