extensionSystem: Update immediately after major upgrades

Currently we periodically check for updated extensions, prepare
an update and perform it at the next login.

This is largely due to the fact that once an extension has been
loaded, its code is cached and reloading it would only make it
*appear* as updated, while in reality still running the old code.

Of course this only applies *once* we have loaded extensions.

Before that, it's possible to download and install updates, and
only then initialize extensions with their latest version.

The trade-off is that network requests, data download and extraction may
introduce a significant delay before extensions
are enabled. Most extensions modify the UI one way or another,
so that delay would likely be noticeable by the user.

Assuming that users are usually happy enough with the current
extension version, that trade-off doesn't seem worthwhile.

However there is an exception: After a major version update,
extensions are likely disabled as out-of-date, or at least
more likely to break (when the version check is disabled).

In that case delaying extension initialization to download
and install updates looks like the better trade-off, so do
that.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2951>
This commit is contained in:
Florian Müllner 2023-09-14 20:30:39 +02:00 committed by Marge Bot
parent 1cc5e770ea
commit ba46a1cf54

View File

@ -27,6 +27,8 @@ export class ExtensionManager extends Signals.EventEmitter {
this._initializationPromise = null;
this._updateNotified = false;
this._updateInProgress = false;
this._updatedUUIDS = [];
this._extensions = new Map();
this._unloadedExtensions = new Map();
@ -316,6 +318,11 @@ export class ExtensionManager extends Signals.EventEmitter {
}
notifyExtensionUpdate(uuid) {
if (this._updateInProgress) {
this._updatedUUIDS.push(uuid);
return;
}
let extension = this.lookup(uuid);
if (!extension)
return;
@ -646,6 +653,30 @@ export class ExtensionManager extends Signals.EventEmitter {
}
}
async _handleMajorUpdate() {
const [majorVersion] = Config.PACKAGE_VERSION.split('.');
const path = `${global.userdatadir}/update-check-${majorVersion}`;
const file = Gio.File.new_for_path(path);
try {
if (!await file.touch_async())
return;
} catch (e) {
logError(e);
}
this._updateInProgress = true;
await ExtensionDownloader.checkForUpdates();
this._installExtensionUpdates();
this._updatedUUIDS.map(uuid => this.lookup(uuid)).forEach(
ext => this.reloadExtension(ext));
this._updatedUUIDS = [];
this._updateInProgress = false;
}
_installExtensionUpdates() {
if (!this.updatesSupported)
return;
@ -719,6 +750,10 @@ export class ExtensionManager extends Signals.EventEmitter {
return extension;
}).filter(extension => extension !== null);
// after updating to a new major version,
// update extensions before loading them
await this._handleMajorUpdate();
for (const extension of extensionObjects) {
// eslint-disable-next-line no-await-in-loop
await this.loadExtension(extension);