Plugins: Uninstall immediately but allow undo

When you uninstall a plugin through the UI, XPIInstall:
1. Sets the plugin's `pendingUninstall` to true
2. Calls our onUninstalling() method
3. Waits for the Add-ons window to be closed
4. Actually uninstalls the plugin
5. Calls our onUninstalled() method

If you undo the uninstallation between steps 2 and 3, the remaining steps
instead look like:
3. Sets the plugin's `pendingUninstall` to false
4. Calls our onOperationCancelled() method

This commit changes our implementation of the bootstrapped plugin lifecycle so
that the shutdown and uninstall hooks are called from onUninstalling() (step 2).
If you close the Add-ons window without undoing, nothing more happens. The
plugin remains uninstalled. If you undo before closing, though, we call the
plugin's lifestyle hooks just as if it had been newly installed (unless it was
disabled before uninstallation, in which case we call install but not startup).

This mirrors the behavior of Firefox WebExtensions and makes things work more
like you'd expect: uninstalling a plugin immediately deactivates it, and undoing
activates it again.
This commit is contained in:
Abe Jellinek 2023-06-06 15:54:44 -04:00
parent a28b949dc1
commit 6106e379c9

View file

@ -26,6 +26,7 @@
Zotero.Plugins = new function () {
var { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
var { XPIInstall } = ChromeUtils.import("resource://gre/modules/addons/XPIInstall.jsm");
var scopes = new Map();
var observers = new Set();
@ -279,6 +280,8 @@ Zotero.Plugins = new function () {
this._addonObserver = {
initialized: false,
uninstalling: new Set(),
init() {
if (!this.initialized) {
AddonManager.addAddonListener(this);
@ -320,13 +323,27 @@ Zotero.Plugins = new function () {
async onUninstalling(addon) {
Zotero.debug("Uninstalling plugin " + addon.id);
},
async onUninstalled(addon) {
Zotero.debug("Uninstalled plugin " + addon.id);
this.uninstalling.add(addon.id);
await _callMethod(addon, 'shutdown', REASONS.ADDON_UNINSTALL);
await _callMethod(addon, 'uninstall');
clearDefaultPrefs(addon);
},
async onUninstalled(addon) {
Zotero.debug("Uninstalled plugin " + addon.id);
},
async onOperationCancelled(addon) {
if (!this.uninstalling.has(addon.id) || addon.type !== "extension") {
return;
}
Zotero.debug("Cancelled uninstallation of plugin " + addon.id);
this.uninstalling.delete(addon.id);
setDefaultPrefs(addon);
await _callMethod(addon, 'install');
if (addon.isActive) {
await _callMethod(addon, 'startup', REASONS.ADDON_INSTALL);
}
}
};
};