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
136
137
138
139
140
141
142
|
--!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(declared, locked)
local requires = {}
for _, requirestr in ipairs(declared) 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, declared)
local lockinfo = {}
local locked = addons.locked(projectdir) or {}
-- @note we need to reload the registry, they have been installed by another process,
-- and we must not see them through the locked versions, we are locking them right now,
-- e.g. `xmake addon --upgrade` pins the old ones before loading this project
local installed = addon.addons({force = true, unpinned = true})
for _, requirestr in ipairs(declared) do
local name = addons.requirename(requirestr)
local addoninfo = assert(installed[addon.dirname(name)], "addon(%s) is not installed!", name)
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
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 a project declares, e.g. add_addons("esp32-devel 1.0.x")
--
-- @note we are also called from a sub-process, the project cannot be loaded until
-- its addons are installed, @see core/project/project.lua
--
-- install the addons which a project declares, e.g. add_addons("esp32-devel 1.0.x")
--
-- @param projectdir the project directory, we only read/write its lock file here
-- @param datafile the declarations of the project, {addons = {...}, repositories = {...}}
--
-- @note we are always run in a working directory which has no project, we cannot load
-- the project again here, @see xmake/core/project/project.lua
--
function main(projectdir, datafile, opt)
opt = opt or {}
projectdir = projectdir or os.projectdir()
local declarations = type(datafile) == "table" and datafile or io.load(datafile)
local declared = table.wrap(declarations and declarations.addons)
if #declared == 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
-- 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
local repositories = table.wrap(declarations.repositories)
if #repositories > 0 then
rcfile = os.tmpfile() .. ".lua"
local file = io.open(rcfile, "w")
for _, repo in ipairs(repositories) do
file:print("add_repositories(%q)", repo)
end
file:close()
end
-- install them with xrepo, it installs the packages in its own working directory
try
{
function ()
xrepo_addon("install", _get_requires(declared, 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, declared)
end
|