From 6a024e442cf6e3a1fe55ab63b3385be592bb1e1e Mon Sep 17 00:00:00 2001 From: ruki Date: Sat, 8 Aug 2026 18:34:44 +0800 Subject: move addon as action --- xmake/actions/addon/main.lua | 274 ++++++++++++++++++++++++++++++++++++++++++ xmake/actions/addon/xmake.lua | 43 +++++++ xmake/plugins/addon/main.lua | 274 ------------------------------------------ xmake/plugins/addon/xmake.lua | 43 ------- 4 files changed, 317 insertions(+), 317 deletions(-) create mode 100644 xmake/actions/addon/main.lua create mode 100644 xmake/actions/addon/xmake.lua delete mode 100644 xmake/plugins/addon/main.lua delete mode 100644 xmake/plugins/addon/xmake.lua diff --git a/xmake/actions/addon/main.lua b/xmake/actions/addon/main.lua new file mode 100644 index 000000000..d072cec7f --- /dev/null +++ b/xmake/actions/addon/main.lua @@ -0,0 +1,274 @@ +--!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.package.addon") +import("core.package.repository") +import("devel.git") +import("private.action.require.impl.environment") + +-- the version directory name for the addons installed from git urls or local directories +local LOCALVERSION = "latest" + +-- validate an addon directory name +function _check_addon_name(name) + assert(type(name) == "string" and name ~= "" and name ~= "." and not name:find("..", 1, true) and not name:find("[/\\:]"), "invalid addon name(%s)!", name) + return name +end + +-- get addon directory in ~/.xmake/addons +function _get_addondir(name, version) + local addondir = addon.installdir() + if name then + addondir = path.join(addondir, addon.dirname(_check_addon_name(name))) + if version then + addondir = path.join(addondir, version) + end + end + return addondir +end + +-- get local and global repositories, with local taking precedence +function _repositories() + return table.join(repository.repositories({global = false}), repository.repositories({global = true})) +end + +-- install an addon from the given repository or the first repository containing it +function _install_from_repo(name, reponame) + + -- check addon name + _check_addon_name(name) + + -- do install + local installname = name + if reponame then + installname = reponame .. "@" .. name + end + local argv = {"lua", "private.xrepo", "install", "--addon"} + -- 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 + if option.get("diagnosis") then + table.insert(argv, "-D") + end + table.insert(argv, installname) + os.execv(os.programfile(), argv) +end + +-- install a single addon from a source directory (as the given name, default to the directory name) +function _install_from_local(dir, name) + assert(os.isdir(dir), "addon path(%s) not found!", dir) + assert(#addon.payloads_of(dir) > 0, "addon path(%s): no payload directory found, e.g. ${bright}plugins${clear}!", dir) + name = name or path.filename(path.absolute(dir)) + local dstdir = _get_addondir(name, LOCALVERSION) + assert(not os.isdir(dstdir), "addon(%s) already exists!", name) + os.vcp(dir, dstdir) + addon.register(name, LOCALVERSION) + cprint("${color.success}install ${bright}%s${clear} ok!", name) +end + +-- install a single addon from a git url or github shortcut, e.g. https://github.com/xmake-addons/serial-monitor +function _install_from_git(url) + local branch + if url:startswith("github:") then + local i = url:find("#", 1, true) + if i then + branch = url:sub(i + 1) + url = url:sub(1, i - 1) + end + url = git.asgiturl(url) + end + local name = (path.filename(url):gsub("%.git$", "")) + local tmpdir = os.tmpfile() .. ".dir" + git.clone(url, {verbose = option.get("verbose"), branch = branch, outputdir = tmpdir}) + os.tryrm(path.join(tmpdir, ".git")) + _install_from_local(tmpdir, name) + os.tryrm(tmpdir) +end + +-- install a single addon +function _install_one(name) + -- parse repo@addon format + local i = name:find("@", 1, true) + if i and not name:find("[/\\:]") then + local reponame = name:sub(1, i - 1) + local addonname = name:sub(i + 1) + _install_from_repo(addonname, reponame) + return + end + + -- github shortcut: github:user/repo or github:user/repo#branch + if name:startswith("github:") then + _install_from_git(name) + return + end + + -- git url or local path + if git.asgiturl(name) then + _install_from_git(name) + return + elseif os.isdir(name) then + _install_from_local(name) + return + end + + -- plain name: try to find it in repositories + _install_from_repo(name) +end + +-- install addons +function _install() + local names = assert(option.get("addons"), "please specify the addons to be installed!") + environment.enter() + for _, name in ipairs(names) do + _install_one(name) + end + environment.leave() +end + +-- remove the given installed addon +function _remove() + local names = assert(option.get("addons"), "please specify the addon name to be removed!") + assert(#names == 1, "please specify only one addon name to be removed!") + local name = names[1] + local dir = _get_addondir(name) + assert(os.isdir(dir), "addon(%s) not found!", name) + os.rmdir(dir) + addon.unregister(name) + cprint("${color.success}remove ${bright}%s${clear} ok!", name) +end + +-- get the description of an addon from its package description file +function _addon_description(dir) + local filepath = path.join(dir, "xmake.lua") + if os.isfile(filepath) then + local content = io.readfile(filepath) + if content then + return content:match("set_description%s*%(\"(.-)\"%)") + end + end +end + +-- collect the installed addons from the addons registry +-- +-- we always rescan the install directory here to repair the registry, +-- e.g. the user may remove some addon directories manually +-- +function _collect_installed_addons() + local entries = {} + for name, addoninfo in pairs(addon.rescan()) do + table.insert(entries, {name = name, version = addoninfo.version, payloads = addoninfo.payloads}) + end + table.sort(entries, function (a, b) return a.name < b.name end) + return entries +end + +-- collect the addons in the given repository, they follow the packages layout (addons//) +function _collect_repo_addons(root, seen) + local entries = {} + for _, dir in ipairs(os.dirs(path.join(root, "*", "*"))) do + local name = path.filename(dir) + if os.isfile(path.join(dir, "xmake.lua")) and not seen[name] then + seen[name] = true + table.insert(entries, {name = name, description = _addon_description(dir)}) + end + end + return entries +end + +-- print an addon entry with its description aligned on the right +function _print_addon(name, description, width, note) + local suffix = description or "" + if note then + suffix = suffix ~= "" and (suffix .. " " .. note) or note + end + if suffix ~= "" then + local padding = math.max(width - #name, 1) + cprint(" ${color.dump.string}%s${clear}%s%s", name, (" "):rep(padding), suffix) + else + cprint(" ${color.dump.string}%s${clear}", name) + end +end + +-- list all addons +function _list() + local seen = {} + local installed = _collect_installed_addons() + for _, entry in ipairs(installed) do + seen[entry.name] = true + end + local avail = {} + for _, repo in ipairs(_repositories()) do + table.join2(avail, _collect_repo_addons(path.join(repo:directory(), "addons"), seen)) + end + + -- compute the alignment width from all addon names + local width = 0 + for _, entries in ipairs({installed, avail}) do + for _, entry in ipairs(entries) do + width = math.max(width, #entry.name + 4) + end + end + + -- installed addons + cprint("${bright}the installed addons:${clear}") + if #installed > 0 then + for _, entry in ipairs(installed) do + local note = string.format("(%s, %s)", entry.version, table.concat(entry.payloads, ", ")) + _print_addon(entry.name, nil, width, note) + end + else + print(" (none)") + end + + -- addons available in repositories (not yet installed) + cprint("${bright}available in configured repositories:${clear}") + if #avail > 0 then + for _, entry in ipairs(avail) do + local note = string.format("(run xmake addon --install %s to install)", entry.name) + _print_addon(entry.name, entry.description, width, note) + end + else + print(" (none)") + end +end + +-- clear all installed addons +function _clear() + addon.clear() + cprint("${color.success}clear all installed addons ok!") +end + +function main() + if option.get("install") then + _install() + elseif option.get("remove") then + _remove() + elseif option.get("list") then + _list() + elseif option.get("clear") then + _clear() + end +end diff --git a/xmake/actions/addon/xmake.lua b/xmake/actions/addon/xmake.lua new file mode 100644 index 000000000..8394c110b --- /dev/null +++ b/xmake/actions/addon/xmake.lua @@ -0,0 +1,43 @@ +--!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("addon") + set_category("action") + on_run("main") + set_menu { + usage = "xmake addon [options]", + description = "Manage addons of xmake.", + options = { + {'i', "install", "k", nil, "Install addons."}, + {'r', "remove", "k", nil, "Remove the given installed addon."}, + {'l', "list", "k", nil, "List all installed addons."}, + {'c', "clear", "k", nil, "Clear all installed addons."}, + {nil, "addons", "vs", nil, "The addon paths, urls or names.", + "e.g.", + " $ xmake addon --install https://github.com/myrepo/serial-monitor", + " $ xmake addon --install github:myrepo/serial-monitor", + " $ xmake addon --install github:myrepo/serial-monitor#dev", + " $ xmake addon --install /tmp/my-addon", + " $ xmake addon --install xmake-repo@serial-monitor", + " $ xmake addon --install serial-monitor", + " $ xmake addon --remove serial-monitor", + " $ xmake addon --list"} + } + } diff --git a/xmake/plugins/addon/main.lua b/xmake/plugins/addon/main.lua deleted file mode 100644 index d072cec7f..000000000 --- a/xmake/plugins/addon/main.lua +++ /dev/null @@ -1,274 +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.package.addon") -import("core.package.repository") -import("devel.git") -import("private.action.require.impl.environment") - --- the version directory name for the addons installed from git urls or local directories -local LOCALVERSION = "latest" - --- validate an addon directory name -function _check_addon_name(name) - assert(type(name) == "string" and name ~= "" and name ~= "." and not name:find("..", 1, true) and not name:find("[/\\:]"), "invalid addon name(%s)!", name) - return name -end - --- get addon directory in ~/.xmake/addons -function _get_addondir(name, version) - local addondir = addon.installdir() - if name then - addondir = path.join(addondir, addon.dirname(_check_addon_name(name))) - if version then - addondir = path.join(addondir, version) - end - end - return addondir -end - --- get local and global repositories, with local taking precedence -function _repositories() - return table.join(repository.repositories({global = false}), repository.repositories({global = true})) -end - --- install an addon from the given repository or the first repository containing it -function _install_from_repo(name, reponame) - - -- check addon name - _check_addon_name(name) - - -- do install - local installname = name - if reponame then - installname = reponame .. "@" .. name - end - local argv = {"lua", "private.xrepo", "install", "--addon"} - -- 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 - if option.get("diagnosis") then - table.insert(argv, "-D") - end - table.insert(argv, installname) - os.execv(os.programfile(), argv) -end - --- install a single addon from a source directory (as the given name, default to the directory name) -function _install_from_local(dir, name) - assert(os.isdir(dir), "addon path(%s) not found!", dir) - assert(#addon.payloads_of(dir) > 0, "addon path(%s): no payload directory found, e.g. ${bright}plugins${clear}!", dir) - name = name or path.filename(path.absolute(dir)) - local dstdir = _get_addondir(name, LOCALVERSION) - assert(not os.isdir(dstdir), "addon(%s) already exists!", name) - os.vcp(dir, dstdir) - addon.register(name, LOCALVERSION) - cprint("${color.success}install ${bright}%s${clear} ok!", name) -end - --- install a single addon from a git url or github shortcut, e.g. https://github.com/xmake-addons/serial-monitor -function _install_from_git(url) - local branch - if url:startswith("github:") then - local i = url:find("#", 1, true) - if i then - branch = url:sub(i + 1) - url = url:sub(1, i - 1) - end - url = git.asgiturl(url) - end - local name = (path.filename(url):gsub("%.git$", "")) - local tmpdir = os.tmpfile() .. ".dir" - git.clone(url, {verbose = option.get("verbose"), branch = branch, outputdir = tmpdir}) - os.tryrm(path.join(tmpdir, ".git")) - _install_from_local(tmpdir, name) - os.tryrm(tmpdir) -end - --- install a single addon -function _install_one(name) - -- parse repo@addon format - local i = name:find("@", 1, true) - if i and not name:find("[/\\:]") then - local reponame = name:sub(1, i - 1) - local addonname = name:sub(i + 1) - _install_from_repo(addonname, reponame) - return - end - - -- github shortcut: github:user/repo or github:user/repo#branch - if name:startswith("github:") then - _install_from_git(name) - return - end - - -- git url or local path - if git.asgiturl(name) then - _install_from_git(name) - return - elseif os.isdir(name) then - _install_from_local(name) - return - end - - -- plain name: try to find it in repositories - _install_from_repo(name) -end - --- install addons -function _install() - local names = assert(option.get("addons"), "please specify the addons to be installed!") - environment.enter() - for _, name in ipairs(names) do - _install_one(name) - end - environment.leave() -end - --- remove the given installed addon -function _remove() - local names = assert(option.get("addons"), "please specify the addon name to be removed!") - assert(#names == 1, "please specify only one addon name to be removed!") - local name = names[1] - local dir = _get_addondir(name) - assert(os.isdir(dir), "addon(%s) not found!", name) - os.rmdir(dir) - addon.unregister(name) - cprint("${color.success}remove ${bright}%s${clear} ok!", name) -end - --- get the description of an addon from its package description file -function _addon_description(dir) - local filepath = path.join(dir, "xmake.lua") - if os.isfile(filepath) then - local content = io.readfile(filepath) - if content then - return content:match("set_description%s*%(\"(.-)\"%)") - end - end -end - --- collect the installed addons from the addons registry --- --- we always rescan the install directory here to repair the registry, --- e.g. the user may remove some addon directories manually --- -function _collect_installed_addons() - local entries = {} - for name, addoninfo in pairs(addon.rescan()) do - table.insert(entries, {name = name, version = addoninfo.version, payloads = addoninfo.payloads}) - end - table.sort(entries, function (a, b) return a.name < b.name end) - return entries -end - --- collect the addons in the given repository, they follow the packages layout (addons//) -function _collect_repo_addons(root, seen) - local entries = {} - for _, dir in ipairs(os.dirs(path.join(root, "*", "*"))) do - local name = path.filename(dir) - if os.isfile(path.join(dir, "xmake.lua")) and not seen[name] then - seen[name] = true - table.insert(entries, {name = name, description = _addon_description(dir)}) - end - end - return entries -end - --- print an addon entry with its description aligned on the right -function _print_addon(name, description, width, note) - local suffix = description or "" - if note then - suffix = suffix ~= "" and (suffix .. " " .. note) or note - end - if suffix ~= "" then - local padding = math.max(width - #name, 1) - cprint(" ${color.dump.string}%s${clear}%s%s", name, (" "):rep(padding), suffix) - else - cprint(" ${color.dump.string}%s${clear}", name) - end -end - --- list all addons -function _list() - local seen = {} - local installed = _collect_installed_addons() - for _, entry in ipairs(installed) do - seen[entry.name] = true - end - local avail = {} - for _, repo in ipairs(_repositories()) do - table.join2(avail, _collect_repo_addons(path.join(repo:directory(), "addons"), seen)) - end - - -- compute the alignment width from all addon names - local width = 0 - for _, entries in ipairs({installed, avail}) do - for _, entry in ipairs(entries) do - width = math.max(width, #entry.name + 4) - end - end - - -- installed addons - cprint("${bright}the installed addons:${clear}") - if #installed > 0 then - for _, entry in ipairs(installed) do - local note = string.format("(%s, %s)", entry.version, table.concat(entry.payloads, ", ")) - _print_addon(entry.name, nil, width, note) - end - else - print(" (none)") - end - - -- addons available in repositories (not yet installed) - cprint("${bright}available in configured repositories:${clear}") - if #avail > 0 then - for _, entry in ipairs(avail) do - local note = string.format("(run xmake addon --install %s to install)", entry.name) - _print_addon(entry.name, entry.description, width, note) - end - else - print(" (none)") - end -end - --- clear all installed addons -function _clear() - addon.clear() - cprint("${color.success}clear all installed addons ok!") -end - -function main() - if option.get("install") then - _install() - elseif option.get("remove") then - _remove() - elseif option.get("list") then - _list() - elseif option.get("clear") then - _clear() - end -end diff --git a/xmake/plugins/addon/xmake.lua b/xmake/plugins/addon/xmake.lua deleted file mode 100644 index 885e35644..000000000 --- a/xmake/plugins/addon/xmake.lua +++ /dev/null @@ -1,43 +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("addon") - set_category("plugin") - on_run("main") - set_menu { - usage = "xmake addon [options]", - description = "Manage addons of xmake.", - options = { - {'i', "install", "k", nil, "Install addons."}, - {'r', "remove", "k", nil, "Remove the given installed addon."}, - {'l', "list", "k", nil, "List all installed addons."}, - {'c', "clear", "k", nil, "Clear all installed addons."}, - {nil, "addons", "vs", nil, "The addon paths, urls or names.", - "e.g.", - " $ xmake addon --install https://github.com/myrepo/serial-monitor", - " $ xmake addon --install github:myrepo/serial-monitor", - " $ xmake addon --install github:myrepo/serial-monitor#dev", - " $ xmake addon --install /tmp/my-addon", - " $ xmake addon --install xmake-repo@serial-monitor", - " $ xmake addon --install serial-monitor", - " $ xmake addon --remove serial-monitor", - " $ xmake addon --list"} - } - } -- cgit v1.3.1