summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-08-15 00:04:39 +0800
committerruki <[email protected]>2026-08-15 00:04:39 +0800
commitca9239022e1cba0faf054e8fe2f178a466149b04 (patch)
treef646b0c7348435a970bcd28f1cd4dcea2e59dec7
parentb13c11f9457e274eeb5e7c51547f619eb4aa6a68 (diff)
improve xrepo addon install
-rw-r--r--xmake/actions/addon/main.lua29
-rw-r--r--xmake/core/package/addon.lua7
-rw-r--r--xmake/core/project/project.lua7
-rw-r--r--xmake/core/sandbox/modules/import/core/package/addon.lua2
-rw-r--r--xmake/modules/private/action/addon/impl/install_addons.lua30
-rw-r--r--xmake/modules/private/action/addon/impl/xrepo.lua54
6 files changed, 84 insertions, 45 deletions
diff --git a/xmake/actions/addon/main.lua b/xmake/actions/addon/main.lua
index 7183925ea..37923e589 100644
--- a/xmake/actions/addon/main.lua
+++ b/xmake/actions/addon/main.lua
@@ -23,6 +23,7 @@ import("core.base.option")
import("core.package.addon")
import("devel.git")
import("private.action.addon.impl.install_addons")
+import("private.action.addon.impl.xrepo", {alias = "xrepo_addon"})
import("private.action.require.impl.environment")
import("private.action.require.impl.search_packages")
@@ -50,30 +51,14 @@ function _get_addondir(name, version)
return addondir
end
--- run the given xrepo action for the addons, e.g. install, remove, search
-function _xrepo(action, names)
- local argv = {"lua", "private.xrepo", action, "--addon"}
- -- we need to pass the common options to the sub-process, e.g. -y, -v, -D
- if option.get("yes") then
- table.insert(argv, "-y")
- end
- if option.get("verbose") then
- table.insert(argv, "-v")
- end
- if option.get("diagnosis") then
- table.insert(argv, "-D")
- end
- if option.get("force") then
- table.insert(argv, "--force")
- end
- table.join2(argv, names)
- os.execv(os.programfile(), argv)
-end
-
-- install an addon from the given repository or the first repository containing it
function _install_from_repo(name, reponame)
_check_addon_name(name)
- _xrepo("install", {reponame and (reponame .. "@" .. name) or name})
+ xrepo_addon("install", {reponame and (reponame .. "@" .. name) or name},
+ {force = option.get("force"),
+ -- @note we run it in a temporary directory, this action manages the global addons,
+ -- so we need not load the project of the current directory again
+ curdir = os.tmpdir()})
end
-- install a single addon from a source directory (as the given name, default to the directory name)
@@ -260,7 +245,7 @@ end
-- search the addons from the repositories
function _search()
local patterns = assert(option.get("addons"), "please specify the addon name pattern to be searched!")
- _xrepo("search", patterns)
+ xrepo_addon("search", patterns, {curdir = os.tmpdir()})
end
-- collect the installed addons from the addons registry
diff --git a/xmake/core/package/addon.lua b/xmake/core/package/addon.lua
index 33eb22e03..731c673ab 100644
--- a/xmake/core/package/addon.lua
+++ b/xmake/core/package/addon.lua
@@ -76,7 +76,7 @@ function addon._save(registry)
addon._ADDONS = nil
local registryfile = addon._registryfile()
-- we need not create an empty registry file if no addons are installed
- if next(registry) == nil and not os.isfile(registryfile) then
+ if table.empty(registry) and not os.isfile(registryfile) then
return
end
local ok, errors = io.save(registryfile, registry)
@@ -211,9 +211,10 @@ function addon._unregister(name, version)
if version then
entry.versions[version] = nil
if entry.active == version then
- entry.active = next(entry.versions)
+ -- we need to select the other one deterministically
+ entry.active = addon.versions(name)[1]
end
- if next(entry.versions) == nil then
+ if table.empty(entry.versions) then
registry[dirname] = nil
end
else
diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua
index 831f882d4..5c2a12e00 100644
--- a/xmake/core/project/project.lua
+++ b/xmake/core/project/project.lua
@@ -259,9 +259,6 @@ end
-- do install the addons which this project declares
function project._do_install_addons()
- if os.getenv("XMAKE_SKIP_ADDONS") then
- return true
- end
-- this project declares nothing?
local addonsinfo, errors = addons.load()
@@ -297,9 +294,7 @@ function project._do_install_addons()
end
table.insert(argv, "private.action.addon.impl.install_addons")
table.insert(argv, os.projectdir())
- local envs = os.getenvs()
- envs.XMAKE_SKIP_ADDONS = "y"
- local ok, errors = os.execv(os.programfile(), argv, {curdir = os.tmpdir(), envs = envs})
+ local ok, errors = os.execv(os.programfile(), argv, {curdir = os.tmpdir()})
if ok ~= 0 then
return false, errors or "install the addons of this project failed!"
end
diff --git a/xmake/core/sandbox/modules/import/core/package/addon.lua b/xmake/core/sandbox/modules/import/core/package/addon.lua
index 89cd60866..dc4740c2e 100644
--- a/xmake/core/sandbox/modules/import/core/package/addon.lua
+++ b/xmake/core/sandbox/modules/import/core/package/addon.lua
@@ -36,8 +36,6 @@ sandbox_core_package_addon.payloads_of = addon.payloads_of
sandbox_core_package_addon.payloadroot = addon.payloadroot
sandbox_core_package_addon.addons = addon.addons
sandbox_core_package_addon.versions = addon.versions
-sandbox_core_package_addon._registry = addon._registry
-sandbox_core_package_addon._registryfile = addon._registryfile
sandbox_core_package_addon.pin = addon.pin
sandbox_core_package_addon.addondir = addon.addondir
sandbox_core_package_addon.rescan = addon.rescan
diff --git a/xmake/modules/private/action/addon/impl/install_addons.lua b/xmake/modules/private/action/addon/impl/install_addons.lua
index 6ece11964..02bb87e2f 100644
--- a/xmake/modules/private/action/addon/impl/install_addons.lua
+++ b/xmake/modules/private/action/addon/impl/install_addons.lua
@@ -19,9 +19,9 @@
--
-- imports
-import("core.base.option")
import("core.package.addon")
import("core.project.addons")
+import("private.action.addon.impl.xrepo", {alias = "xrepo_addon"})
-- the format version of the addons lock file
local LOCKVERSION = "1.0"
@@ -68,7 +68,17 @@ function _lock_addons(projectdir, addonsinfo)
end
end
lockinfo.__meta__ = {version = LOCKVERSION}
- io.save(addons.lockfile(projectdir), lockinfo, {orderkeys = true})
+
+ -- @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`
@@ -89,7 +99,6 @@ function main(projectdir, opt)
-- install them with xrepo, it installs the packages in its own working directory,
-- so we need not a project here
- local argv = {"lua", "private.xrepo", "install", "--addon"}
-- this project declares its own repositories? we pass them to xrepo,
-- they are only used by this installation, we do not register them globally
@@ -101,26 +110,23 @@ function main(projectdir, opt)
file:print("add_repositories(%q)", repo)
end
file:close()
- table.insert(argv, "--includes=" .. rcfile)
end
- for _, name in ipairs({"yes", "verbose", "diagnosis"}) do
- if option.get(name) then
- table.insert(argv, "--" .. name)
- end
- end
- table.join2(argv, _get_requires(addonsinfo, locked))
try
{
function ()
- os.execv(os.programfile(), argv)
+ xrepo_addon("install", _get_requires(addonsinfo, locked), {includes = rcfile})
end,
finally
{
- function ()
+ -- @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
}
}
diff --git a/xmake/modules/private/action/addon/impl/xrepo.lua b/xmake/modules/private/action/addon/impl/xrepo.lua
new file mode 100644
index 000000000..34c1d2632
--- /dev/null
+++ b/xmake/modules/private/action/addon/impl/xrepo.lua
@@ -0,0 +1,54 @@
+--!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 xrepo.lua
+--
+
+-- imports
+import("core.base.option")
+
+-- run the given xrepo action for the addons
+--
+-- @note xrepo installs the packages in its own working project, so it works anywhere,
+-- and we need not implement the download/dependencies/confirm logic again
+--
+-- @param action the action name, e.g. "install", "search"
+-- @param names the addon names, urls or require strings, e.g. {"esp32-devel 1.0.x"}
+-- @param opt the options, e.g. {force = true, includes = "/tmp/xxx.lua", curdir = "/tmp"}
+--
+function main(action, names, opt)
+ opt = opt or {}
+ local argv = {"lua", "private.xrepo", action, "--addon"}
+
+ -- we need to pass the common options to the sub-process, e.g. -y, -v, -D
+ for _, name in ipairs({"yes", "verbose", "diagnosis"}) do
+ if option.get(name) then
+ table.insert(argv, "--" .. name)
+ end
+ end
+ if opt.force then
+ table.insert(argv, "--force")
+ end
+
+ -- the extra lua configuration files, e.g. the repositories which a project declares
+ if opt.includes then
+ table.insert(argv, "--includes=" .. opt.includes)
+ end
+
+ table.join2(argv, names)
+ os.execv(os.programfile(), argv, {curdir = opt.curdir})
+end