class InstallBackendAptdaemon(InstallBackend):
    """Makes use of aptdaemon to refresh the cache and to install updates."""
    def __init__(self, window_main):
        # Pass None for datadir because of LP: #1026257
        InstallBackend.__init__(self, window_main, self.ACTION_INSTALL)
        self.client = client.AptClient()
        self.unity = UnitySupport()

    @inline_callbacks
    def update(self):
        """Refresh the package list"""
        try:
            apt_pkg.pkgsystem_unlock()
        except SystemError:
            pass
        try:
            trans = yield self.client.update_cache(defer=True)
            yield self._run_in_dialog(trans, self.UPDATE)
        except errors.NotAuthorizedError as e:
            self._action_done(self.UPDATE, False, False, str(e), None)
        except:
            self.action_done(self.UPDATE, True, False, None, None)
            raise

    @inline_callbacks
    def commit(self, pkgs_install, pkgs_upgrade, close_on_done):
        """Commit a list of package adds and removes"""
        try:
            apt_pkg.pkgsystem_unlock()
        except SystemError:
            pass
        try:
            reinstall = remove = purge = downgrade = []
            trans = yield self.client.commit_packages(pkgs_install,
                                                      reinstall,
                                                      remove,
                                                      purge,
                                                      pkgs_upgrade,
                                                      downgrade,
                                                      defer=True)
            trans.connect("progress-changed", self._on_progress_changed)
            yield self._run_in_dialog(trans, self.ACTION_INSTALL)
        except errors.NotAuthorizedError as e:
            self._action_done(self.ACTION_INSTALL, False, False, str(e), None)
        except dbus.DBusException as e:
            if e.get_dbus_name() != "org.freedesktop.DBus.Error.NoReply":
                raise
            self._action_done(self.ACTION_INSTALL, False, False, None, None)
        except Exception as e:
            self._action_done(self.ACTION_INSTALL, True, False, None, None)
            raise

    def _on_progress_changed(self, trans, progress):
        #print("_on_progress_changed", progress)
        self.unity.set_progress(progress)

    @inline_callbacks
    def _run_in_dialog(self, trans, action):
        dia = AptProgressDialog(trans, parent=self.window_main)
        dia.set_icon_name("update-manager")
        dia.connect("finished", self._on_finished, action)
        yield dia.run()

    def _on_finished(self, dialog, action):
        dialog.hide()
        # tell unity to hide the progress again
        self.unity.set_progress(-1)
        self._action_done(action, True,
                          dialog._transaction.exit == EXIT_SUCCESS, None, None)
class InstallBackendAptdaemon(InstallBackend):

    """Makes use of aptdaemon to refresh the cache and to install updates."""

    def __init__(self, datadir, window_main):
        InstallBackend.__init__(self, datadir, window_main)
        self.client = client.AptClient()
        self.unity = UnitySupport()
        self._expanded_size = None
        self.button_cancel = None

    def close(self):
        if self.button_cancel:
            self.button_cancel.clicked()
            return True
        else:
            return False

    @inline_callbacks
    def update(self):
        """Refresh the package list"""
        try:
            apt.apt_pkg.pkgsystem_unlock()
        except SystemError:
            pass
        try:
            trans = yield self.client.update_cache(defer=True)
            yield self._run_in_dialog(trans, self.UPDATE,
                                      _("Checking for updates…"),
                                      False, False)
        except errors.NotAuthorizedError:
            self.emit("action-done", self.UPDATE, False, False, None, None)
        except:
            self.emit("action-done", self.UPDATE, True, False, None, None)
            raise

    @inline_callbacks
    def commit(self, pkgs_install, pkgs_upgrade, close_on_done):
        """Commit a list of package adds and removes"""
        try:
            apt.apt_pkg.pkgsystem_unlock()
        except SystemError:
            pass
        try:
            reinstall = remove = purge = downgrade = []
            trans = yield self.client.commit_packages(
                pkgs_install, reinstall, remove, purge, pkgs_upgrade,
                downgrade, defer=True)
            trans.connect("progress-changed", self._on_progress_changed)
            yield self._run_in_dialog(trans, self.INSTALL,
                                      _("Installing updates…"),
                                      True, close_on_done)
        except errors.NotAuthorizedError as e:
            self.emit("action-done", self.INSTALL, False, False, None, None)
        except dbus.DBusException as e:
            #print(e, e.get_dbus_name())
            if e.get_dbus_name() != "org.freedesktop.DBus.Error.NoReply":
                raise
            self.emit("action-done", self.INSTALL, False, False, None, None)
        except Exception as e:
            self.emit("action-done", self.INSTALL, True, False, None, None)
            raise

    def _on_progress_changed(self, trans, progress):
        #print("_on_progress_changed", progress)
        self.unity.set_progress(progress)

    def _on_details_changed(self, trans, details, label_details):
        label_details.set_label(details)

    def _on_status_changed(self, trans, status, label_details, expander):
        label_details.set_label(get_status_string_from_enum(status))
        # Also resize the window if we switch from download details to
        # the terminal window
        if (status == STATUS_COMMITTING and expander and
                expander.terminal.get_visible()):
            self._resize_to_show_details(expander)

    @inline_callbacks
    def _run_in_dialog(self, trans, action, header, show_details,
                       close_on_done):
        builder = Gtk.Builder()
        builder.set_translation_domain("update-manager")
        builder.add_from_file(self.datadir + "/gtkbuilder/UpdateProgress.ui")

        label_header = builder.get_object("label_header")
        label_header.set_label(header)

        progressbar = AptProgressBar(trans)
        progressbar.show()
        progressbar_slot = builder.get_object("progressbar_slot")
        progressbar_slot.add(progressbar)

        self.button_cancel = AptCancelButton(trans)
        if action == self.UPDATE:
            self.button_cancel.set_label(Gtk.STOCK_STOP)
        self.button_cancel.show()
        button_cancel_slot = builder.get_object("button_cancel_slot")
        button_cancel_slot.add(self.button_cancel)

        label_details = builder.get_object("label_details")

        if show_details:
            expander = AptDetailsExpander(trans)
            expander.set_vexpand(True)
            expander.set_hexpand(True)
            expander.show_all()
            expander.connect("notify::expanded", self._on_expanded)
            expander_slot = builder.get_object("expander_slot")
            expander_slot.add(expander)
            expander_slot.show()
        else:
            expander = None

        trans.connect("status-details-changed", self._on_details_changed,
                      label_details)
        trans.connect("status-changed", self._on_status_changed, label_details,
                      expander)
        trans.connect("finished", self._on_finished, action, close_on_done)
        trans.connect("medium-required", self._on_medium_required)
        trans.connect("config-file-conflict", self._on_config_file_conflict)

        yield trans.set_debconf_frontend("gnome")
        yield trans.run()

        self.window_main.push(builder.get_object("pane_update_progress"),
                              self)

        self.window_main.get_window().set_functions(Gdk.WMFunction.MOVE |
                                                    Gdk.WMFunction.RESIZE |
                                                    Gdk.WMFunction.MINIMIZE)

    def _on_expanded(self, expander, param):
        # Make the dialog resizable if the expander is expanded
        # try to restore a previous size
        if not expander.get_expanded():
            self._expanded_size = (expander.terminal.get_visible(),
                                   self.window_main.get_size())
            self.window_main.set_resizable(False)
        elif self._expanded_size:
            self.window_main.set_resizable(True)
            term_visible, (stored_width, stored_height) = self._expanded_size
            # Check if the stored size was for the download details or
            # the terminal widget
            if term_visible != expander.terminal.get_visible():
                # The stored size was for the download details, so we need
                # get a new size for the terminal widget
                self._resize_to_show_details(expander)
            else:
                self.window_main.resize(stored_width, stored_height)
        else:
            self.window_main.set_resizable(True)
            self._resize_to_show_details(expander)

    def _resize_to_show_details(self, expander):
        """Resize the window to show the expanded details.

        Unfortunately the expander only expands to the preferred size of the
        child widget (e.g showing all 80x24 chars of the Vte terminal) if
        the window is rendered the first time and the terminal is also visible.
        If the expander is expanded afterwards the window won't change its
        size anymore. So we have to do this manually. See LP#840942
        """
        win_width, win_height = self.window_main.get_size()
        exp_width = expander.get_allocation().width
        exp_height = expander.get_allocation().height
        if expander.terminal.get_visible():
            terminal_width = expander.terminal.get_char_width() * 80
            terminal_height = expander.terminal.get_char_height() * 24
            self.window_main.resize(terminal_width - exp_width + win_width,
                                    terminal_height - exp_height + win_height)
        else:
            self.window_main.resize(win_width + 100, win_height + 200)

    def _on_medium_required(self, transaction, medium, drive):
        dialog = AptMediumRequiredDialog(medium, drive, self.window_main)
        res = dialog.run()
        dialog.hide()
        if res == Gtk.ResponseType.OK:
            transaction.provide_medium(medium)
        else:
            transaction.cancel()

    def _on_config_file_conflict(self, transaction, old, new):
        dialog = AptConfigFileConflictDialog(old, new, self.window_main)
        res = dialog.run()
        dialog.hide()
        if res == Gtk.ResponseType.YES:
            transaction.resolve_config_file_conflict(old, "replace")
        else:
            transaction.resolve_config_file_conflict(old, "keep")

    def _on_finished(self, trans, status, action, close_on_done):
        error_string = None
        error_desc = None
        if status == EXIT_FAILED:
            error_string = get_error_string_from_enum(trans.error.code)
            error_desc = get_error_description_from_enum(trans.error.code)
        elif status == EXIT_SUCCESS and close_on_done:
            sys.exit(0)
        # tell unity to hide the progress again
        self.unity.set_progress(-1)
        self.emit("action-done", action, True, status == EXIT_SUCCESS,
                  error_string, error_desc)
Ejemplo n.º 3
0
class InstallBackendAptdaemon(InstallBackend, BuilderDialog):
    """Makes use of aptdaemon to refresh the cache and to install updates."""
    def __init__(self, window_main, action):
        InstallBackend.__init__(self, window_main, action)
        ui_path = os.path.join(window_main.datadir,
                               "gtkbuilder/UpdateProgress.ui")
        BuilderDialog.__init__(self, window_main, ui_path,
                               "pane_update_progress")

        self.client = client.AptClient()
        self.unity = UnitySupport()
        self._expanded_size = None
        self.button_cancel = None
        self.trans_failed_msg = None

    def close(self):
        if self.button_cancel and self.button_cancel.get_sensitive():
            try:
                self.button_cancel.clicked()
            except Exception:
                # there is not much left to do if the transaction can't be
                # canceled
                pass
            return True
        else:
            return False

    @inline_callbacks
    def update(self):
        """Refresh the package list"""
        try:
            trans = yield self.client.update_cache(defer=True)
            yield self._show_transaction(trans, self.ACTION_UPDATE,
                                         _("Checking for updates…"), False)
        except errors.NotAuthorizedError:
            self._action_done(self.ACTION_UPDATE,
                              authorized=False,
                              success=False,
                              error_string=None,
                              error_desc=None)
        except Exception:
            self._action_done(self.ACTION_UPDATE,
                              authorized=True,
                              success=False,
                              error_string=None,
                              error_desc=None)
            raise

    @inline_callbacks
    def commit(self, pkgs_install, pkgs_upgrade, pkgs_remove):
        """Commit a list of package adds and removes"""
        try:
            reinstall = purge = downgrade = []
            trans = yield self.client.commit_packages(pkgs_install,
                                                      reinstall,
                                                      pkgs_remove,
                                                      purge,
                                                      pkgs_upgrade,
                                                      downgrade,
                                                      defer=True)
            trans.connect("progress-changed", self._on_progress_changed)
            yield self._show_transaction(trans, self.ACTION_INSTALL,
                                         _("Installing updates…"), True)
        except errors.NotAuthorizedError:
            self._action_done(self.ACTION_INSTALL,
                              authorized=False,
                              success=False,
                              error_string=None,
                              error_desc=None)
        except errors.TransactionFailed as e:
            self.trans_failed_msg = str(e)
        except dbus.DBusException as e:
            #print(e, e.get_dbus_name())
            if e.get_dbus_name() != "org.freedesktop.DBus.Error.NoReply":
                raise
            self._action_done(self.ACTION_INSTALL,
                              authorized=False,
                              success=False,
                              error_string=None,
                              error_desc=None)
        except Exception:
            self._action_done(self.ACTION_INSTALL,
                              authorized=True,
                              success=False,
                              error_string=None,
                              error_desc=None)
            raise

    def _on_progress_changed(self, trans, progress):
        #print("_on_progress_changed", progress)
        self.unity.set_progress(progress)

    def _on_details_changed(self, trans, details, label_details):
        label_details.set_label(details)

    def _on_status_changed(self, trans, status, label_details, expander):
        label_details.set_label(get_status_string_from_enum(status))
        # Also resize the window if we switch from download details to
        # the terminal window
        if status == STATUS_COMMITTING and expander \
           and expander.terminal.get_visible():
            self._resize_to_show_details(expander)

    @inline_callbacks
    def _show_transaction(self, trans, action, header, show_details):
        self.label_header.set_label(header)

        progressbar = AptProgressBar(trans)
        progressbar.show()
        self.progressbar_slot.add(progressbar)

        self.button_cancel = AptCancelButton(trans)
        if action == self.ACTION_UPDATE:
            self.button_cancel.set_label(Gtk.STOCK_STOP)
        self.button_cancel.show()
        self.button_cancel_slot.add(self.button_cancel)

        if show_details:
            expander = AptDetailsExpander(trans)
            expander.set_vexpand(True)
            expander.set_hexpand(True)
            expander.show_all()
            expander.connect("notify::expanded", self._on_expanded)
            self.expander_slot.add(expander)
            self.expander_slot.show()
        else:
            expander = None

        trans.connect("status-details-changed", self._on_details_changed,
                      self.label_details)
        trans.connect("status-changed", self._on_status_changed,
                      self.label_details, expander)
        trans.connect("finished", self._on_finished, action)
        trans.connect("medium-required", self._on_medium_required)
        trans.connect("config-file-conflict", self._on_config_file_conflict)

        yield trans.set_debconf_frontend("gnome")
        yield trans.run()

    def _on_expanded(self, expander, param):
        # Make the dialog resizable if the expander is expanded
        # try to restore a previous size
        if not expander.get_expanded():
            self._expanded_size = (expander.terminal.get_visible(),
                                   self.window_main.get_size())
            self.window_main.end_user_resizable()
        elif self._expanded_size:
            term_visible, (stored_width, stored_height) = self._expanded_size
            # Check if the stored size was for the download details or
            # the terminal widget
            if term_visible != expander.terminal.get_visible():
                # The stored size was for the download details, so we need
                # get a new size for the terminal widget
                self._resize_to_show_details(expander)
            else:
                self.window_main.begin_user_resizable(stored_width,
                                                      stored_height)
        else:
            self._resize_to_show_details(expander)

    def _resize_to_show_details(self, expander):
        """Resize the window to show the expanded details.

        Unfortunately the expander only expands to the preferred size of the
        child widget (e.g showing all 80x24 chars of the Vte terminal) if
        the window is rendered the first time and the terminal is also visible.
        If the expander is expanded afterwards the window won't change its
        size anymore. So we have to do this manually. See LP#840942
        """
        if expander.get_expanded():
            win_width, win_height = self.window_main.get_size()
            exp_width = expander.get_allocation().width
            exp_height = expander.get_allocation().height
            if expander.terminal.get_visible():
                terminal_width = expander.terminal.get_char_width() * 80
                terminal_height = expander.terminal.get_char_height() * 24
                new_width = terminal_width - exp_width + win_width
                new_height = terminal_height - exp_height + win_height
            else:
                new_width = win_width + 100
                new_height = win_height + 200
            self.window_main.begin_user_resizable(new_width, new_height)

    def _on_medium_required(self, transaction, medium, drive):
        dialog = AptMediumRequiredDialog(medium, drive, self.window_main)
        res = dialog.run()
        dialog.hide()
        if res == Gtk.ResponseType.OK:
            transaction.provide_medium(medium)
        else:
            transaction.cancel()

    def _on_config_file_conflict(self, transaction, old, new):
        dialog = AptConfigFileConflictDialog(old, new, self.window_main)
        res = dialog.run()
        dialog.hide()
        if res == Gtk.ResponseType.YES:
            transaction.resolve_config_file_conflict(old, "replace")
        else:
            transaction.resolve_config_file_conflict(old, "keep")

    def _on_finished(self, trans, status, action):
        error_string = None
        error_desc = None
        trans_failed = False
        if status == EXIT_FAILED:
            error_string = get_error_string_from_enum(trans.error.code)
            error_desc = get_error_description_from_enum(trans.error.code)
            if self.trans_failed_msg:
                trans_failed = True
                error_desc = error_desc + "\n" + self.trans_failed_msg
        # tell unity to hide the progress again
        self.unity.set_progress(-1)
        is_success = (status == EXIT_SUCCESS)
        try:
            self._action_done(action,
                              authorized=True,
                              success=is_success,
                              error_string=error_string,
                              error_desc=error_desc,
                              trans_failed=trans_failed)
        except TypeError:
            # this module used to be be lazily imported and in older code
            # trans_failed= is not accepted
            # TODO: this workaround can be dropped in Ubuntu 20.10
            self._action_done(action,
                              authorized=True,
                              success=is_success,
                              error_string=error_string,
                              error_desc=error_desc)
class InstallBackendAptdaemon(InstallBackend):

    """Makes use of aptdaemon to refresh the cache and to install updates."""

    def __init__(self, window_main):
        InstallBackend.__init__(self, window_main)
        self.client = client.AptClient()
        self.unity = UnitySupport()

    @inline_callbacks
    def update(self):
        """Refresh the package list"""
        try:
            apt.apt_pkg.pkgsystem_unlock()
        except SystemError:
            pass
        try:
            trans = yield self.client.update_cache(defer=True)
            yield self._run_in_dialog(trans, self.UPDATE)
        except errors.NotAuthorizedError:
            self.emit("action-done", self.UPDATE, False, False)
        except:
            self.emit("action-done", self.UPDATE, True, False)
            raise

    @inline_callbacks
    def commit(self, pkgs_install, pkgs_upgrade, close_on_done):
        """Commit a list of package adds and removes"""
        try:
            apt.apt_pkg.pkgsystem_unlock()
        except SystemError:
            pass
        try:
            reinstall = remove = purge = downgrade = []
            trans = yield self.client.commit_packages(
                pkgs_install, reinstall, remove, purge, pkgs_upgrade, 
                downgrade, defer=True)
            trans.connect("progress-changed", self._on_progress_changed)
            yield self._run_in_dialog(trans, self.INSTALL)
        except errors.NotAuthorizedError as e:
            self.emit("action-done", self.INSTALL, False, False)
        except dbus.DBusException as e:
            #print e, e.get_dbus_name()
            if e.get_dbus_name() != "org.freedesktop.DBus.Error.NoReply":
                raise
            self.emit("action-done", self.INSTALL, False, False)
        except Exception as e:
            self.emit("action-done", self.INSTALL, True, False)
            raise

    def _on_progress_changed(self, trans, progress):
        #print "_on_progress_changed", progress
        self.unity.set_progress(progress)

    @inline_callbacks
    def _run_in_dialog(self, trans, action):
        dia = AptProgressDialog(trans, parent=self.window_main)
        dia.set_icon_name("update-manager")
        dia.connect("finished", self._on_finished, action)
        yield dia.run()

    def _on_finished(self, dialog, action):
        dialog.hide()
        # tell unity to hide the progress again
        self.unity.set_progress(-1)
        self.emit("action-done", action, 
                  True, dialog._transaction.exit == EXIT_SUCCESS)