diff options
| author | ruki <[email protected]> | 2026-08-05 22:06:11 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-08-05 22:06:11 +0800 |
| commit | 53c06b72cc8b1521aae266543aee634c917a030f (patch) | |
| tree | 4f3560aaaca4f2099cdc854bb83f0466f1905b14 | |
| parent | 2c1dd455654e0811305183510d0c40adb2d70488 (diff) | |
| parent | 59dd47f6429a1162b9cdd242a9dfcfecdfedb1db (diff) | |
Merge pull request #7689 from xmake-io/plugin
Rewrite plugin manager for xmake-repo
| -rw-r--r-- | tests/plugins/repository/test.lua | 25 | ||||
| -rw-r--r-- | xmake/actions/require/xmake.lua | 1 | ||||
| -rw-r--r-- | xmake/core/base/task.lua | 12 | ||||
| -rw-r--r-- | xmake/core/package/package.lua | 88 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/install_packages.lua | 23 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/package.lua | 123 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/impl/repository.lua | 8 | ||||
| -rw-r--r-- | xmake/modules/private/action/require/install.lua | 3 | ||||
| -rw-r--r-- | xmake/modules/private/check/checkers/api/package/kind.lua | 2 | ||||
| -rw-r--r-- | xmake/modules/private/xrepo/action/install.lua | 4 | ||||
| -rw-r--r-- | xmake/plugins/plugin/main.lua | 65 |
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 |
