[gnome-shell] extensionDownloader: Add update/blacklist support for extensions
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] extensionDownloader: Add update/blacklist support for extensions
- Date: Tue, 10 Jul 2012 18:37:11 +0000 (UTC)
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]