aboutsummaryrefslogtreecommitdiffstats
path: root/lua/mason-core/installer/handle.lua
diff options
context:
space:
mode:
authorWilliam Boman <william@redwill.se>2023-11-07 00:29:18 +0100
committerWilliam Boman <william@redwill.se>2025-02-19 12:15:48 +0100
commit6a7662760c515c74f2c37fc825776ead65d307f9 (patch)
tree0f4496d0678c7029b10236cbf48cc0f5ff63c1dc /lua/mason-core/installer/handle.lua
parentfix(pypi): remove -U flag and fix log message (diff)
downloadmason-6a7662760c515c74f2c37fc825776ead65d307f9.tar
mason-6a7662760c515c74f2c37fc825776ead65d307f9.tar.gz
mason-6a7662760c515c74f2c37fc825776ead65d307f9.tar.bz2
mason-6a7662760c515c74f2c37fc825776ead65d307f9.tar.lz
mason-6a7662760c515c74f2c37fc825776ead65d307f9.tar.xz
mason-6a7662760c515c74f2c37fc825776ead65d307f9.tar.zst
mason-6a7662760c515c74f2c37fc825776ead65d307f9.zip
refactor!: change Package API
This changes the following public APIs: **(_breaking_) Events on the `Package` class** The `uninstall:success` event on the `Package` class now receives an `InstallReceipt` as argument, instead of an `InstallHandle`. This receipt is an in-memory representation of what was uninstalled. There's also a new `uninstall:failed` event for situations where uninstallation for some reason fails. Note: this also applies to the registry events (i.e. `package:uninstall:success` and `package:uninstall:failed`). --- **(_breaking_) `Package:uninstall()` is now asynchronous and receives two new arguments, similarly to `Package:install()`** While package uninstallations remain synchronous under the hood, the public API has been changed from synchronous -> asynchronous. Users of this method are recommended to provide a callback in situations where code needs to execute after uninstallation fully completes. --- **(_breaking_) `Package:get_install_path()` has been removed. --- **`Package:install()` now takes an optional callback** This callback allows consumers to be informed whether installation was successful or not without having to go through a different, low-level, API. See below for a comparison between the old and new APIs: ```lua -- before local handle = pkg:install() handle:once("closed", function () -- ... end) -- after pkg:install({}, function (success, result) -- ... end) ```
Diffstat (limited to 'lua/mason-core/installer/handle.lua')
-rw-r--r--lua/mason-core/installer/handle.lua224
1 files changed, 0 insertions, 224 deletions
diff --git a/lua/mason-core/installer/handle.lua b/lua/mason-core/installer/handle.lua
deleted file mode 100644
index 62da5bae..00000000
--- a/lua/mason-core/installer/handle.lua
+++ /dev/null
@@ -1,224 +0,0 @@
-local EventEmitter = require "mason-core.EventEmitter"
-local Optional = require "mason-core.optional"
-local _ = require "mason-core.functional"
-local a = require "mason-core.async"
-local log = require "mason-core.log"
-local platform = require "mason-core.platform"
-local process = require "mason-core.process"
-local spawn = require "mason-core.spawn"
-
-local uv = vim.loop
-
----@alias InstallHandleState
---- | '"IDLE"'
---- | '"QUEUED"'
---- | '"ACTIVE"'
---- | '"CLOSED"'
-
----@class InstallHandleSpawnHandle
----@field uv_handle luv_handle
----@field pid integer
----@field cmd string
----@field args string[]
-local InstallHandleSpawnHandle = {}
-InstallHandleSpawnHandle.__index = InstallHandleSpawnHandle
-
----@param luv_handle luv_handle
----@param pid integer
----@param cmd string
----@param args string[]
-function InstallHandleSpawnHandle:new(luv_handle, pid, cmd, args)
- ---@type InstallHandleSpawnHandle
- local instance = {}
- setmetatable(instance, InstallHandleSpawnHandle)
- instance.uv_handle = luv_handle
- instance.pid = pid
- instance.cmd = cmd
- instance.args = args
- return instance
-end
-
-function InstallHandleSpawnHandle:__tostring()
- return ("%s %s"):format(self.cmd, table.concat(self.args, " "))
-end
-
----@class InstallHandle : EventEmitter
----@field package Package
----@field state InstallHandleState
----@field stdio { buffers: { stdout: string[], stderr: string[] }, sink: StdioSink }
----@field is_terminated boolean
----@field private spawn_handles InstallHandleSpawnHandle[]
-local InstallHandle = {}
-InstallHandle.__index = InstallHandle
-setmetatable(InstallHandle, { __index = EventEmitter })
-
----@param handle InstallHandle
-local function new_sink(handle)
- local stdout, stderr = {}, {}
- return {
- buffers = { stdout = stdout, stderr = stderr },
- sink = {
- stdout = function(chunk)
- stdout[#stdout + 1] = chunk
- handle:emit("stdout", chunk)
- end,
- stderr = function(chunk)
- stderr[#stderr + 1] = chunk
- handle:emit("stderr", chunk)
- end,
- },
- }
-end
-
----@param pkg Package
-function InstallHandle:new(pkg)
- local instance = EventEmitter.new(self)
- instance.state = "IDLE"
- instance.package = pkg
- instance.spawn_handles = {}
- instance.stdio = new_sink(instance)
- instance.is_terminated = false
- return instance
-end
-
----@param luv_handle luv_handle
----@param pid integer
----@param cmd string
----@param args string[]
-function InstallHandle:register_spawn_handle(luv_handle, pid, cmd, args)
- local spawn_handles = InstallHandleSpawnHandle:new(luv_handle, pid, cmd, args)
- log.fmt_trace("Pushing spawn_handles stack for %s: %s (pid: %s)", self, spawn_handles, pid)
- self.spawn_handles[#self.spawn_handles + 1] = spawn_handles
- self:emit "spawn_handles:change"
-end
-
----@param luv_handle luv_handle
-function InstallHandle:deregister_spawn_handle(luv_handle)
- for i = #self.spawn_handles, 1, -1 do
- if self.spawn_handles[i].uv_handle == luv_handle then
- log.fmt_trace("Popping spawn_handles stack for %s: %s", self, self.spawn_handles[i])
- table.remove(self.spawn_handles, i)
- self:emit "spawn_handles:change"
- return true
- end
- end
- return false
-end
-
----@return Optional # Optional<InstallHandleSpawnHandle>
-function InstallHandle:peek_spawn_handle()
- return Optional.of_nilable(self.spawn_handles[#self.spawn_handles])
-end
-
-function InstallHandle:is_idle()
- return self.state == "IDLE"
-end
-
-function InstallHandle:is_queued()
- return self.state == "QUEUED"
-end
-
-function InstallHandle:is_active()
- return self.state == "ACTIVE"
-end
-
-function InstallHandle:is_closed()
- return self.state == "CLOSED"
-end
-
-function InstallHandle:is_closing()
- return self:is_closed() or self.is_terminated
-end
-
----@param new_state InstallHandleState
-function InstallHandle:set_state(new_state)
- local old_state = self.state
- self.state = new_state
- log.fmt_trace("Changing %s state from %s to %s", self, old_state, new_state)
- self:emit("state:change", new_state, old_state)
-end
-
----@param signal integer
-function InstallHandle:kill(signal)
- assert(not self:is_closed(), "Cannot kill closed handle.")
- log.fmt_trace("Sending signal %s to luv handles in %s", signal, self)
- for _, spawn_handles in pairs(self.spawn_handles) do
- process.kill(spawn_handles.uv_handle, signal)
- end
- self:emit("kill", signal)
-end
-
----@param pid integer
-local win_taskkill = a.scope(function(pid)
- spawn.taskkill {
- "/f",
- "/t",
- "/pid",
- pid,
- }
-end)
-
-function InstallHandle:terminate()
- assert(not self:is_closed(), "Cannot terminate closed handle.")
- if self.is_terminated then
- log.fmt_trace("Handle is already terminated %s", self)
- return
- end
- log.fmt_trace("Terminating %s", self)
- -- https://github.com/libuv/libuv/issues/1133
- if platform.is.win then
- for _, spawn_handles in ipairs(self.spawn_handles) do
- win_taskkill(spawn_handles.pid)
- end
- else
- self:kill(15) -- SIGTERM
- end
- self.is_terminated = true
- self:emit "terminate"
- local check = uv.new_check()
- check:start(function()
- for _, spawn_handles in ipairs(self.spawn_handles) do
- local luv_handle = spawn_handles.uv_handle
- local ok, is_closing = pcall(luv_handle.is_closing, luv_handle)
- if ok and not is_closing then
- return
- end
- end
- check:stop()
- if not self:is_closed() then
- self:close()
- end
- end)
-end
-
-function InstallHandle:queued()
- assert(self:is_idle(), "Can only queue idle handles.")
- self:set_state "QUEUED"
-end
-
-function InstallHandle:active()
- assert(self:is_idle() or self:is_queued(), "Can only activate idle or queued handles.")
- self:set_state "ACTIVE"
-end
-
-function InstallHandle:close()
- log.fmt_trace("Closing %s", self)
- assert(not self:is_closed(), "Handle is already closed.")
- for _, spawn_handles in ipairs(self.spawn_handles) do
- local luv_handle = spawn_handles.uv_handle
- local ok, is_closing = pcall(luv_handle.is_closing, luv_handle)
- if ok then
- assert(is_closing, "There are open libuv handles.")
- end
- end
- self.spawn_handles = {}
- self:set_state "CLOSED"
- self:emit "closed"
- self:__clear_event_handlers()
-end
-
-function InstallHandle:__tostring()
- return ("InstallHandle(package=%s, state=%s)"):format(self.package, self.state)
-end
-
-return InstallHandle