aboutsummaryrefslogtreecommitdiffstats
path: root/lua/mason-core/system-package.lua
blob: 1eb14e3fbf3d5ef4135a34f40c416f7e370928b1 (plain) (blame)
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
local Result = require "mason-core.result"
local _ = require "mason-core.functional"
local a = require "mason-core.async"
local registry = require "mason-registry"
local settings = require "mason.settings"
local OneShotChannel = require("mason-core.async.control").OneShotChannel

---@class SystemPackage
---@field name string
---@field condition? fun(): bool
local SystemPackage = {}
SystemPackage.__index = SystemPackage

---@type table<string, OneShotChannel>
SystemPackage.channels = {}

function SystemPackage:new(system_pkg_name)
    ---@type SystemPackage
    local instance = {}
    setmetatable(instance, self)
    instance.name = system_pkg_name
    return instance
end

function SystemPackage:conditional(fn)
    self.condition = fn
    return self
end

---@async
function SystemPackage:get_package()
    pcall(a.wait, registry.refresh_system)
    if not registry.has_system_package(self.name) then
        -- Force update to the very latest registry version
        pcall(a.wait, registry.update)
    end
    if not registry.has_system_package(self.name) then
        return Result.failure("Unable to find system package " .. self.name)
    end
    return Result.pcall(registry.get_system_package, self.name)
end

---@async
---@return Result<boolean>
function SystemPackage:needs_install()
    return Result.try(function(try)
        if self.condition and not self.condition() then
            return false
        end
        local pkg = try(self:get_package())
        if not pkg:is_installed() or pkg:is_installing() then
            return true
        end
        if pkg:get_installed_version() ~= pkg:get_latest_version() then
            return true
        end
        return false
    end)
end

---@async
function SystemPackage:await_channel()
    assert(SystemPackage.channels[self.name], "Tried to await non-existing channel.")
    local success, result = SystemPackage.channels[self.name]:receive()
    if not success then
        return Result.failure("Failed to install system package " .. self.name .. ". Error: " .. result)
    end
    return Result.success()
end

---@async
---@return Result
function SystemPackage:install()
    return Result.try(function(try)
        local pkg = try(self:get_package())
        if not pkg:is_installing() then
            local channel = OneShotChannel:new()
            SystemPackage.channels[self.name] = channel
            pkg:install({}, function(success, result)
                channel:send(success, result)
            end)
        end
        return self:await_channel()
    end)
end

function SystemPackage:__tostring()
    return ("SystemPackage(name=%s)"):format(self.name)
end

SystemPackage.sfw = SystemPackage:new("sfw@latest"):conditional(function()
    return settings.current.firewall.enabled and settings.current.firewall.auto_managed
end)

return SystemPackage