diff options
| author | Saikari <[email protected]> | 2026-07-26 22:50:42 +0300 |
|---|---|---|
| committer | ruki <[email protected]> | 2026-07-30 10:17:31 +0800 |
| commit | 21f1b0efbf5441e5ec82a2caa84984a77ad7e7eb (patch) | |
| tree | 71bc6323bf53b2d92c04eb95e7e257362180c392 | |
| parent | 5f9a9e45ecb47384aa6c80d3543b7c379cb4e5ea (diff) | |
Added tests for plugins
21 files changed, 181 insertions, 702 deletions
diff --git a/tests/plugins/repository/test.lua b/tests/plugins/repository/test.lua new file mode 100644 index 000000000..0f7b1cc60 --- /dev/null +++ b/tests/plugins/repository/test.lua @@ -0,0 +1,56 @@ +function main() + local prog = os.programfile() + local gd = os.tmpfile() .. ".gd" + io.writefile(path.join(gd, ".xmake", "repositories", "xmake-repo", "plugins", "hello-world", "xmake.lua"), [[ +task("hello-world") + set_category("plugin") + on_run("main") + set_menu {usage = "xmake hello-world"} +]]) + io.writefile(path.join(gd, ".xmake", "repositories", "xmake-repo", "plugins", "hello-world", "main.lua"), [[ +function main() print("repo-ok") end +]]) + local out = os.iorunv(prog, {"hello-world"}, {envs = {XMAKE_GLOBALDIR = gd}}) + assert(out:find("repo%-ok", 1, true)) + local out = os.iorunv(prog, {"hello-world"}, {envs = {XMAKE_PROGRAM_DIR = os.programdir(), XMAKE_GLOBALDIR = gd}}) + assert(out:find("xrepo", 1, true)) + + local md = os.tmpfile() .. ".md" + io.writefile(path.join(md, ".xmake", "plugins", "manual-plugin", "xmake.lua"), [[ +task("manual-plugin") + set_category("plugin") + on_run("main") + set_menu {usage = "xmake manual-plugin"} +]]) + io.writefile(path.join(md, ".xmake", "plugins", "manual-plugin", "main.lua"), [[ +function main() print("manual") end +]]) + out = os.iorunv(prog, {"plugin", "--list"}, {envs = {XMAKE_GLOBALDIR = md}}) + assert(out:find("manual%-plugin", 1, true)) + out = os.iorunv(prog, {"plugin", "--list"}, {envs = {XMAKE_GLOBALDIR = gd}}) + assert(out:find("hello%-world", 1, true)) + + out = os.iorunv(prog, {"plugin", "--remove", "manual-plugin"}, {envs = {XMAKE_GLOBALDIR = md}}) + assert(out:find("remove plugin", 1, true)) + out = os.iorunv(prog, {"plugin", "--list"}, {envs = {XMAKE_GLOBALDIR = md}}) + assert(not out:find("manual%-plugin", 1, true)) + + local ld = os.tmpfile() .. ".ld" + io.writefile(path.join(ld, "plugins", "hello-world", "xmake.lua"), [[ +task("hello-world") + set_category("plugin") + on_run("main") + set_menu {usage = "xmake hello-world"} +]]) + io.writefile(path.join(ld, "plugins", "hello-world", "main.lua"), [[ +function main() print("local-ok") end +]]) + out = os.iorunv(prog, {"hello-world"}, {envs = {XMAKE_GLOBALDIR = gd, XMAKE_MAIN_REPO = ld}}) + assert(out:find("local%-ok", 1, true)) + out = os.iorunv(prog, {"hello-world"}, {envs = {XMAKE_GLOBALDIR = gd}}) + assert(out:find("repo%-ok", 1, true)) + + os.tryrm(gd) + os.tryrm(md) + os.tryrm(ld) +end diff --git a/xmake/core/base/task.lua b/xmake/core/base/task.lua index a51b1dbb5..15258f8cc 100644 --- a/xmake/core/base/task.lua +++ b/xmake/core/base/task.lua @@ -81,9 +81,24 @@ 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")} + -- plugins from repositories cloned by `xrepo update-repo` + local reposdir = path.join(global.directory(), "repositories") + for _, dir in ipairs(os.dirs(path.join(reposdir, "*")) or {}) do + local plugindir = path.join(dir, "plugins") + if os.isdir(plugindir) then + table.insert(dirs, plugindir) + end + end + -- local checkout override (XMAKE_MAIN_REPO=/path/to/xmake-repo). + -- placed after the scanned repos so it takes precedence (table.join2 overwrites). + local repodir = os.getenv("XMAKE_MAIN_REPO") + if repodir and os.isdir(repodir) then + table.insert(dirs, path.join(repodir, "plugins")) + end + table.insert(dirs, path.join(os.programdir(), "plugins")) + table.insert(dirs, path.join(os.programdir(), "actions")) + return dirs end -- translate menu diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua index 46858b51b..7a919f9aa 100644 --- a/xmake/core/package/package.lua +++ b/xmake/core/package/package.lua @@ -585,7 +585,6 @@ end -- - toolchain (is also binary) -- - library(default) -- - template --- - plugin -- function _instance:kind() local kind @@ -625,13 +624,6 @@ function _instance:is_template() return self:kind() == "template" end --- is plugin package? --- --- @return true if the package kind is "plugin" --- -function _instance:is_plugin() - return self:kind() == "plugin" -end -- is header-only library? -- @@ -760,9 +752,7 @@ function _instance:is_host() if requireinfo and requireinfo.host then return true end - -- we only get the kind once, because this function will be called frequently. e.g. in plat()/arch() - local kind = self:kind() - return kind == "binary" or kind == "toolchain" or kind == "plugin" + return self:is_binary() end -- is cross-compilation? @@ -1715,10 +1705,6 @@ function _instance:buildhash() if label then str = str .. label end - -- we need to distinguish the install directories of the plugin and package with the same name - if self:is_plugin() then - str = str .. "plugin" - end if configs then -- with old vs_runtime configs @@ -2127,16 +2113,6 @@ function _instance:fetch(opt) is_system = true end end - elseif self:is_plugin() then - - -- we can only fetch the plugin package from the xmake repository - if system ~= true and not self:is_thirdparty() then - local manifest = self:manifest_load() - if manifest then - fetchinfo = {version = manifest.version or self:version_str()} - is_system = false - end - end else -- only fetch it from the xmake repository first diff --git a/xmake/modules/package/manager/xmake/search_package.lua b/xmake/modules/package/manager/xmake/search_package.lua index 04d69d135..32991ae3e 100644 --- a/xmake/modules/package/manager/xmake/search_package.lua +++ b/xmake/modules/package/manager/xmake/search_package.lua @@ -27,43 +27,31 @@ function _search_package(packages, name, opt) local packagename = packageinfo.name local packagedata = packageinfo.data - -- only search the packages with the given kind, e.g. plugin, - -- and we will ignore the plugin packages by default - local kind_matched - if opt.kind then - kind_matched = packagedata.kind == opt.kind - else - kind_matched = packagedata.kind ~= "plugin" - end - if kind_matched then - - local version - local versions = packagedata.versions - if versions then - versions = table.copy(versions) - table.sort(versions, function (a, b) return semver.compare(a, b) > 0 end) - if opt.require_version then - for _, ver in ipairs(versions) do - if semver.satisfies(ver, opt.require_version) then - version = ver - end + local version + local versions = packagedata.versions + if versions then + versions = table.copy(versions) + table.sort(versions, function (a, b) return semver.compare(a, b) > 0 end) + if opt.require_version then + for _, ver in ipairs(versions) do + if semver.satisfies(ver, opt.require_version) then + version = ver end - else - version = versions[1] end + else + version = versions[1] end + end - local description = packagedata.description - -- do not highlight the description if the pattern starts with a quantifier, e.g. `xrepo search -k plugin "*"` - if description and not name:startswith("*") and not name:startswith("+") then - description = description:gsub(string.ipattern(name), function (w) - return "${bright}" .. w .. "${clear}" - end) - end + local description = packagedata.description + if description then + description = description:gsub(string.ipattern(name), function (w) + return "${bright}" .. w .. "${clear}" + end) + end - if not opt.require_version or version then - packages[packagename] = {name = packagename, version = version, description = description, reponame = packagedata.reponame, kind = packagedata.kind} - end + if not opt.require_version or version then + packages[packagename] = {name = packagename, version = version, description = description, reponame = packagedata.reponame} end end end diff --git a/xmake/modules/private/action/require/impl/actions/install.lua b/xmake/modules/private/action/require/impl/actions/install.lua index 95f424a0f..82df01a84 100644 --- a/xmake/modules/private/action/require/impl/actions/install.lua +++ b/xmake/modules/private/action/require/impl/actions/install.lua @@ -32,7 +32,6 @@ import("private.action.require.impl.actions.test") import("private.action.require.impl.actions.patch_sources") import("private.action.require.impl.actions.download_resources") import("private.action.require.impl.utils.filter") -import("private.action.require.impl.utils.plugins") -- patch pkgconfig if not exists function _patch_pkgconfig(package) @@ -514,11 +513,6 @@ function main(package) end assert(fetchinfo, "fetch %s failed!", package_tipname) - -- register the plugin package to the global plugins directory, - -- we need to register it before testing, because the test script may run this plugin task. - if package:is_plugin() then - plugins.register(package) - end -- this package is installed now if installed_now then @@ -535,10 +529,6 @@ function main(package) test(package) end - -- the plugin has been registered and tested, we can discard the previous backup now - if package:is_plugin() then - plugins.confirm(package:name()) - end -- leave the package environments os.setenvs(oldenvs) @@ -569,10 +559,6 @@ function main(package) -- leave the package environments os.setenvs(oldenvs) - -- unregister the broken plugin package and restore the previous version - if package:is_plugin() then - plugins.rollback(package:name()) - end -- copy the invalid package directory to cache local installdir = package:installdir() diff --git a/xmake/modules/private/action/require/impl/package.lua b/xmake/modules/private/action/require/impl/package.lua index a3b58a0bd..3ad758c3a 100644 --- a/xmake/modules/private/action/require/impl/package.lua +++ b/xmake/modules/private/action/require/impl/package.lua @@ -949,7 +949,6 @@ function _load_package(packagename, requireinfo, opt) plat = requireinfo.plat, arch = requireinfo.arch, name = requireinfo.reponame, - kind = requireinfo.kind, locked_repo = locked_requireinfo and locked_requireinfo.repo}) if package then from_repo = true diff --git a/xmake/modules/private/action/require/impl/remove_packages.lua b/xmake/modules/private/action/require/impl/remove_packages.lua index dfe50c3a4..a10fc803d 100644 --- a/xmake/modules/private/action/require/impl/remove_packages.lua +++ b/xmake/modules/private/action/require/impl/remove_packages.lua @@ -23,7 +23,6 @@ import("core.base.option") import("core.base.hashset") import("core.package.package") import("core.cache.localcache") -import("private.action.require.impl.utils.plugins") -- get package configs string function _get_package_configs_str(manifest_file) @@ -95,12 +94,7 @@ function _remove_packagedirs(packagedir, opt) local description = string.format("remove ${color.dump.string}%s-%s${clear}/${yellow}%s${clear}\n -> ${dim}%s${clear} (${red}%s${clear})", package_name, version, hash, configs_str, status and status or "used") local confirm = utils.confirm({default = true, description = description}) if confirm then - local manifest = os.isfile(manifest_file) and io.load(manifest_file) os.rm(hashdir) - -- unregister the plugin package from the global plugins directory - if manifest and manifest.kind == "plugin" then - plugins.unregister(manifest.name or package_name) - end end end end diff --git a/xmake/modules/private/action/require/impl/repository.lua b/xmake/modules/private/action/require/impl/repository.lua index 4a546e091..bfec451a8 100644 --- a/xmake/modules/private/action/require/impl/repository.lua +++ b/xmake/modules/private/action/require/impl/repository.lua @@ -27,47 +27,9 @@ import("core.package.repository") import("devel.git") import("net.proxy") --- find the package directory in the given repository directory --- --- the layout of repository: --- --- packages/z/zlib/xmake.lua --- plugins/hello/xmake.lua --- plugins/h/hello/xmake.lua --- -function _find_packagedir(repodir, packagename, opt) - opt = opt or {} - local dirs = {path.join("packages", packagename:sub(1, 1), packagename)} - -- we only find the plugin directories if this repository has plugins, - -- it can avoid unnecessary filesystem access, because most repositories only have packages - local has_plugins = _g._HAS_PLUGINS - if has_plugins == nil then - has_plugins = {} - _g._HAS_PLUGINS = has_plugins - end - if has_plugins[repodir] == nil then - has_plugins[repodir] = os.isdir(path.join(repodir, "plugins")) - end - if has_plugins[repodir] then - local plugindirs = {path.join("plugins", packagename), - path.join("plugins", packagename:sub(1, 1), packagename)} - if opt.kind == "plugin" then - -- find it from the plugin directories first - dirs = table.join(plugindirs, dirs) - else - table.join2(dirs, plugindirs) - end - end - for _, dir in ipairs(dirs) do - dir = path.join(repodir, dir) - if os.isdir(dir) and os.isfile(path.join(dir, "xmake.lua")) then - return dir - end - end -end -- get package directory from the locked repository -function _get_packagedir_from_locked_repo(packagename, locked_repo, opt) +function _get_packagedir_from_locked_repo(packagename, locked_repo) -- find global repository directory local repo_global @@ -140,8 +102,8 @@ function _get_packagedir_from_locked_repo(packagename, locked_repo, opt) -- find package directory local foundir if ok then - local dir = _find_packagedir(repodir_local, packagename, opt) - if dir then + local dir = path.join(repodir_local, "packages", packagename:sub(1, 1), packagename) + if os.isdir(dir) and os.isfile(path.join(dir, "xmake.lua")) then local repo = repository.load(reponame, locked_repo.url, locked_repo.branch, false) foundir = {dir, repo} vprint("lock package(%s) in %s from repository(%s)/%s", packagename, dir, locked_repo.url, locked_repo.commit) @@ -202,11 +164,6 @@ function packagedir(packagename, opt) -- get cache key local reponame = opt.name local cachekey = packagename - if opt.kind then - -- use a separator that cannot appear in package names to avoid key collision, - -- e.g. package("helloplugin") and plugin("hello") - cachekey = cachekey .. "\0" .. opt.kind - end local locked_repo = opt.locked_repo if locked_repo then cachekey = cachekey .. locked_repo.url .. (locked_repo.commit or "") .. (locked_repo.branch or "") @@ -223,14 +180,14 @@ function packagedir(packagename, opt) -- find the package directory from the locked repository if locked_repo then - foundir = _get_packagedir_from_locked_repo(packagename, locked_repo, opt) + foundir = _get_packagedir_from_locked_repo(packagename, locked_repo) end -- find the package directory from repositories if not foundir then for _, repo in ipairs(repositories()) do - local dir = _find_packagedir(repo:directory(), packagename, opt) - if dir and (not reponame or reponame == repo:name()) then + local dir = path.join(repo:directory(), "packages", 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 end diff --git a/xmake/modules/private/action/require/impl/uninstall_packages.lua b/xmake/modules/private/action/require/impl/uninstall_packages.lua index f5434fb17..685b5c973 100644 --- a/xmake/modules/private/action/require/impl/uninstall_packages.lua +++ b/xmake/modules/private/action/require/impl/uninstall_packages.lua @@ -21,7 +21,6 @@ -- imports import("core.cache.localcache") import("private.action.require.impl.package") -import("private.action.require.impl.utils.plugins") -- uninstall packages -- uninstall required packages @@ -47,10 +46,6 @@ function main(requires, opt) table.insert(packages, instance) end os.tryrm(instance:installdir()) - -- unregister the plugin package from the global plugins directory - if instance:is_plugin() then - plugins.unregister(instance:name()) - end end return packages end diff --git a/xmake/modules/private/action/require/impl/utils/plugins.lua b/xmake/modules/private/action/require/impl/utils/plugins.lua deleted file mode 100644 index 1bcbe8bf5..000000000 --- a/xmake/modules/private/action/require/impl/utils/plugins.lua +++ /dev/null @@ -1,81 +0,0 @@ ---!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 plugins.lua --- - --- imports -import("core.base.global") - --- get the plugin directory of the given plugin package in the global plugins directory -function plugindir(name) - return path.join(global.directory(), "plugins", name) -end - --- register the given plugin package to the global plugins directory, --- then we can run it directly. e.g. `xmake plugin-name` -function register(package) - local installdir = package:installdir() - assert(os.isfile(path.join(installdir, "xmake.lua")), - "plugin(%s): xmake.lua not found in the installed files, it should be installed with `os.cp(\"*\", package:installdir())`!", package:name()) - local dir = plugindir(package:name()) - -- we copy it to the temporary directory first and then swap it, - -- so the previous plugin will not be lost if copying fails. e.g. disk full - -- - -- we cannot use the sibling directory, e.g. `plugins/<name>.tmp`, - -- because the task loader will load all plugins from `plugins/*/xmake.lua` - local tmpdir = path.join(path.directory(dir), ".tmp", package:name()) - os.tryrm(tmpdir) - os.cp(installdir, tmpdir) - -- remove the install logs, they do not belong to the plugin, - -- but we keep manifest.txt to show the plugin version and description. e.g. `xmake plugin --list` - os.tryrm(path.join(tmpdir, "logs")) - -- replace the previous plugin only after the new one is fully ready, - -- and we backup the previous plugin, it can be restored by `rollback()` if the installation fails later. e.g. test failure - local bakdir = tmpdir .. ".bak" - os.tryrm(bakdir) - if os.isdir(dir) then - os.mv(dir, bakdir) - end - os.mv(tmpdir, dir) - vprint("register plugin(%s) to %s", package:name(), dir) -end - --- confirm the registered plugin and discard the previous backup -function confirm(name) - os.tryrm(path.join(path.directory(plugindir(name)), ".tmp", name .. ".bak")) -end - --- rollback the registered plugin and restore the previous backup if the installation fails -function rollback(name) - local dir = plugindir(name) - local bakdir = path.join(path.directory(dir), ".tmp", name .. ".bak") - if os.isdir(bakdir) then - os.tryrm(dir) - os.mv(bakdir, dir) - vprint("restore the previous plugin(%s) to %s", name, dir) - end -end - --- unregister the given plugin from the global plugins directory -function unregister(name) - local dir = plugindir(name) - if os.isdir(dir) then - os.tryrm(dir) - vprint("unregister plugin(%s) from %s", name, dir) - end -end diff --git a/xmake/modules/private/action/require/search.lua b/xmake/modules/private/action/require/search.lua index 73a32b836..d839b92cb 100644 --- a/xmake/modules/private/action/require/search.lua +++ b/xmake/modules/private/action/require/search.lua @@ -20,7 +20,6 @@ -- 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") @@ -42,18 +41,6 @@ function main(names) task.run("repo", {update = true}) end - -- get the extra search options, e.g. --extra="{kind='plugin'}" - local opt = {} - local extra = option.get("extra") - if extra then - local extrainfo, errors = string.deserialize(extra) - if errors then - raise(errors) - end - if type(extrainfo) == "table" then - opt.kind = extrainfo.kind - end - end -- show title print("The package names:") @@ -71,10 +58,8 @@ function main(names) local version = result.version local reponame = result.reponame local description = result.description - local kind = result.kind - cprint(" -> ${color.dump.string}%s%s${clear}%s: %s %s", name, + cprint(" -> ${color.dump.string}%s%s${clear}: %s %s", name, version and ("-" .. version) or "", - kind == "plugin" and " ${magenta}(plugin)${clear}" or "", description or "", reponame and ("(in " .. reponame .. ")") or "") end diff --git a/xmake/modules/private/check/checkers/api/package/kind.lua b/xmake/modules/private/check/checkers/api/package/kind.lua index d2c7afd10..4a9c309e3 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" or value == "plugin" + return value == "binary" or value == "toolchain" or value == "template" end})) end diff --git a/xmake/modules/private/xrepo/action/install.lua b/xmake/modules/private/xrepo/action/install.lua index d235b7a98..b0d297b38 100644 --- a/xmake/modules/private/xrepo/action/install.lua +++ b/xmake/modules/private/xrepo/action/install.lua @@ -30,8 +30,8 @@ function menu_options() -- menu options local options = { - {'k', "kind", "kv", nil, "Enable static/shared library or install plugin package.", - values = {"static", "shared", "plugin"}}, + {'k', "kind", "kv", nil, "Enable static/shared library.", + values = {"static", "shared"} }, {'p', "plat", "kv", nil, "Set the given platform." }, {'a', "arch", "kv", nil, "Set the given architecture." }, {'m', "mode", "kv", nil, "Set the given mode.", @@ -47,10 +47,6 @@ 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, "repo", "kv", nil, "Set the given repository.", - "e.g.", - " - xrepo install --repo=my-repo zlib", - " - xrepo install -k plugin --repo=my-repo hello-world"}, {category = "Visual Studio SDK Configuration" }, {nil, "vs", "kv", nil, "The Microsoft Visual Studio" , " e.g. --vs=2017" }, @@ -97,7 +93,6 @@ function menu_options() " - xrepo install -p android [--ndk=/xxx] -m debug \"pcre2 10.x\"", " - xrepo install -p mingw [--mingw=/xxx] -k shared zlib", " - xrepo install conan::zlib/1.2.11 vcpkg::zlib", - " - xrepo install -k plugin hello-world", values = function (complete, opt) return import("private.xrepo.quick_search.completion")(complete, opt) end} } @@ -183,7 +178,7 @@ function _install_packages(packages) table.insert(config_argv, mode) end local kind = option.get("kind") - if kind and kind ~= "plugin" then + if kind then table.insert(config_argv, "-k") table.insert(config_argv, kind) end @@ -251,15 +246,7 @@ function _install_packages(packages) if #rcfiles > 0 then envs.XMAKE_RCFILES = path.joinenv(rcfiles) end - -- we can skip the repeated configuration and toolchain detection to speed up the plugin installation, - -- because the plugin package is host-only and does not depend on any build configuration. - -- we only skip it if no extra configuration arguments are given, e.g. `xrepo install -k plugin hello` - if kind == "plugin" and #config_argv == 3 - and os.isfile(path.join(workdir, ".xmake", os.host(), os.arch(), "xmake.conf")) then - vprint("skip the configuration for installing plugins") - else - os.vrunv(os.programfile(), config_argv, {envs = envs}) - end + os.vrunv(os.programfile(), config_argv, {envs = envs}) -- do install local require_argv = {"require"} @@ -298,9 +285,7 @@ function _install_packages(packages) if mode == "debug" then extra.debug = true end - if kind == "plugin" then - extra.kind = "plugin" - elseif kind then + if kind then extra.configs = extra.configs or {} extra.configs.shared = kind == "shared" end @@ -321,18 +306,6 @@ function _install_packages(packages) local extra_str = string.serialize(extra, {indent = false, strip = true}) table.insert(require_argv, "--extra=" .. extra_str) end - -- install the packages from the given repository, e.g. xrepo install --repo=my-repo zlib - local repo = option.get("repo") - if repo then - local result = {} - for _, name in ipairs(packages) do - if not name:find("@", 1, true) and not name:find("::", 1, true) then - name = repo .. "@" .. name - end - table.insert(result, name) - end - packages = result - end table.join2(require_argv, packages) end os.vexecv(os.programfile(), require_argv, {envs = envs}) diff --git a/xmake/modules/private/xrepo/action/remove.lua b/xmake/modules/private/xrepo/action/remove.lua index 989983955..ed92a83b8 100644 --- a/xmake/modules/private/xrepo/action/remove.lua +++ b/xmake/modules/private/xrepo/action/remove.lua @@ -31,8 +31,8 @@ function menu_options() -- menu options local options = { - {'k', "kind", "kv", nil, "Enable static/shared library or remove plugin package.", - values = {"static", "shared", "plugin"} }, + {'k', "kind", "kv", nil, "Enable static/shared library.", + values = {"static", "shared"} }, {'p', "plat", "kv", nil, "Set the given platform." }, {'a', "arch", "kv", nil, "Set the given architecture." }, {'m', "mode", "kv", nil, "Set the given mode.", @@ -56,8 +56,7 @@ function menu_options() " - xrepo remove -p iphoneos -a arm64 \"zlib >=1.2.0\"", " - xrepo remove -p android -m debug \"pcre2 10.x\"", " - xrepo remove -p mingw -k shared zlib", - " - xrepo remove conan::zlib/1.2.11 vcpkg::zlib", - " - xrepo remove -k plugin hello-world" } + " - xrepo remove conan::zlib/1.2.11 vcpkg::zlib" } } -- show menu options @@ -138,7 +137,7 @@ function _remove_packages(packages) table.insert(config_argv, mode) end local kind = option.get("kind") - if kind and kind ~= "plugin" then + if kind then table.insert(config_argv, "-k") table.insert(config_argv, kind) end @@ -152,15 +151,7 @@ function _remove_packages(packages) if #rcfiles > 0 then envs.XMAKE_RCFILES = path.joinenv(rcfiles) end - -- we can skip the repeated configuration and toolchain detection to speed up the plugin removal, - -- because the plugin package is host-only and does not depend on any build configuration. - -- we only skip it if no extra configuration arguments are given, e.g. `xrepo remove -k plugin hello` - if kind == "plugin" and #config_argv == 3 - and os.isfile(path.join(workdir, ".xmake", os.host(), os.arch(), "xmake.conf")) then - vprint("skip the configuration for removing plugins") - else - os.vrunv(os.programfile(), config_argv, {envs = envs}) - end + os.vrunv(os.programfile(), config_argv, {envs = envs}) -- do remove local require_argv = {"require", "--uninstall"} @@ -177,9 +168,7 @@ function _remove_packages(packages) if mode == "debug" then extra.debug = true end - if kind == "plugin" then - extra.kind = "plugin" - elseif kind then + if kind then extra.configs = extra.configs or {} extra.configs.shared = kind == "shared" end diff --git a/xmake/modules/private/xrepo/action/search.lua b/xmake/modules/private/xrepo/action/search.lua index ff379c5db..d389e3833 100644 --- a/xmake/modules/private/xrepo/action/search.lua +++ b/xmake/modules/private/xrepo/action/search.lua @@ -30,14 +30,10 @@ function menu_options() -- menu options local options = { - {'k', "kind", "kv", nil, "Set the package kind to be searched.", - values = {"plugin"} }, {nil, "packages", "vs", nil, "The packages list (support lua pattern).", "e.g.", " - xrepo search zlib boost", - " - xrepo search \"pcre*\"", - " - xrepo search -k plugin", - " - xrepo search -k plugin hello-world"} + " - xrepo search \"pcre*\""} } -- show menu options @@ -84,11 +80,6 @@ function _search_packages(packages) if option.get("diagnosis") then table.insert(require_argv, "-D") end - local kind = option.get("kind") - if kind then - local extra_str = string.serialize({kind = kind}, {indent = false, strip = true}) - table.insert(require_argv, "--extra=" .. extra_str) - end table.join2(require_argv, packages) os.vexecv(os.programfile(), require_argv) end @@ -96,10 +87,6 @@ end -- main entry function main() local packages = option.get("packages") - if not packages and option.get("kind") then - -- list all packages with the given kind, e.g. xrepo search -k plugin - packages = {"*"} - end if packages then _search_packages(packages) else diff --git a/xmake/modules/private/xrepo/quick_search/cache.lua b/xmake/modules/private/xrepo/quick_search/cache.lua index 8edfce584..cf75a212d 100644 --- a/xmake/modules/private/xrepo/quick_search/cache.lua +++ b/xmake/modules/private/xrepo/quick_search/cache.lua @@ -36,23 +36,9 @@ function _list_package_dirs() 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["package\0" .. packagename] then + if not unique[packagename] then table.insert(packageinfos, {name = packagename, repo = repo, packagedir = dir}) - unique["package\0" .. packagename] = true - end - end - end - -- find the plugin package directories, e.g. plugins/hello/xmake.lua, plugins/h/hello/xmake.lua - -- the plugin and package can share the same name, so we should not dedupe them with each other - for _, file in ipairs(table.join(os.files(path.join(repo:directory(), "plugins", "*", "xmake.lua")), - os.files(path.join(repo:directory(), "plugins", "*", "*", "xmake.lua")))) do - local dir = path.directory(file) - local subdirname = path.basename(path.directory(dir)) - if subdirname == "plugins" or #subdirname == 1 then - local packagename = path.filename(dir) - if not unique["plugin\0" .. packagename] then - table.insert(packageinfos, {name = packagename, repo = repo, packagedir = dir}) - unique["plugin\0" .. packagename] = true + unique[packagename] = true end end end @@ -71,12 +57,10 @@ 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}) - -- we add the kind to the cache key to avoid the key collision between the plugin and package with the same name - cache:set(packageinfo.name .. "\0" .. (package:kind() or "library"), { + cache:set(packageinfo.name, { reponame = package:repo() and package:repo():name(), description = package:description(), versions = package:versions(), - kind = package:kind(), }) end cache:save() @@ -99,10 +83,7 @@ function find(name, opt) _init() opt = opt or {} local list_result = {} - for key, packagedata in pairs(cache:data()) do - -- strip the kind from the cache key, e.g. `zlib\0library` - -- and it is also compatible with the old cache data without the kind - local packagename = key:split("\0", {plain = true})[1] + for packagename, packagedata in pairs(cache:data()) do local found = false if opt.prefix then found = packagename:startswith(name) diff --git a/xmake/modules/private/xrepo/quick_search/completion.lua b/xmake/modules/private/xrepo/quick_search/completion.lua index a78ec2817..449a988ea 100644 --- a/xmake/modules/private/xrepo/quick_search/completion.lua +++ b/xmake/modules/private/xrepo/quick_search/completion.lua @@ -22,15 +22,10 @@ import("private.xrepo.quick_search.cache") -- complete xrepo packages function _xmake_package_complete(complete, opt) - local unique = {} local candidates = {} local found = cache.find(complete, {prefix = true}) for _, candidate in ipairs(found) do - -- the plugin and package can share the same name, we need to remove the duplicates - if not unique[candidate.name] then - table.insert(candidates, {value = candidate.name, description = candidate.data.description}) - unique[candidate.name] = true - end + table.insert(candidates, {value = candidate.name, description = candidate.data.description}) end return candidates end diff --git a/xmake/plugins/plugin/main.lua b/xmake/plugins/plugin/main.lua index e12a433e2..276508396 100644 --- a/xmake/plugins/plugin/main.lua +++ b/xmake/plugins/plugin/main.lua @@ -62,42 +62,19 @@ end function _save_manifest(manifest) io.save(_manifest_path(), manifest) end - --- is the plugin package name? e.g. hello-world, myrepo@hello-world --- --- the plugin url is the git url or local path, e.g. --- https://github.com/xmake-io/xmake-plugins, [email protected]:xmake-io/xmake-plugins.git, /tmp/xmake-plugins -function _is_package_name(str) - return not os.isdir(str) and not str:find("[/\\:]") +-- install the plugin by name from the repository. +-- Repository plugins are loaded directly from the checkout; +-- ensure the repository is up to date with `xrepo update-repo`. +function _install_name(name) + print("plugin %s will be loaded from the repository after xrepo update-repo.", name) end - --- install the plugin package from repositories, e.g. xmake plugin --install hello-world -function _install_package(name, opt) - opt = opt or {} - local argv = {"lua", "private.xrepo", "install", "--kind=plugin"} - if opt.force then - table.insert(argv, "--force") - end - if option.get("yes") then - table.insert(argv, "-y") - end - if option.get("verbose") then - table.insert(argv, "-v") - end - if option.get("diagnosis") then - table.insert(argv, "-D") - end - table.insert(argv, name) - os.execv(os.programfile(), argv) -end - -- install plugins function _install() - -- install the plugin package from repositories? + -- install the plugin by name from the repository? local name = option.get("plugins") - if name and _is_package_name(name) then - return _install_package(name) + if name and not os.isdir(name) and not name:find("[/\\:]") then + return _install_name(name) end -- enter environment @@ -151,13 +128,6 @@ end -- update plugins function _update() - - -- update the plugin package from repositories? e.g. xmake plugin --update hello-world - local name = option.get("plugins") - if name and _is_package_name(name) then - return _install_package(name, {force = true}) - end - -- enter environment environment.enter() @@ -198,11 +168,9 @@ function _update() environment.leave() end --- remove the given installed plugin +-- remove the given installed plugin (from ~/.xmake/plugins/) function _remove() local name = assert(option.get("plugins"), "please specify the plugin name to be removed!") - -- avoid escaping the plugins directory, e.g. `xmake plugin --remove ../foo`, - -- and `.` or the empty name will be resolved to the plugins directory itself assert(name ~= "" and name ~= "." and not name:find("..", 1, true) and not name:find("[/\\:]"), "invalid plugin name(%s)!", name) local plugindir = path.join(global.directory(), "plugins", name) assert(os.isdir(plugindir), "plugin(%s) not found!", name) @@ -210,24 +178,63 @@ function _remove() cprint("${color.success}remove plugin(%s) ok!", name) end --- list all installed plugins +-- list all installed plugins (manual + repository) function _list() + local seen = {} + -- manually installed plugins local plugindir = path.join(global.directory(), "plugins") cprint("plugins in ${bright}%s${clear}:", plugindir) - for _, dir in ipairs(os.dirs(path.join(plugindir, "*"))) do + local found = false + for _, dir in ipairs(os.dirs(path.join(plugindir, "*")) or {}) do if os.isfile(path.join(dir, "xmake.lua")) then - local version, description - local manifest_file = path.join(dir, "manifest.txt") - if os.isfile(manifest_file) then - local manifest = io.load(manifest_file) - if manifest then - version = manifest.version - description = manifest.description + local name = path.filename(dir) + seen[name] = true + found = true + cprint(" ${color.dump.string}%s${clear}", name) + end + end + if not found then + print(" (none)") + end + + -- repository plugins (from scanned repos) + local reposdir = path.join(global.directory(), "repositories") + for _, dir in ipairs(os.dirs(path.join(reposdir, "*")) or {}) do + local rplugindir = path.join(dir, "plugins") + if os.isdir(rplugindir) then + local reponame = path.filename(dir) + cprint("plugins in repository ${bright}%s${clear}:", reponame) + local repofound = false + for _, subdir in ipairs(os.dirs(path.join(rplugindir, "*")) or {}) do + if os.isfile(path.join(subdir, "xmake.lua")) and not seen[path.filename(subdir)] then + seen[path.filename(subdir)] = true + repofound = true + cprint(" ${color.dump.string}%s${clear}", path.filename(subdir)) + end + end + if not repofound then + print(" (none)") + end + end + end + + -- local checkout plugins + local repodir = os.getenv("XMAKE_MAIN_REPO") + if repodir and os.isdir(repodir) then + local rplugindir = path.join(repodir, "plugins") + if os.isdir(rplugindir) then + cprint("plugins in ${bright}XMAKE_MAIN_REPO${clear}:") + local repofound = false + for _, subdir in ipairs(os.dirs(path.join(rplugindir, "*")) or {}) do + if os.isfile(path.join(subdir, "xmake.lua")) and not seen[path.filename(subdir)] then + seen[path.filename(subdir)] = true + repofound = true + cprint(" ${color.dump.string}%s${clear}", path.filename(subdir)) end end - cprint(" ${color.dump.string}%s${clear}%s: %s", path.filename(dir), - version and ("-" .. version) or "", - description or "") + if not repofound then + print(" (none)") + end end end end @@ -254,4 +261,3 @@ function main() _clear() end end - diff --git a/xmake/plugins/plugin/xmake.lua b/xmake/plugins/plugin/xmake.lua index b61dd05f9..87d85e81d 100644 --- a/xmake/plugins/plugin/xmake.lua +++ b/xmake/plugins/plugin/xmake.lua @@ -36,7 +36,6 @@ task("plugin") " $ xmake plugin --install hello-world", " $ xmake plugin --remove hello-world", " $ xmake plugin --list", - " $ xmake plugin --update", - " $ xmake plugin --update hello-world"} + " $ xmake plugin --update"} } } diff --git a/xmake/plugins/xfetch/main.lua b/xmake/plugins/xfetch/main.lua deleted file mode 100644 index 357219486..000000000 --- a/xmake/plugins/xfetch/main.lua +++ /dev/null @@ -1,289 +0,0 @@ ---!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 main.lua --- - --- imports -import("core.base.option") -import("core.base.global") -import("core.package.package", {alias = "core_package"}) - --- the small ascii logos for the known systems, like fastfetch -local logos = { - xmake = {color = "green", lines = { - [[ _ ]], - [[__ ___ __ __ __ _| | ______]], - [[\ \/ / | \/ |/ _ | |/ / __ \]], - [[ > < | \__/ | /_| | < ___/]], - [[/_/\_\_|_| |_|\__ \|_|\_\____|]]}}, - linux = {color = "yellow", lines = { - [[ .--.]], - [[ |o_o |]], - [[ |:_/ |]], - [[ // \ \]], - [[ (| | )]], - [[/'\_ _/`\]], - [[\___)=(___/]]}}, - windows = {color = "blue", lines = { - [[ ______ ______]], - [[| | |]], - [[|______|______|]], - [[| | |]], - [[|______|______|]]}}, - macosx = {color = "white", lines = { - [[ .:']], - [[ _ :'_]], - [[ .'`_`-'_``.]], - [[:________.-']], - [[:_______:]], - [[ :_______`-;]], - [[ `._.-._.']]}}, - bsd = {color = "red", lines = { - [[/\,-'''''-,/\]], - [[\_) (_/]], - [[| |]], - [[| |]], - [[ ; ;]], - [[ '-_____-']]}}, - archlinux = {color = "cyan", lines = { - [[ /\]], - [[ / \]], - [[ /\ \]], - [[ / \]], - [[ / ,, \]], - [[ / | | -\]], - [[/_-'' ''-_\]]}}, - ubuntu = {color = "red", lines = { - [[ _]], - [[ ---(_)]], - [[ _/ --- \]], - [[(_) | |]], - [[ \ --- _/]], - [[ ---(_)]]}}, - debian = {color = "red", lines = { - [[ _____]], - [[ / __ \]], - [[| / |]], - [[| \___-]], - [[-_]], - [[ --_]]}}, - fedora = {color = "blue", lines = { - [[ _____]], - [[ / __)\]], - [[ | / \ \]], - [[ ___| |__/ /]], - [[ / (_ _)_/]], - [[/ / | |]], - [[\ \__/ |]], - [[ \(_____/]]}}, - centos = {color = "yellow", lines = { - [[ ____^____]], - [[ |\ | /|]], - [[ | \ | / |]], - [[<---- ---->]], - [[ | / | \ |]], - [[ |/__|__\|]], - [[ v]]}}, - linuxmint = {color = "green", lines = { - [[ ___________]], - [[|_ \]], - [[ | | _____ |]], - [[ | | | | | |]], - [[ | | | | | |]], - [[ | \_____/ |]], - [[ \_________/]]}}, - gentoo = {color = "magenta", lines = { - [[ _-----_]], - [[( \]], - [[\ 0 \]], - [[ \ )]], - [[ / _/]], - [[( _-]], - [[\____-]]}}, - opensuse = {color = "green", lines = { - [[ _______]], - [[__| __ \]], - [[ / .\ \]], - [[ \__/ |]], - [[ _______|]], - [[ \_______]], - [[__________/]]}}, - manjaro = {color = "green", lines = { - [[||||||||| ||||]], - [[||||||||| ||||]], - [[|||| ||||]], - [[|||| |||| ||||]], - [[|||| |||| ||||]], - [[|||| |||| ||||]], - [[|||| |||| ||||]]}}, - nixos = {color = "blue", lines = { - [[ \\ \\ //]], - [[ ==\\__\\/ //]], - [[ // \\//]], - [[==// //==]], - [[ //\\___//]], - [[// /\\ \\==]], - [[ // \\ \\]]}}, - alpine = {color = "blue", lines = { - [[ /\ /\]], - [[ / \ \]], - [[ / \ \]], - [[/ \ \]], - [[ \ \]], - [[ \]]}} -} --- get the logo of the current system -function _get_logo() - local name = option.get("logo") - if not name then - -- os.host() is always the real host system, e.g. windows, linux, macosx .. - -- even if we are running in the msys/cygwin subsystem, @see os.subhost() - name = os.host() - if name == "linux" then - name = linuxos.name() - end - end - -- we will show the linux or xmake logo if the logo drawing is not found - local logo = logos[name] - if not logo then - logo = os.host() == "linux" and logos.linux or logos.xmake - end - return logo -end - --- get the user and host name -function _get_title() - local user = os.getenv("USER") or os.getenv("USERNAME") or "user" - local host = os.getenv("HOSTNAME") or os.getenv("COMPUTERNAME") - if not host and is_host("linux", "macosx", "bsd") and os.isfile("/etc/hostname") then - local content = io.readfile("/etc/hostname") - if content then - host = content:trim() - end - end - return user .. "@" .. (host or os.host()) -end - --- get the operation system name and version -function _get_os() - if is_host("linux") then - -- the system version may be unavailable on the rolling release distributions - local version = try { function () return linuxos.version() end } - return linuxos.name() .. (version and (" " .. tostring(version)) or "") .. " " .. os.arch() - elseif is_host("macosx") then - local version = try { function () return macos.version() end } - return "macOS" .. (version and (" " .. tostring(version)) or "") .. " " .. os.arch() - elseif is_host("windows") then - local version = try { function () return winos.version() end } - return "Windows" .. (version and (" " .. tostring(version)) or "") .. " " .. os.arch() - end - return os.host() .. " " .. os.arch() -end - --- get the cpu name -function _get_cpu() - local name = os.cpuinfo("model_name") or os.cpuinfo("vendor") or "unknown" - return string.format("%s (%d)", name, os.cpuinfo("ncpu") or 1) -end - --- format the given size in MB as GiB, we do not use `%.1f` to avoid the locale decimal separator -function _format_gib(size_mb) - local gib10 = math.floor(size_mb / 1024 * 10 + 0.5) - return string.format("%d.%d GiB", math.floor(gib10 / 10), gib10 % 10) -end - --- get the memory usage, the sizes of os.meminfo() are in MB -function _get_memory() - local meminfo = os.meminfo() - if meminfo.totalsize and meminfo.availsize then - -- `%%%%` will be shown as `%`, because cprint will format this string again - return string.format("%s / %s (%d%%%%)", - _format_gib(meminfo.totalsize - meminfo.availsize), - _format_gib(meminfo.totalsize), - math.floor(meminfo.usagerate * 100)) - end -end - --- get the count of the installed packages -function _get_packages() - local count = #os.dirs(path.join(core_package.installdir(), "*", "*")) - return string.format("%d (xrepo)", count) -end - --- get the count of the installed plugins -function _get_plugins() - return tostring(#os.files(path.join(global.directory(), "plugins", "*", "xmake.lua"))) -end - --- get all the information lines -function _get_infolines(color) - local title = _get_title() - local infos = { - {"OS", _get_os()}, - {"CPU", _get_cpu()}, - {"Memory", _get_memory()}, - {"Shell", os.shell()}, - {"Terminal", os.term()}, - {"xmake", "v" .. xmake.version()}, - {"Packages", _get_packages()}, - {"Plugins", _get_plugins()}, - {"Theme", global.get("theme") or "default"} - } - if is_host("linux") then - local kernelver = try { function () return linuxos.kernelver() end } - if kernelver then - table.insert(infos, 2, {"Kernel", tostring(kernelver)}) - end - end - local lines = {} - table.insert(lines, "${bright " .. color .. "}" .. title .. "${clear}") - table.insert(lines, string.rep("-", #title)) - for _, info in ipairs(infos) do - if info[2] then - table.insert(lines, "${bright " .. color .. "}" .. info[1] .. "${clear}: " .. info[2]) - end - end - table.insert(lines, "") - table.insert(lines, "${onblack} ${onred} ${ongreen} ${onyellow} ${onblue} ${onmagenta} ${oncyan} ${onwhite} ${clear}") - return lines -end - -function main() - local logo = _get_logo() - local logolines = logo.lines - local infolines = _get_infolines(logo.color) - -- show the logo and information side by side, like fastfetch - local width = 0 - for _, line in ipairs(logolines) do - width = math.max(width, #line) - end - local startline = 1 - if #infolines > #logolines then - startline = math.floor((#infolines - #logolines) / 2) + 1 - end - print("") - for i = 1, math.max(#logolines, #infolines) do - local left = logolines[i - startline + 1] or "" - local right = infolines[i] or "" - left = left .. string.rep(" ", width - #left) - -- escape `%`, because cprint will format this string again - left = left:gsub("%%", "%%%%") - cprint(" ${bright %s}%s${clear} %s", logo.color, left, right) - end - print("") -end diff --git a/xmake/plugins/xfetch/xmake.lua b/xmake/plugins/xfetch/xmake.lua deleted file mode 100644 index a3296d233..000000000 --- a/xmake/plugins/xfetch/xmake.lua +++ /dev/null @@ -1,32 +0,0 @@ ---!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 xmake.lua --- - -task("xfetch") - set_category("plugin") - on_run("main") - set_menu { - usage = "xmake xfetch [options]", - description = "Fetch and show the system and xmake information.", - options = { - {'l', "logo", "kv", nil, "Show the given logo.", - "e.g.", - " $ xmake xfetch --logo=archlinux"} - } - } |
