devshell: Add interactive python shell
RFC PATCH 1/1 devshell: Add interactive python shell
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')"
---
I've marked this as RFC since this is not production ready at this point. It does illustrate what we could possibly do for an interactive python shell though. Usage is "bitbake bash -c devpyshell" and then you can type 'd.getVar("WORKDIR")' into the prompt.
Cleanup needed:
* The formatting of the prompt and return data is ugly and needs correctly handling.
* Shutdown is broken as there is a hanging python child process left around you have to kill manually before you can restart bitbake.
* d.keys() crashes the terminal. Large data transfer breaks it?
* Would local=locals() get us the correct context rather than building manually?
Whether I'll find time to fix these things I don't know, is anyone interested in working on this?
meta/classes/devshell.bbclass +32 -0
@@ -25,3 +25,35 @@ python () { d.appendVar("OE_TERMINAL_EXPORTS", " " + k[0]) d.delVarFlag("do_devshell", "fakeroot") } + +python do_devpyshell() { + m, s = os.openpty() + sname = os.ttyname(s) + os.system('stty cs8 -icanon -echo < %s' % 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()) + bb.utils.nonblockingfd(sys.stdout) + bb.utils.nonblockingfd(sys.stdin) + + _context = { + "os": os, + "bb": bb, + "time": time, + "d": d, + } + + import code + try: + code.interact("BB: ", local=_context) + except Exception as e: + bb.fatal(str(e)) +} +addtask devpyshell after do_patch + +do_devpyshell[nostamp] = "1"
scripts/oepydevshell-internal.py new file +32 -0
@@ -0,0 +1,32 @@ +#!/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: + print(sys.argv[1]) + pty = open(sys.argv[1], "w+b") + nonblockingfd(pty) + nonblockingfd(sys.stdin) + while True: + (ready, _, _) = select.select([pty, sys.stdin], [] , [], 1) + if pty in ready: + r = pty.read() + sys.stdout.write(r) + if sys.stdin in ready: + r = sys.stdin.read() + pty.write(r) +except Exception as e: + print(str(e)) + time.sleep(5) +