summaryrefslogtreecommitdiff
path: root/xmake/modules
diff options
context:
space:
mode:
authorruki <[email protected]>2026-08-15 17:57:22 +0800
committerGitHub <[email protected]>2026-08-15 17:57:22 +0800
commit0a32ec18d737259052271fa3be5cfdb50dbd1d15 (patch)
tree50be742aed502e6f5432ff841766bec4e38ff16d /xmake/modules
parent069474769dcfb01898f2c7066c1bf71d5da79125 (diff)
parent67ffcd8a481a5c6c51da8044bfe1ebed980b1e56 (diff)
Merge pull request #7696 from xmake-io/addon
Add addon support for plugins
Diffstat (limited to 'xmake/modules')
-rw-r--r--xmake/modules/package/manager/xmake/search_package.lua4
-rw-r--r--xmake/modules/private/action/addon/impl/install_addons.lua133
-rw-r--r--xmake/modules/private/action/addon/impl/xrepo.lua57
-rw-r--r--xmake/modules/private/action/require/impl/actions/install.lua50
-rw-r--r--xmake/modules/private/action/require/impl/install_packages.lua4
-rw-r--r--xmake/modules/private/action/require/impl/package.lua37
-rw-r--r--xmake/modules/private/action/require/impl/repository.lua2
-rw-r--r--xmake/modules/private/action/require/install.lua8
-rw-r--r--xmake/modules/private/action/require/search.lua8
-rw-r--r--xmake/modules/private/check/checkers/api/package/kind.lua4
-rw-r--r--xmake/modules/private/xrepo/action/install.lua7
-rw-r--r--xmake/modules/private/xrepo/action/remove.lua18
-rw-r--r--xmake/modules/private/xrepo/action/search.lua6
-rw-r--r--xmake/modules/private/xrepo/quick_search/cache.lua68
14 files changed, 369 insertions, 37 deletions
diff --git a/xmake/modules/package/manager/xmake/search_package.lua b/xmake/modules/package/manager/xmake/search_package.lua
index 32991ae3e..a5ed3caf8 100644
--- a/xmake/modules/package/manager/xmake/search_package.lua
+++ b/xmake/modules/package/manager/xmake/search_package.lua
@@ -23,7 +23,7 @@ import("core.base.semver")
import("private.xrepo.quick_search.cache")
function _search_package(packages, name, opt)
- for _, packageinfo in ipairs(cache.find(name, {description = opt.description ~= false})) do
+ for _, packageinfo in ipairs(cache.find(name, {description = opt.description ~= false, kind = opt.kind})) do
local packagename = packageinfo.name
local packagedata = packageinfo.data
@@ -59,7 +59,7 @@ end
-- search package using the xmake package manager
--
-- @param name the package name with pattern
--- @param opt the options, e.g. {require_version = "1.x"}
+-- @param opt the options, e.g. {require_version = "1.x", kind = "addon"}
--
function main(name, opt)
opt = opt or {}
diff --git a/xmake/modules/private/action/addon/impl/install_addons.lua b/xmake/modules/private/action/addon/impl/install_addons.lua
new file mode 100644
index 000000000..a20ed740b
--- /dev/null
+++ b/xmake/modules/private/action/addon/impl/install_addons.lua
@@ -0,0 +1,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
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..46ada2d01
--- /dev/null
+++ b/xmake/modules/private/action/addon/impl/xrepo.lua
@@ -0,0 +1,57 @@
+--!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")
+import("core.package.addon")
+
+-- 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"}
+--
+-- @note we always run it in a working directory which has no project, @see addon.workdir()
+--
+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 or addon.workdir()})
+end
diff --git a/xmake/modules/private/action/require/impl/actions/install.lua b/xmake/modules/private/action/require/impl/actions/install.lua
index 7fb54a951..7ddb66cca 100644
--- a/xmake/modules/private/action/require/impl/actions/install.lua
+++ b/xmake/modules/private/action/require/impl/actions/install.lua
@@ -22,6 +22,7 @@
import("core.base.option")
import("core.base.tty")
import("core.package.package", {alias = "core_package"})
+import("core.package.addon")
import("core.project.target")
import("core.project.project")
import("core.platform.platform")
@@ -283,6 +284,50 @@ function _merge_staticlibs(package)
end
end
+-- register the installed addon, so that xmake can find its payloads, e.g. plugins
+--
+-- @note the addon manifest(addon.lua) is only read when installing it, everything which
+-- is needed later is recorded in the addons registry, @see core/package/addon.lua
+--
+function _register_addon(package)
+
+ -- get the addon deps from the package recipe
+ local deps
+ for _, dep in ipairs(package:plaindeps() or {}) do
+ if dep:is_addon() then
+ deps = deps or {}
+ table.insert(deps, dep:name())
+ end
+ end
+
+ -- the addon describes itself? we prefer its own description
+ --
+ -- @note the deps are duplicated in its manifest, but the recipe is authoritative,
+ -- xmake needs them before downloading the addon sources, so we only report the
+ -- mismatch, they must be kept in sync
+ --
+ local description = package:description()
+ local manifest = package:data("addon.manifest")
+ if manifest then
+ description = manifest.description or description
+ for _, dep in ipairs(manifest.deps) do
+ if not (deps and table.contains(deps, dep)) then
+ wprint("addon(%s): dep(%s) is declared in its manifest, but not in the package recipe!",
+ package:name(), dep)
+ end
+ end
+ end
+
+ -- we also record where it comes from, so that the projects can lock it,
+ -- @see xmake/modules/private/action/addon/impl/install_addons.lua
+ local repo = package:repo()
+ addon.register(package:name(), package:version_str() or "latest",
+ {description = description, deps = deps,
+ repo = repo and {url = repo:url(), commit = repo:commit(), branch = repo:branch()} or nil,
+ manifest_deps = manifest and manifest.deps or nil,
+ globalmodules = manifest and #manifest.globalmodules > 0 and manifest.globalmodules or nil})
+end
+
-- get failed install directory
function _get_installdir_failed(package)
return path.join(package:cachedir(), "installdir.failed")
@@ -499,6 +544,11 @@ function main(package)
-- save the package info to the manifest file
package:manifest_save()
+
+ -- register this addon, so that xmake can find its payloads, e.g. plugins
+ if package:is_addon() then
+ _register_addon(package)
+ end
installed_now = true
end
end
diff --git a/xmake/modules/private/action/require/impl/install_packages.lua b/xmake/modules/private/action/require/impl/install_packages.lua
index 9573b38f6..2d633109e 100644
--- a/xmake/modules/private/action/require/impl/install_packages.lua
+++ b/xmake/modules/private/action/require/impl/install_packages.lua
@@ -211,6 +211,8 @@ function _get_confirm(packages, opt)
-- show tips
if opt.toolchain then
cprint("${bright color.warning}note: ${clear}install or modify (m) these ${bright}toolchain${clear} packages first (pass -y to skip confirm)?")
+ elseif opt.packagekind == "addon" then
+ cprint("${bright color.warning}note: ${clear}install or modify (m) these ${bright}addons${clear} (pass -y to skip confirm)?")
else
cprint("${bright color.warning}note: ${clear}install or modify (m) these packages (pass -y to skip confirm)?")
end
@@ -862,7 +864,7 @@ end
-- - requires_extra: the extra require configs from `add_requires()`, indexed by the require string
-- - nodeps: only install the given packages, do not install their dependent packages
-- - system: load package from system if `true`, and never load it if `false` (only for non-3rd packages)
--- - packagekind: the package kind, e.g. "plugin", it will be loaded from the `plugins` root directory of repositories
+-- - packagekind: the package kind, e.g. "addon", it will be loaded from the `addons` root directory of repositories
-- @note `toolchain` is reserved and it will be set internally, @see load_packages
--
-- @return the installed packages, including the toolchain packages and all dependent packages
diff --git a/xmake/modules/private/action/require/impl/package.lua b/xmake/modules/private/action/require/impl/package.lua
index c3998c728..1105384c8 100644
--- a/xmake/modules/private/action/require/impl/package.lua
+++ b/xmake/modules/private/action/require/impl/package.lua
@@ -198,7 +198,7 @@ end
-- - plat: the given platform of this package
-- - arch: the given architecture of this package
-- - name: the given repository name, we will only find this package in the given repository
--- - rootdir: the root directory of repositories, e.g. "packages" (default), "plugins"
+-- - rootdir: the root directory of repositories, e.g. "packages" (default), "addons"
-- - locked_repo: the locked repository info in `xmake-requires.lock`, e.g. {url = .., commit = .., branch = ..}
--
function _load_package_from_repository(packagename, opt)
@@ -209,6 +209,23 @@ function _load_package_from_repository(packagename, opt)
end
end
+-- get the root directory of repositories for the given package
+--
+-- e.g. "packages" (default), "addons", "plugins" (deprecated)
+--
+-- @note the addon packages are only searched from the `addons` root directory,
+-- and we need to set it explicitly, e.g. add_deps("foo", {kind = "addon"})
+--
+function _get_repository_rootdir(requireinfo, opt)
+ local packagekind = requireinfo.kind or opt.packagekind
+ if packagekind == "addon" then
+ return "addons"
+ elseif packagekind == "plugin" then
+ return "plugins"
+ end
+ return "packages"
+end
+
-- load package package from base
--
-- e.g. package("foo") set_base("bar")
@@ -956,7 +973,7 @@ end
-- @param opt the options
-- - system: load package from system if `true`, and never load it if `false`,
-- it's only used when `add_requires("zlib", {system = nil})` is not set (only for non-3rd packages)
--- - packagekind: the package kind, e.g. "plugin", it will be loaded from the `plugins` root directory of repositories
+-- - packagekind: the package kind, e.g. "addon", it will be loaded from the `addons` root directory of repositories
-- - toolchain: only load toolchain packages, the non-toolchain toplevel packages will be ignored
-- - requirepath: the current require path, e.g. "foo.bar", it's used to detect circular dependencies
-- and match `add_requireconfs()`
@@ -969,6 +986,12 @@ function _load_package(packagename, requireinfo, opt)
-- check circular dependency
opt = opt or {}
+
+ -- the `addon` and `self` names are reserved, we use them to reference the addon resources,
+ -- e.g. add_rules("@addon/esp32/flash"), import("@self.sdkconfig")
+ if packagename == "addon" or packagename == "self" then
+ raise("package(%s): the name `%s` is reserved by xmake for the addon references, please rename it!", packagename, packagename)
+ end
if opt.requirepath then
local splitinfo = opt.requirepath:split(".", {plain = true})
if #splitinfo > 3 and
@@ -1014,7 +1037,7 @@ function _load_package(packagename, requireinfo, opt)
plat = requireinfo.plat,
arch = requireinfo.arch,
name = requireinfo.reponame,
- rootdir = opt.packagekind == "plugin" and "plugins" or "packages",
+ rootdir = _get_repository_rootdir(requireinfo, opt),
locked_repo = locked_requireinfo and locked_requireinfo.repo})
if package then
from_repo = true
@@ -1025,7 +1048,7 @@ function _load_package(packagename, requireinfo, opt)
if package and package:get("base") then
_load_package_from_base(package, package:get("base"), {
name = requireinfo.reponame,
- rootdir = opt.packagekind == "plugin" and "plugins" or "packages",
+ rootdir = _get_repository_rootdir(requireinfo, opt),
locked_repo = locked_requireinfo and locked_requireinfo.repo})
end
@@ -1211,7 +1234,6 @@ function _load_packages(requires, opt)
parentinfo = requireinfo,
nodeps = opt.nodeps,
resolvedinfo = opt.resolvedinfo,
- packagekind = opt.packagekind,
system = false})
for _, dep in ipairs(plaindeps) do
dep:parents_add(package)
@@ -1680,6 +1702,9 @@ function get_configs_str(package)
end
if requireinfo.kind then
table.insert(configs, requireinfo.kind)
+ elseif package:is_addon() then
+ -- @note the kind is only set for the dependencies, e.g. add_deps("foo", {kind = "addon"})
+ table.insert(configs, "addon")
end
local ignored_configs_for_buildhash = hashset.from(requireinfo.ignored_configs_for_buildhash or {})
local configs_overrided = requireinfo.configs_overrided or {}
@@ -1765,7 +1790,7 @@ end
-- - requires_extra: the extra require configs from `add_requires()`, e.g. {["zlib >=1.2.11"] = {configs = {shared = true}}}
-- - nodeps: only load the given packages, do not load their dependent packages
-- - system: load package from system if `true`, and never load it if `false` (only for non-3rd packages)
--- - packagekind: the package kind, e.g. "plugin", it will be loaded from the `plugins` root directory of repositories
+-- - packagekind: the package kind, e.g. "addon", it will be loaded from the `addons` root directory of repositories
-- - toolchain: only load toolchain packages and their dependent packages
-- - requirepath: the parent require path, e.g. "foo.bar", it's used to detect circular dependencies and match `add_requireconfs()`
-- - parentinfo: the parent requireinfo, the child package will inherit some builtin configs from it, e.g. runtimes, pic
diff --git a/xmake/modules/private/action/require/impl/repository.lua b/xmake/modules/private/action/require/impl/repository.lua
index 6b16a7183..d17bdb570 100644
--- a/xmake/modules/private/action/require/impl/repository.lua
+++ b/xmake/modules/private/action/require/impl/repository.lua
@@ -153,7 +153,7 @@ end
-- get package directory from repositories
--
-- @param packagename the package name
--- @param opt {rootdir = "packages|plugins"}
+-- @param opt {rootdir = "packages|addons|plugins"}
function packagedir(packagename, opt)
-- strip trailing ~tag, e.g. zlib~debug
diff --git a/xmake/modules/private/action/require/install.lua b/xmake/modules/private/action/require/install.lua
index 6adf0dfa2..ebc648124 100644
--- a/xmake/modules/private/action/require/install.lua
+++ b/xmake/modules/private/action/require/install.lua
@@ -82,7 +82,13 @@ function main(requires_raw)
-- install packages
environment.enter()
- local packagekind = option.get("plugin") and "plugin" or "package"
+ -- @note the `--plugin` option is deprecated, please use `--addon` instead
+ local packagekind = "package"
+ if option.get("addon") then
+ packagekind = "addon"
+ elseif option.get("plugin") then
+ packagekind = "plugin"
+ end
local packages = install_packages(requires, {packagekind = packagekind, requires_extra = requires_extra})
if packages then
_check_missing_packages(packages)
diff --git a/xmake/modules/private/action/require/search.lua b/xmake/modules/private/action/require/search.lua
index e714c6c19..a0f98e0d9 100644
--- a/xmake/modules/private/action/require/search.lua
+++ b/xmake/modules/private/action/require/search.lua
@@ -20,6 +20,7 @@
-- imports
import("core.base.task")
+import("core.base.option")
import("private.action.require.impl.utils.filter")
import("private.action.require.impl.repository")
import("private.action.require.impl.environment")
@@ -41,11 +42,14 @@ function main(names)
task.run("repo", {update = true})
end
+ -- we only search the addon packages if `--addon` is enabled
+ local kind = option.get("addon") and "addon" or nil
+
-- show title
- print("The package names:")
+ print(kind == "addon" and "The addon names:" or "The package names:")
-- search packages
- for name, packages in pairs(search_packages(names)) do
+ for name, packages in pairs(search_packages(names, {kind = kind})) do
if #packages > 0 then
-- show name
diff --git a/xmake/modules/private/check/checkers/api/package/kind.lua b/xmake/modules/private/check/checkers/api/package/kind.lua
index d2c7afd10..2e4f2495b 100644
--- a/xmake/modules/private/check/checkers/api/package/kind.lua
+++ b/xmake/modules/private/check/checkers/api/package/kind.lua
@@ -37,6 +37,8 @@ function main(opt)
end
return true
end
- return value == "binary" or value == "toolchain" or value == "template" or value == "plugin"
+ -- @note the `plugin` kind is deprecated, please use the `addon` kind instead
+ return value == "binary" or value == "toolchain" or value == "template" or
+ value == "addon" or value == "plugin"
end}))
end
diff --git a/xmake/modules/private/xrepo/action/install.lua b/xmake/modules/private/xrepo/action/install.lua
index 9e9bb1086..4abb57c7f 100644
--- a/xmake/modules/private/xrepo/action/install.lua
+++ b/xmake/modules/private/xrepo/action/install.lua
@@ -47,7 +47,9 @@ function menu_options()
"e.g.",
" - xrepo install -p cross --toolchain=mytool --includes='toolchain1.lua" .. path.envsep() .. "toolchain2.lua'"},
{nil, "policies", "kv", nil, "Set the policies." },
- {nil, "plugin", "k", nil, "Install plugin packages from <repository>/plugins/"},
+ {nil, "addon", "k", nil, "Install addon packages from <repository>/addons/"},
+ {nil, "plugin", "k", nil, "Install plugin packages from <repository>/plugins/",
+ "(deprecated, please use --addon instead)"},
{category = "Visual Studio SDK Configuration" },
{nil, "vs", "kv", nil, "The Microsoft Visual Studio"
, " e.g. --vs=2017" },
@@ -282,6 +284,9 @@ function _install_packages(packages)
if option.get("build") or is_debug then
table.insert(require_argv, "--build")
end
+ if option.get("addon") then
+ table.insert(require_argv, "--addon")
+ end
if option.get("plugin") then
table.insert(require_argv, "--plugin")
end
diff --git a/xmake/modules/private/xrepo/action/remove.lua b/xmake/modules/private/xrepo/action/remove.lua
index ed92a83b8..eed956c6e 100644
--- a/xmake/modules/private/xrepo/action/remove.lua
+++ b/xmake/modules/private/xrepo/action/remove.lua
@@ -20,6 +20,7 @@
-- imports
import("core.base.option")
+import("core.package.addon")
import("private.action.require.impl.remove_packages", {alias = "remove_all_packages"})
-- get menu options
@@ -44,6 +45,10 @@ function menu_options()
{nil, "toolchain", "kv", nil, "Set the toolchain name." },
{nil, "toolchain_host", "kv", nil, "Set the host toolchain name." },
{ },
+ {nil, "addon", "k", nil, "Remove the given installed addon packages.",
+ "e.g.",
+ " - xrepo remove --addon serial-monitor" },
+ {'f', "force", "k", nil, "Force to remove the addon packages, even if they are depended on by the others." },
{nil, "all", "k", nil, "Remove all packages and ignore extra package configs.",
"If `--all` is enabled, the package name parameter will support lua pattern",
"e.g.",
@@ -193,10 +198,21 @@ function _remove_packages(packages)
os.vexecv(os.programfile(), require_argv)
end
+-- remove the given installed addons
+function _remove_addons(names)
+ for _, name in ipairs(names) do
+ addon.remove(name, {force = option.get("force")})
+ cprint("${color.success}remove ${bright}%s${clear} ok!", name)
+ end
+end
+
-- main entry
function main()
local packages = option.get("packages")
- if option.get("all") then
+ if option.get("addon") then
+ assert(packages, "please specify the addons to be removed.")
+ _remove_addons(packages)
+ elseif option.get("all") then
remove_all_packages(packages)
elseif packages then
_remove_packages(packages)
diff --git a/xmake/modules/private/xrepo/action/search.lua b/xmake/modules/private/xrepo/action/search.lua
index d389e3833..c532af44e 100644
--- a/xmake/modules/private/xrepo/action/search.lua
+++ b/xmake/modules/private/xrepo/action/search.lua
@@ -30,6 +30,9 @@ function menu_options()
-- menu options
local options =
{
+ {nil, "addon", "k", nil, "Search the addon packages from <repository>/addons/",
+ "e.g.",
+ " - xrepo search --addon serial"},
{nil, "packages", "vs", nil, "The packages list (support lua pattern).",
"e.g.",
" - xrepo search zlib boost",
@@ -80,6 +83,9 @@ function _search_packages(packages)
if option.get("diagnosis") then
table.insert(require_argv, "-D")
end
+ if option.get("addon") then
+ table.insert(require_argv, "--addon")
+ end
table.join2(require_argv, packages)
os.vexecv(os.programfile(), require_argv)
end
diff --git a/xmake/modules/private/xrepo/quick_search/cache.lua b/xmake/modules/private/xrepo/quick_search/cache.lua
index cf75a212d..feba8cda9 100644
--- a/xmake/modules/private/xrepo/quick_search/cache.lua
+++ b/xmake/modules/private/xrepo/quick_search/cache.lua
@@ -25,20 +25,36 @@ import("private.action.require.impl.repository")
local cache = globalcache.cache("quick_search")
+-- get the cache key of the given package
+--
+-- @note the addons are stored with the `addon::` prefix,
+-- because an addon and a package may have the same name
+--
+function _cachekey(packagename, kind)
+ return kind == "addon" and ("addon::" .. packagename) or packagename
+end
+
-- search package directories from repositories
+--
+-- the packages are stored in <repodir>/packages/<first-letter>/<name>,
+-- and the addons are stored in <repodir>/addons/<first-letter>/<name>
+--
function _list_package_dirs()
-- find the package directories from all repositories
local unique = {}
local packageinfos = {}
for _, repo in ipairs(repository.repositories()) do
- for _, file in ipairs(os.files(path.join(repo:directory(), "packages", "*", "*", "xmake.lua"))) do
- local dir = path.directory(file)
- local subdirname = path.basename(path.directory(dir))
- if #subdirname == 1 then -- ignore l/luajit/port/xmake.lua
- local packagename = path.filename(dir)
- if not unique[packagename] then
- table.insert(packageinfos, {name = packagename, repo = repo, packagedir = dir})
- unique[packagename] = true
+ for _, rootinfo in ipairs({{rootdir = "packages"}, {rootdir = "addons", kind = "addon"}}) do
+ for _, file in ipairs(os.files(path.join(repo:directory(), rootinfo.rootdir, "*", "*", "xmake.lua"))) do
+ local dir = path.directory(file)
+ local subdirname = path.basename(path.directory(dir))
+ if #subdirname == 1 then -- ignore l/luajit/port/xmake.lua
+ local packagename = path.filename(dir)
+ local cachekey = _cachekey(packagename, rootinfo.kind)
+ if not unique[cachekey] then
+ table.insert(packageinfos, {name = packagename, kind = rootinfo.kind, repo = repo, packagedir = dir})
+ unique[cachekey] = true
+ end
end
end
end
@@ -57,7 +73,9 @@ end
function update()
for _, packageinfo in ipairs(_list_package_dirs()) do
local package = core_package.load_from_repository(packageinfo.name, packageinfo.packagedir, {repo = packageinfo.repo})
- cache:set(packageinfo.name, {
+ cache:set(_cachekey(packageinfo.name, packageinfo.kind), {
+ name = packageinfo.name,
+ kind = packageinfo.kind,
reponame = package:repo() and package:repo():name(),
description = package:description(),
versions = package:versions(),
@@ -79,22 +97,30 @@ function get()
end
-- find package
+--
+-- @param name the package name (support lua pattern)
+-- @param opt the options, e.g. {prefix = true, description = true, kind = "addon"}
+--
function find(name, opt)
_init()
opt = opt or {}
local list_result = {}
- for packagename, packagedata in pairs(cache:data()) do
- local found = false
- if opt.prefix then
- found = packagename:startswith(name)
- else
- found = packagename:find(path.pattern(name))
- end
- if not found and opt.description and packagedata.description and packagedata.description:find(name) then
- found = true
- end
- if found then
- table.insert(list_result, {name = packagename, data = packagedata})
+ for cachekey, packagedata in table.orderpairs(cache:data()) do
+ -- we only search the packages with the given kind, e.g. nil (package), "addon"
+ local packagename = packagedata.name or cachekey
+ if packagedata.kind == opt.kind then
+ local found = false
+ if opt.prefix then
+ found = packagename:startswith(name)
+ else
+ found = packagename:find(path.pattern(name))
+ end
+ if not found and opt.description and packagedata.description and packagedata.description:find(name) then
+ found = true
+ end
+ if found then
+ table.insert(list_result, {name = packagename, data = packagedata})
+ end
end
end
return list_result