1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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
|