#!/usr/bin/env python import sys import subprocess import os import xml.etree.ElementTree as ET verbose = True DEFAULT_RULES_XML = '@XKB_CONFIG_ROOT@/rules/evdev.xml' # Meson needs to fill this in so we can call the tool in the buildir. EXTRA_PATH='@MESON_BUILD_ROOT@' os.environ['PATH'] = ':'.join([EXTRA_PATH, os.getenv('PATH')]) # The function generating the progress bar (if any). progress_bar = lambda x, desc: x if os.isatty(sys.stdout.fileno()): try: from tqdm import tqdm progress_bar = tqdm verbose = False except ImportError: pass def xkbcommontool(r='evdev', m='pc105', l='us', v=None, o=None): args = [ 'rmlvo-to-keymap', '--rules', r, '--model', m, '--layout', l, ] if v is not None: args += ['--variant', v] if o is not None: args += ['--options', o] if verbose: print(':: {}'.format(' '.join(args))) try: output = subprocess.check_output(args, stderr=subprocess.STDOUT) if verbose: print(output.decode('utf-8')) except subprocess.CalledProcessError as err: print('ERROR: Failed to compile: {}'.format(' '.join(args))) print(err.output.decode('utf-8')) sys.exit(1) def xkbcomp(r='evdev', m='pc105', l='us', v='', o=''): args = ['setxkbmap', '-print'] if r is not None: args.append('-rules') args.append('{}'.format(r)) if m is not None: args.append('-model') args.append('{}'.format(m)) if l is not None: args.append('-layout') args.append('{}'.format(l)) if o is not None: args.append('-option') args.append('{}'.format(o)) if verbose: print(':: {}'.format(' '.join(args))) try: xkbcomp_args = ['xkbcomp', '-xkb', '-', '-'] setxkbmap = subprocess.Popen(args, stdout=subprocess.PIPE) xkbcomp = subprocess.Popen(xkbcomp_args, stdin=setxkbmap.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE) setxkbmap.stdout.close() stdout, stderr = xkbcomp.communicate() if xkbcomp.returncode != 0: print('ERROR: Failed to compile: {}'.format(' '.join(args))) if xkbcomp.returncode != 0 or verbose: print(stdout.decode('utf-8')) print(stderr.decode('utf-8')) # This catches setxkbmap errors. except subprocess.CalledProcessError as err: print('ERROR: Failed to compile: {}'.format(' '.join(args))) print(err.output.decode('utf-8')) def parse(root): layouts = root.findall('layoutList/layout') options = [ e.text for e in root.findall('optionList/group/option/configItem/name') ] # Switch this to xkbcomp if needed. tool = xkbcommontool # tool = xkbcomp for l in progress_bar(layouts, 'layout '): layout = l.find('configItem/name').text tool(l=layout) variants = l.findall('variantList/variant') for v in progress_bar(variants, 'variant'): variant = v.find('configItem/name').text tool(l=layout, v=variant) for option in progress_bar(options, 'option '): tool(l=layout, v=variant, o=option) def main(args): try: path = args[1] except IndexError: path = DEFAULT_RULES_XML with open(path) as f: root = ET.fromstring(f.read()) parse(root) if __name__ == '__main__': main(sys.argv)