diff options
Diffstat (limited to 'lua/nvim-lsp-installer/installers')
| -rw-r--r-- | lua/nvim-lsp-installer/installers/cargo.lua | 69 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/composer.lua | 90 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/context.lua | 285 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/dotnet.lua | 58 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/gem.lua | 65 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/go.lua | 54 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/init.lua | 186 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/npm.lua | 131 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/opam.lua | 60 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/pip3.lua | 91 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/shell.lua | 117 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/std.lua | 344 |
12 files changed, 0 insertions, 1550 deletions
diff --git a/lua/nvim-lsp-installer/installers/cargo.lua b/lua/nvim-lsp-installer/installers/cargo.lua deleted file mode 100644 index 0413b637..00000000 --- a/lua/nvim-lsp-installer/installers/cargo.lua +++ /dev/null @@ -1,69 +0,0 @@ -require "nvim-lsp-installer.notify"( - ( - "%s has been deprecated. See https://github.com/williamboman/nvim-lsp-installer/wiki/Async-infrastructure-changes-notice" - ):format "nvim-lsp-installer.installers.cargo", - vim.log.levels.WARN -) - -local process = require "nvim-lsp-installer.process" -local path = require "nvim-lsp-installer.path" - -local M = {} - ----@param crate string The crate to install. ----@param opts {git:boolean, features:string|nil} -function M.crate(crate, opts) - ---@type ServerInstallerFunction - return function(_, callback, ctx) - opts = opts or {} - local args = { "install", "--root", ".", "--locked" } - - if ctx.requested_server_version then - vim.list_extend(args, { "--version", ctx.requested_server_version }) - end - - if opts.features then - vim.list_extend(args, { "--features", opts.features }) - end - - if opts.git then - vim.list_extend(args, { "--git", crate }) - else - vim.list_extend(args, { crate }) - end - - ctx.receipt:with_primary_source(ctx.receipt.cargo(crate)) - - process.spawn("cargo", { - args = args, - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - }, callback) - end -end - ----@param opts {path:string|nil} -function M.install(opts) - ---@type ServerInstallerFunction - return function(_, callback, ctx) - opts = opts or {} - local args = { "install", "--root", "." } - if opts.path then - vim.list_extend(args, { "--path", opts.path }) - end - process.spawn("cargo", { - args = args, - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - }, callback) - end -end - ----@param root_dir string The directory to resolve the executable from. -function M.env(root_dir) - return { - PATH = process.extend_path { path.concat { root_dir, "bin" } }, - } -end - -return M diff --git a/lua/nvim-lsp-installer/installers/composer.lua b/lua/nvim-lsp-installer/installers/composer.lua deleted file mode 100644 index 6d60e0b1..00000000 --- a/lua/nvim-lsp-installer/installers/composer.lua +++ /dev/null @@ -1,90 +0,0 @@ -require "nvim-lsp-installer.notify"( - ( - "%s has been deprecated. See https://github.com/williamboman/nvim-lsp-installer/wiki/Async-infrastructure-changes-notice" - ):format "nvim-lsp-installer.installers.composer", - vim.log.levels.WARN -) - -local installers = require "nvim-lsp-installer.installers" -local std = require "nvim-lsp-installer.installers.std" -local platform = require "nvim-lsp-installer.platform" -local process = require "nvim-lsp-installer.process" -local fs = require "nvim-lsp-installer.fs" -local path = require "nvim-lsp-installer.path" -local Data = require "nvim-lsp-installer.data" - -local list_copy = Data.list_copy - -local M = {} - -M.composer_cmd = platform.is_win and "composer.bat" or "composer" - ----@param installer ServerInstallerFunction -local function ensure_composer(installer) - return installers.pipe { - std.ensure_executables { - { "php", "php was not found in path. Refer to https://www.php.net/." }, - { M.composer_cmd, "composer was not found in path. Refer to https://getcomposer.org/download/." }, - }, - installer, - } -end - ----@param packages string[] The composer packages to install. The first item in this list will be the recipient of the server version, should the user request a specific one. -function M.require(packages) - return ensure_composer( - ---@type ServerInstallerFunction - function(_, callback, ctx) - local pkgs = list_copy(packages) - local c = process.chain { - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - } - - ctx.receipt:with_primary_source(ctx.receipt.composer(pkgs[1])) - for i = 2, #pkgs do - ctx.receipt:with_secondary_source(ctx.receipt.composer(pkgs[i])) - end - - if not (fs.file_exists(path.concat { ctx.install_dir, "composer.json" })) then - c.run(M.composer_cmd, { "init", "--no-interaction", "--stability=stable" }) - end - - if ctx.requested_server_version then - -- The "head" package is the recipient for the requested version. It's.. by design... don't ask. - pkgs[1] = ("%s:%s"):format(pkgs[1], ctx.requested_server_version) - end - - c.run(M.composer_cmd, vim.list_extend({ "require" }, pkgs)) - c.spawn(callback) - end - ) -end - -function M.install() - return ensure_composer( - ---@type ServerInstallerFunction - function(_, callback, ctx) - process.spawn(M.composer_cmd, { - args = { - "install", - "--no-interaction", - "--no-dev", - "--optimize-autoloader", - "--classmap-authoritative", - }, - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - }, callback) - end - ) -end - ----@param root_dir string The directory to resolve the executable from. -function M.env(root_dir) - return { - PATH = process.extend_path { path.concat { root_dir, "vendor", "bin" } }, - } -end - -return M diff --git a/lua/nvim-lsp-installer/installers/context.lua b/lua/nvim-lsp-installer/installers/context.lua deleted file mode 100644 index 14789959..00000000 --- a/lua/nvim-lsp-installer/installers/context.lua +++ /dev/null @@ -1,285 +0,0 @@ -require "nvim-lsp-installer.notify"( - ( - "%s has been deprecated. See https://github.com/williamboman/nvim-lsp-installer/wiki/Async-infrastructure-changes-notice" - ):format "nvim-lsp-installer.installers.context", - vim.log.levels.WARN -) - -local a = require "nvim-lsp-installer.core.async" -local log = require "nvim-lsp-installer.log" -local process = require "nvim-lsp-installer.process" -local installers = require "nvim-lsp-installer.installers" -local platform = require "nvim-lsp-installer.platform" -local fs = require "nvim-lsp-installer.fs" -local path = require "nvim-lsp-installer.path" -local github_client = require "nvim-lsp-installer.core.managers.github.client" - -local M = {} - ----@param repo string @The GitHub repo ("username/repo"). -function M.use_github_latest_tag(repo) - ---@type ServerInstallerFunction - return function(_, callback, context) - context.github_repo = repo - if context.requested_server_version then - log.fmt_debug( - "Requested server version already provided (%s), skipping fetching tags from GitHub.", - context.requested_server_version - ) - -- User has already provided a version - don't fetch the tags from GitHub - return callback(true) - end - context.stdio_sink.stdout "Fetching tags from GitHub API...\n" - a.run(github_client.fetch_latest_tag, function(success, result) - if not success then - context.stdio_sink.stderr(tostring(result) .. "\n") - return callback(false) - end - result - :on_success(function(latest_tag) - context.requested_server_version = latest_tag.name - callback(true) - end) - :on_failure(function(failure) - context.stdio_sink.stderr(tostring(failure) .. "\n") - callback(false) - end) - end, repo) - end -end - ----@param repo string @The GitHub repo ("username/repo"). ----@param opts FetchLatestGithubReleaseOpts|nil -function M.use_github_release(repo, opts) - opts = opts or {} - ---@type ServerInstallerFunction - return function(_, callback, context) - context.github_repo = repo - if context.requested_server_version then - log.fmt_debug( - "Requested server version already provided (%s), skipping fetching latest release from GitHub.", - context.requested_server_version - ) - -- User has already provided a version - don't fetch the latest version from GitHub - return callback(true) - end - context.stdio_sink.stdout "Fetching latest release version from GitHub API...\n" - a.run(github_client.fetch_latest_release, function(success, result) - if not success then - context.stdio_sink.stderr(tostring(result) .. "\n") - return callback(false) - end - result - :on_success(function(latest_release) - context.requested_server_version = latest_release.tag_name - callback(true) - end) - :on_failure(function(failure) - context.stdio_sink.stderr(tostring(failure) .. "\n") - callback(false) - end) - end, repo, opts) - end -end - ----@param repo string @The GitHub report ("username/repo"). ----@param file string|fun(resolved_version: string): string @The name of a file available in the provided repo's GitHub releases. ----@param opts FetchLatestGithubReleaseOpts -function M.use_github_release_file(repo, file, opts) - return installers.pipe { - M.use_github_release(repo, opts), - function(server, callback, context) - local function get_download_url(version) - local target_file - if type(file) == "function" then - target_file = file(version) - else - target_file = file - end - if not target_file then - log.fmt_error( - "Unable to find which release file to download. server_name=%s, repo=%s", - server.name, - repo - ) - context.stdio_sink.stderr( - ( - "Could not find which release file to download. Most likely the current operating system, architecture (%s), or libc (%s) is not supported.\n" - ):format(platform.arch, platform.get_libc()) - ) - return nil - end - - return ("https://github.com/%s/releases/download/%s/%s"):format(repo, version, target_file) - end - - local download_url = get_download_url(context.requested_server_version) - if not download_url then - return callback(false) - end - context.github_release_file = download_url - callback(true) - end, - } -end - ----Creates an installer that moves the current installation directory to the server's root directory. -function M.promote_install_dir() - ---@type ServerInstallerFunction - return vim.schedule_wrap(function(server, callback, context) - if server:promote_install_dir(context.install_dir) then - context.install_dir = server.root_dir - callback(true) - else - context.stdio_sink.stderr( - ("Failed to promote temporary install directory to %s.\n"):format(server.root_dir) - ) - callback(false) - end - end) -end - ----Access the context ojbect to create a new installer. ----@param fn fun(context: ServerInstallContext): ServerInstallerFunction -function M.capture(fn) - ---@type ServerInstallerFunction - return function(server, callback, context) - local installer = fn(context) - installer(server, callback, context) - end -end - ----@param fn fun(receipt_builder: InstallReceiptBuilder, ctx: ServerInstallContext) -function M.receipt(fn) - return M.capture(function(ctx) - fn(ctx.receipt, ctx) - return installers.noop - end) -end - ----Update the context object. ----@param fn fun(context: ServerInstallContext): ServerInstallerFunction -function M.set(fn) - ---@type ServerInstallerFunction - return function(_, callback, context) - fn(context) - callback(true) - end -end - ----@param rel_path string @The relative path from the current installation working directory. -function M.set_working_dir(rel_path) - ---@type ServerInstallerFunction - return vim.schedule_wrap(function(server, callback, context) - local new_dir = path.concat { context.install_dir, rel_path } - log.fmt_debug( - "Changing installation working directory for %s from %s to %s", - server.name, - context.install_dir, - new_dir - ) - if not fs.dir_exists(new_dir) then - local ok = pcall(fs.mkdirp, new_dir) - if not ok then - context.stdio_sink.stderr(("Failed to create directory %s.\n"):format(new_dir)) - return callback(false) - end - end - context.install_dir = new_dir - callback(true) - end) -end - -function M.use_os_distribution() - ---Parses the provided contents of an /etc/\*-release file and identifies the Linux distribution. - ---@param contents string @The contents of a /etc/\*-release file. - ---@return table<string, any> - local function parse_linux_dist(contents) - local lines = vim.split(contents, "\n") - - local entries = {} - - for i = 1, #lines do - local line = lines[i] - local index = line:find "=" - if index then - local key = line:sub(1, index - 1) - local value = line:sub(index + 1) - entries[key] = value - end - end - - if entries.ID == "ubuntu" then - -- Parses the Ubuntu OS VERSION_ID into their version components, e.g. "18.04" -> {major=18, minor=04} - local version_id = entries.VERSION_ID:gsub([["]], "") - local version_parts = vim.split(version_id, "%.") - local major = tonumber(version_parts[1]) - local minor = tonumber(version_parts[2]) - - return { - id = "ubuntu", - version_id = version_id, - version = { major = major, minor = minor }, - } - else - return { - id = "linux-generic", - } - end - end - - return installers.when { - ---@type ServerInstallerFunction - linux = function(_, callback, ctx) - local stdio = process.in_memory_sink() - process.spawn("bash", { - args = { "-c", "cat /etc/*-release" }, - stdio_sink = stdio.sink, - }, function(success) - if success then - ctx.os_distribution = parse_linux_dist(table.concat(stdio.buffers.stdout, "")) - callback(true) - else - ctx.os_distribution = { - id = "linux-generic", - } - callback(true) - end - end) - end, - mac = function(_, callback, ctx) - ctx.os_distribution = { - id = "macOS", - } - callback(true) - end, - win = function(_, callback, ctx) - ctx.os_distribution = { - id = "windows", - } - callback(true) - end, - } -end - -function M.use_homebrew_prefix() - return installers.on { - mac = function(_, callback, ctx) - local stdio = process.in_memory_sink() - process.spawn("brew", { - args = { "--prefix" }, - stdio_sink = stdio.sink, - }, function(success) - if success then - ctx.homebrew_prefix = vim.trim(table.concat(stdio.buffers.stdout, "")) - callback(true) - else - ctx.stdio_sink.stderr "Failed to locate Homebrew installation.\n" - callback(false) - end - end) - end, - } -end - -return M diff --git a/lua/nvim-lsp-installer/installers/dotnet.lua b/lua/nvim-lsp-installer/installers/dotnet.lua deleted file mode 100644 index 2c09aed4..00000000 --- a/lua/nvim-lsp-installer/installers/dotnet.lua +++ /dev/null @@ -1,58 +0,0 @@ -require "nvim-lsp-installer.notify"( - ( - "%s has been deprecated. See https://github.com/williamboman/nvim-lsp-installer/wiki/Async-infrastructure-changes-notice" - ):format "nvim-lsp-installer.installers.dotnet", - vim.log.levels.WARN -) - -local installers = require "nvim-lsp-installer.installers" -local std = require "nvim-lsp-installer.installers.std" -local process = require "nvim-lsp-installer.process" - -local M = {} - ----@param installer ServerInstallerFunction -local function ensure_dotnet(installer) - return installers.pipe { - std.ensure_executables { - { - "dotnet", - "dotnet was not found in path. Refer to https://dotnet.microsoft.com/download for installation instructions.", - }, - }, - installer, - } -end - ----@param package string -function M.package(package) - return ensure_dotnet( - ---@type ServerInstallerFunction - function(_, callback, ctx) - local args = { - "tool", - "update", - "--tool-path", - ".", - } - if ctx.requested_server_version then - vim.list_extend(args, { "--version", ctx.requested_server_version }) - end - vim.list_extend(args, { package }) - process.spawn("dotnet", { - args = args, - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - }, callback) - ctx.receipt:with_primary_source(ctx.receipt.dotnet(package)) - end - ) -end - -function M.env(root_dir) - return { - PATH = process.extend_path { root_dir }, - } -end - -return M diff --git a/lua/nvim-lsp-installer/installers/gem.lua b/lua/nvim-lsp-installer/installers/gem.lua deleted file mode 100644 index c8d03298..00000000 --- a/lua/nvim-lsp-installer/installers/gem.lua +++ /dev/null @@ -1,65 +0,0 @@ -require "nvim-lsp-installer.notify"( - ( - "%s has been deprecated. See https://github.com/williamboman/nvim-lsp-installer/wiki/Async-infrastructure-changes-notice" - ):format "nvim-lsp-installer.installers.gem", - vim.log.levels.WARN -) - -local path = require "nvim-lsp-installer.path" -local Data = require "nvim-lsp-installer.data" -local process = require "nvim-lsp-installer.process" -local installers = require "nvim-lsp-installer.installers" -local std = require "nvim-lsp-installer.installers.std" -local platform = require "nvim-lsp-installer.platform" - -local M = {} - -M.gem_cmd = platform.is_win and "gem.cmd" or "gem" - ----@param packages string[] @The Gem packages to install. The first item in this list will be the recipient of the server version, should the user request a specific one. -function M.packages(packages) - return installers.pipe { - std.ensure_executables { - { "ruby", "ruby was not found in path, refer to https://wiki.openstack.org/wiki/RubyGems." }, - { "gem", "gem was not found in path, refer to https://wiki.openstack.org/wiki/RubyGems." }, - }, - ---@type ServerInstallerFunction - function(_, callback, ctx) - local pkgs = Data.list_copy(packages or {}) - - ctx.receipt:with_primary_source(ctx.receipt.gem(pkgs[1])) - for i = 2, #pkgs do - ctx.receipt:with_secondary_source(ctx.receipt.gem(pkgs[i])) - end - - if ctx.requested_server_version then - -- The "head" package is the recipient for the requested version. It's.. by design... don't ask. - pkgs[1] = ("%s:%s"):format(pkgs[1], ctx.requested_server_version) - end - - process.spawn(M.gem_cmd, { - args = { - "install", - "--no-user-install", - "--install-dir=.", - "--bindir=bin", - "--no-document", - table.concat(pkgs, " "), - }, - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - }, callback) - end, - } -end - ----@param root_dir string -function M.env(root_dir) - return { - GEM_HOME = root_dir, - GEM_PATH = root_dir, - PATH = process.extend_path { path.concat { root_dir, "bin" } }, - } -end - -return M diff --git a/lua/nvim-lsp-installer/installers/go.lua b/lua/nvim-lsp-installer/installers/go.lua deleted file mode 100644 index 89d09f5f..00000000 --- a/lua/nvim-lsp-installer/installers/go.lua +++ /dev/null @@ -1,54 +0,0 @@ -require "nvim-lsp-installer.notify"( - ( - "%s has been deprecated. See https://github.com/williamboman/nvim-lsp-installer/wiki/Async-infrastructure-changes-notice" - ):format "nvim-lsp-installer.installers.go", - vim.log.levels.WARN -) - -local std = require "nvim-lsp-installer.installers.std" -local installers = require "nvim-lsp-installer.installers" -local process = require "nvim-lsp-installer.process" - -local M = {} - ----@param packages string[] The Go packages to install. The first item in this list will be the recipient of the server version, should the user request a specific one. -function M.packages(packages) - return installers.pipe { - std.ensure_executables { { "go", "go was not found in path, refer to https://golang.org/doc/install." } }, - ---@type ServerInstallerFunction - function(_, callback, ctx) - local c = process.chain { - env = process.graft_env { - GOBIN = ctx.install_dir, - }, - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - } - - -- Install the head package - do - local head_package = packages[1] - ctx.receipt:with_primary_source(ctx.receipt.go(head_package)) - local version = ctx.requested_server_version or "latest" - c.run("go", { "install", "-v", ("%s@%s"):format(head_package, version) }) - end - - -- Install secondary packages - for i = 2, #packages do - local package = packages[i] - ctx.receipt:with_secondary_source(ctx.receipt.go(package)) - c.run("go", { "install", "-v", ("%s@latest"):format(package) }) - end - - c.spawn(callback) - end, - } -end - -function M.env(root_dir) - return { - PATH = process.extend_path { root_dir }, - } -end - -return M diff --git a/lua/nvim-lsp-installer/installers/init.lua b/lua/nvim-lsp-installer/installers/init.lua deleted file mode 100644 index cfe48faa..00000000 --- a/lua/nvim-lsp-installer/installers/init.lua +++ /dev/null @@ -1,186 +0,0 @@ -local platform = require "nvim-lsp-installer.platform" -local log = require "nvim-lsp-installer.log" -local Data = require "nvim-lsp-installer.data" - -local M = {} - ----@param installer ServerInstallerFunction[]|ServerInstallerFunction ----@return ServerInstallerFunction -local function normalize_installer(installer) - if type(installer) == "table" then - return M.pipe(installer) - else - return installer - end -end - ----@alias ServerInstallCallback fun(success: boolean) - ----@class ServerInstallContext ----@field receipt InstallReceiptBuilder ----@field requested_server_version string|nil @The version requested by the user. ----@field stdio_sink StdioSink ----@field github_release_file string|nil @Only available if context.use_github_release_file has been called. ----@field github_repo string|nil @Only available if context.use_github_release_file has been called. ----@field os_distribution table<string, any> @Only available if context.use_os_distribution has been called. ----@field homebrew_prefix string @Only available if context.use_homebrew_prefix has been called. ----@field install_dir string - ----@alias ServerInstallerFunction fun(server: Server, callback: ServerInstallCallback, context: ServerInstallContext) - ---- Composes multiple installer functions into one. ----@param installers ServerInstallerFunction[] ----@return ServerInstallerFunction -function M.pipe(installers) - if #installers == 0 then - error "No installers to pipe." - end - - return function(server, callback, context) - local function execute(idx) - local ok, err = pcall( - installers[idx], - server, - vim.schedule_wrap(function(success) - if not success then - -- oh no, error. exit early - callback(success) - elseif installers[idx + 1] then - -- iterate - execute(idx + 1) - else - -- we done - callback(success) - end - end), - context - ) - if not ok then - context.stdio_sink.stderr(tostring(err) .. "\n") - callback(false) - end - end - - execute(1) - end -end - ---- Composes multiple installer function into one - in reversed order. ----@param installers ServerInstallerFunction[] -function M.compose(installers) - return M.pipe(Data.list_reverse(installers)) -end - ----@param installers ServerInstallerFunction[] ----@return ServerInstallerFunction @An installer function that will serially execute the provided installers, until the first one succeeds. -function M.first_successful(installers) - if #installers == 0 then - error "No installers to pipe." - end - - return function(server, callback, context) - local function execute(idx) - log.fmt_trace("Executing installer idx=%d", idx) - local ok, err = pcall(installers[idx], server, function(success) - log.fmt_trace("Installer idx=%d on exit with success=%s", idx, success) - if not success and installers[idx + 1] then - -- iterate - execute(idx + 1) - else - callback(success) - end - end, context) - if not ok then - context.stdio_sink.stderr(tostring(err) .. "\n") - if installers[idx + 1] then - execute(idx + 1) - else - callback(false) - end - end - end - - execute(1) - end -end - ---- Wraps the provided server installer to always succeeds. ----@param installer ServerInstallerFunction ----@return ServerInstallerFunction -function M.always_succeed(installer) - return function(server, callback, context) - installer(server, function() - callback(true) - end, context) - end -end - ----@param platform_table table<Platform, ServerInstallerFunction> ----@return ServerInstallerFunction | ServerInstallerFunction[] | nil -local function get_by_platform(platform_table) - if platform.is_mac then - return platform_table.mac or platform_table.unix - elseif platform.is_linux then - return platform_table.linux or platform_table.unix - elseif platform.is_unix then - return platform_table.unix - elseif platform.is_win then - return platform_table.win - else - return nil - end -end - ---- Creates a server installer that executes the given installer for the current platform. ---- If there is no server installer provided for the current platform, the installer will instantly exit successfully. ----@param platform_table table<Platform, ServerInstallerFunction> ----@return ServerInstallerFunction -function M.on(platform_table) - return function(server, callback, context) - local installer = get_by_platform(platform_table) - if installer then - normalize_installer(installer)(server, callback, context) - else - callback(true) - end - end -end - ---- Creates a server installer that executes the given installer for the current platform. ---- If there is no server installer provided for the current platform, the installer will instantly exit with a failure. ----@param platform_table table<Platform, ServerInstallerFunction|ServerInstallerFunction[]> ----@return ServerInstallerFunction -function M.when(platform_table) - return function(server, callback, context) - local installer = get_by_platform(platform_table) - if installer then - normalize_installer(installer)(server, callback, context) - else - context.stdio_sink.stderr( - ("Current operating system is not yet supported for server %q.\n"):format(server.name) - ) - callback(false) - end - end -end - ----@param installer ServerInstallerFunction|ServerInstallerFunction[] @The installer to execute in a new installer context. -function M.branch_context(installer) - ---@type ServerInstallerFunction - return function(server, callback, ctx) - local receipt = ctx.receipt - -- This temporary nil assignment is done to avoid deepcopy traversing the receipt builder unnecessarily - ctx.receipt = nil - local new_context = vim.deepcopy(ctx) - ctx.receipt = receipt - new_context.receipt = receipt - normalize_installer(installer)(server, callback, new_context) - end -end - ----@type ServerInstallerFunction -function M.noop(_, callback) - callback(true) -end - -return M diff --git a/lua/nvim-lsp-installer/installers/npm.lua b/lua/nvim-lsp-installer/installers/npm.lua deleted file mode 100644 index e436b0be..00000000 --- a/lua/nvim-lsp-installer/installers/npm.lua +++ /dev/null @@ -1,131 +0,0 @@ -require "nvim-lsp-installer.notify"( - ( - "%s has been deprecated. See https://github.com/williamboman/nvim-lsp-installer/wiki/Async-infrastructure-changes-notice" - ):format "nvim-lsp-installer.installers.npm", - vim.log.levels.WARN -) - -local path = require "nvim-lsp-installer.path" -local fs = require "nvim-lsp-installer.fs" -local Data = require "nvim-lsp-installer.data" -local installers = require "nvim-lsp-installer.installers" -local std = require "nvim-lsp-installer.installers.std" -local platform = require "nvim-lsp-installer.platform" -local process = require "nvim-lsp-installer.process" - -local list_copy = Data.list_copy - -local M = {} - -M.npm_command = platform.is_win and "npm.cmd" or "npm" - ----@param installer ServerInstallerFunction -local function ensure_npm(installer) - return installers.pipe { - std.ensure_executables { - { "node", "node was not found in path. Refer to https://nodejs.org/en/." }, - { - "npm", - "npm was not found in path. Refer to https://docs.npmjs.com/downloading-and-installing-node-js-and-npm.", - }, - }, - installer, - } -end - ----@param standalone boolean @If true, will run `npm install` as a standalone command, with no consideration to the surrounding installer context (i.e. the requested version in context is ignored, global-style is not applied). -local function create_installer(standalone) - ---@param packages string[] - return function(packages) - return ensure_npm( - ---@type ServerInstallerFunction - function(_, callback, ctx) - local pkgs = list_copy(packages or {}) - local c = process.chain { - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - } - - if not standalone then - -- Use global-style. The reasons for this are: - -- a) To avoid polluting the executables (aka bin-links) that npm creates. - -- b) The installation is, after all, more similar to a "global" installation. We don't really gain - -- any of the benefits of not using global style (e.g., deduping the dependency tree). - -- - -- We write to .npmrc manually instead of going through npm because managing a local .npmrc file - -- is a bit unreliable across npm versions (especially <7), so we take extra measures to avoid - -- inadvertently polluting global npm config. - fs.append_file(path.concat { ctx.install_dir, ".npmrc" }, "global-style=true") - - ctx.receipt:with_primary_source(ctx.receipt.npm(pkgs[1])) - for i = 2, #pkgs do - ctx.receipt:with_secondary_source(ctx.receipt.npm(pkgs[i])) - end - end - - -- stylua: ignore start - if not (fs.dir_exists(path.concat { ctx.install_dir, "node_modules" }) or - fs.file_exists(path.concat { ctx.install_dir, "package.json" })) - then - -- Create a package.json to set a boundary for where npm installs packages. - c.run(M.npm_command, { "init", "--yes", "--scope=lsp-installer" }) - end - - if not standalone and ctx.requested_server_version and #pkgs > 0 then - -- The "head" package is the recipient for the requested version. It's.. by design... don't ask. - pkgs[1] = ("%s@%s"):format(pkgs[1], ctx.requested_server_version) - end - - -- stylua: ignore end - c.run(M.npm_command, vim.list_extend({ "install" }, pkgs)) - c.spawn(callback) - end - ) - end -end - ----Creates an installer that installs the provided packages. Will respect user's requested version. -M.packages = create_installer(false) - ----Creates an installer that installs the provided packages. Will NOT respect user's requested version. ----This is useful in situation where there's a need to install an auxiliary npm package. -M.install = create_installer(true) - ----Creates a server installer that executes the given locally installed npm executable. ----@param executable string ----@param args string[] -function M.exec(executable, args) - ---@type ServerInstallerFunction - return function(_, callback, ctx) - process.spawn(executable, { - args = args, - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - env = process.graft_env(M.env(ctx.install_dir)), - }, callback) - end -end - ----Creates a server installer that runs the given script. ----@param script string @The npm script to run (npm run). -function M.run(script) - return ensure_npm( - ---@type ServerInstallerFunction - function(_, callback, ctx) - process.spawn(M.npm_command, { - args = { "run", script }, - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - }, callback) - end - ) -end - ----@param root_dir string @The directory to resolve the executable from. -function M.env(root_dir) - return { - PATH = process.extend_path { path.concat { root_dir, "node_modules", ".bin" } }, - } -end - -return M diff --git a/lua/nvim-lsp-installer/installers/opam.lua b/lua/nvim-lsp-installer/installers/opam.lua deleted file mode 100644 index 349810ce..00000000 --- a/lua/nvim-lsp-installer/installers/opam.lua +++ /dev/null @@ -1,60 +0,0 @@ -require "nvim-lsp-installer.notify"( - ( - "%s has been deprecated. See https://github.com/williamboman/nvim-lsp-installer/wiki/Async-infrastructure-changes-notice" - ):format "nvim-lsp-installer.installers.opam", - vim.log.levels.WARN -) - -local std = require "nvim-lsp-installer.installers.std" -local installers = require "nvim-lsp-installer.installers" -local process = require "nvim-lsp-installer.process" -local path = require "nvim-lsp-installer.path" -local Data = require "nvim-lsp-installer.data" - -local list_copy = Data.list_copy - -local M = {} - ----@param packages string[] The OPAM packages to install. The first item in this list will be the recipient of the server version, should the user request a specific one. -function M.packages(packages) - return installers.pipe { - std.ensure_executables { - { "opam", "opam was not found in path, refer to https://opam.ocaml.org/doc/Install.html" }, - }, - ---@type ServerInstallerFunction - function(_, callback, ctx) - local pkgs = list_copy(packages) - - ctx.receipt:with_primary_source(ctx.receipt.opam(pkgs[1])) - for i = 2, #pkgs do - ctx.receipt:with_secondary_source(ctx.receipt.opam(pkgs[i])) - end - - if ctx.requested_server_version then - pkgs[1] = ("%s.%s"):format(pkgs[1], ctx.requested_server_version) - end - - local install_args = { - "install", - ("--destdir=%s"):format(ctx.install_dir), - "--yes", - "--verbose", - } - vim.list_extend(install_args, pkgs) - - process.spawn("opam", { - args = install_args, - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - }, callback) - end, - } -end - -function M.env(root_dir) - return { - PATH = process.extend_path { path.concat { root_dir, "bin" } }, - } -end - -return M diff --git a/lua/nvim-lsp-installer/installers/pip3.lua b/lua/nvim-lsp-installer/installers/pip3.lua deleted file mode 100644 index a7c8b13c..00000000 --- a/lua/nvim-lsp-installer/installers/pip3.lua +++ /dev/null @@ -1,91 +0,0 @@ -require "nvim-lsp-installer.notify"( - ( - "%s has been deprecated. See https://github.com/williamboman/nvim-lsp-installer/wiki/Async-infrastructure-changes-notice" - ):format "nvim-lsp-installer.installers.pip3", - vim.log.levels.WARN -) - -local path = require "nvim-lsp-installer.path" -local Data = require "nvim-lsp-installer.data" -local installers = require "nvim-lsp-installer.installers" -local std = require "nvim-lsp-installer.installers.std" -local platform = require "nvim-lsp-installer.platform" -local process = require "nvim-lsp-installer.process" -local settings = require "nvim-lsp-installer.settings" -local context = require "nvim-lsp-installer.installers.context" -local log = require "nvim-lsp-installer.log" - -local M = {} - -local REL_INSTALL_DIR = "venv" - ----@param python_executable string ----@param packages string[] -local function create_installer(python_executable, packages) - return installers.pipe { - std.ensure_executables { - { - python_executable, - ("%s was not found in path. Refer to https://www.python.org/downloads/."):format(python_executable), - }, - }, - ---@type ServerInstallerFunction - function(_, callback, ctx) - local pkgs = Data.list_copy(packages or {}) - local c = process.chain { - cwd = ctx.install_dir, - stdio_sink = ctx.stdio_sink, - env = process.graft_env(M.env(ctx.install_dir)), - } - - ctx.receipt:with_primary_source(ctx.receipt.pip3(pkgs[1])) - for i = 2, #pkgs do - ctx.receipt:with_secondary_source(ctx.receipt.pip3(pkgs[i])) - end - - c.run(python_executable, { "-m", "venv", REL_INSTALL_DIR }) - if ctx.requested_server_version then - -- The "head" package is the recipient for the requested version. It's.. by design... don't ask. - pkgs[1] = ("%s==%s"):format(pkgs[1], ctx.requested_server_version) - end - - local install_command = { "-m", "pip", "install", "-U" } - vim.list_extend(install_command, settings.current.pip.install_args) - c.run("python", vim.list_extend(install_command, pkgs)) - - c.spawn(callback) - end, - } -end - ----@param packages string[] @The pip packages to install. The first item in this list will be the recipient of the server version, should the user request a specific one. -function M.packages(packages) - local py3 = create_installer("python3", packages) - local py = create_installer("python", packages) - -- see https://github.com/williamboman/nvim-lsp-installer/issues/128 - local installer_variants = platform.is_win and { py, py3 } or { py3, py } - - local py3_host_prog = vim.g.python3_host_prog - if py3_host_prog then - log.fmt_trace("Found python3_host_prog (%s)", py3_host_prog) - table.insert(installer_variants, 1, create_installer(py3_host_prog, packages)) - end - - return installers.pipe { - context.promote_install_dir(), - installers.first_successful(installer_variants), - } -end - ----@param root_dir string @The directory to resolve the executable from. -function M.env(root_dir) - return { - PATH = process.extend_path { M.path(root_dir) }, - } -end - -function M.path(root_dir) - return path.concat { root_dir, REL_INSTALL_DIR, platform.is_win and "Scripts" or "bin" } -end - -return M diff --git a/lua/nvim-lsp-installer/installers/shell.lua b/lua/nvim-lsp-installer/installers/shell.lua deleted file mode 100644 index 2cc8a845..00000000 --- a/lua/nvim-lsp-installer/installers/shell.lua +++ /dev/null @@ -1,117 +0,0 @@ -require "nvim-lsp-installer.notify"( - ( - "%s has been deprecated. See https://github.com/williamboman/nvim-lsp-installer/wiki/Async-infrastructure-changes-notice" - ):format "nvim-lsp-installer.installers.shell", - vim.log.levels.WARN -) - -local installers = require "nvim-lsp-installer.installers" -local process = require "nvim-lsp-installer.process" - -local M = {} - ----@param opts {shell: string, cmd: string[], env: table|nil} -local function shell(opts) - ---@type ServerInstallerFunction - return function(_, callback, context) - local _, stdio = process.spawn(opts.shell, { - args = opts.args, - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - env = process.graft_env(opts.env or {}, { - "PSMODULEPATH", -- https://github.com/williamboman/nvim-lsp-installer/issues/271 - }), - }, callback) - - if stdio and opts.cmd then - local stdin = stdio[1] - - stdin:write(opts.cmd) - stdin:write "\n" - stdin:close() - end - end -end - ----@param raw_script string @The bash script to execute as-is. ----@param opts {prefix: string, env: table} -function M.bash(raw_script, opts) - local default_opts = { - prefix = "set -euo pipefail;", - env = {}, - } - opts = vim.tbl_deep_extend("force", default_opts, opts or {}) - - return shell { - shell = "bash", - args = { "-c", (opts.prefix or "") .. raw_script }, - env = opts.env, - } -end - ----@param raw_script string @The sh script to execute as-is. ----@param opts {prefix: string, env: table} -function M.sh(raw_script, opts) - local default_opts = { - prefix = "set -eu;", - env = {}, - } - opts = vim.tbl_deep_extend("force", default_opts, opts or {}) - - return shell { - shell = "sh", - cmd = (opts.prefix or "") .. raw_script, - env = opts.env, - } -end - ----@param raw_script string @The cmd.exe script to execute as-is. ----@param opts {env: table} -function M.cmd(raw_script, opts) - local default_opts = { - env = {}, - } - opts = vim.tbl_deep_extend("force", default_opts, opts or {}) - - return shell { - shell = "cmd.exe", - args = { "/C", raw_script }, - env = opts.env, - } -end - ----@param raw_script string @The powershell script to execute as-is. ----@param opts {prefix: string, env: table} -function M.powershell(raw_script, opts) - local default_opts = { - env = {}, - -- YIKES https://stackoverflow.com/a/63301751 - prefix = [[ - $ProgressPreference = 'SilentlyContinue'; - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; - ]], - } - opts = vim.tbl_deep_extend("force", default_opts, opts or {}) - - return shell { - shell = "powershell.exe", - args = { "-NoProfile", "-Command", (opts.prefix or "") .. raw_script }, - env = opts.env, - } -end - ----@param raw_script string @A script that is compatible with bash and cmd.exe. ----@param opts {env: table} -function M.polyshell(raw_script, opts) - local default_opts = { - env = {}, - } - opts = vim.tbl_deep_extend("force", default_opts, opts or {}) - - return installers.when { - unix = M.bash(raw_script, { env = opts.env }), - win = M.cmd(raw_script, { env = opts.env }), - } -end - -return M diff --git a/lua/nvim-lsp-installer/installers/std.lua b/lua/nvim-lsp-installer/installers/std.lua deleted file mode 100644 index 9db1251c..00000000 --- a/lua/nvim-lsp-installer/installers/std.lua +++ /dev/null @@ -1,344 +0,0 @@ -require "nvim-lsp-installer.notify"( - ( - "%s has been deprecated. See https://github.com/williamboman/nvim-lsp-installer/wiki/Async-infrastructure-changes-notice" - ):format "nvim-lsp-installer.installers.std", - vim.log.levels.WARN -) - -local path = require "nvim-lsp-installer.path" -local fs = require "nvim-lsp-installer.fs" -local process = require "nvim-lsp-installer.process" -local platform = require "nvim-lsp-installer.platform" -local installers = require "nvim-lsp-installer.installers" -local shell = require "nvim-lsp-installer.installers.shell" -local Data = require "nvim-lsp-installer.data" - -local list_not_nil, when = Data.list_not_nil, Data.when - -local USER_AGENT = "nvim-lsp-installer (+https://github.com/williamboman/nvim-lsp-installer)" - -local M = {} - ----@param url string @The url to download. ----@param out_file string @The relative path to where to write the contents of the url. -function M.download_file(url, out_file) - return installers.when { - ---@type ServerInstallerFunction - unix = function(_, callback, context) - context.stdio_sink.stdout(("Downloading file %q...\n"):format(url)) - process.attempt { - jobs = { - process.lazy_spawn("wget", { - args = { "--header", ("User-Agent: %s"):format(USER_AGENT), "-nv", "-O", out_file, url }, - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }), - process.lazy_spawn("curl", { - args = { "-H", ("User-Agent: %s"):format(USER_AGENT), "-fsSL", "-o", out_file, url }, - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }), - }, - on_finish = callback, - } - end, - win = shell.powershell( - ("iwr -Headers @{'User-Agent' = '%s'} -UseBasicParsing -Uri %q -OutFile %q"):format( - USER_AGENT, - url, - out_file - ) - ), - } -end - ----@param file string @The relative path to the file to unzip. ----@param dest string|nil @The destination of the unzip. -function M.unzip(file, dest) - return installers.pipe { - installers.when { - ---@type ServerInstallerFunction - unix = function(_, callback, context) - process.spawn("unzip", { - args = { "-d", dest, file }, - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }, callback) - end, - win = shell.powershell( - ("Microsoft.PowerShell.Archive\\Expand-Archive -Path %q -DestinationPath %q"):format(file, dest) - ), - }, - installers.always_succeed(M.rmrf(file)), - } -end - ----@see unzip(). ----@param url string @The url of the .zip file. ----@param dest string|nil @The url of the .zip file. Defaults to ".". -function M.unzip_remote(url, dest) - return installers.pipe { - M.download_file(url, "archive.zip"), - M.unzip("archive.zip", dest or "."), - } -end - ----@param file string @The relative path to the tar file to extract. -function M.untar(file) - return installers.pipe { - ---@type ServerInstallerFunction - function(_, callback, context) - process.spawn("tar", { - args = { "-xvf", file }, - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }, callback) - end, - installers.always_succeed(M.rmrf(file)), - } -end - ----@param file string -local function win_extract(file) - return installers.pipe { - ---@type ServerInstallerFunction - function(_, callback, context) - -- The trademarked "throw shit until it sticks" technique - local sevenzip = process.lazy_spawn("7z", { - args = { "x", "-y", "-r", file }, - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }) - local peazip = process.lazy_spawn("peazip", { - args = { "-ext2here", path.concat { context.install_dir, file } }, -- peazip require absolute paths, or else! - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }) - local winzip = process.lazy_spawn("wzunzip", { - args = { file }, - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }) - local winrar = process.lazy_spawn("winrar", { - args = { "e", file }, - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }) - process.attempt { - jobs = { sevenzip, peazip, winzip, winrar }, - on_finish = callback, - } - end, - installers.always_succeed(M.rmrf(file)), - } -end - ----@param file string -local function win_untarxz(file) - return installers.pipe { - win_extract(file), - M.untar(file:gsub(".xz$", "")), - } -end - ----@param file string -local function win_arc_unarchive(file) - return installers.pipe { - ---@type ServerInstallerFunction - function(_, callback, context) - context.stdio_sink.stdout "Attempting to unarchive using arc." - process.spawn("arc", { - args = { "unarchive", file }, - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }, callback) - end, - installers.always_succeed(M.rmrf(file)), - } -end - ----@param url string @The url to the .tar.xz file to extract. -function M.untarxz_remote(url) - return installers.pipe { - M.download_file(url, "archive.tar.xz"), - installers.when { - unix = M.untar "archive.tar.xz", - win = installers.first_successful { - win_untarxz "archive.tar.xz", - win_arc_unarchive "archive.tar.xz", - }, - }, - } -end - ----@param url string @The url to the .tar.gz file to extract. -function M.untargz_remote(url) - return installers.pipe { - M.download_file(url, "archive.tar.gz"), - M.untar "archive.tar.gz", - } -end - ----@param file string @The relative path to the file to gunzip. -function M.gunzip(file) - return installers.when { - ---@type ServerInstallerFunction - unix = function(_, callback, context) - process.spawn("gzip", { - args = { "-d", file }, - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }, callback) - end, - win = win_extract(file), - } -end - ----@see gunzip() ----@param url string @The url to the .gz file to extract. ----@param out_file string|nil @The name of the extracted .gz file. -function M.gunzip_remote(url, out_file) - local archive = ("%s.gz"):format(out_file or "archive") - return installers.pipe { - M.download_file(url, archive), - M.gunzip(archive), - installers.always_succeed(M.rmrf(archive)), - } -end - ----Recursively deletes the provided path. Will fail on paths that are not inside the configured install_root_dir. ----@param rel_path string @The relative path to the file/directory to remove. -function M.rmrf(rel_path) - ---@type ServerInstallerFunction - return function(_, callback, context) - local abs_path = path.concat { context.install_dir, rel_path } - context.stdio_sink.stdout(("Deleting %q\n"):format(abs_path)) - vim.schedule(function() - local ok = pcall(fs.rmrf, abs_path) - if ok then - callback(true) - else - context.stdio_sink.stderr(("Failed to delete %q.\n"):format(abs_path)) - callback(false) - end - end) - end -end - ----@param rel_path string @The relative path to the file to write. ----@param contents string @The file contents. -function M.write_file(rel_path, contents) - ---@type ServerInstallerFunction - return function(_, callback, ctx) - local file = path.concat { ctx.install_dir, rel_path } - ctx.stdio_sink.stdout(("Writing file %q\n"):format(file)) - fs.write_file(file, contents) - callback(true) - end -end - ----Shallow git clone. ----@param repo_url string ----@param opts {directory: string, recursive: boolean} -function M.git_clone(repo_url, opts) - ---@type ServerInstallerFunction - return function(_, callback, context) - opts = vim.tbl_deep_extend("force", { - directory = ".", - recursive = false, - }, opts or {}) - - local c = process.chain { - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - } - - c.run( - "git", - list_not_nil( - "clone", - "--depth", - "1", - when(opts.recursive, "--recursive"), - when(opts.recursive, "--shallow-submodules"), - repo_url, - opts.directory - ) - ) - - if context.requested_server_version then - c.run("git", { "-C", opts.directory, "fetch", "--depth", "1", "origin", context.requested_server_version }) - c.run("git", { "-C", opts.directory, "checkout", "FETCH_HEAD" }) - end - - c.spawn(callback) - end -end - ----@param opts {args: string[]} -function M.gradlew(opts) - ---@type ServerInstallerFunction - return function(_, callback, context) - process.spawn(path.concat { context.install_dir, platform.is_win and "gradlew.bat" or "gradlew" }, { - args = opts.args, - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }, callback) - end -end - ----Creates an installer that ensures that the provided executables are available in the current runtime. ----@param executables string[][] @A list of (executable, error_msg) tuples. ----@return ServerInstallerFunction -function M.ensure_executables(executables) - return vim.schedule_wrap( - ---@type ServerInstallerFunction - function(_, callback, context) - local has_error = false - for i = 1, #executables do - local entry = executables[i] - local executable = entry[1] - local error_msg = entry[2] - if vim.fn.executable(executable) ~= 1 then - has_error = true - context.stdio_sink.stderr(error_msg .. "\n") - end - end - callback(not has_error) - end - ) -end - ----@path old_path string @The relative path to the file/dir to rename. ----@path new_path string @The relative path to what to rename the file/dir to. -function M.rename(old_path, new_path) - ---@type ServerInstallerFunction - return function(_, callback, context) - local ok = pcall( - fs.rename, - path.concat { context.install_dir, old_path }, - path.concat { context.install_dir, new_path } - ) - if not ok then - context.stdio_sink.stderr(("Failed to rename %q to %q.\n"):format(old_path, new_path)) - end - callback(ok) - end -end - ----@param flags string @The chmod flag to apply. ----@param files string[] @A list of relative paths to apply the chmod on. -function M.chmod(flags, files) - return installers.on { - ---@type ServerInstallerFunction - unix = function(_, callback, context) - process.spawn("chmod", { - args = vim.list_extend({ flags }, files), - cwd = context.install_dir, - stdio_sink = context.stdio_sink, - }, callback) - end, - } -end - -return M |
