[PATCH f18-alpha] 2nd version of Make progress hub spokes possible and move the root password there

Martin Sivak msivak at redhat.com
Wed Sep 12 13:55:00 UTC 2012


- Splits doInstall to doInstall and doConfiguration
- Updates text and gui mode to use doConfiguration
---
 pyanaconda/install.py                         | 60 +++++++++++--------
 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         | 75 ++++++++++++++++++++++-
 pyanaconda/ui/gui/hubs/progress.py            | 86 +++++++++++++++++++++++++--
 pyanaconda/ui/gui/spokes/password.py          | 10 ++--
 pyanaconda/ui/tui/hubs/progress.py            | 24 +++++---
 8 files changed, 279 insertions(+), 46 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 6080610..912dd6b 100644
--- a/pyanaconda/install.py
+++ b/pyanaconda/install.py
@@ -40,6 +40,40 @@ 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)
+        
+    # 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.
@@ -54,8 +88,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.
@@ -78,27 +111,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)
-
-        # 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 f5e211f..5dfe8ed 100644
--- a/pyanaconda/ui/gui/hubs/__init__.py
+++ b/pyanaconda/ui/gui/hubs/__init__.py
@@ -222,8 +222,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 1eb32c9..a7efce6 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>
@@ -121,6 +122,76 @@
                           <placeholder/>
                         </child>
                         <child>
+                          <placeholder/>
+                        </child>
+                        <child type="tab">
+                          <placeholder/>
+                        </child>
+                        <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">2</property>
+                          </packing>
+                        </child>
+                        <child type="tab">
+                          <object class="GtkLabel" id="label1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label" translatable="yes">page 3</property>
+                          </object>
+                          <packing>
+                            <property name="position">2</property>
+                            <property name="tab_fill">False</property>
+                          </packing>
+                        </child>
+                        <child>
                           <object class="GtkGrid" id="rebootGrid">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
@@ -169,7 +240,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 13d1811..819d5ab 100644
--- a/pyanaconda/ui/gui/hubs/progress.py
+++ b/pyanaconda/ui/gui/hubs/progress.py
@@ -49,10 +49,73 @@ class ProgressHub(Hub):
 
         self._totalSteps = 0
         self._currentStep = 0
-
+        self._configurationDone = False
+        
         self._rnotes = itertools.cycle(self._get_rnotes())
 
-    def _update_progress(self):
+    def _update_install_progress(self):
+        from pyanaconda import progress
+        import Queue
+
+        q = progress.progressQ
+
+        # Grab all messages may have appeared since last time this method ran.
+        while True:
+            # Attempt to get a message out of the queue for how we should update
+            # the progress bar.  If there's no message, don't error out.
+            try:
+                (code, args) = q.get(False)
+            except Queue.Empty:
+                break
+
+            if code == progress.PROGRESS_CODE_INIT:
+                self._init_progress_bar(args[0])
+            elif code == progress.PROGRESS_CODE_STEP:
+                self._step_progress_bar()
+            elif code == progress.PROGRESS_CODE_MESSAGE:
+                self._update_progress_message(args[0])
+            elif code == progress.PROGRESS_CODE_COMPLETE:
+                # There shouldn't be any more progress bar updates, so return False
+                # to indicate this method should be removed from the idle loop.  Also,
+                # stop the rnotes cycling and display the finished message.
+                self._progress_bar_complete()
+                q.task_done()
+
+                # 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()
+
+                else:
+                    # some mandatory spokes are not ready
+                    # switch to configure and finish page
+                    self._progressNotebook.next_page()
+                    
+                return False
+
+            q.task_done()
+
+        return True
+
+    def _do_configuration(self, widget = None):
+        from pyanaconda.install import doConfiguration
+        from pyanaconda.threads import threadMgr, AnacondaThread
+
+        assert self._configurationDone == False
+        
+        self._configurationDone = True
+        
+        # TODO disable all personalization spokes
+        self.builder.get_object("progressWindow-scroll").set_sensitive(False)
+        
+        # Switch back to progress
+        self._progressNotebook.set_current_page(0)
+        
+        self._progress_id = GLib.timeout_add(250, self._update_configuration_progress)
+        threadMgr.add(AnacondaThread(name="AnaConfigurationThread", target=doConfiguration,
+                                     args=(self.storage, self.payload, self.data, self.instclass)))
+    
+    def _update_configuration_progress(self):
         from pyanaconda import progress
         import Queue
 
@@ -82,7 +145,7 @@ class ProgressHub(Hub):
 
                 GLib.source_remove(self._rnotes_id)
 
-                self._progressNotebook.next_page()
+                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]:
@@ -94,6 +157,7 @@ class ProgressHub(Hub):
 
         return True
 
+    
     def _get_rnotes(self):
         import glob
 
@@ -133,6 +197,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)
 
@@ -146,15 +213,21 @@ class ProgressHub(Hub):
         # seconds, so we need to do the first call manually.
         self._cycle_rnotes()
 
-        self._progress_id = GLib.idle_add(self._update_progress)
+        self._progress_id = GLib.timeout_add(250, self._update_install_progress)
         self._rnotes_id = GLib.timeout_add_seconds(60, self._cycle_rnotes)
         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
@@ -162,6 +235,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