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 @@ | |||
| 1 | do_devshell[dirs] = "${S}" | 1 | inherit terminal |
| 2 | do_devshell[nostamp] = "1" | ||
| 3 | 2 | ||
| 4 | XAUTHORITY ?= "${HOME}/.Xauthority" | 3 | python do_devshell () { |
| 5 | 4 | oe_terminal(d.getVar('SHELL', True), 'OpenEmbedded Developer Shell', d) | |
| 6 | devshell_do_devshell() { | ||
| 7 | export DISPLAY='${DISPLAY}' | ||
| 8 | export DBUS_SESSION_BUS_ADDRESS='${DBUS_SESSION_BUS_ADDRESS}' | ||
| 9 | export XAUTHORITY='${XAUTHORITY}' | ||
| 10 | export TERMWINDOWTITLE="Bitbake Developer Shell" | ||
| 11 | export EXTRA_OEMAKE='${EXTRA_OEMAKE}' | ||
| 12 | export SHELLCMDS="bash" | ||
| 13 | ${TERMCMDRUN} | ||
| 14 | if [ $? -ne 0 ]; then | ||
| 15 | echo "Fatal: '${TERMCMD}' not found. Check TERMCMD variable." | ||
| 16 | exit 1 | ||
| 17 | fi | ||
| 18 | } | 5 | } |
| 19 | addtask devshell after do_patch | ||
| 20 | 6 | ||
| 21 | EXPORT_FUNCTIONS do_devshell | 7 | addtask devshell after do_patch |
| 22 | 8 | ||
| 9 | do_devshell[dirs] = "${S}" | ||
| 10 | 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 @@ | |||
| 1 | OE_TERMINAL ?= 'auto' | ||
| 2 | OE_TERMINAL[type] = 'choice' | ||
| 3 | OE_TERMINAL[choices] = 'auto none \ | ||
| 4 | ${@" ".join(o.name \ | ||
| 5 | for o in oe.terminal.prioritized())}' | ||
| 6 | |||
| 7 | OE_TERMINAL_EXPORTS = 'XAUTHORITY SHELL DBUS_SESSION_BUS_ADDRESS DISPLAY EXTRA_OEMAKE' | ||
| 8 | OE_TERMINAL_EXPORTS[type] = 'list' | ||
| 9 | |||
| 10 | XAUTHORITY ?= "${HOME}/.Xauthority" | ||
| 11 | SHELL ?= "bash" | ||
| 12 | |||
| 13 | |||
| 14 | def oe_terminal(command, title, d): | ||
| 15 | import oe.data | ||
| 16 | import oe.terminal | ||
| 17 | |||
| 18 | terminal = oe.data.typed_value('OE_TERMINAL', d).lower() | ||
| 19 | if terminal == 'none': | ||
| 20 | bb.fatal('Devshell usage disabled with OE_TERMINAL') | ||
| 21 | elif terminal != 'auto': | ||
| 22 | try: | ||
| 23 | oe.terminal.spawn(terminal, command, title) | ||
| 24 | return | ||
| 25 | except oe.terminal.UnsupportedTerminal: | ||
| 26 | bb.warn('Unsupported terminal "%s", defaulting to "auto"' % | ||
| 27 | terminal) | ||
| 28 | except oe.terminal.ExecutionError as exc: | ||
| 29 | bb.fatal('Unable to spawn terminal %s: %s' % (terminal, exc)) | ||
| 30 | |||
| 31 | env = dict(os.environ) | ||
| 32 | for export in oe.data.typed_value('OE_TERMINAL_EXPORTS', d): | ||
| 33 | env[export] = d.getVar(export, True) | ||
| 34 | |||
| 35 | try: | ||
| 36 | oe.terminal.spawn_preferred(command, title, env) | ||
| 37 | except oe.terminal.NoSupportedTerminals: | ||
| 38 | bb.fatal('No valid terminal found, unable to open devshell') | ||
| 39 | except oe.terminal.ExecutionError as exc: | ||
| 40 | 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 @@ | |||
| 1 | import logging | ||
| 2 | import os | ||
| 3 | import oe.classutils | ||
| 4 | import shlex | ||
| 5 | from bb.process import Popen, ExecutionError | ||
| 6 | |||
| 7 | logger = logging.getLogger('BitBake.OE.Terminal') | ||
| 8 | |||
| 9 | |||
| 10 | class UnsupportedTerminal(StandardError): | ||
| 11 | pass | ||
| 12 | |||
| 13 | class NoSupportedTerminals(StandardError): | ||
| 14 | pass | ||
| 15 | |||
| 16 | |||
| 17 | class Registry(oe.classutils.ClassRegistry): | ||
| 18 | command = None | ||
| 19 | |||
| 20 | def __init__(cls, name, bases, attrs): | ||
| 21 | super(Registry, cls).__init__(name.lower(), bases, attrs) | ||
| 22 | |||
| 23 | @property | ||
| 24 | def implemented(cls): | ||
| 25 | return bool(cls.command) | ||
| 26 | |||
| 27 | |||
| 28 | class Terminal(Popen): | ||
| 29 | __metaclass__ = Registry | ||
| 30 | |||
| 31 | def __init__(self, command, title=None, env=None): | ||
| 32 | self.format_command(command, title) | ||
| 33 | |||
| 34 | try: | ||
| 35 | Popen.__init__(self, self.command, env=env) | ||
| 36 | except OSError as exc: | ||
| 37 | import errno | ||
| 38 | if exc.errno == errno.ENOENT: | ||
| 39 | raise UnsupportedTerminal(self.name) | ||
| 40 | else: | ||
| 41 | raise | ||
| 42 | |||
| 43 | def format_command(self, command, title): | ||
| 44 | fmt = {'title': title or 'Terminal', 'command': command} | ||
| 45 | if isinstance(self.command, basestring): | ||
| 46 | self.command = shlex.split(self.command.format(**fmt)) | ||
| 47 | else: | ||
| 48 | self.command = [element.format(**fmt) for element in self.command] | ||
| 49 | |||
| 50 | class XTerminal(Terminal): | ||
| 51 | def __init__(self, command, title=None, env=None): | ||
| 52 | Terminal.__init__(self, command, title, env) | ||
| 53 | if not os.environ.get('DISPLAY'): | ||
| 54 | raise UnsupportedTerminal(self.name) | ||
| 55 | |||
| 56 | class Gnome(XTerminal): | ||
| 57 | command = 'gnome-terminal --disable-factory -t "{title}" -x {command}' | ||
| 58 | priority = 2 | ||
| 59 | |||
| 60 | class Konsole(XTerminal): | ||
| 61 | command = 'konsole -T "{title}" -e {command}' | ||
| 62 | priority = 2 | ||
| 63 | |||
| 64 | class XTerm(XTerminal): | ||
| 65 | command = 'xterm -T "{title}" -e {command}' | ||
| 66 | priority = 1 | ||
| 67 | |||
| 68 | class Rxvt(XTerminal): | ||
| 69 | command = 'rxvt -T "{title}" -e {command}' | ||
| 70 | priority = 1 | ||
| 71 | |||
| 72 | class Screen(Terminal): | ||
| 73 | command = 'screen -D -m -t "{title}" {command}' | ||
| 74 | |||
| 75 | |||
| 76 | def prioritized(): | ||
| 77 | return Registry.prioritized() | ||
| 78 | |||
| 79 | def spawn_preferred(command, title=None, env=None): | ||
| 80 | """Spawn the first supported terminal, by priority""" | ||
| 81 | for terminal in prioritized(): | ||
| 82 | try: | ||
| 83 | spawn(terminal.name, command, title, env) | ||
| 84 | break | ||
| 85 | except UnsupportedTerminal: | ||
| 86 | continue | ||
| 87 | else: | ||
| 88 | raise NoSupportedTerminals() | ||
| 89 | |||
| 90 | def spawn(name, command, title=None, env=None): | ||
| 91 | """Spawn the specified terminal, by name""" | ||
| 92 | logger.debug(1, 'Attempting to spawn terminal "%s"', name) | ||
| 93 | try: | ||
| 94 | terminal = Registry.registry[name] | ||
| 95 | except KeyError: | ||
| 96 | raise UnsupportedTerminal(name) | ||
| 97 | |||
| 98 | pipe = terminal(command, title, env) | ||
| 99 | output = pipe.communicate()[0] | ||
| 100 | if pipe.returncode != 0: | ||
| 101 | raise ExecutionError(pipe.command, pipe.returncode, output) | ||
