diff --git a/plugin_installer/config.ui b/plugin_installer/config.ui index 7b1abd4..521b076 100644 --- a/plugin_installer/config.ui +++ b/plugin_installer/config.ui @@ -7,14 +7,66 @@ False 12 12 + 18 + 6 - - Check update after start + + _Show message when automatic update was successful True True - False False + start + True True + + + + 0 + 3 + + + + + _Update plugins automatically + True + True + False + start + True + True + + + + 0 + 2 + + + + + _Check for updates after start + True + True + False + start + True + True + + + + 0 + 1 + + + + + True + False + start + Plugin updates + 0 diff --git a/plugin_installer/plugin_installer.py b/plugin_installer/plugin_installer.py index b9c0737..c726f5f 100644 --- a/plugin_installer/plugin_installer.py +++ b/plugin_installer/plugin_installer.py @@ -47,6 +47,7 @@ from gajim.plugins.helpers import get_builder from gajim.gtk.dialogs import WarningDialog from gajim.gtk.dialogs import HigDialog from gajim.gtk.dialogs import YesNoDialog +from gajim.gtk.dialogs import ConfirmationDialogCheck from gajim.gtkgui_helpers import get_action log = logging.getLogger('gajim.plugin_system.plugin_installer') @@ -108,7 +109,9 @@ class PluginInstaller(GajimPlugin): def init(self): self.description = _('Install and Upgrade Plugins') self.config_dialog = PluginInstallerPluginConfigDialog(self) - self.config_default_values = {'check_update': (True, '')} + self.config_default_values = {'check_update': (True, ''), + 'auto_update': (False, ''), + 'auto_update_feedback': (True, '')} self.gui_extension_points = {'plugin_window': (self.on_activate, None)} self.window = None self.progressbar = None @@ -123,17 +126,20 @@ class PluginInstaller(GajimPlugin): self.on_activate(app.interface.instances['plugins']) def warn_update(self, plugins): - def open_update(dummy): + def open_update(checked): + if checked: + self.config['auto_update'] = True get_action('plugins').activate() page = self.notebook.page_num(self.available_plugins_box) self.notebook.set_current_page(page) if plugins: plugins_str = '\n' + '\n'.join(plugins) YesNoDialog( - _('Plugins updates'), - _('Some updates are available for your installer plugins. ' - 'Do you want to update those plugins:\n%s') - % plugins_str, on_response_yes=open_update) + _('Plugin updates'), + _('There are updates available for plugins you have installed.\n' + 'Do you want to update those plugins:\n%s') % plugins_str, + checktext=_('Update plugins automatically next time'), + on_response_yes=open_update) else: log.info('No updates found') if hasattr(self, 'thread'): @@ -143,7 +149,8 @@ class PluginInstaller(GajimPlugin): if hasattr(self, 'thread'): return log.info('Checking for Updates...') - self.start_download(check_update=True) + auto_update = self.config['auto_update'] + self.start_download(check_update=True, auto_update=auto_update) self.timeout_id = 0 def deactivate(self): @@ -225,19 +232,18 @@ class PluginInstaller(GajimPlugin): if self.available_plugins_model[i][Column.UPGRADE]: dir_list.append(self.available_plugins_model[i][Column.DIR]) - self.start_download(remote_dirs=dir_list) + self.start_download(remote_dirs=dir_list, auto_update=False) def on_error(self, reason): if reason == 'CERTIFICATE_VERIFY_FAILED': YesNoDialog( _('Security error during download'), - _('A security error occurred when ' + _('A security error occurred while ' 'downloading. The certificate of the ' 'plugin archive could not be verified. ' - 'this might be a security attack. ' - '\n\nYou can continue at your risk. ' - 'Do you want to do so? ' - '(not recommended)' + 'This might be a security attack. ' + '\n\nYou can continue at your own risk (not recommended). ' + 'Do you want to continue?' ), on_response_yes=lambda dlg: self.start_download(secure=False, upgrading=True)) @@ -251,49 +257,66 @@ class PluginInstaller(GajimPlugin): _('An error occurred when downloading\n\n' '[%s]' % (str(text))), self.window) - def start_download(self, secure=True, remote_dirs=False, - upgrading=False, check_update=False): + def start_download(self, secure=True, remote_dirs=False, upgrading=False, + check_update=False, auto_update=False): log.info('Start Download...') log.debug( - 'secure: %s, remote_dirs: %s, upgrading: %s, check_update: %s', - secure, remote_dirs, upgrading, check_update) + 'secure: %s, remote_dirs: %s, upgrading: %s, check_update: %s, auto_update: %s', + secure, remote_dirs, upgrading, check_update, auto_update) self.thread = DownloadAsync( - self, secure=secure, remote_dirs=remote_dirs, - upgrading=upgrading, check_update=check_update) + self, secure=secure, remote_dirs=remote_dirs, upgrading=upgrading, + check_update=check_update, auto_update=auto_update) self.thread.start() - def on_plugin_downloaded(self, plugin_dirs): + def on_plugin_downloaded(self, plugin_dirs, auto_update): need_restart = False for _dir in plugin_dirs: updated = app.plugin_manager.update_plugins(replace=False, activate=True, plugin_name=_dir) if updated: - plugin = app.plugin_manager.get_active_plugin(updated[0]) - for row in range(len(self.available_plugins_model)): - model_row = self.available_plugins_model[row] - if plugin.name == model_row[Column.NAME]: - model_row[Column.LOCAL_VERSION] = plugin.version - model_row[Column.UPGRADE] = False - break - # get plugin icon - icon_file = os.path.join(plugin.__path__, os.path.split( - plugin.__path__)[1]) + '.png' - icon = FALLBACK_ICON - if os.path.isfile(icon_file): - icon = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_file, 16, 16) - row = [plugin, plugin.name, True, plugin.activatable, icon] - self.installed_plugins_model.append(row) + if not auto_update: + plugin = app.plugin_manager.get_active_plugin(updated[0]) + for row in range(len(self.available_plugins_model)): + model_row = self.available_plugins_model[row] + if plugin.name == model_row[Column.NAME]: + model_row[Column.LOCAL_VERSION] = plugin.version + model_row[Column.UPGRADE] = False + break + if not auto_update: + # Get plugin icon + icon_file = os.path.join(plugin.__path__, os.path.split( + plugin.__path__)[1]) + '.png' + icon = FALLBACK_ICON + if os.path.isfile(icon_file): + icon = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_file, 16, 16) + row = [plugin, plugin.name, True, plugin.activatable, icon] + self.installed_plugins_model.append(row) else: need_restart = True if need_restart: txt = _('All plugins downloaded.\nThe updates will ' - 'be installed on next Gajim restart.') + 'be installed the next time Gajim is started.') else: txt = _('All selected plugins downloaded and activated') - dialog = HigDialog( - self.window, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, '', txt) - dialog.set_modal(False) - dialog.popup() + if not auto_update: + dialog = HigDialog( + self.window, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, '', txt) + dialog.set_modal(False) + dialog.popup() + if auto_update and self.config['auto_update_feedback']: + def on_ok(checked): + if checked: + self.config['auto_update_feedback'] = False + # Hide cancel button to mimic InfoDialogCheck + ConfirmationDialogCheck(_('Plugins updated'), + _('Plugin updates have successfully been downloaded.' + 'Updates will be installed on next Gajim restart.'), + _('Do not show this message again'), + on_response_ok=on_ok).get_widget_for_response( + Gtk.ResponseType.CANCEL).hide() + if auto_update and not self.config['auto_update_feedback']: + log.info('Updates downloaded, will install on next restart') + def available_plugins_treeview_selection_changed(self, treeview_selection): model, iter_ = treeview_selection.get_selected() @@ -325,7 +348,8 @@ class PluginInstaller(GajimPlugin): class DownloadAsync(threading.Thread): - def __init__(self, plugin, secure, remote_dirs, upgrading, check_update): + def __init__(self, plugin, secure, remote_dirs, + upgrading, check_update, auto_update): threading.Thread.__init__(self) self.plugin = plugin self.window = plugin.window @@ -335,6 +359,7 @@ class DownloadAsync(threading.Thread): self.upgrading = upgrading self.secure = secure self.check_update = check_update + self.auto_update = auto_update self.pulse = None def model_append(self, row): @@ -355,9 +380,10 @@ class DownloadAsync(threading.Thread): if self.check_update: self.run_check_update() else: - GLib.idle_add(self.progressbar.show) - self.pulse = GLib.timeout_add(150, self.progressbar_pulse) - self.run_download_plugin_list() + if not self.auto_update: + GLib.idle_add(self.progressbar.show) + self.pulse = GLib.timeout_add(150, self.progressbar_pulse) + self.run_download_plugin_list() except urllib.error.URLError as exc: if isinstance(exc.reason, ssl.SSLError): ssl_reason = exc.reason.reason @@ -413,7 +439,7 @@ class DownloadAsync(threading.Thread): pix.close() icon = pix.get_pixbuf() - # transform to dictonary + # Transform to dictonary config_dict = {} for key, value in config.items('info'): config_dict[key] = value @@ -457,6 +483,7 @@ class DownloadAsync(threading.Thread): def run_check_update(self): to_update = [] + auto_update_list = [] zipbuf = self.download_url(MANIFEST_URL) plugin_list = self.parse_manifest(zipbuf) for plugin in plugin_list: @@ -465,7 +492,17 @@ class DownloadAsync(threading.Thread): if (V(plugin['version']) > V(local_version)) and \ self.plugin_is_valid(plugin): to_update.append(plugin['name']) - GLib.idle_add(self.plugin.warn_update, to_update) + auto_update_list.append(plugin['remote_dir']) + if not self.auto_update: + GLib.idle_add(self.plugin.warn_update, to_update) + else: + if auto_update_list: + self.remote_dirs = auto_update_list + GLib.idle_add(self.download_plugin) + else: + log.info('No updates found') + if hasattr(self.plugin, 'thread'): + del self.plugin.thread def run_download_plugin_list(self): if not self.remote_dirs: @@ -501,7 +538,7 @@ class DownloadAsync(threading.Thread): os.mkdir(local_dir) local_dir = os.path.dirname(local_dir) - # downloading zip file + # Downloading zip file try: plugin = posixpath.join(PLUGINS_URL, filename) buf = self.download_url(plugin) @@ -510,7 +547,8 @@ class DownloadAsync(threading.Thread): continue with ZipFile(buf) as zip_file: zip_file.extractall(local_dir) - GLib.idle_add(self.plugin.on_plugin_downloaded, self.remote_dirs) + GLib.idle_add(self.plugin.on_plugin_downloaded, + self.remote_dirs, self.auto_update) class PluginInstallerPluginConfigDialog(GajimPluginConfigDialog): @@ -523,6 +561,23 @@ class PluginInstallerPluginConfigDialog(GajimPluginConfigDialog): def on_run(self): self.xml.check_update.set_active(self.plugin.config['check_update']) + self.xml.auto_update.set_sensitive(self.plugin.config['check_update']) + self.xml.auto_update.set_active(self.plugin.config['auto_update']) + self.xml.auto_update_feedback.set_sensitive(self.plugin.config['check_update']) + self.xml.auto_update_feedback.set_active(self.plugin.config['auto_update_feedback']) def on_check_update_toggled(self, widget): self.plugin.config['check_update'] = widget.get_active() + if not self.plugin.config['check_update']: + self.plugin.config['auto_update'] = False + self.xml.auto_update.set_sensitive(self.plugin.config['check_update']) + self.xml.auto_update.set_active(self.plugin.config['auto_update']) + self.xml.auto_update_feedback.set_sensitive(self.plugin.config['auto_update']) + self.xml.auto_update_feedback.set_active(self.plugin.config['auto_update_feedback']) + + def on_auto_update_toggled(self, widget): + self.plugin.config['auto_update'] = widget.get_active() + self.xml.auto_update_feedback.set_sensitive(self.plugin.config['auto_update']) + + def on_auto_update_feedback_toggled(self, widget): + self.plugin.config['auto_update_feedback'] = widget.get_active()