diff options
| -rw-r--r-- | meta/classes/devshell.bbclass | 24 | ||||
| -rw-r--r-- | meta/classes/terminal.bbclass | 40 | ||||
| -rw-r--r-- | meta/lib/oe/terminal.py | 101 | 
3 files changed, 147 insertions, 18 deletions
| diff --git a/meta/classes/devshell.bbclass b/meta/classes/devshell.bbclass index 5f262f426e..ddb6e55303 100644 --- a/meta/classes/devshell.bbclass +++ b/meta/classes/devshell.bbclass @@ -1,22 +1,10 @@ -do_devshell[dirs] = "${S}" -do_devshell[nostamp] = "1" +inherit terminal -XAUTHORITY ?= "${HOME}/.Xauthority" - -devshell_do_devshell() { -	export DISPLAY='${DISPLAY}' -	export DBUS_SESSION_BUS_ADDRESS='${DBUS_SESSION_BUS_ADDRESS}' -	export XAUTHORITY='${XAUTHORITY}' -	export TERMWINDOWTITLE="Bitbake Developer Shell" -	export EXTRA_OEMAKE='${EXTRA_OEMAKE}' -	export SHELLCMDS="bash" -	${TERMCMDRUN} -	if [ $? -ne 0 ]; then -	    echo "Fatal: '${TERMCMD}' not found. Check TERMCMD variable." -	    exit 1 -	fi +python do_devshell () { +    oe_terminal(d.getVar('SHELL', True), 'OpenEmbedded Developer Shell', d)  } -addtask devshell after do_patch -EXPORT_FUNCTIONS do_devshell +addtask devshell after do_patch +do_devshell[dirs] = "${S}" +do_devshell[nostamp] = "1" diff --git a/meta/classes/terminal.bbclass b/meta/classes/terminal.bbclass new file mode 100644 index 0000000000..41230466c4 --- /dev/null +++ b/meta/classes/terminal.bbclass @@ -0,0 +1,40 @@ +OE_TERMINAL ?= 'auto' +OE_TERMINAL[type] = 'choice' +OE_TERMINAL[choices] = 'auto none \ +                        ${@" ".join(o.name \ +                                    for o in oe.terminal.prioritized())}' + +OE_TERMINAL_EXPORTS = 'XAUTHORITY SHELL DBUS_SESSION_BUS_ADDRESS DISPLAY EXTRA_OEMAKE' +OE_TERMINAL_EXPORTS[type] = 'list' + +XAUTHORITY ?= "${HOME}/.Xauthority" +SHELL ?= "bash" + + +def oe_terminal(command, title, d): +    import oe.data +    import oe.terminal + +    terminal = oe.data.typed_value('OE_TERMINAL', d).lower() +    if terminal == 'none': +        bb.fatal('Devshell usage disabled with OE_TERMINAL') +    elif terminal != 'auto': +        try: +            oe.terminal.spawn(terminal, command, title) +            return +        except oe.terminal.UnsupportedTerminal: +            bb.warn('Unsupported terminal "%s", defaulting to "auto"' % +                    terminal) +        except oe.terminal.ExecutionError as exc: +            bb.fatal('Unable to spawn terminal %s: %s' % (terminal, exc)) + +    env = dict(os.environ) +    for export in oe.data.typed_value('OE_TERMINAL_EXPORTS', d): +        env[export] = d.getVar(export, True) + +    try: +        oe.terminal.spawn_preferred(command, title, env) +    except oe.terminal.NoSupportedTerminals: +        bb.fatal('No valid terminal found, unable to open devshell') +    except oe.terminal.ExecutionError as exc: +        bb.fatal('Unable to spawn terminal %s: %s' % (terminal, exc)) diff --git a/meta/lib/oe/terminal.py b/meta/lib/oe/terminal.py new file mode 100644 index 0000000000..3767935586 --- /dev/null +++ b/meta/lib/oe/terminal.py @@ -0,0 +1,101 @@ +import logging +import os +import oe.classutils +import shlex +from bb.process import Popen, ExecutionError + +logger = logging.getLogger('BitBake.OE.Terminal') + + +class UnsupportedTerminal(StandardError): +    pass + +class NoSupportedTerminals(StandardError): +    pass + + +class Registry(oe.classutils.ClassRegistry): +    command = None + +    def __init__(cls, name, bases, attrs): +        super(Registry, cls).__init__(name.lower(), bases, attrs) + +    @property +    def implemented(cls): +        return bool(cls.command) + + +class Terminal(Popen): +    __metaclass__ = Registry + +    def __init__(self, command, title=None, env=None): +        self.format_command(command, title) + +        try: +            Popen.__init__(self, self.command, env=env) +        except OSError as exc: +            import errno +            if exc.errno == errno.ENOENT: +                raise UnsupportedTerminal(self.name) +            else: +                raise + +    def format_command(self, command, title): +        fmt = {'title': title or 'Terminal', 'command': command} +        if isinstance(self.command, basestring): +            self.command = shlex.split(self.command.format(**fmt)) +        else: +            self.command = [element.format(**fmt) for element in self.command] + +class XTerminal(Terminal): +    def __init__(self, command, title=None, env=None): +        Terminal.__init__(self, command, title, env) +        if not os.environ.get('DISPLAY'): +            raise UnsupportedTerminal(self.name) + +class Gnome(XTerminal): +    command = 'gnome-terminal --disable-factory -t "{title}" -x {command}' +    priority = 2 + +class Konsole(XTerminal): +    command = 'konsole -T "{title}" -e {command}' +    priority = 2 + +class XTerm(XTerminal): +    command = 'xterm -T "{title}" -e {command}' +    priority = 1 + +class Rxvt(XTerminal): +    command = 'rxvt -T "{title}" -e {command}' +    priority = 1 + +class Screen(Terminal): +    command = 'screen -D -m -t "{title}" {command}' + + +def prioritized(): +    return Registry.prioritized() + +def spawn_preferred(command, title=None, env=None): +    """Spawn the first supported terminal, by priority""" +    for terminal in prioritized(): +        try: +            spawn(terminal.name, command, title, env) +            break +        except UnsupportedTerminal: +            continue +    else: +        raise NoSupportedTerminals() + +def spawn(name, command, title=None, env=None): +    """Spawn the specified terminal, by name""" +    logger.debug(1, 'Attempting to spawn terminal "%s"', name) +    try: +        terminal = Registry.registry[name] +    except KeyError: +        raise UnsupportedTerminal(name) + +    pipe = terminal(command, title, env) +    output = pipe.communicate()[0] +    if pipe.returncode != 0: +        raise ExecutionError(pipe.command, pipe.returncode, output) | 
