aboutsummaryrefslogtreecommitdiffstats
path: root/lua/mason-core/managers/composer/init.lua
blob: 96ab5f142677cff75757e19a3f66e4f4a5d19399 (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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
local _ = require "mason-core.functional"
local process = require "mason-core.process"
local path = require "mason-core.path"
local Result = require "mason-core.result"
local spawn = require "mason-core.spawn"
local Optional = require "mason-core.optional"
local installer = require "mason-core.installer"
local platform = require "mason-core.platform"

local M = {}

local create_bin_path = _.compose(path.concat, function(executable)
    return _.append(executable, { "vendor", "bin" })
end, _.if_else(_.always(platform.is.win), _.format "%s.bat", _.identity))

---@param packages string[]
local function with_receipt(packages)
    return function()
        local ctx = installer.context()

        ctx.receipt:with_primary_source(ctx.receipt.composer(packages[1]))
        for i = 2, #packages do
            ctx.receipt:with_secondary_source(ctx.receipt.composer(packages[i]))
        end
    end
end

---@async
---@param packages { [number]: string, bin: string[] | nil } @The composer packages to install. The first item in this list will be the recipient of the requested version, if set.
function M.packages(packages)
    return function()
        return M.require(packages).with_receipt()
    end
end

---@async
---@param packages { [number]: string, bin: string[] | nil } @The composer packages to install. The first item in this list will be the recipient of the requested version, if set.
function M.require(packages)
    local ctx = installer.context()
    local pkgs = _.list_copy(packages)

    if not ctx.fs:file_exists "composer.json" then
        ctx.spawn.composer { "init", "--no-interaction", "--stability=stable" }
    end

    ctx.requested_version:if_present(function(version)
        pkgs[1] = ("%s:%s"):format(pkgs[1], version)
    end)

    ctx.spawn.composer { "require", pkgs }

    if packages.bin then
        _.each(function(executable)
            ctx:link_bin(executable, create_bin_path(executable))
        end, packages.bin)
    end

    return {
        with_receipt = with_receipt(packages),
    }
end

---@async
function M.install()
    local ctx = installer.context()
    ctx.spawn.composer {
        "install",
        "--no-interaction",
        "--no-dev",
        "--optimize-autoloader",
        "--classmap-authoritative",
    }
end

---@async
---@param receipt InstallReceipt
---@param install_dir string
function M.check_outdated_primary_package(receipt, install_dir)
    if receipt.primary_source.type ~= "composer" then
        return Result.failure "Receipt does not have a primary source of type composer"
    end
    return spawn
        .composer({
            "outdated",
            "--no-interaction",
            "--format=json",
            cwd = install_dir,
        })
        :map_catching(function(result)
            local outdated_packages = vim.json.decode(result.stdout)
            local outdated_package = _.find_first(function(pkg)
                return pkg.name == receipt.primary_source.package
            end, outdated_packages.installed)
            return Optional.of_nilable(outdated_package)
                :map(function(pkg)
                    if pkg.version ~= pkg.latest then
                        return {
                            name = pkg.name,
                            current_version = pkg.version,
                            latest_version = pkg.latest,
                        }
                    end
                end)
                :or_else_throw "Primary package is not outdated."
        end)
end

---@async
---@param receipt InstallReceipt
---@param install_dir string
function M.get_installed_primary_package_version(receipt, install_dir)
    if receipt.primary_source.type ~= "composer" then
        return Result.failure "Receipt does not have a primary source of type composer"
    end
    return spawn
        .composer({
            "info",
            "--format=json",
            receipt.primary_source.package,
            cwd = install_dir,
        })
        :map_catching(function(result)
            local info = vim.json.decode(result.stdout)
            return info.versions[1]
        end)
end

---@param install_dir string
function M.env(install_dir)
    return {
        PATH = process.extend_path { path.concat { install_dir, "vendor", "bin" } },
    }
end

return M