hostkeymap: Centralize parsing, don't be so noisy

And add /etc/vconsole.conf parsing to close bug 882183
This commit is contained in:
Cole Robinson 2013-10-02 12:35:01 -04:00
parent 7c7f3ad0b2
commit 187ce92621

View File

@ -18,10 +18,119 @@
#
import logging
import os
import re
_cached_keymap = None
_ETC_VCONSOLE = "/etc/vconsole.conf"
_KEYBOARD_DIR = "/etc/sysconfig/keyboard"
_XORG_CONF = "/etc/X11/xorg.conf"
_CONSOLE_SETUP_CONF = "/etc/default/console-setup"
_KEYBOARD_DEFAULT = "/etc/default/keyboard"
def _find_xkblayout(f):
"""
Reads a keyboard layout from a file that defines an XKBLAYOUT
variable, e.g. /etc/default/{keyboard,console-setup}.
The format of these files is such that they can be 'sourced'
in a shell script.
Used for both /etc/default/keyboard and /etc/default/console-setup.
The former is used by Debian 6.0 (Squeeze) and later. The latter is
used by older versions of Debian, and Ubuntu.
"""
kt = None
keymap_re = re.compile(r'\s*XKBLAYOUT="(?P<kt>[a-z-]+)"')
for line in f:
m = keymap_re.match(line)
if m:
kt = m.group('kt')
break
return kt
def _xorg_keymap(f):
"""
Look in /etc/X11/xorg.conf for the host machine's keymap, and attempt to
map it to a keymap supported by qemu
"""
kt = None
keymap_re = re.compile(r'\s*Option\s+"XkbLayout"\s+"(?P<kt>[a-z-]+)"')
for line in f:
m = keymap_re.match(line)
if m:
kt = m.group('kt')
break
return kt
def _sysconfig_keyboard(f):
kt = None
while 1:
s = f.readline()
if s == "":
break
if (re.search("KEYMAP", s) is not None or
re.search("KEYTABLE", s) is not None or
(re.search("KEYBOARD", s) is not None and
re.search("KEYBOARDTYPE", s) is None)):
if s.count('"'):
delim = '"'
elif s.count('='):
delim = '='
else:
continue
kt = s.split(delim)[1].strip()
break
return kt
def _default_keymap():
"""
Look in various config files for the host machine's keymap, and attempt
to map it to a keymap supported by qemu
"""
# Set keymap to same as hosts
default = "en-us"
keymap = None
kt = None
for path, cb in [
(_ETC_VCONSOLE, _sysconfig_keyboard),
(_KEYBOARD_DIR, _sysconfig_keyboard),
(_XORG_CONF, _xorg_keymap),
(_KEYBOARD_DEFAULT, _find_xkblayout),
(_CONSOLE_SETUP_CONF, _find_xkblayout)]:
if not os.path.exists(path):
continue
try:
f = open(path, "r")
kt = cb(f)
f.close()
if kt:
logging.debug("Found keymap=%s in %s", kt, path)
break
logging.debug("Didn't find keymap in '%s'", path)
except Exception, e:
logging.debug("Error parsing '%s': %s", path, str(e))
if kt is None:
logging.debug("Did not parse any usable keymapping.")
return default
kt = kt.lower()
keymap = sanitize_keymap(kt)
if not keymap:
logging.debug("Didn't match keymap '%s' in keytable!", kt)
return default
return keymap
##################
# Public helpers #
##################
# Host keytable entry : keymap name in qemu/xen
# Only use lower case entries: all lookups are .lower()'d
@ -61,75 +170,8 @@ keytable = {
"tr": "tr",
}
KEYBOARD_DIR = "/etc/sysconfig/keyboard"
XORG_CONF = "/etc/X11/xorg.conf"
CONSOLE_SETUP_CONF = "/etc/default/console-setup"
def find_xkblayout(path):
"""
Reads a keyboard layout from a file that defines an XKBLAYOUT
variable, e.g. /etc/default/{keyboard,console-setup}.
The format of these files is such that they can be 'sourced'
in a shell script.
"""
kt = None
try:
f = open(path, "r")
except IOError, e:
logging.debug('Could not open "%s": %s ', path, str(e))
else:
keymap_re = re.compile(r'\s*XKBLAYOUT="(?P<kt>[a-z-]+)"')
for line in f:
m = keymap_re.match(line)
if m:
kt = m.group('kt')
break
else:
logging.debug("Didn't find keymap in '%s'!", path)
f.close()
return kt
def _find_keymap_from_etc_default():
"""
Look under /etc/default for the host machine's keymap.
This checks both /etc/default/keyboard and /etc/default/console-setup.
The former is used by Debian 6.0 (Squeeze) and later. The latter is
used by older versions of Debian, and Ubuntu.
"""
KEYBOARD_DEFAULT = "/etc/default/keyboard"
paths = [KEYBOARD_DEFAULT, CONSOLE_SETUP_CONF]
for path in paths:
kt = find_xkblayout(path)
if kt is not None:
break
return kt
def _xorg_keymap():
"""Look in /etc/X11/xorg.conf for the host machine's keymap, and attempt to
map it to a keymap supported by qemu"""
kt = None
try:
f = open(XORG_CONF, "r")
except IOError, e:
logging.debug('Could not open "%s": %s ', XORG_CONF, str(e))
else:
keymap_re = re.compile(r'\s*Option\s+"XkbLayout"\s+"(?P<kt>[a-z-]+)"')
for line in f:
m = keymap_re.match(line)
if m:
kt = m.group('kt')
break
else:
logging.debug("Didn't find keymap in '%s'!", XORG_CONF)
f.close()
return kt
_cached_keymap = None
def default_keymap():
@ -139,52 +181,6 @@ def default_keymap():
return _cached_keymap
def _default_keymap():
"""
Look in various config files for the host machine's keymap, and attempt
to map it to a keymap supported by qemu
"""
# Set keymap to same as hosts
default = "en-us"
keymap = None
kt = None
try:
f = open(KEYBOARD_DIR, "r")
except IOError, e:
logging.debug('Could not open "/etc/sysconfig/keyboard" ' + str(e))
kt = _xorg_keymap()
if not kt:
kt = _find_keymap_from_etc_default()
else:
while 1:
s = f.readline()
if s == "":
break
if re.search("KEYTABLE", s) is not None or \
(re.search("KEYBOARD", s) is not None and
re.search("KEYBOARDTYPE", s) is None):
if s.count('"'):
delim = '"'
elif s.count('='):
delim = '='
else:
continue
kt = s.split(delim)[1].strip()
f.close()
if kt is None:
logging.debug("Did not parse any usable keymapping.")
return default
kt = kt.lower()
keymap = sanitize_keymap(kt)
if not keymap:
logging.debug("Didn't match keymap '%s' in keytable!", kt)
return default
return keymap
def sanitize_keymap(kt):
"""
Make sure the passed keymap roughly matches something in keytable