aboutsummaryrefslogtreecommitdiffstats
path: root/lua/mason-core/installer/UninstallRunner.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/mason-core/installer/UninstallRunner.lua')
-rw-r--r--lua/mason-core/installer/UninstallRunner.lua119
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