diff options
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/nvim-lsp-installer/fs.lua | 2 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/init.lua | 44 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/std.lua | 103 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/process.lua | 84 |
4 files changed, 179 insertions, 54 deletions
diff --git a/lua/nvim-lsp-installer/fs.lua b/lua/nvim-lsp-installer/fs.lua index ab775f4d..e6864685 100644 --- a/lua/nvim-lsp-installer/fs.lua +++ b/lua/nvim-lsp-installer/fs.lua @@ -19,7 +19,7 @@ end function M.rename(path, new_path) assert_ownership(path) assert_ownership(new_path) - return uv.fs_rename(path, new_path) + uv.fs_rename(path, new_path) end function M.mkdirp(path) diff --git a/lua/nvim-lsp-installer/installers/init.lua b/lua/nvim-lsp-installer/installers/init.lua index 0dd48972..83b46a1b 100644 --- a/lua/nvim-lsp-installer/installers/init.lua +++ b/lua/nvim-lsp-installer/installers/init.lua @@ -1,4 +1,5 @@ local platform = require "nvim-lsp-installer.platform" +local log = require "nvim-lsp-installer.log" local Data = require "nvim-lsp-installer.data" local M = {} @@ -32,6 +33,37 @@ function M.pipe(installers) end end +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 + -- much fp, very wow function M.compose(installers) return M.pipe(Data.list_reverse(installers)) @@ -64,7 +96,11 @@ function M.on(platform_table) return function(server, callback, context) local installer = get_by_platform(platform_table) if installer then - installer(server, callback, context) + if type(installer) == "function" then + installer(server, callback, context) + else + M.pipe(installer)(server, callback, context) + end else callback(true) end @@ -76,7 +112,11 @@ function M.when(platform_table) return function(server, callback, context) local installer = get_by_platform(platform_table) if installer then - installer(server, callback, context) + if type(installer) == "function" then + installer(server, callback, context) + else + M.pipe(installer)(server, callback, context) + end else context.stdio_sink.stderr( ("Current operating system is not yet supported for server %q.\n"):format(server.name) diff --git a/lua/nvim-lsp-installer/installers/std.lua b/lua/nvim-lsp-installer/installers/std.lua index bdd60eca..c7728fe7 100644 --- a/lua/nvim-lsp-installer/installers/std.lua +++ b/lua/nvim-lsp-installer/installers/std.lua @@ -1,4 +1,5 @@ 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" @@ -52,15 +53,60 @@ function M.unzip_remote(url, dest) } end -function M.untar(file, opts) - local default_opts = { - strip_components = 0, - } - opts = vim.tbl_deep_extend("force", default_opts, opts or {}) +function M.untar(file) return installers.pipe { function(server, callback, context) process.spawn("tar", { - args = { "-xvf", file, "--strip-components", opts.strip_components }, + args = { "-xvf", file }, + cwd = server.root_dir, + stdio_sink = context.stdio_sink, + }, callback) + end, + installers.always_succeed(M.delete_file(file)), + } +end + +local function win_extract(file) + return installers.pipe { + function(server, callback, context) + -- The trademarked "throw shit until it sticks" technique + local sevenzip = process.lazy_spawn("7z", { + args = { "x", "-y", "-r", file }, + cwd = server.root_dir, + stdio_sink = context.stdio_sink, + }) + local peazip = process.lazy_spawn("peazip", { + args = { "-ext2here", path.concat { server.root_dir, file } }, -- peazip require absolute paths, or else! + cwd = server.root_dir, + stdio_sink = context.stdio_sink, + }) + local winzip = process.lazy_spawn("wzunzip", { + args = { file }, + cwd = server.root_dir, + stdio_sink = context.stdio_sink, + }) + process.attempt { + jobs = { sevenzip, peazip, winzip }, + on_finish = callback, + } + end, + installers.always_succeed(M.delete_file(file)), + } +end + +local function win_untarxz(file) + return installers.pipe { + win_extract(file), + M.untar(file:gsub(".xz$", "")), + } +end + +local function win_arc_unarchive(file) + return installers.pipe { + function(server, callback, context) + context.stdio_sink.stdout "Attempting to unarchive using arc." + process.spawn("arc", { + args = { "unarchive", file }, cwd = server.root_dir, stdio_sink = context.stdio_sink, }, callback) @@ -69,28 +115,37 @@ function M.untar(file, opts) } end -function M.untarxz_remote(url, tar_opts) +function M.untarxz_remote(url) return installers.pipe { M.download_file(url, "archive.tar.xz"), - M.untar("archive.tar.xz", tar_opts), + installers.when { + unix = M.untar "archive.tar.xz", + win = installers.first_successful { + win_untarxz "archive.tar.xz", + win_arc_unarchive "archive.tar.xz", + }, + }, } end -function M.untargz_remote(url, tar_opts) +function M.untargz_remote(url) return installers.pipe { M.download_file(url, "archive.tar.gz"), - M.untar("archive.tar.gz", tar_opts), + M.untar "archive.tar.gz", } end function M.gunzip(file) - return function(server, callback, context) - process.spawn("gzip", { - args = { "-d", file }, - cwd = server.root_dir, - stdio_sink = context.stdio_sink, - }, callback) - end + return installers.when { + unix = function(server, callback, context) + process.spawn("gzip", { + args = { "-d", file }, + cwd = server.root_dir, + stdio_sink = context.stdio_sink, + }, callback) + end, + win = win_extract(file), + } end function M.gunzip_remote(url, out_file) @@ -159,6 +214,20 @@ function M.ensure_executables(executables) end) end +function M.rename(old_path, new_path) + return function(server, callback, context) + local ok = pcall( + fs.rename, + path.concat { server.root_dir, old_path }, + path.concat { server.root_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 + function M.chmod(flags, files) return installers.on { unix = function(server, callback, context) diff --git a/lua/nvim-lsp-installer/process.lua b/lua/nvim-lsp-installer/process.lua index e7ede690..f81ba8cb 100644 --- a/lua/nvim-lsp-installer/process.lua +++ b/lua/nvim-lsp-installer/process.lua @@ -62,7 +62,7 @@ local function sanitize_env_list(env_list) sanitized_list[#sanitized_list + 1] = env else local idx = env:find "=" - sanitized_list[#sanitized_list + 1] = env:sub(1, idx) .. "=<redacted>" + sanitized_list[#sanitized_list + 1] = env:sub(1, idx) .. "<redacted>" end end return sanitized_list @@ -115,6 +115,8 @@ function M.spawn(cmd, opts, callback) check:stop() callback(successful) end) + + log.fmt_debug("Job pid=%s exited with exit_code=%s, signal=%s", pid_or_err, exit_code, signal) end) if handle == nil then @@ -137,29 +139,31 @@ function M.spawn(cmd, opts, callback) end function M.chain(opts) - local stack = {} + local jobs = {} return { run = function(cmd, args) - stack[#stack + 1] = { cmd = cmd, args = args } + jobs[#jobs + 1] = M.lazy_spawn( + cmd, + vim.tbl_deep_extend("force", opts, { + args = args, + }) + ) end, spawn = function(callback) local function execute(idx) - local item = stack[idx] - M.spawn( - item.cmd, - vim.tbl_deep_extend("force", opts, { - args = item.args, - }), - function(successful) - if successful and stack[idx + 1] then - -- iterate - execute(idx + 1) - else - -- we done - callback(successful) - end + local ok, err = pcall(jobs[idx], function(successful) + if successful and jobs[idx + 1] then + -- iterate + execute(idx + 1) + else + -- we done + callback(successful) end - ) + end) + if not ok then + log.fmt_error("Chained job failed to execute. Error=%s", tostring(err)) + callback(false) + end end execute(1) @@ -226,24 +230,36 @@ function M.attempt(opts) if #jobs == 0 then error "process.attempt(...) need at least one job." end - local function spawn(idx) - jobs[idx](function(success) - if success then - -- this job succeeded. exit early - on_finish(true) - elseif jobs[idx + 1] then - -- iterate - if on_iterate then - on_iterate() - end - log.debug "Previous job failed, attempting next." - spawn(idx + 1) - else - -- we exhausted all jobs without success - log.debug "All jobs failed." - on_finish(false) + + local spawn, on_job_exit + + on_job_exit = function(cur_idx, success) + if success then + -- this job succeeded. exit early + on_finish(true) + elseif jobs[cur_idx + 1] then + -- iterate + if on_iterate then + on_iterate() end + log.debug "Previous job failed, attempting next." + spawn(cur_idx + 1) + else + -- we exhausted all jobs without success + log.debug "All jobs failed." + on_finish(false) + end + end + + spawn = function(idx) + local ok, err = pcall(jobs[idx], function(success) + on_job_exit(idx, success) end) + if not ok then + log.fmt_error("Job failed to execute. Error=%s", tostring(err)) + on_job_exit(idx, false) + on_finish(false) + end end spawn(1) |
