diff options
| author | William Boman <william@redwill.se> | 2023-11-07 00:29:18 +0100 |
|---|---|---|
| committer | William Boman <william@redwill.se> | 2025-02-19 12:15:48 +0100 |
| commit | 6a7662760c515c74f2c37fc825776ead65d307f9 (patch) | |
| tree | 0f4496d0678c7029b10236cbf48cc0f5ff63c1dc /lua/mason-core/installer/handle.lua | |
| parent | fix(pypi): remove -U flag and fix log message (diff) | |
| download | mason-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.lua | 224 |
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 |
