summaryrefslogtreecommitdiff
path: root/xmake/modules/private/action/addon/impl/install_addons.lua
blob: a20ed740b4df406e507de728945d453db0e6ef2e (plain)
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
--!A cross-platform build utility based on Lua
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- Copyright (C) 2015-present, Xmake Open Source Community.
--
-- @author      ruki
-- @file        install_addons.lua
--

-- imports
import("core.package.addon")
import("core.project.addons")
import("private.action.addon.impl.xrepo", {alias = "xrepo_addon"})

-- get the requires of the declared addons
--
-- @note we install the locked versions, but the declaration is authoritative, so we
-- resolve them again if the user has changed it or upgrades them
--
function _get_requires(addonsinfo, locked)
    local requires = {}
    for _, requirestr in ipairs(addonsinfo.addons) do
        local name = addons.requirename(requirestr)
        local lockinfo = locked and locked[name]
        if addons.locked_valid(requirestr, lockinfo) then
            requirestr = name .. " " .. lockinfo.version
        end
        table.insert(requires, requirestr)
    end
    return requires
end

-- lock the installed addons, so that we always get the same ones
--
-- @note we get the installed versions from the addons registry, they are
-- registered when installing them, @see core/package/addon.lua
--
function _lock_addons(projectdir, addonsinfo)
    local lockinfo = {}
    local locked = addons.locked(projectdir) or {}
    -- @note we need to reload the registry, they have been installed by another process
    local installed = addon.addons({force = true})
    for _, requirestr in ipairs(addonsinfo.addons) do
        local name = addons.requirename(requirestr)
        local addoninfo = installed[addon.dirname(name)]
        if addoninfo then
            local oldversion = locked[name] and locked[name].version
            if oldversion and oldversion ~= addoninfo.version then
                cprint("${color.success}upgrade ${bright}%s${clear}: %s -> %s", name, oldversion, addoninfo.version)
            end
            -- we lock the repository too, so that the other users get it from the same source,
            -- @see xmake/modules/private/action/require/impl/lock_packages.lua
            lockinfo[name] = {version = addoninfo.version, repo = addoninfo.repo}
        end
    end
    lockinfo.__meta__ = {version = addons.lockfile_version()}

    -- @note we need to write it deterministically, the key order of a lua table is random,
    -- otherwise the lock file would change even if nothing changed,
    -- @see xmake/modules/private/action/require/impl/lock_packages.lua
    local content = string.serialize(lockinfo, {orderkeys = true})
    local tmpfile = os.tmpfile()
    io.writefile(tmpfile, content, {encoding = "binary"})

    -- and we only write it if the content is different, so we can keep the file time
    os.cp(tmpfile, addons.lockfile(projectdir), {copy_if_different = true})
    os.rm(tmpfile)
end

-- install the addons which the given project declares in its `xmake-addons.lua`
--
-- @note we are also called from a sub-process, the project cannot be loaded until
-- its addons are installed, @see core/project/project.lua
--
function main(projectdir, opt)
    opt = opt or {}
    projectdir = projectdir or os.projectdir()
    local addonsinfo = addons.load(projectdir)
    if not addonsinfo or #addonsinfo.addons == 0 then
        return
    end

    -- upgrade them? we need to resolve the declared versions again
    local locked = not opt.upgrade and addons.locked(projectdir) or nil

    -- install them with xrepo, it installs the packages in its own working directory,
    -- so we need not a project here

    -- this project declares its own repositories? we pass them to xrepo,
    -- they are only used by this installation, we do not register them globally
    local rcfile
    if #addonsinfo.repositories > 0 then
        rcfile = os.tmpfile() .. ".lua"
        local file = io.open(rcfile, "w")
        for _, repo in ipairs(addonsinfo.repositories) do
            file:print("add_repositories(%q)", repo)
        end
        file:close()
    end

    try
    {
        function ()
            xrepo_addon("install", _get_requires(addonsinfo, locked), {includes = rcfile})
        end,
        finally
        {
            -- @note try() swallows the errors if we do not re-raise them here
            function (ok, errors)
                if rcfile then
                    os.tryrm(rcfile)
                end
                if not ok then
                    raise(errors)
                end
            end
        }
    }

    -- and lock them, so that the other users get the same versions
    _lock_addons(projectdir, addonsinfo)
end