From 0514854c3fe40bad1b16efffa35d995d3261a753 Mon Sep 17 00:00:00 2001 From: Michael Park Date: Wed, 28 Feb 2024 20:18:02 +0000 Subject: [PATCH] feat: add update to README feat: add uv as an installer for python UV is a very fast installer for python packages that can be 10-100x faster to resolve packages. This adds an option for Mason to use it instead of pip to resolve python packages that are installed via Mason. More info about the replacement: https://github.com/astral-sh/uv I have no relationship with uv, it is just very fast and it would be nice to have updates for packages like sqlfluff take a lot less time than they currently do to resolve during updates. --- README.md | 4 ++ doc/mason.txt | 4 ++ lua/mason-core/installer/managers/pypi.lua | 57 ++++++++++++++----- .../installer/registry/providers/pypi.lua | 3 + lua/mason/settings.lua | 4 ++ .../registry/providers/pypi_spec.lua | 1 + 6 files changed, 60 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 9e33b653c..89343475e 100644 --- a/README.md +++ b/README.md @@ -252,6 +252,10 @@ local DEFAULT_SETTINGS = { -- Whether to upgrade pip to the latest version in the virtual environment before installing packages. upgrade_pip = false, + ---@since 1.8.0 + -- Whether to use uv to install packages instead of pip + use_uv = false, + ---@since 1.0.0 -- These args will be added to `pip install` calls. Note that setting extra args might impact intended behavior -- and is not recommended. diff --git a/doc/mason.txt b/doc/mason.txt index e7a2d3bf6..4fa4b1b57 100644 --- a/doc/mason.txt +++ b/doc/mason.txt @@ -314,6 +314,10 @@ Example: -- Whether to upgrade pip to the latest version in the virtual environment before installing packages. upgrade_pip = false, + ---@since 1.8.0 + -- Whether to use uv to install packages instead of pip + use_uv = false, + ---@since 1.0.0 -- These args will be added to `pip install` calls. Note that setting extra args might impact intended behavior -- and is not recommended. diff --git a/lua/mason-core/installer/managers/pypi.lua b/lua/mason-core/installer/managers/pypi.lua index d596028e5..6c4734767 100644 --- a/lua/mason-core/installer/managers/pypi.lua +++ b/lua/mason-core/installer/managers/pypi.lua @@ -7,11 +7,16 @@ local log = require "mason-core.log" local path = require "mason-core.path" local platform = require "mason-core.platform" local semver = require "mason-core.semver" +local settings = require "mason.settings" local spawn = require "mason-core.spawn" local M = {} +local use_uv = settings.current.pip.use_uv local VENV_DIR = "venv" +if use_uv then + VENV_DIR = ".venv" +end local is_executable = _.compose(_.equals(1), vim.fn.executable) @@ -19,11 +24,19 @@ local is_executable = _.compose(_.equals(1), vim.fn.executable) ---@param candidates string[] local function resolve_python3(candidates) a.scheduler() + if use_uv then + candidates = { "uv" } + end local available_candidates = _.filter(is_executable, candidates) for __, candidate in ipairs(available_candidates) do ---@type string local version_output = spawn[candidate]({ "--version" }):map(_.prop "stdout"):get_or_else "" - local ok, version = pcall(semver.new, version_output:match "Python (3%.%d+.%d+)") + local ok, version + if use_uv then + ok, version = pcall(semver.new, version_output:match "uv (%d+.%d+.%d+)") + else + ok, version = pcall(semver.new, version_output:match "Python (3%.%d+.%d+)") + end if ok then return { executable = candidate, version = version } end @@ -70,9 +83,14 @@ local function create_venv() ) return Result.failure "Failed to find python3 installation." end - log.fmt_debug("Found python3 installation version=%s, executable=%s", target.version, target.executable) ctx.stdio_sink.stdout "Creating virtual environment…\n" - return ctx.spawn[target.executable] { "-m", "venv", VENV_DIR } + if use_uv then + log.fmt_debug("Found uv installation version=%s, executable=%s", target.version, target.executable) + return ctx.spawn[target.executable] { "venv", VENV_DIR } + else + log.fmt_debug("Found python3 installation version=%s, executable=%s", target.version, target.executable) + return ctx.spawn[target.executable] { "-m", "venv", VENV_DIR } + end end ---@param ctx InstallContext @@ -107,15 +125,28 @@ end ---@param pkgs string[] ---@param extra_args? string[] local function pip_install(pkgs, extra_args) - return venv_python { - "-m", - "pip", - "--disable-pip-version-check", - "install", - "-U", - extra_args or vim.NIL, - pkgs, - } + if use_uv then + local ctx = installer.context() + local task = ctx.spawn["uv"] { + "pip", + "install", + "-U", + extra_args or vim.NIL, + pkgs, + } + -- vim.api.nvim_set_current_dir(curdir) + return task + else + return venv_python { + "-m", + "pip", + "--disable-pip-version-check", + "install", + "-U", + extra_args or vim.NIL, + pkgs, + } + end end ---@async @@ -129,7 +160,7 @@ function M.init(opts) ctx:promote_cwd() try(create_venv()) - if opts.upgrade_pip then + if opts.upgrade_pip and not use_uv then ctx.stdio_sink.stdout "Upgrading pip inside the virtual environment…\n" try(pip_install({ "pip" }, opts.install_extra_args)) end diff --git a/lua/mason-core/installer/registry/providers/pypi.lua b/lua/mason-core/installer/registry/providers/pypi.lua index c162c1201..afd7165c5 100644 --- a/lua/mason-core/installer/registry/providers/pypi.lua +++ b/lua/mason-core/installer/registry/providers/pypi.lua @@ -27,6 +27,7 @@ function M.parse(source, purl) pip = { upgrade = settings.current.pip.upgrade_pip, extra_args = settings.current.pip.install_args, + use_uv = settings.current.pip.use_uv, }, } @@ -44,11 +45,13 @@ function M.install(ctx, source) try(pypi.init { upgrade_pip = source.pip.upgrade, install_extra_args = source.pip.extra_args, + use_uv = source.pip.use_uv, }) try(pypi.install(source.package, source.version, { extra = source.extra, extra_packages = source.extra_packages, install_extra_args = source.pip.extra_args, + use_uv = source.pip.use_uv, })) end) end diff --git a/lua/mason/settings.lua b/lua/mason/settings.lua index 56fbcfb9f..8eb680378 100644 --- a/lua/mason/settings.lua +++ b/lua/mason/settings.lua @@ -60,6 +60,10 @@ local DEFAULT_SETTINGS = { -- Whether to upgrade pip to the latest version in the virtual environment before installing packages. upgrade_pip = false, + ---@since 1.8.0 + -- Whether to use uv to install packages instead of pip + use_uv = false, + ---@since 1.0.0 -- These args will be added to `pip install` calls. Note that setting extra args might impact intended behavior -- and is not recommended. diff --git a/tests/mason-core/installer/registry/providers/pypi_spec.lua b/tests/mason-core/installer/registry/providers/pypi_spec.lua index 5ba9609b3..615f5b2e4 100644 --- a/tests/mason-core/installer/registry/providers/pypi_spec.lua +++ b/tests/mason-core/installer/registry/providers/pypi_spec.lua @@ -31,6 +31,7 @@ describe("pypi provider :: parsing", function() pip = { upgrade = true, extra_args = { "--proxy", "http://localghost" }, + use_uv = false, }, }, pypi.parse({ extra_packages = { "extra" } }, purl())