[PATCH] Add support for autostep and --autoscreenshot (#1234896)

Vratislav Podzimek vpodzime at redhat.com
Wed Jul 29 09:30:32 UTC 2015


On Tue, 2015-07-28 at 17:03 +0200, Martin Kolman wrote:
> Add the missing support for the autostep [--autoscreenshot]
> kickstart command to Anaconda. If just autostep is specified, Anaconda will
> iterate over all active spokes just before leaving a hub.
> If the --autoscreenshot option specified, it will also take a screenshot of
> all hubs and of each spoke.
> 
> Also turn the take-screenshot code into a proper function that can
> be called when auto-screenshotting and remove the old copy-screenshot
> post-script (the last batch of screenshots is taken after the
> postscripts have run, so screenshot copying is now handled
> elsewhere).
> 
> Resolves: rhbz#1234896
> Signed-off-by: Martin Kolman <mkolman at redhat.com>
> ---
>  pyanaconda/constants.py              |   4 +
>  pyanaconda/iutil.py                  |  27 ++++++
>  pyanaconda/ui/gui/__init__.py        | 172 +++++++++++++++++++++++++++++++----
>  pyanaconda/ui/gui/hubs/__init__.py   |  55 +++++++++++
>  pyanaconda/ui/gui/spokes/__init__.py |   9 ++
>  pyanaconda/ui/gui/spokes/welcome.py  |   5 +-
>  6 files changed, 253 insertions(+), 19 deletions(-)
> 
> diff --git a/pyanaconda/constants.py b/pyanaconda/constants.py
> index 807bf0d..d9ee11f 100644
> --- a/pyanaconda/constants.py
> +++ b/pyanaconda/constants.py
> @@ -154,6 +154,10 @@ PW_ASCII_CHARS = string.digits + string.ascii_letters + string.punctuation + " "
>  # Recognizing a tarfile
>  TAR_SUFFIX = (".tar", ".tbz", ".tgz", ".txz", ".tar.bz2", "tar.gz", "tar.xz")
>  
> +# screenshots
> +SCREENSHOTS_DIRECTORY = "/tmp/anaconda-screenshots"
> +SCREENSHOTS_TARGET_DIRECTORY = "/root/anaconda-screenshots"
> +
>  # cmdline arguments that append instead of overwrite
>  CMDLINE_APPEND = ["modprobe.blacklist"]
>  
> diff --git a/pyanaconda/iutil.py b/pyanaconda/iutil.py
> index c827431..57baf90 100644
> --- a/pyanaconda/iutil.py
> +++ b/pyanaconda/iutil.py
> @@ -27,6 +27,7 @@ import os.path
>  import errno
>  import subprocess
>  import unicodedata
> +import shutil
>  import string
>  import tempfile
>  import types
> @@ -36,6 +37,7 @@ import signal
>  
>  from pyanaconda.flags import flags
>  from pyanaconda.constants import DRACUT_SHUTDOWN_EJECT, TRANSLATIONS_UPDATE_DIR, UNSUPPORTED_HW
> +from pyanaconda.constants import SCREENSHOTS_DIRECTORY, SCREENSHOTS_TARGET_DIRECTORY
>  from pyanaconda.regexes import URL_PARSE
>  
>  from pyanaconda.i18n import _
> @@ -1191,3 +1193,28 @@ def get_platform_groupid():
>  def parent_dir(directory):
>      """Return the parent's path"""
>      return "/".join(os.path.normpath(directory).split("/")[:-1])
> +
> +def sysroot_path(path):
> +    """Make the given relative or absolute path "sysrooted"
> +       :param str path: path to be sysrooted
> +       :returns: sysrooted path
> +       :rtype: str
> +    """
> +    return os.path.join(getSysroot(), path.lstrip(os.path.sep))
> +
> +def save_screenshots():
> +    """Save screenshots to the installed system"""
> +    if not os.path.exists(SCREENSHOTS_DIRECTORY):
> +        # there are no screenshots to copy
> +        return
> +    target_path = sysroot_path(SCREENSHOTS_TARGET_DIRECTORY)
> +    log.info("saving screenshots taken during the installation to: %s", target_path)
> +    try:
> +        # create the screenshots directory
> +        mkdirChain(target_path)
> +        # copy all screenshots
> +        for filename in os.listdir(SCREENSHOTS_DIRECTORY):
> +            shutil.copy(os.path.join(SCREENSHOTS_DIRECTORY, filename), target_path)
> +
> +    except OSError:
> +        log.exception("saving screenshots to installed system failed")
> diff --git a/pyanaconda/ui/gui/__init__.py b/pyanaconda/ui/gui/__init__.py
> index 9251949..2169aad 100644
> --- a/pyanaconda/ui/gui/__init__.py
> +++ b/pyanaconda/ui/gui/__init__.py
> @@ -27,10 +27,10 @@ from gi.repository import Gdk, Gtk, AnacondaWidgets, Keybinder, GdkPixbuf, GLib,
>  
>  from pyanaconda.i18n import _
>  from pyanaconda.constants import IPMI_ABORTED
> -from pyanaconda import product, iutil
> +from pyanaconda import product, iutil, constants
>  
>  from pyanaconda.ui import UserInterface, common
> -from pyanaconda.ui.gui.utils import gtk_action_wait, unbusyCursor
> +from pyanaconda.ui.gui.utils import gtk_action_wait, gtk_call_once, unbusyCursor
>  from pyanaconda import ihelp
>  import os.path
>  
> @@ -109,7 +109,7 @@ class GUIObject(common.UIObject):
>      helpFile = None
>      translationDomain = "anaconda"
>  
> -    screenshots_directory = "/tmp/anaconda-screenshots"
> +    handles_autostep = False
>  
>      def __init__(self, data):
>          """Create a new UIObject instance, including loading its uiFile and
> @@ -156,6 +156,14 @@ class GUIObject(common.UIObject):
>          Keybinder.init()
>          Keybinder.bind("<Shift>Print", self._handlePrntScreen, [])
>  
> +        self._automaticEntry = False
> +        self._autostepRunning = False
> +        self._autostepDone = False
> +        self._autostepDoneCallback = None
> +
> +        # this indicates if the screen is the last spoke to be processed for a hub
> +        self.lastAutostepSpoke = False
> +
>      def _findUIFile(self):
>          path = os.environ.get("UIPATH", "./:/tmp/updates/:/tmp/updates/ui/:/usr/share/anaconda/ui/")
>          dirs = path.split(":")
> @@ -171,28 +179,119 @@ class GUIObject(common.UIObject):
>          raise IOError("Could not load UI file '%s' for object '%s'" % (self.uiFile, self))
>  
>      def _handlePrntScreen(self, *args, **kwargs):
> -        global _screenshotIndex
>          global _last_screenshot_timestamp
>          # as a single press of the assigned key generates
>          # multiple callbacks, we need to skip additional
>          # callbacks for some time once a screenshot is taken
>          if (time.time() - _last_screenshot_timestamp) >= SCREENSHOT_DELAY:
> -            # Make sure the screenshot directory exists.
> -            if not os.access(self.screenshots_directory, os.W_OK):
> -                os.makedirs(self.screenshots_directory)
> -
> -            fn = os.path.join(self.screenshots_directory,
> -                              "screenshot-%04d.png" % _screenshotIndex)
> -            root_window = Gdk.get_default_root_window()
> -            pixbuf = Gdk.pixbuf_get_from_window(root_window, 0, 0,
> -                                                root_window.get_width(),
> -                                                root_window.get_height())
> -            pixbuf.savev(fn, 'png', [], [])
> -            log.info("screenshot nr. %d taken", _screenshotIndex)
> -            _screenshotIndex += 1
> +            self.take_screenshot()
>              # start counting from the time the screenshot operation is done
>              _last_screenshot_timestamp = time.time()
>  
> +    def take_screenshot(self, name=None):
> +        """Take a screenshot of the whole screen (works even with multiple displays)
> +
> +        :param name: optional name for the screenshot that will be appended to the filename,
> +                     after the standard prefix & screenshot number
> +        :type name: str or NoneType
> +        """
> +        global _screenshotIndex
> +        # Make sure the screenshot directory exists.
> +        iutil.mkdirChain(constants.SCREENSHOTS_DIRECTORY)
> +
> +        if name is None:
> +            screenshot_filename = "screenshot-%04d.png" % _screenshotIndex
> +        else:
> +            screenshot_filename = "screenshot-%04d-%s.png" % (_screenshotIndex, name)
> +
> +        fn = os.path.join(constants.SCREENSHOTS_DIRECTORY, screenshot_filename)
> +
> +        root_window = self.main_window.get_window()
> +        pixbuf = Gdk.pixbuf_get_from_window(root_window, 0, 0,
> +                                            root_window.get_width(),
> +                                            root_window.get_height())
> +        pixbuf.savev(fn, 'png', [], [])
> +        log.info("%s taken", screenshot_filename)
> +        _screenshotIndex += 1
> +
> +    @property
> +    def automaticEntry(self):
> +        """Report if the given GUIObject has been displayed under automatic control
> +
> +        This is needed for example for installations with an incomplete kickstart,
> +        as we need to differentiate the automatic screenshot pass from the user
> +        entering a spoke to manually configure things. We also need to skip applying
> +        changes if the spoke is entered automatically.
> +        """
> +        return self._automaticEntry
> +
> +    @automaticEntry.setter
> +    def automaticEntry(self, value):
> +        self._automaticEntry = value
> +
> +    @property
> +    def autostepRunning(self):
> +        """Report if the GUIObject is currently running autostep"""
> +        return self._autostepRunning
> +
> +    @autostepRunning.setter
> +    def autostepRunning(self, value):
> +        self._autostepRunning = value
> +
> +    @property
> +    def autostepDone(self):
> +        """Report if autostep for this GUIObject has been finished"""
> +        return self._autostepDone
> +
> +    @autostepDone.setter
> +    def autostepDone(self, value):
> +        self._autostepDone = value
> +
> +    @property
> +    def autostepDoneCallback(self):
> +        """A callback to be run once autostep has been finished"""
> +        return self._autostepDoneCallback
> +
> +    @autostepDoneCallback.setter
> +    def autostepDoneCallback(self, callback):
> +        self._autostepDoneCallback = callback
I meant my comment about the properties to be replaced by public
attributes for all these properties that do nothing in their
getters/setters. If you agree that these all could be changed to public
attributes, please change them (there's no need to send v3 just because
of this change).

Otherwise the new version looks good to me.

-- 
Vratislav Podzimek

Anaconda Rider | Red Hat, Inc. | Brno - Czech Republic



More information about the anaconda-patches mailing list