summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-08-05 22:06:11 +0800
committerGitHub <[email protected]>2026-08-05 22:06:11 +0800
commit53c06b72cc8b1521aae266543aee634c917a030f (patch)
tree4f3560aaaca4f2099cdc854bb83f0466f1905b14
parent2c1dd455654e0811305183510d0c40adb2d70488 (diff)
parent59dd47f6429a1162b9cdd242a9dfcfecdfedb1db (diff)
Merge pull request #7689 from xmake-io/plugin
Rewrite plugin manager for xmake-repo
-rw-r--r--tests/plugins/repository/test.lua25
-rw-r--r--xmake/actions/require/xmake.lua1
-rw-r--r--xmake/core/base/task.lua12
-rw-r--r--xmake/core/package/package.lua88
-rw-r--r--xmake/modules/private/action/require/impl/install_packages.lua23
-rw-r--r--xmake/modules/private/action/require/impl/package.lua123
-rw-r--r--xmake/modules/private/action/require/impl/repository.lua8
-rw-r--r--xmake/modules/private/action/require/install.lua3
-rw-r--r--xmake/modules/private/check/checkers/api/package/kind.lua2
-rw-r--r--xmake/modules/private/xrepo/action/install.lua4
-rw-r--r--xmake/plugins/plugin/main.lua65
11 files changed, 282 insertions, 72 deletions
diff --git a/tests/plugins/repository/test.lua b/tests/plugins/repository/test.lua
index f1cfba8c7..7b1619d5e 100644
--- a/tests/plugins/repository/test.lua
+++ b/tests/plugins/repository/test.lua
@@ -11,6 +11,19 @@ task("%s")
io.writefile(path.join(dir, "main.lua"), string.format([[function main() print("%s") end]], name))
end
+-- write a plugin package description, the plugin sources are placed in its `src` directory
+--
+-- plugins in a repository are described as packages, e.g. <repodir>/plugins/<first-letter>/<name>/xmake.lua
+function _write_plugin_package(dir, name)
+ io.writefile(path.join(dir, "xmake.lua"), string.format([[
+package("%s")
+ set_kind("plugin")
+ set_description("say hello from %s")
+ set_sourcedir(path.join(os.scriptdir(), "src"))
+]], name, name))
+ _write_plugin(path.join(dir, "src"), name)
+end
+
-- create a temporary plugin repository (packages layout: plugins/<first-letter>/<name>) and register it
--
-- @return reponame, names, cleanup
@@ -21,7 +34,7 @@ function _mock_repo(basenames)
local names = {}
for _, base in ipairs(basenames) do
local name = base .. "-" .. suffix
- _write_plugin(path.join(repodir, "plugins", name:sub(1, 1), name), name)
+ _write_plugin_package(path.join(repodir, "plugins", name:sub(1, 1), name), name)
table.insert(names, name)
end
@@ -52,12 +65,12 @@ function test_install_from_repo(t)
local name = names[1]
-- install by plain name (searched across all repositories)
- os.runv("xmake", {"plugin", "--install", name})
+ os.runv("xmake", {"plugin", "--install", "-y", name})
t:require(os.iorunv("xmake", {name}):find(name, 1, true))
-- reinstall by repo@name
os.runv("xmake", {"plugin", "--remove", name})
- os.runv("xmake", {"plugin", "--install", reponame .. "@" .. name})
+ os.runv("xmake", {"plugin", "--install", "-y", reponame .. "@" .. name})
t:require(os.iorunv("xmake", {name}):find(name, 1, true))
os.runv("xmake", {"plugin", "--remove", name})
@@ -86,7 +99,7 @@ function test_list(t)
local reponame, names, cleanup = _mock_repo({"hello", "world"})
-- install the first plugin, leave the second only available
- os.runv("xmake", {"plugin", "--install", names[1]})
+ os.runv("xmake", {"plugin", "--install", "-y", names[1]})
local out = os.iorunv("xmake", {"plugin", "--list"})
t:require(out:find("the built-in plugins:", 1, true))
t:require(out:find("project", 1, true))
@@ -100,6 +113,6 @@ end
-- invalid installs should fail
function test_install_invalid(t)
- t:require_not(try { function () os.runv("xmake", {"plugin", "--install", "plugin-test-missing"}); return true end })
- t:require_not(try { function () os.runv("xmake", {"plugin", "--install", "somerepo@.."}); return true end })
+ t:require_not(try { function () os.runv("xmake", {"plugin", "--install", "-y", "plugin-test-missing"}); return true end })
+ t:require_not(try { function () os.runv("xmake", {"plugin", "--install", "-y", "somerepo@.."}); return true end })
end
diff --git a/xmake/actions/require/xmake.lua b/xmake/actions/require/xmake.lua
index bf81e3810..6b04f2621 100644
--- a/xmake/actions/require/xmake.lua
+++ b/xmake/actions/require/xmake.lua
@@ -39,6 +39,7 @@ task("require")
{nil, "linkjobs", "kv", nil, "Set the number of parallel link jobs."},
{nil, "shallow", "k", nil, "Does not install or download dependent packages."},
{nil, "build", "k", nil, "Always build and install packages from source."},
+ {nil, "plugin", "k", nil, "Install plugin packages from <repository>/plugins/."},
{'l', "list", "k", nil, "List all package dependencies in project.",
"e.g.",
" $ xmake require --list"},
diff --git a/xmake/core/base/task.lua b/xmake/core/base/task.lua
index a51b1dbb5..d6f581cf9 100644
--- a/xmake/core/base/task.lua
+++ b/xmake/core/base/task.lua
@@ -81,9 +81,15 @@ end
-- the directories of tasks
function task._directories()
- return {path.join(global.directory(), "plugins"),
- path.join(os.programdir(), "plugins"),
- path.join(os.programdir(), "actions")}
+ local dirs = {
+ path.join(global.directory(), "plugins"),
+ path.join(os.programdir(), "plugins"),
+ path.join(os.programdir(), "actions")}
+ local plugindirs = os.getenv("XMAKE_PLUGIN_DIRS")
+ if plugindirs then
+ table.insert(dirs, 1, plugindirs)
+ end
+ return dirs
end
-- translate menu
diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua
index 0d164ce95..e014d9578 100644
--- a/xmake/core/package/package.lua
+++ b/xmake/core/package/package.lua
@@ -54,6 +54,16 @@ local sandbox_os = require("sandbox/modules/os")
local sandbox_module = require("sandbox/modules/import/core/sandbox/module")
-- new an instance
+--
+-- @param name the package name, the namespace prefix will be stripped and saved separately,
+-- e.g. "zlib", "myns::zlib", but "vcpkg::zlib" will be kept as a whole,
+-- because `vcpkg` is a package manager, but not a namespace
+-- @param info the package description scope info
+-- @param opt the options
+-- - scriptdir: the directory of the package description file, the relative paths in
+-- this package will be relative to it
+-- - repo: the repository instance which this package belongs to
+--
function _instance.new(name, info, opt)
opt = opt or {}
local instance = table.inherit(_instance)
@@ -610,6 +620,11 @@ function _instance:is_toolchain()
return self:kind() == "toolchain"
end
+-- is plugin package?
+function _instance:is_plugin()
+ return self:kind() == "plugin"
+end
+
-- is library package?
--
-- @return true if the package kind is "library" or default
@@ -907,20 +922,24 @@ function _instance:installdir(...)
installdir = self:get("installdir")
if not installdir then
local name = self:name():lower():gsub("::", "_")
- if self:is_local() then
- installdir = path.join(package.installdir({localdir = true}), name:sub(1, 1):lower(), name)
+ if self:is_plugin() then
+ installdir = path.join(global.directory(), "plugins", name)
else
- installdir = path.join(package.installdir(), name:sub(1, 1):lower(), name)
- end
- local version_str = self:version_str()
- if version_str then
- -- strip invalid characters on windows, e.g. `>= <=`
- if os.is_host("windows") then
- version_str = version_str:gsub("[>=<|%*]", "")
+ if self:is_local() then
+ installdir = path.join(package.installdir({localdir = true}), name:sub(1, 1):lower(), name)
+ else
+ installdir = path.join(package.installdir(), name:sub(1, 1):lower(), name)
+ end
+ local version_str = self:version_str()
+ if version_str then
+ -- strip invalid characters on windows, e.g. `>= <=`
+ if os.is_host("windows") then
+ version_str = version_str:gsub("[>=<|%*]", "")
+ end
+ installdir = path.join(installdir, version_str)
end
- installdir = path.join(installdir, version_str)
+ installdir = path.join(installdir, self:buildhash())
end
- installdir = path.join(installdir, self:buildhash())
end
self._INSTALLDIR = installdir
end
@@ -1136,7 +1155,7 @@ function _instance:_load()
if on_load then
on_load(self)
end
-
+
-- load all components
self:_load_components()
@@ -1174,6 +1193,11 @@ function _instance:_rawenvs()
envs.DYLD_LIBRARY_PATH = {"lib"}
end
end
+
+ -- add plugin env for on_test
+ if self:is_plugin() then
+ envs.XMAKE_PLUGIN_DIRS = path.directory(self:installdir())
+ end
self._RAWENVS = envs
end
return envs
@@ -3015,6 +3039,14 @@ function package.searchdirs()
end
-- load the package from the system directories
+--
+-- it will be used for `add_requires("zlib", {system = true})` and the 3rd package managers,
+-- e.g. add_requires("vcpkg::zlib"), add_requires("conan::zlib/1.2.11")
+--
+-- @param packagename the package name, e.g. "zlib", "vcpkg::zlib", "xmake::zlib"
+--
+-- @return the package instance and errors
+--
function package.load_from_system(packagename)
-- get package info
@@ -3083,6 +3115,15 @@ function package.load_from_system(packagename)
end
-- load the package from the project file
+--
+-- it will load the package which is defined by `package()` in the project xmake.lua,
+-- and we will also try to find it from the project namespaces if it's not found directly
+--
+-- @param packagename the package name, e.g. "zlib", it can be without the namespace prefix
+-- @param project the project module, we need to pass it to avoid the cyclic imports
+--
+-- @return the package instance and errors, it will be nil if this package is not defined in the project
+--
function package.load_from_project(packagename, project)
-- load packages (with cache)
@@ -3111,8 +3152,20 @@ function package.load_from_project(packagename, project)
end
-- load the package from the package directory or package description file
+--
+-- @param packagename the package name, e.g. "zlib"
+-- @param packagedir the package directory, we will load `packagedir/xmake.lua`, it can be nil if `opt.packagefile` is set
+-- @param opt the options
+-- - packagefile: load the package from the given description file directly instead of `packagedir/xmake.lua`
+-- - plat: the given platform, we need to set it to the description scope at same time,
+-- e.g. add_requires("zlib~mingw", {plat = "mingw"})
+-- @see https://github.com/orgs/xmake-io/discussions/3439
+-- - arch: the given architecture, it's the same as `opt.plat`
+-- - repo: the repository instance which this package belongs to
+--
+-- @return the package instance and errors
+--
function package.load_from_repository(packagename, packagedir, opt)
-
opt = opt or {}
-- find the package script path
@@ -3173,6 +3226,15 @@ function package.load_from_repository(packagename, packagedir, opt)
return nil, string.format("%s: package(%s) not found!", scriptpath, packagename)
end
+ -- we need set the default on_install script if it's plugin package
+ if packageinfo:get("kind") == "plugin" and not packageinfo:get("install") then
+ -- only one code line, we can directly omit the sandbox wrapper.
+ local on_install = function (pkg)
+ os.cp("*", pkg:installdir())
+ end
+ packageinfo:set("install", on_install)
+ end
+
package._memcache():set2("packageinfos.repository", cachekey, packageinfo)
end
diff --git a/xmake/modules/private/action/require/impl/install_packages.lua b/xmake/modules/private/action/require/impl/install_packages.lua
index f0da9eb2e..9573b38f6 100644
--- a/xmake/modules/private/action/require/impl/install_packages.lua
+++ b/xmake/modules/private/action/require/impl/install_packages.lua
@@ -167,6 +167,13 @@ function _get_confirm_from_3rd(packages)
end
-- get user confirm
+--
+-- @param packages the packages to be installed
+-- @param opt the options
+-- - toolchain: these packages are toolchain packages, we will show a different tip for it
+--
+-- @return the confirm result and the modified packages
+--
function _get_confirm(packages, opt)
opt = opt or {}
@@ -683,6 +690,11 @@ function _get_package_installdeps(packages)
end
-- install packages
+--
+-- @param requires the package requires, e.g. {"zlib >=1.2.11", "libpng"}
+-- @param opt the options, @see main
+-- - toolchain: only install the toolchain packages and their dependent packages
+--
function _install_packages(requires, opt)
opt = opt or {}
@@ -845,8 +857,15 @@ end
-- install all required packages
--
--- @param requires the requires table
--- @param opt the options
+-- @param requires the package requires, e.g. {"zlib >=1.2.11", "libpng"}
+-- @param opt the options, it will be passed to `package.load_packages` directly
+-- - 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
+-- @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
--
function main(requires, opt)
-- we need to install toolchain packages first,
diff --git a/xmake/modules/private/action/require/impl/package.lua b/xmake/modules/private/action/require/impl/package.lua
index 3ad758c3a..c3998c728 100644
--- a/xmake/modules/private/action/require/impl/package.lua
+++ b/xmake/modules/private/action/require/impl/package.lua
@@ -43,6 +43,15 @@ function _memcache()
end
-- load require info
+--
+-- @param require_str the require string, e.g. "zlib >=1.2.11", "libplist[shared,debug]"
+-- @param requires_extra the extra require configs from `add_requires()`, indexed by the require string
+-- @param opt the options
+-- - requirepath: the parent require path, e.g. "foo.bar", it's used to get the resolved requireinfo
+-- - resolvedinfo: the resolved requireinfo of dependency conflicts, indexed by require path
+--
+-- @return the package name and requireinfo
+--
function _load_require(require_str, requires_extra, opt)
opt = opt or {}
@@ -183,6 +192,15 @@ function _load_package_from_project(packagename)
end
-- load package package from repositories
+--
+-- @param packagename the package name
+-- @param opt the options
+-- - 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"
+-- - locked_repo: the locked repository info in `xmake-requires.lock`, e.g. {url = .., commit = .., branch = ..}
+--
function _load_package_from_repository(packagename, opt)
opt = opt or {}
local packagedir, repo = repository.packagedir(packagename, opt)
@@ -192,6 +210,13 @@ function _load_package_from_repository(packagename, opt)
end
-- load package package from base
+--
+-- e.g. package("foo") set_base("bar")
+--
+-- @param package the package instance
+-- @param basename the base package name
+-- @param opt the options, @see _load_package_from_repository
+--
function _load_package_from_base(package, basename, opt)
local package_base = _load_package_from_project(basename)
if not package_base then
@@ -203,6 +228,10 @@ function _load_package_from_base(package, basename, opt)
end
-- has locked requires?
+--
+-- @param opt the options
+-- - force: force to use the locked requires even if `xmake require --upgrade` is called
+--
function _has_locked_requires(opt)
opt = opt or {}
if not option.get("upgrade") or opt.force then
@@ -211,6 +240,13 @@ function _has_locked_requires(opt)
end
-- get locked requires
+--
+-- @param requirekey the require key in `xmake-requires.lock`, @see _get_packagelock_key
+-- @param opt the options
+-- - force: force to reload `xmake-requires.lock` and ignore `--upgrade`
+--
+-- @return the locked requireinfo and the version of `xmake-requires.lock`
+--
function _get_locked_requires(requirekey, opt)
opt = opt or {}
local requireslock = _memcache():get("requireslock")
@@ -260,6 +296,10 @@ end
--
-- orderdeps: a -> b -> c
--
+-- @param package the package instance
+-- @param opt the options
+-- - private: also sort the private library deps, e.g. add_deps("foo", {private = true})
+--
function _sort_librarydeps(package, opt)
-- we must use native deps list instead of package:deps() to generate correct link order
local orderdeps = {}
@@ -564,6 +604,13 @@ function _match_requirepath(requirepath, requireconf)
end
-- init requireinfo
+--
+-- @param requireinfo the requireinfo
+-- @param package the package instance
+-- @param opt the options
+-- - is_toplevel: this package is a toplevel package in `add_requires()`, but not a dependent package,
+-- and we will pass some root configs to it, e.g. toolchains, runtimes, lto, asan ..
+--
function _init_requireinfo(requireinfo, package, opt)
-- pass root configs to top library package
requireinfo.configs = requireinfo.configs or {}
@@ -899,7 +946,25 @@ function _select_package_runtimes(package)
end
end
--- load required packages
+-- load the given required package
+--
+-- we will load it from the project, repositories and system in order,
+-- and the requireinfo will be initialized and attached to the package instance.
+--
+-- @param packagename the package name, e.g. "zlib", "zlib~debug", "vcpkg::zlib"
+-- @param requireinfo the requireinfo, @see _load_require
+-- @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
+-- - 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()`
+-- - parentinfo: the parent requireinfo, this package will inherit some builtin configs from it, e.g. runtimes, pic
+--
+-- @return the package instance, it will be nil if this package is filtered by `opt.toolchain`,
+-- and it will raise an error if this package is not found in any repositories
+--
function _load_package(packagename, requireinfo, opt)
-- check circular dependency
@@ -949,6 +1014,7 @@ function _load_package(packagename, requireinfo, opt)
plat = requireinfo.plat,
arch = requireinfo.arch,
name = requireinfo.reponame,
+ rootdir = opt.packagekind == "plugin" and "plugins" or "packages",
locked_repo = locked_requireinfo and locked_requireinfo.repo})
if package then
from_repo = true
@@ -958,7 +1024,9 @@ function _load_package(packagename, requireinfo, opt)
-- load base package
if package and package:get("base") then
_load_package_from_base(package, package:get("base"), {
- name = requireinfo.reponame, locked_repo = locked_requireinfo and locked_requireinfo.repo})
+ name = requireinfo.reponame,
+ rootdir = opt.packagekind == "plugin" and "plugins" or "packages",
+ locked_repo = locked_requireinfo and locked_requireinfo.repo})
end
-- load package from system
@@ -1105,7 +1173,14 @@ function _load_package(packagename, requireinfo, opt)
return package
end
--- load all required packages
+-- load all required packages and their dependent packages
+--
+-- @param requires the package requires, e.g. {"zlib >=1.2.11", "libpng"}
+-- @param opt the options, @see load_packages
+--
+-- @return the packages with all dependent packages (the deps are always in front of their parents),
+-- and the packages without deps
+--
function _load_packages(requires, opt)
-- no requires?
@@ -1136,6 +1211,7 @@ 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)
@@ -1420,6 +1496,11 @@ end
-- compatible with all previous link dependencies?
-- @see https://github.com/xmake-io/xmake/issues/2719
+--
+-- @param package the package instance
+-- @param opt the options
+-- - install_finished: the installation has been finished, we do not need to check compatibility again
+--
function _compatible_with_previous_librarydeps(package, opt)
-- skip to check compatibility if installation has been finished
@@ -1524,6 +1605,13 @@ function cachedir()
end
-- this package should be install?
+--
+-- @param package the package instance
+-- @param opt the options
+-- - install_finished: the installation has been finished, it's used to check if this package
+-- has been installed successfully, and we will ignore `package.install_always`
+-- policy and the librarydeps compatibility checking
+--
function should_install(package, opt)
opt = opt or {}
if package:is_template() then
@@ -1631,7 +1719,15 @@ function get_configs_str(package)
return configs_str
end
--- get locked requireinfo
+-- get locked requireinfo from `xmake-requires.lock`
+--
+-- @param requireinfo the requireinfo, it must contain the requirekey
+-- @param opt the options
+-- - force: force to reload `xmake-requires.lock` and ignore `--upgrade`
+--
+-- @return the locked requireinfo and the version of `xmake-requires.lock`,
+-- it will be nil if the lock file does not exist or its version is incompatible
+--
function get_locked_requireinfo(requireinfo, opt)
local requirekey = requireinfo.requirekey
local locked_requireinfo, requireslock_version
@@ -1645,6 +1741,13 @@ function get_locked_requireinfo(requireinfo, opt)
end
-- load requires
+--
+-- @param requires the package requires, e.g. {"zlib >=1.2.11", "libpng"}
+-- @param requires_extra the extra require configs from `add_requires()`, indexed by the require string
+-- @param opt the options, @see _load_require
+--
+-- @return the require items, e.g. {{name = "zlib", info = {version = ">=1.2.11", ..}}, ..}
+--
function load_requires(requires, requires_extra, opt)
opt = opt or {}
local requireitems = {}
@@ -1656,6 +1759,18 @@ function load_requires(requires, requires_extra, opt)
end
-- load all required packages
+--
+-- @param requires the package requires, e.g. {"zlib >=1.2.11", "libpng"}
+-- @param opt the options
+-- - 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
+-- - 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
+-- - resolvedinfo: the resolved requireinfo of dependency conflicts, it's only used to reload packages internally
+--
function load_packages(requires, opt)
opt = opt or {}
local unique = {}
diff --git a/xmake/modules/private/action/require/impl/repository.lua b/xmake/modules/private/action/require/impl/repository.lua
index 3df59c42c..6b16a7183 100644
--- a/xmake/modules/private/action/require/impl/repository.lua
+++ b/xmake/modules/private/action/require/impl/repository.lua
@@ -151,6 +151,9 @@ function pulled()
end
-- get package directory from repositories
+--
+-- @param packagename the package name
+-- @param opt {rootdir = "packages|plugins"}
function packagedir(packagename, opt)
-- strip trailing ~tag, e.g. zlib~debug
@@ -162,7 +165,8 @@ function packagedir(packagename, opt)
-- get cache key
local reponame = opt.name
- local cachekey = packagename
+ local rootdir = opt.rootdir or "packages"
+ local cachekey = rootdir .. "/" .. packagename
local locked_repo = opt.locked_repo
if locked_repo then
cachekey = cachekey .. locked_repo.url .. (locked_repo.commit or "") .. (locked_repo.branch or "")
@@ -185,7 +189,7 @@ function packagedir(packagename, opt)
-- find the package directory from repositories
if not foundir then
for _, repo in ipairs(repositories()) do
- local dir = path.join(repo:directory(), "packages", packagename:sub(1, 1), packagename)
+ local dir = path.join(repo:directory(), rootdir, packagename:sub(1, 1), packagename)
if os.isdir(dir) and os.isfile(path.join(dir, "xmake.lua")) and (not reponame or reponame == repo:name()) then
foundir = {dir, repo}
break
diff --git a/xmake/modules/private/action/require/install.lua b/xmake/modules/private/action/require/install.lua
index b7ba9ef5e..6adf0dfa2 100644
--- a/xmake/modules/private/action/require/install.lua
+++ b/xmake/modules/private/action/require/install.lua
@@ -82,7 +82,8 @@ function main(requires_raw)
-- install packages
environment.enter()
- local packages = install_packages(requires, {requires_extra = requires_extra})
+ local packagekind = option.get("plugin") and "plugin" or "package"
+ local packages = install_packages(requires, {packagekind = packagekind, requires_extra = requires_extra})
if packages then
_check_missing_packages(packages)
end
diff --git a/xmake/modules/private/check/checkers/api/package/kind.lua b/xmake/modules/private/check/checkers/api/package/kind.lua
index 4a9c309e3..d2c7afd10 100644
--- a/xmake/modules/private/check/checkers/api/package/kind.lua
+++ b/xmake/modules/private/check/checkers/api/package/kind.lua
@@ -37,6 +37,6 @@ function main(opt)
end
return true
end
- return value == "binary" or value == "toolchain" or value == "template"
+ return value == "binary" or value == "toolchain" or value == "template" or value == "plugin"
end}))
end
diff --git a/xmake/modules/private/xrepo/action/install.lua b/xmake/modules/private/xrepo/action/install.lua
index b0d297b38..9e9bb1086 100644
--- a/xmake/modules/private/xrepo/action/install.lua
+++ b/xmake/modules/private/xrepo/action/install.lua
@@ -47,6 +47,7 @@ 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/"},
{category = "Visual Studio SDK Configuration" },
{nil, "vs", "kv", nil, "The Microsoft Visual Studio"
, " e.g. --vs=2017" },
@@ -281,6 +282,9 @@ function _install_packages(packages)
if option.get("build") or is_debug then
table.insert(require_argv, "--build")
end
+ if option.get("plugin") then
+ table.insert(require_argv, "--plugin")
+ end
local extra = {system = false}
if mode == "debug" then
extra.debug = true
diff --git a/xmake/plugins/plugin/main.lua b/xmake/plugins/plugin/main.lua
index 5158352c0..facbc0b4c 100644
--- a/xmake/plugins/plugin/main.lua
+++ b/xmake/plugins/plugin/main.lua
@@ -24,6 +24,7 @@ import("core.base.global")
import("core.package.repository")
import("devel.git")
import("private.action.require.impl.environment")
+import("private.action.require.impl.install_packages")
-- validate a plugin directory name
function _check_plugin_name(name)
@@ -42,36 +43,30 @@ function _repositories()
return table.join(repository.repositories({global = false}), repository.repositories({global = true}))
end
--- find a plugin directory in the given repository directory
---
--- plugins in a repository follow the same layout as packages:
--- <repodir>/plugins/<first-letter>/<name>/xmake.lua
-function _find_plugin_in_repo(repodir, name)
- local dir = path.join(repodir, "plugins", name:sub(1, 1):lower(), name)
- if os.isdir(dir) and os.isfile(path.join(dir, "xmake.lua")) then
- return dir
- end
-end
-
-- install a plugin from the given repository or the first repository containing it
function _install_plugins_from_repo(name, reponame)
+
+ -- check plugin name
_check_plugin_name(name)
- for _, repo in ipairs(_repositories()) do
- if not reponame or repo:name() == reponame then
- local srcdir = _find_plugin_in_repo(repo:directory(), name)
- if srcdir then
- local dstdir = _get_plugindir(name)
- assert(not os.isdir(dstdir), "plugin(%s) already exists!", name)
- os.vcp(srcdir, dstdir)
- cprint("${color.success}install ${bright}%s${clear} from repository ${bright}%s${clear} ok!", name, repo:name())
- return
- end
- end
- end
+
+ -- do install
+ local installname = name
if reponame then
- raise("plugin(%s): not found in repository %s!", name, reponame)
+ installname = reponame .. "@" .. name
+ end
+ local argv = {"lua", "private.xrepo", "install", "--plugin"}
+ -- 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
- raise("plugin(%s): not found in any repository! try ${bright}xrepo update-repo${clear} first.", name)
+ if option.get("diagnosis") then
+ table.insert(argv, "-D")
+ end
+ table.insert(argv, installname)
+ os.execv(os.programfile(), argv)
end
-- install a single plugin from a source directory (as the given name, default to the directory name)
@@ -137,20 +132,9 @@ end
function _install()
local names = assert(option.get("plugins"), "please specify the plugins to be installed!")
environment.enter()
- try
- {
- function ()
- for _, name in ipairs(names) do
- _install_one(name)
- end
- end,
- catch
- {
- function (errors)
- raise(errors)
- end
- }
- }
+ for _, name in ipairs(names) do
+ _install_one(name)
+ end
environment.leave()
end
@@ -171,7 +155,8 @@ function _plugin_description(dir)
if os.isfile(filepath) then
local content = io.readfile(filepath)
if content then
- return content:match("description%s*=%s*\"(.-)\"")
+ -- parse description from task or package scope
+ return content:match("description%s*=%s*\"(.-)\"") or content:match("set_description%s*%(\"(.-)\"%)")
end
end
end