summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-08-05 23:57:23 +0800
committerruki <[email protected]>2026-08-05 23:57:23 +0800
commit5c68815ee523bb6fff7d285016e57efbc88d483a (patch)
tree9a489c26bc85ab263e887893b5b24fa3a437b6c0
parente33ddd0560f28d86beb65ec6087fc126d786f56b (diff)
rewrite to install plugin from xmake-repo
-rw-r--r--xmake/actions/require/xmake.lua1
-rw-r--r--xmake/core/base/task.lua12
-rw-r--r--xmake/core/package/package.lua83
-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.lua53
7 files changed, 100 insertions, 58 deletions
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 ec4ea38b3..59c11b2cb 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)
@@ -912,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
- installdir = path.join(installdir, version_str)
+ 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, self:buildhash())
end
- installdir = path.join(installdir, self:buildhash())
end
self._INSTALLDIR = installdir
end
@@ -1141,7 +1155,7 @@ function _instance:_load()
if on_load then
on_load(self)
end
-
+
-- load all components
self:_load_components()
@@ -1179,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
@@ -3020,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
@@ -3088,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)
@@ -3116,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, ditto
+-- - 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
@@ -3178,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/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..fde93547a 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,18 @@ 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
- raise("plugin(%s): not found in any repository! try ${bright}xrepo update-repo${clear} first.", name)
+ os.execv(os.programfile(), {"lua", "private.xrepo", "install", "--plugin", installname})
end
-- install a single plugin from a source directory (as the given name, default to the directory name)
@@ -137,20 +120,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 +143,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