[PATCH 3/3] Work with VConsole keymap and X layouts separately

Vratislav Podzimek vpodzime at redhat.com
Thu Oct 4 20:48:12 UTC 2012


We need to set VConsole keymap and X layouts separately. We may
get them all from kickstart, but if not, we have to convert the
given one to the missing one and save the configuration. If X11
configuration is written before the server is started, it is
loaded. This way we can get rid of using XklWrapper in main anaconda
script.

Also we need to write one more configuration file. And it's better
to try to write all configuration files ignoring errors and in case
some error(s) appeared, raise exception at the end of the procedure.

Resolves: rhbz#853877
Resolves: rhbz#856362
Resolves: rhbz#859867

Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
---
 anaconda                             |  16 +---
 anaconda.spec.in                     |   2 +-
 pyanaconda/keyboard.py               | 139 +++++++++++++++++++++++++----------
 pyanaconda/kickstart.py              |   3 +-
 pyanaconda/ui/gui/spokes/keyboard.py |   8 +-
 pyanaconda/ui/gui/spokes/welcome.py  |   6 +-
 6 files changed, 112 insertions(+), 62 deletions(-)

diff --git a/anaconda b/anaconda
index 411bb07..f9a6fab 100755
--- a/anaconda
+++ b/anaconda
@@ -577,20 +577,6 @@ def setupDisplay(anaconda, opts):
     # with X running we can initialize the UI interface
     anaconda.initInterface()
 
-    # setup layouts
-    if anaconda.displayMode == 'g' and anaconda.ksdata.keyboard.layouts_list:
-        from pyanaconda.keyboard import XklWrapper, XklWrapperError
-
-        layouts = anaconda.ksdata.keyboard.layouts_list
-        xklwrapper = XklWrapper.get_instance()
-
-        try:
-            xklwrapper.replace_layouts(layouts)
-
-        except XklWrapperError as xklerr:
-            msg = "Failed to activate layouts %s" % ",".join(layouts)
-            log.error(msg)
-
     anaconda.instClass.configure(anaconda)
 
 def prompt_for_ssh():
@@ -853,7 +839,7 @@ if __name__ == "__main__":
             ksdata.keyboard.keyboard = opts.keymap
 
     if ksdata.keyboard.keyboard:
-        keyboard.activate_console_keymap(ksdata.keyboard.keyboard)
+        keyboard.activate_keyboard(ksdata.keyboard)
 
     # Some post-install parts of anaconda are implemented as kickstart
     # scripts.  Add those to the ksdata now.
diff --git a/anaconda.spec.in b/anaconda.spec.in
index 861d87d..0722064 100644
--- a/anaconda.spec.in
+++ b/anaconda.spec.in
@@ -26,7 +26,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 %define intltoolver 0.31.2-3
 %define libnlver 1.0
 %define libselinuxver 1.6
-%define pykickstartver 1.99.18
+%define pykickstartver 1.99.20
 %define rpmpythonver 4.2-0.61
 %define slangver 2.0.6-2
 %define yumver 3.4.3-32
diff --git a/pyanaconda/keyboard.py b/pyanaconda/keyboard.py
index 30a9de9..21cb3a5 100755
--- a/pyanaconda/keyboard.py
+++ b/pyanaconda/keyboard.py
@@ -31,7 +31,6 @@ for listing and various modifications of keyboard layouts settings.
 """
 
 import os
-import re
 import dbus
 from pyanaconda import iutil
 
@@ -96,7 +95,7 @@ def get_layouts_xorg_conf(keyboard):
     layouts = list()
     variants = list()
 
-    for layout_variant in keyboard.layouts_list:
+    for layout_variant in keyboard.x_layouts:
         (layout, variant) = _parse_layout_variant(layout_variant)
         layouts.append(layout)
         variants.append(variant)
@@ -128,83 +127,149 @@ def get_layouts_xorg_conf(keyboard):
 
     return ret
 
-def write_layouts_config(keyboard, root):
+def write_keyboard_config(keyboard, root, convert=True, weight=0):
     """
     Function that writes files with layouts configuration to
-    $root/etc/X11/xorg.conf.d/01-anaconda-layouts.conf and
-    $root/etc/sysconfig/keyboard.
+    $root/etc/X11/xorg.conf.d/01-anaconda-layouts.conf,
+    $root/etc/sysconfig/keyboard and $root/etc/vconsole.conf.
 
     @param keyboard: ksdata.keyboard object
     @param root: path to the root of the installed system
+    @param convert: whether to convert specified values to get the missing
+                    ones
+    @param weight: weight (prefix) of the xorg.conf file written out
 
     """
 
+    localed = LocaledWrapper()
+
+    if convert:
+        # populate vc_keymap and x_layouts if they are missing
+        if keyboard.x_layouts and not keyboard.vc_keymap:
+            keyboard.vc_keymap = \
+                        localed.set_and_convert_layout(keyboard.x_layouts[0])
+
+        if not keyboard.vc_keymap:
+            keyboard.vc_keymap = "us"
+
+        if not keyboard.x_layouts:
+            c_lay_var = localed.set_and_convert_keymap(keyboard.vc_keymap)
+            keyboard.x_layouts.append(c_lay_var)
+
     xconf_dir = os.path.normpath(root + "/etc/X11/xorg.conf.d")
-    xconf_file = "01-anaconda-keyboard.conf"
+    xconf_file = "%0.2d-anaconda-keyboard.conf" % weight
 
     sysconf_dir = os.path.normpath(root + "/etc/sysconfig")
     sysconf_file = "keyboard"
 
+    vcconf_dir = os.path.normpath(root + "/etc")
+    vcconf_file = "vconsole.conf"
+
+    errors = []
+
     try:
         if not os.path.isdir(xconf_dir):
             os.makedirs(xconf_dir)
 
     except OSError as oserr:
-        raise KeyboardConfigError("Cannot create directory xorg.conf.d")
+        errors.append("Cannot create directory xorg.conf.d")
 
-    try:
-        with open(os.path.join(xconf_dir, xconf_file), "w") as fobj:
-            fobj.write(get_layouts_xorg_conf(keyboard))
+    if keyboard.x_layouts:
+        try:
+            with open(os.path.join(xconf_dir, xconf_file), "w") as fobj:
+                fobj.write(get_layouts_xorg_conf(keyboard))
+        except IOError as ioerr:
+            errors.append("Cannot write X keyboard configuration file")
+
+    if keyboard.vc_keymap:
+        try:
+            with open(os.path.join(sysconf_dir, sysconf_file), "w") as fobj:
+                fobj.write('vconsole.keymap="%s"\n' % keyboard.vc_keymap)
 
-        with open(os.path.join(sysconf_dir, sysconf_file), "w") as fobj:
-            fobj.write('vconsole.keymap="%s"\n' % keyboard.keyboard)
+        except IOError as ioerr:
+            errors.append("Cannot write sysconfig keyboard configuration file")
 
-    except IOError as ioerr:
-        raise KeyboardConfigError("Cannot write keyboard configuration files")
+        try:
+            with open(os.path.join(vcconf_dir, vcconf_file), "w") as fobj:
+                fobj.write('KEYMAP="%s"\n' % keyboard.vc_keymap)
+        except IOError as ioerr:
+            errors.append("Cannot write vconsole configuration file")
 
-def activate_console_keymap(keymap):
+    if errors:
+        raise KeyboardConfigError("\n".join(errors))
+
+def _try_to_load_keymap(keymap):
     """
-    Try to setup a given keymap as a console keymap. If there is no such
-    keymap, try to setup a basic variant (e.g. 'cz' instead of 'cz (qwerty)').
+    Method that tries to load keymap and returns boolean indicating if it was
+    successfull or not. It can be used to test if given string is VConsole
+    keymap or not, but in case it is given valid keymap, IT REALLY LOADS IT!.
 
-    @param keymap: a keymap
     @type keymap: string
     @raise KeyboardConfigError: if loadkeys command is not available
-    @return: False if failed to activate both the given keymap and its basic
-             variant, True otherwise
+    @return: True if given string was a valid keymap and thus was loaded,
+             False otherwise
 
     """
 
+    # BUG: systemd-localed should be able to tell us if we are trying to
+    #      activate invalid keymap. Then we will be able to get rid of this
+    #      fuction
+
+    ret = 0
+
     try:
-        #TODO: replace with calling systemd-localed methods once it can load
-        #      X layouts
         ret = iutil.execWithRedirect("loadkeys", [keymap], stdout="/dev/tty5",
                                      stderr="/dev/tty5")
     except OSError as oserr:
         msg = "'loadkeys' command not available (%s)" % oserr.strerror
         raise KeyboardConfigError(msg)
 
-    if ret != 0:
-        log.error("Failed to activate keymap %s" % keymap)
+    return ret == 0
 
-        #failed to activate the given keymap, extract and try
-        #the basic keymap -- e.g. 'cz-cp1250' -> 'cz'
-        parts = re.split(r'[- _(]', keymap, 1)
-        if len(parts) == 0:
-            log.error("Failed to extract basic keymap from: %s" % keymap)
-            return False
+def activate_keyboard(keyboard):
+    """
+    Try to setup VConsole keymap and X11 layouts as specified in kickstart.
 
-        keymap = parts[0]
+    @param keyboard: ksdata.keyboard object
+    @type keyboard: ksdata.keyboard object
 
-        ret = iutil.execWithRedirect("loadkeys", [keymap], stdout="/dev/tty5",
-                                     stderr="/dev/tty5")
+    """
+
+    localed = LocaledWrapper()
+    c_lay_var = ""
+    c_keymap = ""
 
-        if ret != 0:
-            log.error("Failed to activate basic variant %s" % keymap)
+    if keyboard._keyboard and not (keyboard.vc_keymap or keyboard.x_layouts):
+        # we were give only one value in old format of the keyboard command
+        # try to guess if we were given VConsole keymap or X11 layout
+        is_keymap = _try_to_load_keymap(keyboard._keyboard)
+
+        if is_keymap:
+            keyboard.vc_keymap = keyboard._keyboard
         else:
-            log.error("Activated basic variant %s, instead" % keymap)
+            keyboard.x_layouts.append(keyboard._keyboard)
 
-    return ret == 0
+    if keyboard.vc_keymap:
+        valid_keymap = _try_to_load_keymap(keyboard.vc_keymap)
+        if not valid_keymap:
+            log.error("'%s' is not a valid VConsole keymap, not loading" % \
+                        keyboard.vc_keymap)
+        else:
+            # activate VConsole keymap and get converted layout and variant
+            c_lay_var = localed.set_and_convert_keymap(keyboard.vc_keymap)
+
+    if not keyboard.x_layouts and c_lay_var:
+        keyboard.x_layouts.append(c_lay_var)
+
+    if keyboard.x_layouts:
+        c_keymap = localed.set_and_convert_layout(keyboard.x_layouts[0])
+
+        if not keyboard.vc_keymap:
+            keyboard.vc_keymap = c_keymap
+
+        # write out full configuration that will be loaded by X server
+        # (systemd-localed writes configuration with only one layout)
+        write_keyboard_config(keyboard, root="/", convert=False, weight=99)
 
 def item_str(s):
     """Convert a zero-terminated byte array to a proper str"""
diff --git a/pyanaconda/kickstart.py b/pyanaconda/kickstart.py
index 18b04c0..03bc5b9 100644
--- a/pyanaconda/kickstart.py
+++ b/pyanaconda/kickstart.py
@@ -1367,8 +1367,7 @@ class ZFCP(commands.zfcp.F14_ZFCP):
 
 class Keyboard(commands.keyboard.F18_Keyboard):
     def execute(self, *args):
-        if self.layouts_list:
-            keyboard.write_layouts_config(self, ROOT_PATH)
+        keyboard.write_keyboard_config(self, ROOT_PATH)
 
 ###
 ### HANDLERS
diff --git a/pyanaconda/ui/gui/spokes/keyboard.py b/pyanaconda/ui/gui/spokes/keyboard.py
index c2e9b86..1147244 100644
--- a/pyanaconda/ui/gui/spokes/keyboard.py
+++ b/pyanaconda/ui/gui/spokes/keyboard.py
@@ -174,9 +174,9 @@ class KeyboardSpoke(NormalSpoke):
 
     def apply(self):
         # Clear and repopulate self.data with actual values
-        self.data.keyboard.layouts_list = list()
+        self.data.keyboard.x_layouts = list()
         for row in self._store:
-            self.data.keyboard.layouts_list.append(row[0])
+            self.data.keyboard.x_layouts.append(row[0])
         # FIXME:  Set the keyboard layout here, too.
 
     @property
@@ -391,8 +391,8 @@ class KeyboardSpoke(NormalSpoke):
             self._downButton.set_sensitive(True)
 
     def _add_data_layouts(self):
-        if self.data.keyboard.layouts_list:
-            for layout in self.data.keyboard.layouts_list:
+        if self.data.keyboard.x_layouts:
+            for layout in self.data.keyboard.x_layouts:
                 self._addLayout(self._store, layout)
         else:
             self._addLayout(self._store, "us")
diff --git a/pyanaconda/ui/gui/spokes/welcome.py b/pyanaconda/ui/gui/spokes/welcome.py
index 0bd5d90..2dcad10 100644
--- a/pyanaconda/ui/gui/spokes/welcome.py
+++ b/pyanaconda/ui/gui/spokes/welcome.py
@@ -64,7 +64,7 @@ class LanguageMixIn(object):
             if lang_timezone:
                 self.data.timezone.timezone = lang_timezone
 
-        if self.data.keyboard.layouts_list:
+        if self.data.keyboard.x_layouts:
             #do not add layouts if there are any specified in the kickstart
             return
 
@@ -80,8 +80,8 @@ class LanguageMixIn(object):
             new_layouts.append(language_layout)
 
         for layout in new_layouts:
-            if layout not in self.data.keyboard.layouts_list:
-                self.data.keyboard.layouts_list.append(layout)
+            if layout not in self.data.keyboard.x_layouts:
+                self.data.keyboard.x_layouts.append(layout)
                 if flags.can_touch_runtime_system("add runtime X layout"):
                     self._xklwrapper.add_layout(layout)
 
-- 
1.7.11.4



More information about the anaconda-patches mailing list