summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSaikari <[email protected]>2026-07-11 06:12:51 +0300
committerruki <[email protected]>2026-07-30 10:17:31 +0800
commitcb143527bc830df298613ff5a8ff32ee7f6cb9f0 (patch)
tree75cb1c98c61329b93bd361d45ca3b1eb2399655d
parent20127575d8f48d9b286021c779bdd85090273c39 (diff)
fix: enhance plugin management with rollback and confirmation features
-rw-r--r--xmake/modules/private/action/require/impl/actions/install.lua9
-rw-r--r--xmake/modules/private/action/require/impl/utils/plugins.lua25
-rw-r--r--xmake/modules/private/action/require/search.lua6
-rw-r--r--xmake/plugins/plugin/main.lua5
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)