[gnome-shell] extensionDownloader: Add update/blacklist support for extensions



commit 1e286e43ada7f20214890d5d9d3c3a5cb837e4f4
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Tue Jun 26 20:47:44 2012 -0400

    extensionDownloader: Add update/blacklist support for extensions
    
    This is a bare-bones copy/replace. It does not implement ChangeLog
    support. If we cannot get System Updates integration, I will implement
    notification support.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=679099

 js/misc/fileUtils.js         |   27 +++++++++++-
 js/ui/extensionDownloader.js |   87 +++++++++++++++++++++++++++++++++++++++--
 js/ui/shellDBus.js           |    6 +++
 3 files changed, 112 insertions(+), 8 deletions(-)
---
diff --git a/js/misc/fileUtils.js b/js/misc/fileUtils.js
index 7466be8..4e62025 100644
--- a/js/misc/fileUtils.js
+++ b/js/misc/fileUtils.js
@@ -28,7 +28,7 @@ function deleteGFile(file) {
     return file['delete'](null);
 }
 
-function recursivelyDeleteDir(dir) {
+function recursivelyDeleteDir(dir, deleteParent) {
     let children = dir.enumerate_children('standard::name,standard::type',
                                           Gio.FileQueryInfoFlags.NONE, null);
 
@@ -39,8 +39,29 @@ function recursivelyDeleteDir(dir) {
         if (type == Gio.FileType.REGULAR)
             deleteGFile(child);
         else if (type == Gio.FileType.DIRECTORY)
-            recursivelyDeleteDir(child);
+            recursivelyDeleteDir(child, true);
     }
 
-    deleteGFile(dir);
+    if (deleteParent)
+        deleteGFile(dir);
+}
+
+function recursivelyMoveDir(srcDir, destDir) {
+    let children = srcDir.enumerate_children('standard::name,standard::type',
+                                             Gio.FileQueryInfoFlags.NONE, null);
+
+    if (!destDir.query_exists(null))
+        destDir.make_directory_with_parents(null);
+
+    let info, child;
+    while ((info = children.next_file(null)) != null) {
+        let type = info.get_file_type();
+        let srcChild = srcDir.get_child(info.get_name());
+        let destChild = destDir.get_child(info.get_name());
+        log([srcChild.get_path(), destChild.get_path()]);
+        if (type == Gio.FileType.REGULAR)
+            srcChild.move(destChild, Gio.FileCopyFlags.NONE, null, null);
+        else if (type == Gio.FileType.DIRECTORY)
+            recursivelyMoveDir(srcChild, destChild);
+    }
 }
diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js
index 4dd683d..83f8a36 100644
--- a/js/ui/extensionDownloader.js
+++ b/js/ui/extensionDownloader.js
@@ -7,6 +7,7 @@ const GLib = imports.gi.GLib;
 const Gio = imports.gi.Gio;
 const Soup = imports.gi.Soup;
 const St = imports.gi.St;
+const Shell = imports.gi.Shell;
 
 const Config = imports.misc.config;
 const ExtensionUtils = imports.misc.extensionUtils;
@@ -18,7 +19,8 @@ const _signals = ExtensionSystem._signals;
 
 const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
 const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
-const REPOSITORY_URL_INFO =     REPOSITORY_URL_BASE + '/extension-info/';
+const REPOSITORY_URL_INFO     = REPOSITORY_URL_BASE + '/extension-info/';
+const REPOSITORY_URL_UPDATE   = REPOSITORY_URL_BASE + '/update-info/';
 
 let _httpSession;
 
@@ -61,17 +63,16 @@ function uninstallExtension(uuid) {
     if (!ExtensionSystem.unloadExtension(uuid))
         return false;
 
-    FileUtils.recursivelyDeleteDir(extension.dir);
+    FileUtils.recursivelyDeleteDir(extension.dir, true);
     return true;
 }
 
-function gotExtensionZipFile(session, message, uuid, callback, errback) {
+function gotExtensionZipFile(session, message, uuid, dir, callback, errback) {
     if (message.status_code != Soup.KnownStatusCode.OK) {
         errback('DownloadExtensionError', message.status_code);
         return;
     }
 
-    let dir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
     try {
         if (!dir.query_exists(null))
             dir.make_directory_with_parents(null);
@@ -105,6 +106,81 @@ function gotExtensionZipFile(session, message, uuid, callback, errback) {
     });
 }
 
+function updateExtension(uuid) {
+    // This gets a bit tricky. We want the update to be seamless -
+    // if we have any error during downloading or extracting, we
+    // want to not unload the current version.
+
+    let oldExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension');
+    let newExtensionTmpDir = GLib.Dir.make_tmp('XXXXXX-shell-extension');
+
+    let params = { shell_version: Config.PACKAGE_VERSION };
+
+    let url = REPOSITORY_URL_DOWNLOAD.format(uuid);
+    let message = Soup.form_request_new_from_hash('GET', url, params);
+
+    _httpSession.queue_message(message, Lang.bind(this, function(session, message) {
+        gotExtensionZipFile(session, message, uuid, newExtensionTmpDir, function() {
+            let oldExtension = ExtensionUtils.extensions[uuid];
+            let extensionDir = oldExtension.dir;
+
+            if (!ExtensionSystem.unloadExtension(uuid))
+                return;
+
+            FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir);
+            FileUtils.recursivelyMoveDir(newExtensionTmpDir, extensionDir);
+
+            let extension = ExtensionUtils.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER);
+
+            try {
+                ExtensionSystem.loadExtension(extension);
+            } catch(e) {
+                ExtensionSystem.unloadExtension(uuid);
+
+                logError(e, 'Error loading extension %s'.format(uuid));
+
+                FileUtils.recursivelyDeleteDir(extensionDir, false);
+                FileUtils.recursivelyMoveDir(oldExtensionTmpDir, extensionDir);
+
+                // Restore what was there before. We can't do much if we
+                // fail here.
+                ExtensionSystem.loadExtension(oldExtension);
+                return;
+            }
+
+            FileUtils.recursivelyDeleteDir(oldExtensionTmpDir, true);
+        }, function(code, message) {
+            log('Error while updating extension %s: %s (%s)'.format(uuid, code, message ? message : ''));
+        });
+    }));
+}
+
+function checkForUpdates() {
+    let metadatas = {};
+    for (let uuid in ExtensionUtils.extensions) {
+        metadatas[uuid] = ExtensionUtils.extensions[uuid].metadata;
+    }
+
+    let params = { shell_version: Config.PACKAGE_VERSION,
+                   installed: JSON.stringify(metadatas) };
+
+    let url = REPOSITORY_URL_UPDATE;
+    let message = Soup.form_request_new_from_hash('GET', url, params);
+    _httpSession.queue_message(message, function(session, message) {
+        if (message.status_code != Soup.KnownStatusCode.OK)
+            return;
+
+        let operations = JSON.parse(message.response_body.data);
+        for (let uuid in operations) {
+            let operation = operations[uuid];
+            if (operation == 'blacklist')
+                uninstallExtension(uuid);
+            else if (operation == 'upgrade' || operation == 'downgrade')
+                updateExtension(uuid);
+        }
+    });
+}
+
 const InstallExtensionDialog = new Lang.Class({
     Name: 'InstallExtensionDialog',
     Extends: ModalDialog.ModalDialog,
@@ -149,6 +225,7 @@ const InstallExtensionDialog = new Lang.Class({
         let message = Soup.form_request_new_from_hash('GET', url, params);
 
         let uuid = this._uuid;
+        let dir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
         let invocation = this._invocation;
         function errback(code, message) {
             invocation.return_dbus_error('org.gnome.Shell.' + code, message ? message.toString() : '');
@@ -176,7 +253,7 @@ const InstallExtensionDialog = new Lang.Class({
         }
 
         _httpSession.queue_message(message, Lang.bind(this, function(session, message) {
-            gotExtensionZipFile(session, message, uuid, callback, errback);
+            gotExtensionZipFile(session, message, uuid, dir, callback, errback);
         }));
 
         this.close(global.get_current_time());
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
index 83074e4..661818e 100644
--- a/js/ui/shellDBus.js
+++ b/js/ui/shellDBus.js
@@ -214,6 +214,8 @@ const GnomeShellExtensionsIface = <interface name="org.gnome.Shell.Extensions">
 <method name="ReloadExtension">
     <arg type="s" direction="in" name="uuid"/>
 </method>
+<method name="CheckForUpdates">
+</method>
 <property name="ShellVersion" type="s" access="read" />
 </interface>;
 
@@ -306,6 +308,10 @@ const GnomeShellExtensions = new Lang.Class({
         ExtensionSystem.loadExtension(uuid);
     },
 
+    CheckForUpdates: function() {
+        ExtensionDownloader.checkForUpdates();
+    },
+
     ShellVersion: Config.PACKAGE_VERSION,
 
     _extensionStateChanged: function(_, newState) {



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