From 8ee97ed089583df5aa400fe0a4566de76d6e5cc7 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Mon, 28 Oct 2019 23:59:13 -0400 Subject: [PATCH] Add conditional build to remove update mechanism --- Makefile | 9 +- Settings.ui | 141 +++++++++++ extension.js | 2 + prefs.js | 17 ++ ...shell.extensions.dash-to-panel.gschema.xml | 6 + update.js | 235 ++++++++++++++++++ 6 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 update.js diff --git a/Makefile b/Makefile index 4f4a120..ac39741 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,10 @@ UUID = dash-to-panel@jderose9.github.com BASE_MODULES = extension.js stylesheet.css metadata.json COPYING README.md -EXTRA_MODULES = appIcons.js convenience.js panel.js panelManager.js proximity.js intellihide.js panelStyle.js overview.js taskbar.js transparency.js windowPreview.js prefs.js utils.js Settings.ui +EXTRA_MODULES = appIcons.js convenience.js panel.js panelManager.js proximity.js intellihide.js panelStyle.js overview.js taskbar.js transparency.js windowPreview.js prefs.js update.js utils.js Settings.ui EXTRA_IMAGES = highlight_stacked_bg.svg highlight_stacked_bg_2.svg highlight_stacked_bg_3.svg -TOLOCALIZE = prefs.js appIcons.js +TOLOCALIZE = prefs.js appIcons.js update.js MSGSRC = $(wildcard po/*.po) ifeq ($(strip $(DESTDIR)),) INSTALLBASE = $(HOME)/.local/share/gnome-shell/extensions @@ -72,6 +72,11 @@ _build: all -rm -fR ./_build mkdir -p _build cp $(BASE_MODULES) $(EXTRA_MODULES) _build + +ifeq ($(TARGET),ego) + find _build -name '*.js' -exec sed -i '/\/\/!start-update/,/\/\/!end-update/d' {} + +endif + mkdir -p _build/img cd img ; cp $(EXTRA_IMAGES) ../_build/img/ mkdir -p _build/schemas diff --git a/Settings.ui b/Settings.ui index 173fa77..6e37185 100644 --- a/Settings.ui +++ b/Settings.ui @@ -7681,6 +7681,147 @@ 1 + + + False + 20 + 0 + in + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 6 + 32 + + + True + False + True + This allows you to update the extension directly from the GitHub repository. + True + True + 0 + + + + 0 + 1 + 2 + + + + + True + False + start + Updates + + + 0 + 0 + 2 + + + + + True + False + start + Periodically check for updates + + + 0 + 3 + + + + + True + False + end + 6 + + + True + True + end + center + + + False + True + 0 + + + + + Check now + True + True + True + end + center + + + False + True + 1 + + + + + 1 + 3 + + + + + True + False + 12 + <span weight="bold" color="#B42B30">Be aware, these official Dash to Panel releases might not be reviewed yet on extensions.gnome.org!</span> <a href="https://extensions.gnome.org/about/">Read more</a> + True + True + 0 + + + 0 + 2 + 2 + + + + + + + + + + + + + + False + True + 2 + + True diff --git a/extension.js b/extension.js index 1f3c8af..14e55c9 100644 --- a/extension.js +++ b/extension.js @@ -88,7 +88,9 @@ function _enable() { Me.settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-panel'); Me.desktopSettings = Convenience.getSettings('org.gnome.desktop.interface'); + Me.imports.update.init(); panelManager = new PanelManager.dtpPanelManager(); + panelManager.enable(); Utils.removeKeybinding('open-application-menu'); diff --git a/prefs.js b/prefs.js index 13b05a8..38b3a3b 100644 --- a/prefs.js +++ b/prefs.js @@ -34,6 +34,7 @@ const Convenience = Me.imports.convenience; const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); const _ = Gettext.gettext; const N_ = function(e) { return e }; +const Update = Me.imports.update; const SCALE_UPDATE_TIMEOUT = 500; const DEFAULT_PANEL_SIZES = [ 128, 96, 64, 48, 32, 24, 16 ]; @@ -1804,6 +1805,22 @@ const Settings = new Lang.Class({ } ); }); + + let updateCheckSwitch = this._builder.get_object('updates_check_switch'); + + updateCheckSwitch.set_sensitive(false); + + this._builder.get_object('updates_check_now_button').connect('clicked', widget => { + this._settings.set_boolean('force-check-update', true); + }); + +//!start-update + updateCheckSwitch.set_sensitive(true); + this._settings.bind('check-update', + updateCheckSwitch, + 'active', + Gio.SettingsBindFlags.DEFAULT); +//!end-update }, _setPreviewTitlePosition: function() { diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index 63cae80..185842e 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -71,6 +71,12 @@ + + false + + + false + '' diff --git a/update.js b/update.js new file mode 100644 index 0000000..9683775 --- /dev/null +++ b/update.js @@ -0,0 +1,235 @@ +/* + * This file is part of the Dash-To-Panel extension for Gnome 3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +const GLib = imports.gi.GLib; +const Gio = imports.gi.Gio; +const Soup = imports.gi.Soup; +const FileUtils = imports.misc.fileUtils; + +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +const _ = Gettext.gettext; + +let apiUrl = ''; + +function init() { + Me.settings.connect('changed::force-check-update', () => { + if (Me.settings.get_boolean('force-check-update')) { + checkForUpdate(true); + Me.settings.set_boolean('force-check-update', false); + } + }); + +//!start-update + //check for update now, then every 4 hours + checkForUpdate(); + imports.mainloop.timeout_add(14400000, () => checkForUpdate()); + + Me.settings.connect('changed::version-to-install', () => installRelease(Me.settings.get_string('version-to-install'), true)); +//!end-update +} + +function checkForUpdate(fromSettings) { + if (!apiUrl) { + return notifyError(_('Unavailable when installed from extension.gnome.org')); + } + +//!start-update + if (fromSettings || Me.settings.get_boolean('check-update')) { + getLatestReleaseInfo((err, latestRelease) => { + if (err) { + return notifyError(err); + } + + let latestVersion = latestRelease.tag.substring(1); + + if (Me.metadata.version < latestVersion && latestRelease.zipUrl) { + notify( + _('Version %s (%s) is available').format(latestVersion, latestRelease.name), + [{ text: _('Details'), func: () => imports.misc.util.spawn(['xdg-open', latestRelease.url]) }, + { text: _('Update'), func: () => installRelease(latestRelease.zipUrl, fromSettings) }] + ); + } else if (fromSettings) { + notify(_('Already up to date')); + } + }); + } +//!end-update +} + +function notifyError(err) { + Me.imports.utils.notify(_('Error: ') + err, 'dialog-error', null, true); +} + +function notify(msg, action) { + Me.imports.utils.notify(msg, 'dialog-information', action, true); +} + +//!start-update +apiUrl = 'https://api.github.com/repos/home-sweet-gnome/dash-to-panel/'; +const tagsApiUrl = apiUrl + 'tags'; +const releasesApiUrl = apiUrl + 'releases'; + +let httpSession; + +function getLatestReleaseInfo(cb) { + getReleaseInfo('/latest', cb); +} + +function getTaggedReleaseInfo(releaseTag, cb) { + getReleaseInfo('/tags/' + releaseTag, cb); +} + +function getReleaseInfo(suffix, cb) { + getHttpMessageResponseBody(createGet(releasesApiUrl + suffix), (err, body) => { + if (err) { + return cb(err); + } + + try { + let release = JSON.parse(body.data); + let releaseInfo = { + name: release.name, + tag: release.tag_name, + url: release.html_url, + zipUrl: (release.assets.length ? release.assets[0].browser_download_url : 0), + }; + + cb(null, releaseInfo); + } catch (e) { + cb(e.message); + } + }); +} + +function installRelease(releaseAssetUrl, fromSettings) { + getHttpMessageResponseBody(createGet(releaseAssetUrl), (err, body) => { + if (err) { + return notifyInstallResult(err); + } + + let name = 'dtp_install'; + let zipFile = createTmp(name + '.zip'); + let stream = zipFile.replace(null, false, Gio.FileCreateFlags.NONE, null); + let extDir = Gio.file_new_for_path(Me.path); + let tmpDir = createTmp(name, true); + let bckDir = createTmp(Me.uuid, true); + + stream.write_bytes(body.flatten().get_as_bytes(), null); + stream.close(null); + + unzipFile(zipFile, tmpDir, err => { + if (err) { + return notifyInstallResult(err); + } + + try { + FileUtils.recursivelyMoveDir(extDir, bckDir); + FileUtils.recursivelyMoveDir(tmpDir, extDir); + + if (fromSettings) { + let [success, out, err, exitCode] = GLib.spawn_command_line_sync('pidof "gnome-shell-extension-prefs"'); + + if (success && !exitCode) { + GLib.spawn_command_line_sync('kill -9 ' + imports.byteArray.toString(out)); + } + } + } catch (e) { + FileUtils.recursivelyDeleteDir(extDir, false); + FileUtils.recursivelyMoveDir(bckDir, extDir); + + return notifyInstallResult(e.message); + } + + notifyInstallResult(null); + }); + }); +} + +function notifyInstallResult(err) { + if (err) { + notifyError(err); + } else if (imports.gi.Meta.is_wayland_compositor()) { + notify( + _('Update successful, please log out/in'), + { text: _('Log out'), func: () => new imports.misc.systemActions.getDefault().activateLogout() } + ); + } else { + notify( + _('Update successful, please restart GNOME Shell'), + { text: _('Restart GNOME Shell'), func: () => imports.gi.Meta.restart(_("Restarting GNOME Shell...")) } + ); + } +} + +function createTmp(name, isDir) { + let tmp = Gio.file_new_for_path('/tmp/' + name); + + if (isDir && tmp.query_exists(null)) { + FileUtils.recursivelyDeleteDir(tmp, false); + } + + return tmp; +} + +function unzipFile(zipFile, destDir, cb) { + let [success, pid] = GLib.spawn_async( + null, + ['unzip', '-uod', destDir.get_path(), '--', zipFile.get_path()], + null, + GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD | GLib.SpawnFlags.STDOUT_TO_DEV_NULL, + null + ); + + if (!success) { + return cb('unzip spawn error'); + } + + GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, (pid, status) => { + GLib.spawn_close_pid(pid); + + if (status != 0) { + return cb('extraction error') + } + + return cb(null); + }); +} + +function createGet(url, params) { + return Soup.form_request_new_from_hash('GET', url, params || {}); +} + +function getHttpMessageResponseBody(message, cb) { + if (!httpSession) { + httpSession = new Soup.Session(); + httpSession.user_agent = Me.metadata.uuid; + } + + httpSession.queue_message(message, (httpSession, message) => { + try { + if (!message.response_body || !message.response_body.data) { + return cb('No data received'); + } + + return cb(null, message.response_body); + } catch (e) { + return cb(e.message); + } + }); +} +//!end-update