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/UninstallRunner.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/UninstallRunner.lua')
| -rw-r--r-- | lua/mason-core/installer/UninstallRunner.lua | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/lua/mason-core/installer/UninstallRunner.lua b/lua/mason-core/installer/UninstallRunner.lua new file mode 100644 index 00000000..661bfefa --- /dev/null +++ b/lua/mason-core/installer/UninstallRunner.lua @@ -0,0 +1,119 @@ +local InstallContext = require "mason-core.installer.context" +local Result = require "mason-core.result" +local _ = require "mason-core.functional" +local a = require "mason-core.async" +local compiler = require "mason-core.installer.compiler" +local control = require "mason-core.async.control" +local fs = require "mason-core.fs" +local log = require "mason-core.log" +local registry = require "mason-registry" + +local OneShotChannel = control.OneShotChannel + +---@class UninstallRunner +---@field handle InstallHandle +---@field global_semaphore Semaphore +---@field package_permit Permit? +---@field global_permit Permit? +local UninstallRunner = {} +UninstallRunner.__index = UninstallRunner + +---@param handle InstallHandle +---@param global_semaphore Semaphore +---@return UninstallRunner +function UninstallRunner:new(handle, global_semaphore) + local instance = {} + setmetatable(instance, self) + instance.handle = handle + instance.global_semaphore = global_semaphore + return instance +end + +---@param opts PackageUninstallOpts +---@param callback? InstallRunnerCallback +function UninstallRunner:execute(opts, callback) + local pkg = self.handle.package + local location = self.handle.location + log.fmt_info("Executing uninstaller for %s %s", pkg, opts) + a.run(function() + Result.try(function(try) + if not opts.bypass_permit then + try(self:acquire_permit()):receive() + end + ---@type InstallReceipt? + local receipt = pkg:get_receipt(location):or_else(nil) + if receipt == nil then + log.fmt_warn("Receipt not found when uninstalling %s", pkg) + end + try(pkg:unlink(location)) + fs.sync.rmrf(location:package(pkg.name)) + return receipt + end):get_or_throw() + end, function(success, result) + if not self.handle:is_closing() then + self.handle:close() + end + self:release_permit() + + if success then + local receipt = result + log.fmt_info("Uninstallation succeeded for %s", pkg) + if callback then + callback(true, receipt) + end + pkg:emit("uninstall:success", receipt) + registry:emit("package:uninstall:success", pkg, receipt) + else + log.fmt_error("Uninstallation failed for %s error=%s", pkg, result) + if callback then + callback(false, result) + end + pkg:emit("uninstall:failed", result) + registry:emit("package:uninstall:failed", pkg, result) + end + end) +end + +---@private +function UninstallRunner:acquire_permit() + local channel = OneShotChannel:new() + log.fmt_debug("Acquiring permit for %s", self.handle.package) + local handle = self.handle + if handle:is_active() or handle:is_closing() then + log.fmt_debug("Received active or closing handle %s", handle) + return Result.failure "Invalid handle state." + end + + handle:queued() + a.run(function() + self.global_permit = self.global_semaphore:acquire() + self.package_permit = handle.package:acquire_permit() + end, function(success, err) + if not success or handle:is_closing() then + if not success then + log.error("Acquiring permits failed", err) + end + self:release_permit() + else + log.fmt_debug("Activating handle %s", handle) + handle:active() + channel:send() + end + end) + + return Result.success(channel) +end + +---@private +function UninstallRunner:release_permit() + if self.global_permit then + self.global_permit:forget() + self.global_permit = nil + end + if self.package_permit then + self.package_permit:forget() + self.package_permit = nil + end +end + +return UninstallRunner |
