diff options
Diffstat (limited to 'meta/lib/oe/terminal.py')
-rw-r--r-- | meta/lib/oe/terminal.py | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/meta/lib/oe/terminal.py b/meta/lib/oe/terminal.py new file mode 100644 index 0000000000..e14fc5dbc4 --- /dev/null +++ b/meta/lib/oe/terminal.py @@ -0,0 +1,126 @@ +import logging +import os +import oe.classutils +import oe.data +import shlex +import bb +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): + self.format_command(command, title) + logger.debug(1, "%s: running %s", self.name, self.command) + + try: + Popen.__init__(self, self.command, shell=False) + 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): + Terminal.__init__(self, command, title) + 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 run(command, title, d): + terminal = oe.data.typed_value('OE_TERMINAL', d).lower() + if terminal == 'none': + bb.fatal('Devshell usage disabled with OE_TERMINAL') + elif terminal != 'auto': + try: + spawn(terminal, command, title) + return + except UnsupportedTerminal: + bb.warn('Unsupported terminal "%s", defaulting to "auto"' % + terminal) + except ExecutionError as exc: + bb.fatal('Unable to spawn terminal %s: %s' % (terminal, exc)) + + try: + spawn_preferred(command, title) + except NoSupportedTerminals: + bb.fatal('No valid terminal found, unable to open devshell') + except ExecutionError as exc: + bb.fatal('Unable to spawn terminal %s: %s' % (terminal, exc)) + +def spawn_preferred(command, title=None): + """Spawn the first supported terminal, by priority""" + for terminal in prioritized(): + try: + spawn(terminal.name, command, title) + break + except UnsupportedTerminal: + continue + else: + raise NoSupportedTerminals() + +def spawn(name, command, title=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) + output = pipe.communicate()[0] + if pipe.returncode != 0: + raise ExecutionError(pipe.command, pipe.returncode, output) |