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
This commit is contained in:
parent
539993b4f4
commit
1e286e43ad
@ -28,7 +28,7 @@ function deleteGFile(file) {
|
|||||||
return file['delete'](null);
|
return file['delete'](null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function recursivelyDeleteDir(dir) {
|
function recursivelyDeleteDir(dir, deleteParent) {
|
||||||
let children = dir.enumerate_children('standard::name,standard::type',
|
let children = dir.enumerate_children('standard::name,standard::type',
|
||||||
Gio.FileQueryInfoFlags.NONE, null);
|
Gio.FileQueryInfoFlags.NONE, null);
|
||||||
|
|
||||||
@ -39,8 +39,29 @@ function recursivelyDeleteDir(dir) {
|
|||||||
if (type == Gio.FileType.REGULAR)
|
if (type == Gio.FileType.REGULAR)
|
||||||
deleteGFile(child);
|
deleteGFile(child);
|
||||||
else if (type == Gio.FileType.DIRECTORY)
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ const GLib = imports.gi.GLib;
|
|||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Soup = imports.gi.Soup;
|
const Soup = imports.gi.Soup;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
const Config = imports.misc.config;
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
@ -18,7 +19,8 @@ const _signals = ExtensionSystem._signals;
|
|||||||
|
|
||||||
const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
|
const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
|
||||||
const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
|
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;
|
let _httpSession;
|
||||||
|
|
||||||
@ -61,17 +63,16 @@ function uninstallExtension(uuid) {
|
|||||||
if (!ExtensionSystem.unloadExtension(uuid))
|
if (!ExtensionSystem.unloadExtension(uuid))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
FileUtils.recursivelyDeleteDir(extension.dir);
|
FileUtils.recursivelyDeleteDir(extension.dir, true);
|
||||||
return 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) {
|
if (message.status_code != Soup.KnownStatusCode.OK) {
|
||||||
errback('DownloadExtensionError', message.status_code);
|
errback('DownloadExtensionError', message.status_code);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let dir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
|
|
||||||
try {
|
try {
|
||||||
if (!dir.query_exists(null))
|
if (!dir.query_exists(null))
|
||||||
dir.make_directory_with_parents(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({
|
const InstallExtensionDialog = new Lang.Class({
|
||||||
Name: 'InstallExtensionDialog',
|
Name: 'InstallExtensionDialog',
|
||||||
Extends: ModalDialog.ModalDialog,
|
Extends: ModalDialog.ModalDialog,
|
||||||
@ -149,6 +225,7 @@ const InstallExtensionDialog = new Lang.Class({
|
|||||||
let message = Soup.form_request_new_from_hash('GET', url, params);
|
let message = Soup.form_request_new_from_hash('GET', url, params);
|
||||||
|
|
||||||
let uuid = this._uuid;
|
let uuid = this._uuid;
|
||||||
|
let dir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
|
||||||
let invocation = this._invocation;
|
let invocation = this._invocation;
|
||||||
function errback(code, message) {
|
function errback(code, message) {
|
||||||
invocation.return_dbus_error('org.gnome.Shell.' + code, message ? message.toString() : '');
|
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) {
|
_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());
|
this.close(global.get_current_time());
|
||||||
|
@ -214,6 +214,8 @@ const GnomeShellExtensionsIface = <interface name="org.gnome.Shell.Extensions">
|
|||||||
<method name="ReloadExtension">
|
<method name="ReloadExtension">
|
||||||
<arg type="s" direction="in" name="uuid"/>
|
<arg type="s" direction="in" name="uuid"/>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="CheckForUpdates">
|
||||||
|
</method>
|
||||||
<property name="ShellVersion" type="s" access="read" />
|
<property name="ShellVersion" type="s" access="read" />
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
@ -306,6 +308,10 @@ const GnomeShellExtensions = new Lang.Class({
|
|||||||
ExtensionSystem.loadExtension(uuid);
|
ExtensionSystem.loadExtension(uuid);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
CheckForUpdates: function() {
|
||||||
|
ExtensionDownloader.checkForUpdates();
|
||||||
|
},
|
||||||
|
|
||||||
ShellVersion: Config.PACKAGE_VERSION,
|
ShellVersion: Config.PACKAGE_VERSION,
|
||||||
|
|
||||||
_extensionStateChanged: function(_, newState) {
|
_extensionStateChanged: function(_, newState) {
|
||||||
|
Loading…
Reference in New Issue
Block a user