-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a standalone spoke that reports progress of configuration tasks. This is heavily based on ProgressSpoke from anaconda itself, with few minor differences: - logic for "continue"/"reboot" buttons removed - automatic close on finish (as initial-setup normally does) - add basic error reporting - anaconda has elaborate exception handling machinery but initial setup doesn't; add simple try/except in the key place, so user will see the error, not a silent failure
- Loading branch information
Showing
3 changed files
with
356 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- Generated with glade 3.22.1 --> | ||
<interface> | ||
<requires lib="gtk+" version="3.0"/> | ||
<requires lib="AnacondaWidgets" version="3.0"/> | ||
<object class="AnacondaStandaloneWindow" id="progressWindow"> | ||
<property name="can_focus">False</property> | ||
<property name="window_name" translatable="yes">INSTALLATION PROGRESS</property> | ||
<child internal-child="main_box"> | ||
<object class="GtkBox" id="AnacondaStandaloneWindow-main_box1"> | ||
<property name="can_focus">False</property> | ||
<property name="orientation">vertical</property> | ||
<child internal-child="nav_box"> | ||
<object class="GtkEventBox" id="AnacondaStandaloneWindow-nav_box1"> | ||
<property name="can_focus">False</property> | ||
<child internal-child="nav_area"> | ||
<object class="GtkGrid" id="AnacondaStandaloneWindow-nav_area1"> | ||
<property name="can_focus">False</property> | ||
<child> | ||
<placeholder/> | ||
</child> | ||
<child> | ||
<placeholder/> | ||
</child> | ||
</object> | ||
</child> | ||
</object> | ||
<packing> | ||
<property name="expand">False</property> | ||
<property name="fill">False</property> | ||
<property name="position">0</property> | ||
</packing> | ||
</child> | ||
<child internal-child="alignment"> | ||
<object class="GtkAlignment" id="AnacondaStandaloneWindow-alignment1"> | ||
<property name="can_focus">False</property> | ||
<property name="yalign">0</property> | ||
<property name="left_padding">12</property> | ||
<property name="right_padding">6</property> | ||
<child internal-child="action_area"> | ||
<object class="GtkBox" id="progressWindow-actionArea"> | ||
<property name="can_focus">False</property> | ||
<property name="orientation">vertical</property> | ||
<property name="spacing">6</property> | ||
<child> | ||
<object class="GtkBox" id="progressBox"> | ||
<property name="visible">True</property> | ||
<property name="can_focus">False</property> | ||
<property name="valign">center</property> | ||
<property name="orientation">vertical</property> | ||
<property name="spacing">6</property> | ||
<child> | ||
<object class="GtkBox" id="box1"> | ||
<property name="visible">True</property> | ||
<property name="can_focus">False</property> | ||
<property name="valign">center</property> | ||
<property name="spacing">6</property> | ||
<child> | ||
<object class="GtkSpinner" id="progressSpinner"> | ||
<property name="visible">True</property> | ||
<property name="can_focus">False</property> | ||
<property name="active">True</property> | ||
</object> | ||
<packing> | ||
<property name="expand">False</property> | ||
<property name="fill">True</property> | ||
<property name="position">0</property> | ||
</packing> | ||
</child> | ||
<child> | ||
<object class="GtkLabel" id="progressLabel"> | ||
<property name="visible">True</property> | ||
<property name="can_focus">False</property> | ||
<property name="halign">start</property> | ||
<property name="label" translatable="yes">Preparing to install</property> | ||
</object> | ||
<packing> | ||
<property name="expand">True</property> | ||
<property name="fill">True</property> | ||
<property name="position">1</property> | ||
</packing> | ||
</child> | ||
</object> | ||
<packing> | ||
<property name="expand">False</property> | ||
<property name="fill">True</property> | ||
<property name="position">0</property> | ||
</packing> | ||
</child> | ||
<child> | ||
<object class="GtkProgressBar" id="progressBar"> | ||
<property name="visible">True</property> | ||
<property name="can_focus">False</property> | ||
<property name="valign">center</property> | ||
</object> | ||
<packing> | ||
<property name="expand">False</property> | ||
<property name="fill">True</property> | ||
<property name="position">1</property> | ||
</packing> | ||
</child> | ||
</object> | ||
<packing> | ||
<property name="expand">True</property> | ||
<property name="fill">True</property> | ||
<property name="position">0</property> | ||
</packing> | ||
</child> | ||
<child> | ||
<object class="GtkNotebook" id="progressNotebook"> | ||
<property name="visible">True</property> | ||
<property name="can_focus">False</property> | ||
<property name="valign">end</property> | ||
<property name="margin_bottom">10</property> | ||
<property name="show_tabs">False</property> | ||
<property name="show_border">False</property> | ||
<child> | ||
<object class="GtkBox" id="emptyBox"> | ||
<property name="visible">True</property> | ||
<property name="can_focus">False</property> | ||
<child> | ||
<placeholder/> | ||
</child> | ||
</object> | ||
</child> | ||
<child> | ||
<object class="GtkLabel" id="rebootLabel"> | ||
<property name="visible">True</property> | ||
<property name="can_focus">False</property> | ||
<property name="halign">end</property> | ||
<property name="valign">end</property> | ||
<property name="label">%s is now successfully installed and ready for you to use! | ||
Go ahead and reboot to start using it!</property> | ||
<property name="justify">right</property> | ||
<property name="wrap">True</property> | ||
</object> | ||
<packing> | ||
<property name="position">1</property> | ||
</packing> | ||
</child> | ||
<child type="tab"> | ||
<placeholder/> | ||
</child> | ||
</object> | ||
<packing> | ||
<property name="expand">False</property> | ||
<property name="fill">True</property> | ||
<property name="position">1</property> | ||
</packing> | ||
</child> | ||
</object> | ||
</child> | ||
</object> | ||
<packing> | ||
<property name="expand">True</property> | ||
<property name="fill">True</property> | ||
<property name="position">1</property> | ||
</packing> | ||
</child> | ||
</object> | ||
</child> | ||
<child internal-child="accessible"> | ||
<object class="AtkObject" id="progressWindow-atkobject"> | ||
<property name="AtkObject::accessible-name" translatable="yes">INSTALLATION PROGRESS</property> | ||
</object> | ||
</child> | ||
</object> | ||
</interface> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
# | ||
# Copyright (C) 2011-2013 Red Hat, Inc. | ||
# | ||
# This copyrighted material is made available to anyone wishing to use, | ||
# modify, copy, or redistribute it subject to the terms and conditions of | ||
# the GNU General Public License v.2, or (at your option) any later version. | ||
# This program is distributed in the hope that it will be useful, but WITHOUT | ||
# ANY WARRANTY expressed or implied, including the implied warranties 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, write to the | ||
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the | ||
# source code or documentation are not subject to the GNU General Public | ||
# License and may only be used or replicated with the express permission of | ||
# Red Hat, Inc. | ||
import gi | ||
gi.require_version('Gtk', '3.0') | ||
from gi.repository import Gtk | ||
|
||
from initial_setup import InitialSetupTask | ||
from initial_setup.gui.hubs import InitialSetupMainHub | ||
from pyanaconda.anaconda_loggers import get_module_logger | ||
from pyanaconda.core.i18n import _, C_ | ||
from pyanaconda.modules.common.constants.services import USERS | ||
from pyanaconda.product import productName | ||
from pyanaconda.flags import flags | ||
from pyanaconda.core import util | ||
from pyanaconda.core.configuration.anaconda import conf | ||
from pyanaconda.core.constants import IPMI_FINISHED | ||
from pyanaconda.ui.common import FirstbootOnlySpokeMixIn | ||
from pykickstart.constants import KS_SHUTDOWN, KS_REBOOT | ||
from pyanaconda.ui.gui.spokes import StandaloneSpoke | ||
from pyanaconda.ui.gui.utils import gtk_call_once | ||
|
||
log = get_module_logger(__name__) | ||
|
||
__all__ = ["ProgressSpoke"] | ||
|
||
|
||
class ProgressSpoke(FirstbootOnlySpokeMixIn, StandaloneSpoke): | ||
""" | ||
.. inheritance-diagram:: ProgressSpoke | ||
:parts: 3 | ||
""" | ||
|
||
builderObjects = ["progressWindow"] | ||
mainWidgetName = "progressWindow" | ||
uiFile = "setup_progress.glade" | ||
postForHub = InitialSetupMainHub | ||
|
||
@staticmethod | ||
def get_screen_id(): | ||
"""Return a unique id of this UI screen.""" | ||
return "installation-progress" | ||
|
||
def __init__(self, data, storage, payload): | ||
super().__init__(data, storage, payload) | ||
self._progressBar = self.builder.get_object("progressBar") | ||
self._progressLabel = self.builder.get_object("progressLabel") | ||
self._progressNotebook = self.builder.get_object("progressNotebook") | ||
self._spinner = self.builder.get_object("progressSpinner") | ||
self._task = None | ||
|
||
# Record if groups, users or root password has been set before Initial Setup | ||
# has been started, so that we don't trample over existing configuration. | ||
log.info("collecting initial state") | ||
users_proxy = USERS.get_proxy() | ||
self._groups_already_configured = bool(users_proxy.Groups) | ||
self._users_already_configured = bool(users_proxy.Users) | ||
self._root_password_already_configured = users_proxy.IsRootPasswordSet | ||
|
||
@property | ||
def completed(self): | ||
"""This spoke is never completed, initially.""" | ||
return False | ||
|
||
def apply(self): | ||
"""There is nothing to apply.""" | ||
pass | ||
|
||
def _on_installation_done(self): | ||
log.debug("The initial setup has finished.") | ||
|
||
# Stop the spinner. | ||
gtk_call_once(self._spinner.stop) | ||
gtk_call_once(self._spinner.hide) | ||
|
||
# Finish the installation task. Re-raise tracebacks if any. | ||
try: | ||
self._task.finish() | ||
except Exception as e: | ||
log.exception("Initial setup failed") | ||
self.showErrorMessageHelper(str(e)) | ||
|
||
util.ipmi_report(IPMI_FINISHED) | ||
|
||
if conf.license.eula: | ||
self.set_warning(_("Use of this product is subject to the license agreement " | ||
"found at %s") % conf.license.eula) | ||
self.window.show_all() | ||
|
||
# Show the reboot message. | ||
self._progressNotebook.set_current_page(1) | ||
|
||
# Enable the continue button. | ||
self.window.set_may_continue(True) | ||
|
||
# Hide the quit button. | ||
quit_button = self.window.get_quit_button() | ||
quit_button.hide() | ||
|
||
# automatically close; if there was an error, showErrorMessageHelper | ||
# already waited for the user to click ok | ||
self.window.emit("continue-clicked") | ||
|
||
def initialize(self): | ||
super().initialize() | ||
# Disable the continue button. | ||
self.window.set_may_continue(False) | ||
|
||
# Set the label of the continue button. | ||
continue_label = C_("GUI|Progress", "_Finish Installation") | ||
|
||
continue_button = self.window.get_continue_button() | ||
continue_button.set_label(continue_label) | ||
|
||
# Set the reboot label. | ||
continue_text = _( | ||
"%s is now successfully installed and ready for you to use!\n" | ||
"Go ahead and quit the application to start using it!" | ||
) % productName | ||
|
||
label = self.builder.get_object("rebootLabel") | ||
label.set_text(continue_text) | ||
|
||
# Don't show the reboot message. | ||
self._progressNotebook.set_current_page(0) | ||
|
||
def refresh(self): | ||
from pyanaconda.installation import RunInstallationTask | ||
super().refresh() | ||
|
||
# Initialize the progress bar. | ||
gtk_call_once(self._progressBar.set_fraction, 0.0) | ||
|
||
# Start the installation task. | ||
self._task = InitialSetupTask( | ||
groups_already_configured=self._groups_already_configured, | ||
users_already_configured=self._users_already_configured, | ||
root_password_already_configured=self._root_password_already_configured, | ||
) | ||
self._task.progress_changed_signal.connect( | ||
self._on_progress_changed | ||
) | ||
self._task.stopped_signal.connect( | ||
self._on_installation_done | ||
) | ||
self._task.start() | ||
|
||
# Start the spinner. | ||
gtk_call_once(self._spinner.start) | ||
|
||
log.debug("The installation has started.") | ||
|
||
def showErrorMessageHelper(self, text): | ||
dlg = Gtk.MessageDialog(title="Error", message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.OK, text=text) | ||
dlg.set_position(Gtk.WindowPosition.CENTER) | ||
dlg.set_modal(True) | ||
dlg.set_transient_for(self.main_window) | ||
dlg.run() | ||
dlg.destroy() | ||
|
||
def _on_progress_changed(self, step, message): | ||
"""Handle a new progress report.""" | ||
if message: | ||
gtk_call_once(self._progressLabel.set_text, message) | ||
|
||
if self._task.steps > 0: | ||
gtk_call_once(self._progressBar.set_fraction, step/self._task.steps) |