[OE-core] [PATCH] devshell: Add interactive python shell
Richard Purdie
richard.purdie at linuxfoundation.org
Thu May 22 16:28:57 UTC 2014
Being able to interact with the python context in the Bitbake task execution
environment has long been desirable. This patch introduces such a
mechanism. Executing "bitbake X -c devpyshell" will open a terminal connected
to a python interactive interpretor in the task context so for example you can
run commands like "d.getVar('WORKDIR')"
This version fixes various issues with the previous RFC version from a
while ago and generally seems to work effectively.
Signed-off-by: Richard Purdie <richard.purdie at linuxfoundation.org>
diff --git a/meta/classes/devshell.bbclass b/meta/classes/devshell.bbclass
index 92edb9e..a8e707d 100644
--- a/meta/classes/devshell.bbclass
+++ b/meta/classes/devshell.bbclass
@@ -31,3 +31,79 @@ python () {
d.setVarFlag("do_devshell", "manualfakeroot", "1")
d.delVarFlag("do_devshell", "fakeroot")
}
+
+python do_devpyshell() {
+ m, s = os.openpty()
+ sname = os.ttyname(s)
+ os.system('stty cs8 -icanon min 1 -isig -echo -F %s > /dev/null 2> /dev/null' % sname)
+ pid = os.fork()
+ if pid:
+ oe_terminal("oepydevshell-internal.py %s" % sname, 'OpenEmbedded Developer PyShell', d)
+ os._exit(0)
+ else:
+ os.dup2(m, sys.stdin.fileno())
+ os.dup2(m, sys.stdout.fileno())
+ os.dup2(m, sys.stderr.fileno())
+ os.close(s)
+
+ sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+
+ bb.utils.nonblockingfd(sys.stdout)
+ bb.utils.nonblockingfd(sys.stderr)
+ bb.utils.nonblockingfd(sys.stdin)
+
+ _context = {
+ "os": os,
+ "bb": bb,
+ "time": time,
+ "d": d,
+ }
+
+ import code, select
+
+ ps1 = "pydevshell> "
+ ps2 = "... "
+ buf = []
+ more = False
+ try:
+ i = code.InteractiveInterpreter(locals=_context)
+ print("OE PyShell (PN = %s)\n" % d.getVar("PN", True))
+
+ def prompt(more):
+ if more:
+ prompt = ps2
+ else:
+ prompt = ps1
+ sys.stdout.write(prompt)
+
+ prompt(more)
+ while True:
+ try:
+ try:
+ (r, _, _) = select.select([sys.stdin], [], [], 1)
+ if not r:
+ continue
+ line = sys.stdin.readline().strip()
+ except EOFError as e:
+ sys.stdout.write("\n")
+ except (OSError, IOError) as e:
+ if e.errno == 11:
+ continue
+ raise
+ else:
+ buf.append(line)
+ source = "\n".join(buf)
+ more = i.runsource(source, "<pyshell>")
+ if not more:
+ buf = []
+ prompt(more)
+ except KeyboardInterrupt:
+ i.write("\nKeyboardInterrupt\n")
+ buf = []
+ more = False
+ except Exception as e:
+ bb.fatal(str(e))
+}
+addtask devpyshell after do_patch
+
+do_devpyshell[nostamp] = "1"
diff --git a/scripts/oepydevshell-internal.py b/scripts/oepydevshell-internal.py
new file mode 100755
index 0000000..11bb828
--- /dev/null
+++ b/scripts/oepydevshell-internal.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import time
+import select
+import fcntl
+
+def nonblockingfd(fd):
+ fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+
+if len(sys.argv) != 2:
+ print("Incorrect parameters")
+ sys.exit(1)
+
+try:
+ pty = open(sys.argv[1], "w+b", 0)
+ nonblockingfd(pty)
+ nonblockingfd(sys.stdin)
+ # Don't buffer output by line endings
+ sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+
+ i = ""
+ o = ""
+
+ while True:
+ writers = []
+ if i:
+ writers.append(sys.stdout)
+ if o:
+ writers.append(pty)
+ (ready, _, _) = select.select([pty, sys.stdin], writers , [], 1)
+ try:
+ if pty in ready:
+ i = i + pty.read()
+ if i:
+ # Write a page at a time to avoid overflowing output
+ # d.keys() is a good way to do that
+ sys.stdout.write(i[:4096])
+ i = i[4096:]
+ if sys.stdin in ready:
+ o = o + sys.stdin.read()
+ if o:
+ pty.write(o)
+ o = ""
+ except (IOError, OSError) as e:
+ if e.errno == 11:
+ continue
+ raise
+except Exception as e:
+ print("Exception in oepydehshell-internal: " + str(e))
+ time.sleep(5)
+
+
More information about the Openembedded-core
mailing list