mirror of
https://git.yoctoproject.org/git/poky
synced 2026-01-01 13:58:04 +00:00
Being able to interact with the python context in the Bitbake task execution
environment has long been desireable. 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 now includes readline support for command history and various other
bug fixes such as exiting cleanly compared to previous versions.
(From OE-Core rev: 36734f34fe6e4b91e293234687e63c02f5b3117e)
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
155 lines
4.4 KiB
Plaintext
155 lines
4.4 KiB
Plaintext
inherit terminal
|
|
|
|
DEVSHELL = "${SHELL}"
|
|
|
|
python do_devshell () {
|
|
if d.getVarFlag("do_devshell", "manualfakeroot"):
|
|
d.prependVar("DEVSHELL", "pseudo ")
|
|
fakeenv = d.getVar("FAKEROOTENV", True).split()
|
|
for f in fakeenv:
|
|
k = f.split("=")
|
|
d.setVar(k[0], k[1])
|
|
d.appendVar("OE_TERMINAL_EXPORTS", " " + k[0])
|
|
d.delVarFlag("do_devshell", "fakeroot")
|
|
|
|
oe_terminal(d.getVar('DEVSHELL', True), 'OpenEmbedded Developer Shell', d)
|
|
}
|
|
|
|
addtask devshell after do_patch
|
|
|
|
do_devshell[dirs] = "${S}"
|
|
do_devshell[nostamp] = "1"
|
|
|
|
# devshell and fakeroot/pseudo need careful handling since only the final
|
|
# command should run under fakeroot emulation, any X connection should
|
|
# be done as the normal user. We therfore carefully construct the envionment
|
|
# manually
|
|
python () {
|
|
if d.getVarFlag("do_devshell", "fakeroot"):
|
|
# We need to signal our code that we want fakeroot however we
|
|
# can't manipulate the environment and variables here yet (see YOCTO #4795)
|
|
d.setVarFlag("do_devshell", "manualfakeroot", "1")
|
|
d.delVarFlag("do_devshell", "fakeroot")
|
|
}
|
|
|
|
def devpyshell(d):
|
|
|
|
import code
|
|
import select
|
|
import signal
|
|
import termios
|
|
|
|
m, s = os.openpty()
|
|
sname = os.ttyname(s)
|
|
|
|
def noechoicanon(fd):
|
|
old = termios.tcgetattr(fd)
|
|
old[3] = old[3] &~ termios.ECHO &~ termios.ICANON
|
|
# &~ termios.ISIG
|
|
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
|
|
|
# No echo or buffering over the pty
|
|
noechoicanon(s)
|
|
|
|
pid = os.fork()
|
|
if pid:
|
|
os.close(m)
|
|
oe_terminal("oepydevshell-internal.py %s %d" % (sname, pid), 'OpenEmbedded Developer PyShell', d)
|
|
os._exit(0)
|
|
else:
|
|
os.close(s)
|
|
|
|
os.dup2(m, sys.stdin.fileno())
|
|
os.dup2(m, sys.stdout.fileno())
|
|
os.dup2(m, sys.stderr.fileno())
|
|
|
|
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
|
|
sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 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,
|
|
}
|
|
|
|
ps1 = "pydevshell> "
|
|
ps2 = "... "
|
|
buf = []
|
|
more = False
|
|
|
|
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)
|
|
|
|
# Restore Ctrl+C since bitbake masks this
|
|
def signal_handler(signal, frame):
|
|
raise KeyboardInterrupt
|
|
signal.signal(signal.SIGINT, signal_handler)
|
|
|
|
child = None
|
|
|
|
prompt(more)
|
|
while True:
|
|
try:
|
|
try:
|
|
(r, _, _) = select.select([sys.stdin], [], [], 1)
|
|
if not r:
|
|
continue
|
|
line = sys.stdin.readline().strip()
|
|
if not line:
|
|
prompt(more)
|
|
continue
|
|
except EOFError as e:
|
|
sys.stdout.write("\n")
|
|
except (OSError, IOError) as e:
|
|
if e.errno == 11:
|
|
continue
|
|
if e.errno == 5:
|
|
return
|
|
raise
|
|
else:
|
|
if not child:
|
|
child = int(line)
|
|
continue
|
|
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
|
|
prompt(more)
|
|
except SystemExit:
|
|
# Easiest way to ensure everything exits
|
|
os.kill(child, signal.SIGTERM)
|
|
break
|
|
|
|
python do_devpyshell() {
|
|
import signal
|
|
|
|
try:
|
|
devpyshell(d)
|
|
except SystemExit:
|
|
# Stop the SIGTERM above causing an error exit code
|
|
return
|
|
finally:
|
|
return
|
|
}
|
|
addtask devpyshell after do_patch
|
|
|
|
do_devpyshell[nostamp] = "1"
|