diff options
| author | Saikari <[email protected]> | 2026-07-11 06:12:51 +0300 |
|---|---|---|
| committer | ruki <[email protected]> | 2026-07-30 10:17:31 +0800 |
| commit | cb143527bc830df298613ff5a8ff32ee7f6cb9f0 (patch) | |
| tree | 75cb1c98c61329b93bd361d45ca3b1eb2399655d | |
| parent | 20127575d8f48d9b286021c779bdd85090273c39 (diff) | |
fix: enhance plugin management with rollback and confirmation features
4 files changed, 37 insertions, 8 deletions
diff --git a/xmake/modules/private/action/require/impl/actions/install.lua b/xmake/modules/private/action/require/impl/actions/install.lua index 3d1c15621..95f424a0f 100644 --- a/xmake/modules/private/action/require/impl/actions/install.lua +++ b/xmake/modules/private/action/require/impl/actions/install.lua @@ -535,6 +535,11 @@ 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) @@ -564,9 +569,9 @@ function main(package) -- leave the package environments os.setenvs(oldenvs) - -- unregister the broken plugin package + -- unregister the broken plugin package and restore the previous version if package:is_plugin() then - plugins.unregister(package:name()) + plugins.rollback(package:name()) end -- copy the invalid package directory to cache diff --git a/xmake/modules/private/action/require/impl/utils/plugins.lua b/xmake/modules/private/action/require/impl/utils/plugins.lua index f7d4d305f..4656312fc 100644 --- a/xmake/modules/private/action/require/impl/utils/plugins.lua +++ b/xmake/modules/private/action/require/impl/utils/plugins.lua @@ -44,12 +44,33 @@ function register(package) -- 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 - os.tryrm(dir) + -- 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) + os.tryrm(dir) + local bakdir = path.join(path.directory(dir), ".tmp", name .. ".bak") + if os.isdir(bakdir) then + 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) diff --git a/xmake/modules/private/action/require/search.lua b/xmake/modules/private/action/require/search.lua index 75ebd8d50..73a32b836 100644 --- a/xmake/modules/private/action/require/search.lua +++ b/xmake/modules/private/action/require/search.lua @@ -47,10 +47,12 @@ function main(names) local extra = option.get("extra") if extra then local extrainfo, errors = string.deserialize(extra) - if not extrainfo then + if errors then raise(errors) end - opt.kind = extrainfo.kind + if type(extrainfo) == "table" then + opt.kind = extrainfo.kind + end end -- show title diff --git a/xmake/plugins/plugin/main.lua b/xmake/plugins/plugin/main.lua index 4045fb053..e12a433e2 100644 --- a/xmake/plugins/plugin/main.lua +++ b/xmake/plugins/plugin/main.lua @@ -201,8 +201,9 @@ end -- remove the given installed plugin 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` - assert(not name:find("..", 1, true) and not name:find("[/\\:]"), "invalid plugin name(%s)!", name) + -- 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) os.rmdir(plugindir) |
