[PATCH 1/2] Make progress hub spokes possible and move the root password there
Martin Sivak
msivak at redhat.com
Thu Sep 13 11:57:43 UTC 2012
- Splits doInstall to doInstall and doConfiguration
- Updates text and gui mode to use doConfiguration
---
pyanaconda/install.py | 67 ++++++++++++---------
pyanaconda/ui/gui/categories/customization.py | 32 ++++++++++
pyanaconda/ui/gui/categories/user_settings.py | 32 ++++++++++
pyanaconda/ui/gui/hubs/__init__.py | 6 +-
pyanaconda/ui/gui/hubs/progress.glade | 58 +++++++++++++++++-
pyanaconda/ui/gui/hubs/progress.py | 87 +++++++++++++++++++++------
pyanaconda/ui/gui/spokes/password.py | 10 ++-
pyanaconda/ui/tui/hubs/progress.py | 24 +++++---
8 files changed, 255 insertions(+), 61 deletions(-)
create mode 100644 pyanaconda/ui/gui/categories/customization.py
create mode 100644 pyanaconda/ui/gui/categories/user_settings.py
diff --git a/pyanaconda/install.py b/pyanaconda/install.py
index 3db5ee0..d401e2f 100644
--- a/pyanaconda/install.py
+++ b/pyanaconda/install.py
@@ -42,6 +42,44 @@ def _writeKS(ksdata):
# Make it so only root can read - could have passwords
os.chmod(path, 0600)
+def doConfiguration(storage, payload, ksdata, instClass):
+ from pyanaconda import progress
+ from pyanaconda.kickstart import runPostScripts
+
+ progress.send_init(4)
+
+ # Now run the execute methods of ksdata that require an installed system
+ # to be present first.
+ with progress_report(_("Configuring installed system")):
+ ksdata.authconfig.execute(storage, ksdata, instClass)
+ ksdata.selinux.execute(storage, ksdata, instClass)
+ ksdata.firstboot.execute(storage, ksdata, instClass)
+ ksdata.services.execute(storage, ksdata, instClass)
+ ksdata.keyboard.execute(storage, ksdata, instClass)
+ ksdata.timezone.execute(storage, ksdata, instClass)
+ ksdata.lang.execute(storage, ksdata, instClass)
+
+ with progress_report(_("Writing network configuration")):
+ writeNetworkConf(storage, ksdata, instClass)
+
+ # Creating users and groups requires some pre-configuration.
+ with progress_report(_("Creating users")):
+ u = Users()
+ createLuserConf(ROOT_PATH, algoname=getPassAlgo(ksdata.authconfig.authconfig))
+
+ ksdata.rootpw.execute(storage, ksdata, instClass, u)
+ ksdata.group.execute(storage, ksdata, instClass, u)
+ ksdata.user.execute(storage, ksdata, instClass, u)
+
+ with progress_report(_("Running post install scripts")):
+ runPostScripts(ksdata.scripts)
+
+ # Write the kickstart file to the installed system (or, copy the input
+ # kickstart file over if one exists).
+ _writeKS(ksdata)
+
+ progress.send_complete()
+
def doInstall(storage, payload, ksdata, instClass):
"""Perform an installation. This method takes the ksdata as prepared by
the UI (the first hub, in graphical mode) and applies it to the disk.
@@ -56,8 +94,7 @@ def doInstall(storage, payload, ksdata, instClass):
steps = len(storage.devicetree.findActions(type="create", object="format")) + \
len(storage.devicetree.findActions(type="resize", object="format")) + \
len(storage.devicetree.findActions(type="migrate", object="format"))
- steps += 5 # packages setup, packages, bootloader, post install,
- # configuring
+ steps += 4 # packages setup, packages, bootloader, post install
progress.send_init(steps)
# Do partitioning.
@@ -85,30 +122,4 @@ def doInstall(storage, payload, ksdata, instClass):
with progress_report(_("Installing bootloader")):
writeBootLoader(storage, payload, instClass)
- with progress_report(_("Configuring installed system")):
- # Now run the execute methods of ksdata that require an installed system
- # to be present first.
- ksdata.authconfig.execute(storage, ksdata, instClass)
- ksdata.selinux.execute(storage, ksdata, instClass)
- ksdata.firstboot.execute(storage, ksdata, instClass)
- ksdata.services.execute(storage, ksdata, instClass)
- ksdata.keyboard.execute(storage, ksdata, instClass)
- ksdata.timezone.execute(storage, ksdata, instClass)
- ksdata.lang.execute(storage, ksdata, instClass)
-
- writeNetworkConf(storage, ksdata, instClass)
-
- # Creating users and groups requires some pre-configuration.
- createLuserConf(ROOT_PATH, algoname=getPassAlgo(ksdata.authconfig.authconfig))
- u = Users()
- ksdata.rootpw.execute(storage, ksdata, instClass, u)
- ksdata.group.execute(storage, ksdata, instClass, u)
- ksdata.user.execute(storage, ksdata, instClass, u)
-
- runPostScripts(ksdata.scripts)
-
- # Write the kickstart file to the installed system (or, copy the input
- # kickstart file over if one exists).
- _writeKS(ksdata)
-
progress.send_complete()
diff --git a/pyanaconda/ui/gui/categories/customization.py b/pyanaconda/ui/gui/categories/customization.py
new file mode 100644
index 0000000..68b422c
--- /dev/null
+++ b/pyanaconda/ui/gui/categories/customization.py
@@ -0,0 +1,32 @@
+# Localization category classes
+#
+# Copyright (C) 2011 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.
+#
+# Red Hat Author(s): Chris Lumens <clumens at redhat.com>
+# Martin Sivak <msivak at redhat.com>
+#
+
+N_ = lambda x: x
+
+from pyanaconda.ui.gui.categories import SpokeCategory
+from pyanaconda.ui.gui.hubs.progress import ProgressHub
+
+__all__ = ["CustomizationCategory"]
+
+class CustomizationCategory(SpokeCategory):
+ displayOnHub = ProgressHub
+ title = N_("CUSTOMIZATION")
diff --git a/pyanaconda/ui/gui/categories/user_settings.py b/pyanaconda/ui/gui/categories/user_settings.py
new file mode 100644
index 0000000..b9838b8
--- /dev/null
+++ b/pyanaconda/ui/gui/categories/user_settings.py
@@ -0,0 +1,32 @@
+# Localization category classes
+#
+# Copyright (C) 2011 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.
+#
+# Red Hat Author(s): Chris Lumens <clumens at redhat.com>
+# Martin Sivak <msivak at redhat.com>
+#
+
+N_ = lambda x: x
+
+from pyanaconda.ui.gui.categories import SpokeCategory
+from pyanaconda.ui.gui.hubs.progress import ProgressHub
+
+__all__ = ["UserSettingsCategory"]
+
+class UserSettingsCategory(SpokeCategory):
+ displayOnHub = ProgressHub
+ title = N_("USER SETTINGS")
diff --git a/pyanaconda/ui/gui/hubs/__init__.py b/pyanaconda/ui/gui/hubs/__init__.py
index 4d8c6e3..13f6192 100644
--- a/pyanaconda/ui/gui/hubs/__init__.py
+++ b/pyanaconda/ui/gui/hubs/__init__.py
@@ -224,8 +224,12 @@ class Hub(GUIObject, common.Hub):
self.window.set_info(Gtk.MessageType.WARNING, msg)
+ @property
+ def continuePossible(self):
+ return len(self._incompleteSpokes) == 0 and len(self._notReadySpokes) == 0
+
def _updateContinueButton(self):
- self.continueButton.set_sensitive(len(self._incompleteSpokes) == 0 and len(self._notReadySpokes) == 0)
+ self.continueButton.set_sensitive(self.continuePossible)
def _update_spokes(self):
from pyanaconda.ui.gui import communication
diff --git a/pyanaconda/ui/gui/hubs/progress.glade b/pyanaconda/ui/gui/hubs/progress.glade
index 036fcb4..39a1532 100644
--- a/pyanaconda/ui/gui/hubs/progress.glade
+++ b/pyanaconda/ui/gui/hubs/progress.glade
@@ -6,7 +6,7 @@
<property name="startup_id">filler</property>
<property name="can_focus">False</property>
<property name="startup_id">filler</property>
- <property name="window_name">PERSONALIZATION</property>
+ <property name="window_name">CONFIGURATION</property>
<child internal-child="main_box">
<object class="GtkBox" id="AnacondaHubWindow-main_box1">
<property name="can_focus">False</property>
@@ -29,6 +29,7 @@
<property name="can_focus">False</property>
<property name="yalign">0</property>
<property name="xscale">0.5</property>
+ <property name="yscale">0.5</property>
<child internal-child="action_area">
<object class="GtkBox" id="progressWindow-actionArea">
<property name="can_focus">False</property>
@@ -111,6 +112,59 @@
<property name="show_tabs">False</property>
<property name="show_border">False</property>
<child>
+ <object class="GtkGrid" id="configurationGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="configurationLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">end</property>
+ <property name="label" translatable="yes">%s is now successfully installed on your system, but some configuration still needs to be done.
+Finish it and then click the Finish configuration button please.</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="configureButton">
+ <property name="label" translatable="yes">_Finish configuration</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">end</property>
+ <property name="valign">end</property>
+ <property name="hexpand">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="_do_configuration" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkGrid" id="rebootGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -159,7 +213,7 @@ for you to use! Go ahead and reboot to start using it!</property>
</child>
</object>
<packing>
- <property name="position">1</property>
+ <property name="position">3</property>
</packing>
</child>
<child type="tab">
diff --git a/pyanaconda/ui/gui/hubs/progress.py b/pyanaconda/ui/gui/hubs/progress.py
index 4033d7b..c1fd030 100644
--- a/pyanaconda/ui/gui/hubs/progress.py
+++ b/pyanaconda/ui/gui/hubs/progress.py
@@ -49,8 +49,33 @@ class ProgressHub(Hub):
self._totalSteps = 0
self._currentStep = 0
+ self._configurationDone = False
- def _update_progress(self):
+ def _do_configuration(self, widget = None, reenable_ransom = True):
+ from pyanaconda.install import doConfiguration
+ from pyanaconda.threads import threadMgr, AnacondaThread
+
+ assert self._configurationDone == False
+
+ self._configurationDone = True
+
+ # Disable all personalization spokes
+ self.builder.get_object("progressWindow-scroll").set_sensitive(False)
+
+ if reenable_ransom:
+ self._start_ransom_notes()
+
+ self._progress_id = GLib.timeout_add(250, self._update_progress, self._configuration_done)
+ threadMgr.add(AnacondaThread(name="AnaConfigurationThread", target=doConfiguration,
+ args=(self.storage, self.payload, self.data, self.instclass)))
+
+ def _start_ransom_notes(self):
+ # Adding this as a timeout below means it'll get called after 60
+ # seconds, so we need to do the first call manually.
+ self._cycle_rnotes()
+ self._rnotes_id = GLib.timeout_add_seconds(60, self._cycle_rnotes)
+
+ def _update_progress(self, callback = None):
from pyanaconda import progress
import Queue
@@ -78,13 +103,8 @@ class ProgressHub(Hub):
self._progress_bar_complete()
q.task_done()
- GLib.source_remove(self._rnotes_id)
-
- self._progressNotebook.set_current_page(0)
-
- # kickstart install, continue automatically if reboot or shutdown selected
- if flags.automatedInstall and self.data.reboot.action in [KS_REBOOT, KS_SHUTDOWN]:
- self.continueButton.emit("clicked")
+ if callback:
+ callback()
return False
@@ -92,6 +112,31 @@ class ProgressHub(Hub):
return True
+
+ def _configuration_done(self):
+ # Configuration done, remove ransom notes timer
+ # and switch to the Reboot page
+
+ GLib.source_remove(self._rnotes_id)
+ self._progressNotebook.set_current_page(1)
+
+ # kickstart install, continue automatically if reboot or shutdown selected
+ if flags.automatedInstall and self.data.reboot.action in [KS_REBOOT, KS_SHUTDOWN]:
+ self.continueButton.emit("clicked")
+
+
+ def _install_done(self):
+ # package installation done, check personalization spokes
+ # and start the configuration step if all is ready
+ if not self._inSpoke and self.continuePossible:
+ self._do_configuration(reenable_ransom = False)
+
+ else:
+ # some mandatory spokes are not ready
+ # switch to configure and finish page
+ GLib.source_remove(self._rnotes_id)
+ self._progressNotebook.set_current_page(0)
+
def _get_rnotes(self):
import glob
@@ -130,6 +175,9 @@ class ProgressHub(Hub):
self._progressLabel = self.builder.get_object("progressLabel")
self._progressNotebook = self.builder.get_object("progressNotebook")
+ lbl = self.builder.get_object("configurationLabel")
+ lbl.set_text(lbl.get_text() % productName)
+
lbl = self.builder.get_object("rebootLabel")
lbl.set_text(lbl.get_text() % productName)
@@ -142,14 +190,14 @@ class ProgressHub(Hub):
self._progressNotebook.append_page(img, None)
# An infinite list of the page numbers containing ransom notes images.
- self._rnotesPages = itertools.cycle(range(1, self._progressNotebook.get_n_pages()-1))
+ self._rnotesPages = itertools.cycle(range(2, self._progressNotebook.get_n_pages()-2))
else:
# Add a blank page to the notebook and we'll just cycle to that
# over and over again.
blank = Gtk.Box()
blank.show()
self._progressNotebook.append_page(blank, None)
- self._rnotesPages = itertools.cycle([1])
+ self._rnotesPages = itertools.cycle([2])
def refresh(self):
from pyanaconda.install import doInstall
@@ -157,19 +205,21 @@ class ProgressHub(Hub):
Hub.refresh(self)
- # Adding this as a timeout below means it'll get called after 60
- # seconds, so we need to do the first call manually.
- self._cycle_rnotes()
-
- self._progress_id = GLib.timeout_add(250, self._update_progress)
- self._rnotes_id = GLib.timeout_add_seconds(60, self._cycle_rnotes)
+ self._start_ransom_notes()
+ self._progress_id = GLib.timeout_add(250, self._update_progress, self._install_done)
threadMgr.add(AnacondaThread(name="AnaInstallThread", target=doInstall,
args=(self.storage, self.payload, self.data, self.instclass)))
+ def _updateContinueButton(self):
+ if self._configurationDone:
+ self.continueButton.set_sensitive(self.continuePossible)
+ else:
+ self.builder.get_object("configureButton").set_sensitive(self.continuePossible)
+
@property
def continueButton(self):
return self.builder.get_object("rebootButton")
-
+
def _init_progress_bar(self, steps):
self._totalSteps = steps
self._currentStep = 0
@@ -177,6 +227,9 @@ class ProgressHub(Hub):
with gdk_threaded():
self._progressBar.set_fraction(0.0)
+ spinner = self.builder.get_object("progressSpinner")
+ spinner.start()
+
def _step_progress_bar(self):
if not self._totalSteps:
return
diff --git a/pyanaconda/ui/gui/spokes/password.py b/pyanaconda/ui/gui/spokes/password.py
index ac6e353..b3d33de 100644
--- a/pyanaconda/ui/gui/spokes/password.py
+++ b/pyanaconda/ui/gui/spokes/password.py
@@ -30,8 +30,7 @@ import pwquality
import string
from pyanaconda.ui.gui.spokes import NormalSpoke
-# Need a new category I guess
-from pyanaconda.ui.gui.categories.localization import LocalizationCategory
+from pyanaconda.ui.gui.categories.user_settings import UserSettingsCategory
#from _isys import isCapsLockEnabled
__all__ = ["PasswordSpoke"]
@@ -43,8 +42,7 @@ class PasswordSpoke(NormalSpoke):
mainWidgetName = "passwordWindow"
uiFile = "spokes/password.glade"
- # update this category to something... new?
- category = LocalizationCategory
+ category = UserSettingsCategory
icon = "dialog-password-symbolic"
title = N_("ROOT PASSWORD")
@@ -102,7 +100,7 @@ class PasswordSpoke(NormalSpoke):
# We are by default complete, but locked. If a user attempts to set
# a password but fails, then we are no longer complete.
return not self._error
-
+
def _validatePassword(self):
# Do various steps to validate the password
# sets self._error to an error string
@@ -164,4 +162,4 @@ class PasswordSpoke(NormalSpoke):
self.window.clear_info()
self.window.set_info(Gtk.MessageType.WARNING, self._error)
self.pw.grab_focus()
- self.window.show_all()
\ No newline at end of file
+ self.window.show_all()
diff --git a/pyanaconda/ui/tui/hubs/progress.py b/pyanaconda/ui/tui/hubs/progress.py
index cbf384d..e0a0176 100644
--- a/pyanaconda/ui/tui/hubs/progress.py
+++ b/pyanaconda/ui/tui/hubs/progress.py
@@ -80,11 +80,6 @@ class ProgressHub(TUIHub):
# There shouldn't be any more progress updates, so return
q.task_done()
- # kickstart install, continue automatically if reboot or shutdown selected
- if flags.automatedInstall and self.data.reboot.action in [KS_REBOOT, KS_SHUTDOWN]:
- # Just pretend like we got input, and our input doesn't care
- # what it gets, it just quits.
- self.input(None, None)
if self._stepped:
print('')
@@ -94,7 +89,7 @@ class ProgressHub(TUIHub):
return True
def refresh(self, args):
- from pyanaconda.install import doInstall
+ from pyanaconda.install import doInstall, doConfiguration
from pyanaconda.threads import threadMgr, AnacondaThread
# We print this here because we don't really use the window object
@@ -105,7 +100,22 @@ class ProgressHub(TUIHub):
self.instclass)))
# This will run until we're all done with the install thread.
- return self._update_progress()
+ self._update_progress()
+
+ threadMgr.add(AnacondaThread(name="AnaConfigurationThread", target=doConfiguration,
+ args=(self.storage, self.payload, self.data,
+ self.instclass)))
+
+ # This will run until we're all done with the configuration thread.
+ self._update_progress()
+
+ # kickstart install, continue automatically if reboot or shutdown selected
+ if flags.automatedInstall and self.data.reboot.action in [KS_REBOOT, KS_SHUTDOWN]:
+ # Just pretend like we got input, and our input doesn't care
+ # what it gets, it just quits.
+ self.input(None, None)
+
+ return True
def prompt(self, args = None):
return(_("\tInstallation complete. Press return to quit"))
--
1.7.11.4
More information about the anaconda-patches
mailing list