From 2127d0cef9be4eeab3e0192ab9bcd7aa36f9d658 Mon Sep 17 00:00:00 2001 From: Saikari Date: Tue, 28 Jul 2026 00:04:16 +0300 Subject: Refactor plugin installation logic to support custom plugin URLs and improve error handling during installation --- xmake/plugins/plugin/main.lua | 259 ++++++++++++++++++------------------------ 1 file changed, 111 insertions(+), 148 deletions(-) (limited to 'xmake/plugins/plugin/main.lua') diff --git a/xmake/plugins/plugin/main.lua b/xmake/plugins/plugin/main.lua index db03c7abb..09de02983 100644 --- a/xmake/plugins/plugin/main.lua +++ b/xmake/plugins/plugin/main.lua @@ -45,36 +45,22 @@ end -- get plugin urls for batch install function _plugin_urls() - local urls = { - "https://github.com/xmake-io/xmake-plugins.git", - "https://gitlab.com/tboox/xmake-plugins.git", - "https://gitee.com/tboox/xmake-plugins.git"} - fasturl.add(urls) - return fasturl.sort(urls) -end - --- run a function with a temporary directory that is removed on success or failure -function _with_tmpdir(fn) - local tmpdir = os.tmpfile() .. ".dir" - return try - { - function () - return fn(tmpdir) - end, - catch - { - function (errors) - os.tryrm(tmpdir) - raise(errors) - end - }, - finally - { - function () - os.tryrm(tmpdir) - end - } - } + local urls = option.get("plugins") + if urls then + local result = {} + for _, url in ipairs(table.wrap(urls)) do + table.insert(result, git.asgiturl(url) or url) + end + urls = result + else + urls = { + "https://github.com/xmake-io/xmake-plugins.git", + "https://gitlab.com/tboox/xmake-plugins.git", + "https://gitee.com/tboox/xmake-plugins.git"} + fasturl.add(urls) + urls = fasturl.sort(urls) + end + return urls end function _manifest_path() @@ -143,67 +129,34 @@ function _install_from_git(url) branch = url:sub(i + 1) url = url:sub(1, i - 1) end - url = "https://github.com/" .. url .. ".git" + url = git.asgiturl("github:" .. url) end - _with_tmpdir(function (tmpdir) - local clone_opt = {verbose = option.get("verbose"), outputdir = tmpdir} - if branch then - clone_opt.branch = branch - end - git.clone(git.asgiturl(url) or url, clone_opt) - local found = false - local function install(srcdir, name) - local dstdir = _get_plugindir(name) - assert(not os.isdir(dstdir), "plugin(%s) already exists!", name) - os.vcp(srcdir, dstdir) - cprint(" ${color.success}-> ${bright}%s${clear}", name) - found = true - end - if os.isfile(path.join(tmpdir, "xmake.lua")) then - install(tmpdir, path.basename(path.filename(url))) - else - for _, filepath in ipairs(os.files(path.join(tmpdir, "*", "xmake.lua"))) do - local srcdir = path.directory(filepath) - install(srcdir, path.filename(srcdir)) - end - end - if not found then - raise("no plugin found in %s", url) - end - end) -end - --- install a single plugin -function _install_one(name) - -- parse repo@plugin format - local i = name:find("@", 1, true) - if i and not name:find("[/\\:]") then - local reponame = name:sub(1, i - 1) - local pluginname = name:sub(i + 1) - _install_plugins_from_repo(pluginname, reponame) - return + local tmpdir = os.tmpfile() .. ".dir" + local clone_opt = {verbose = option.get("verbose"), outputdir = tmpdir} + if branch then + clone_opt.branch = branch end - - -- github shortcut: github:user/repo or github:user/repo#branch - if name:startswith("github:") then - _install_from_git(name) - return + git.clone(git.asgiturl(url) or url, clone_opt) + local found = false + local function install(srcdir, name) + local dstdir = _get_plugindir(name) + assert(not os.isdir(dstdir), "plugin(%s) already exists!", name) + os.vcp(srcdir, dstdir) + cprint(" ${color.success}-> ${bright}%s${clear}", name) + found = true end - - -- git url or local path - if name:startswith("file://") or git.asgiturl(name) then - _install_from_git(name) - return - elseif os.isdir(name) then - _install_from_local(name) - return - elseif name:find("[/\\:]") then - _install_from_git(name) - return + if os.isfile(path.join(tmpdir, "xmake.lua")) then + install(tmpdir, path.basename(path.filename(url))) + else + for _, filepath in ipairs(os.files(path.join(tmpdir, "*", "xmake.lua"))) do + local srcdir = path.directory(filepath) + install(srcdir, path.filename(srcdir)) + end + end + os.tryrm(tmpdir) + if not found then + raise("no plugin found in %s", url) end - - -- plain name: try to find it in repositories - _install_plugins_from_repo(name) end -- install plugins @@ -212,69 +165,84 @@ function _install() -- enter environment environment.enter() - local errors try { function () - -- install requested plugins - local names = option.get("plugins") - if names then - for _, name in ipairs(names) do - _install_one(name) + -- do install + local name = option.get("plugins") + if name and #name > 0 then + -- parse repo@plugin format + local i = name:find("@", 1, true) + if i and not name:find("[/\\:]") then + local reponame = name:sub(1, i - 1) + local pluginname = name:sub(i + 1) + _install_plugins_from_repo(pluginname, 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 name:startswith("file://") or git.asgiturl(name) then + _install_from_git(name) + return + elseif os.isdir(name) then + _install_from_local(name) + return + elseif name:find("[/\\:]") then + _install_from_git(name) + return + end + + -- plain name: try to find it in repositories + _install_plugins_from_repo(name) return end -- do batch install from plugin collection urls local urls = _plugin_urls() + local tmpdir = os.tmpfile() .. ".dir" local plugindir = _get_plugindir() local installed_url - _with_tmpdir(function (tmpdir) - for _, url in ipairs(urls) do - cprint("installing plugins from ${bright}%s${clear} ..", url) - local ok = try - { - function () - git.clone(url, {verbose = option.get("verbose"), outputdir = tmpdir}) - return true - end - } - if ok then - installed_url = url - break - end - os.tryrm(tmpdir) - end - assert(installed_url, "failed to install plugins from all urls!") - for _, filepath in ipairs(os.files(path.join(tmpdir, "*", "xmake.lua"))) do - local srcdir = path.directory(filepath) - local name = path.filename(srcdir) - local dstdir = _get_plugindir(name) - assert(not os.isdir(dstdir), "plugin(%s) already exists!", name) - os.vcp(srcdir, dstdir) - cprint(" ${color.success}-> ${bright}%s${clear}", name) - end - end) - local manifest = _load_manifest() or {} - manifest.urls = manifest.urls or {} - table.join2(manifest.urls, installed_url) - _save_manifest(manifest) + for _, url in ipairs(urls) do + cprint("installing plugins from ${bright}%s${clear} ..", url) + git.clone(url, {verbose = option.get("verbose"), outputdir = tmpdir}) + installed_url = url + break + end + for _, filepath in ipairs(os.files(path.join(tmpdir, "*", "xmake.lua"))) do + local srcdir = path.directory(filepath) + local name = path.filename(srcdir) + local dstdir = _get_plugindir(name) + assert(not os.isdir(dstdir), "plugin(%s) already exists!", name) + os.vcp(srcdir, dstdir) + cprint(" ${color.success}-> ${bright}%s${clear}", name) + end + os.tryrm(tmpdir) + + if installed_url then + local manifest = _load_manifest() or {} + manifest.urls = manifest.urls or {} + table.join2(manifest.urls, installed_url) + _save_manifest(manifest) + end cprint("${color.success}all plugins have been installed in ${bright}%s${clear}!", plugindir) end, catch { - function (_errors) - errors = _errors + function (errors) + raise(errors) end } } -- leave environment environment.leave() - if errors then - raise(errors) - end end -- update plugins @@ -283,7 +251,6 @@ function _update() -- enter environment environment.enter() - local errors try { function () @@ -295,40 +262,36 @@ function _update() local plugindir = _get_plugindir() for _, url in ipairs(urls) do cprint("updating plugins from ${bright}%s${clear} ..", url) - _with_tmpdir(function (tmpdir) - git.clone(url, {verbose = option.get("verbose"), outputdir = tmpdir}) - for _, filepath in ipairs(os.files(path.join(tmpdir, "*", "xmake.lua"))) do - local srcdir = path.directory(filepath) - local name = path.filename(srcdir) - local dstdir = _get_plugindir(name) - os.tryrm(dstdir) - os.vcp(srcdir, dstdir) - cprint(" ${color.success}-> ${bright}%s${clear}", name) - end - end) + local tmpdir = os.tmpfile() .. ".dir" + git.clone(url, {verbose = option.get("verbose"), outputdir = tmpdir}) + for _, filepath in ipairs(os.files(path.join(tmpdir, "*", "xmake.lua"))) do + local srcdir = path.directory(filepath) + local name = path.filename(srcdir) + local dstdir = _get_plugindir(name) + os.tryrm(dstdir) + os.vcp(srcdir, dstdir) + cprint(" ${color.success}-> ${bright}%s${clear}", name) + end + os.tryrm(tmpdir) end cprint("${color.success}all plugins have been updated in ${bright}%s${clear}!", plugindir) end, catch { - function (_errors) - errors = _errors + function (errors) + raise(errors) end } } -- leave environment environment.leave() - if errors then - raise(errors) - end end -- remove the given installed plugin function _remove() - local names = assert(option.get("plugins"), "please specify the plugin name to be removed!") - assert(#names == 1, "please specify only one plugin name to be removed!") - local name = _check_plugin_name(names[1]) + local name = assert(option.get("plugins"), "please specify the plugin name to be removed!") + assert(name ~= "" and name ~= "." and not name:find("..", 1, true) and not name:find("[/\\:]"), "invalid plugin name(%s)!", name) local dir = _get_plugindir(name) assert(os.isdir(dir), "plugin(%s) not found!", name) os.rmdir(dir) -- cgit v1.3.1