aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/classes/devshell.bbclass24
-rw-r--r--meta/classes/terminal.bbclass40
-rw-r--r--meta/lib/oe/terminal.py101
3 files changed, 147 insertions, 18 deletions
diff --git a/meta/classes/devshell.bbclass b/meta/classes/devshell.bbclass
index 5f262f426e9..ddb6e55303a 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 00000000000..41230466c41
--- /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 00000000000..37679355863
--- /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)