[gnome-shell] extensionSystem: Prevent broken updates



commit 6ddd43f36178939d0e1873a40f1cf66f26c61140
Author: Florian Müllner <fmuellner gnome org>
Date:   Thu May 7 13:54:24 2020 +0200

    extensionSystem: Prevent broken updates
    
    Spidermonkey caches imports, which means that uninstalling an
    old extension version and installing a new one doesn't work as
    expected: If the previous version was loaded, then its code will
    be imported instead.
    
    For the last couple of releases this has been a reliable source
    of extension bug reports after major GNOME updates. Thankfully
    chrome-gnome-shell removed its update support in favor of our
    built-in support now, but users may still use older versions
    or perform those actions manually, so it still makes sense to
    catch this case and set an appropriate error.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1248

 js/ui/extensionSystem.js | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)
---
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index 16f5f8a66d..50244d95fc 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -26,6 +26,7 @@ var ExtensionManager = class {
         this._updateNotified = false;
 
         this._extensions = new Map();
+        this._unloadedExtensions = new Map();
         this._enabledExtensions = [];
         this._extensionOrder = [];
 
@@ -318,6 +319,14 @@ var ExtensionManager = class {
         return extension;
     }
 
+    _canLoad(extension) {
+        if (!this._unloadedExtensions.has(extension.uuid))
+            return true;
+
+        const version = this._unloadedExtensions.get(extension.uuid);
+        return extension.metadata.version === version;
+    }
+
     loadExtension(extension) {
         // Default to error, we set success as the last step
         extension.state = ExtensionState.ERROR;
@@ -326,6 +335,9 @@ var ExtensionManager = class {
 
         if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
             extension.state = ExtensionState.OUT_OF_DATE;
+        } else if (!this._canLoad(extension)) {
+            this.logExtensionError(extension.uuid, new Error(
+                'A different version was loaded previously. You need to log out for changes to take 
effect.'));
         } else {
             let enabled = this._enabledExtensions.includes(extension.uuid);
             if (enabled) {
@@ -336,6 +348,8 @@ var ExtensionManager = class {
             } else {
                 extension.state = ExtensionState.INITIALIZED;
             }
+
+            this._unloadedExtensions.delete(extension.uuid);
         }
 
         this._updateCanChange(extension);
@@ -343,15 +357,22 @@ var ExtensionManager = class {
     }
 
     unloadExtension(extension) {
+        const { uuid, type } = extension;
+
         // Try to disable it -- if it's ERROR'd, we can't guarantee that,
         // but it will be removed on next reboot, and hopefully nothing
         // broke too much.
-        this._callExtensionDisable(extension.uuid);
+        this._callExtensionDisable(uuid);
 
         extension.state = ExtensionState.UNINSTALLED;
         this.emit('extension-state-changed', extension);
 
-        this._extensions.delete(extension.uuid);
+        // If we did install an importer, it is now cached and it's
+        // impossible to load a different version
+        if (type === ExtensionType.PER_USER && extension.imports)
+            this._unloadedExtensions.set(uuid, extension.metadata.version);
+
+        this._extensions.delete(uuid);
         return true;
     }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]