summaryrefslogtreecommitdiffstats
path: root/meta/classes
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2014-05-27 16:09:16 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2014-05-28 08:27:00 +0100
commitcd7b437d4b6800aab47ea9d9b00bbac1bb270bc5 (patch)
tree9f6590f7b0d8d7257f066f648712c9db9da0e504 /meta/classes
parent3bf24188b6735bc156f0e2f0acde0277b8443737 (diff)
downloadpoky-cd7b437d4b6800aab47ea9d9b00bbac1bb270bc5.tar.gz
devshell: Add interactive python shell
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>
Diffstat (limited to 'meta/classes')
-rw-r--r--meta/classes/devshell.bbclass121
1 files changed, 121 insertions, 0 deletions
diff --git a/meta/classes/devshell.bbclass b/meta/classes/devshell.bbclass
index 92edb9ef25..41164a3f33 100644
--- a/meta/classes/devshell.bbclass
+++ b/meta/classes/devshell.bbclass
@@ -31,3 +31,124 @@ python () {
31 d.setVarFlag("do_devshell", "manualfakeroot", "1") 31 d.setVarFlag("do_devshell", "manualfakeroot", "1")
32 d.delVarFlag("do_devshell", "fakeroot") 32 d.delVarFlag("do_devshell", "fakeroot")
33} 33}
34
35def devpyshell(d):
36
37 import code
38 import select
39 import signal
40 import termios
41
42 m, s = os.openpty()
43 sname = os.ttyname(s)
44
45 def noechoicanon(fd):
46 old = termios.tcgetattr(fd)
47 old[3] = old[3] &~ termios.ECHO &~ termios.ICANON
48 # &~ termios.ISIG
49 termios.tcsetattr(fd, termios.TCSADRAIN, old)
50
51 # No echo or buffering over the pty
52 noechoicanon(s)
53
54 pid = os.fork()
55 if pid:
56 os.close(m)
57 oe_terminal("oepydevshell-internal.py %s %d" % (sname, pid), 'OpenEmbedded Developer PyShell', d)
58 os._exit(0)
59 else:
60 os.close(s)
61
62 os.dup2(m, sys.stdin.fileno())
63 os.dup2(m, sys.stdout.fileno())
64 os.dup2(m, sys.stderr.fileno())
65
66 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
67 sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
68
69 bb.utils.nonblockingfd(sys.stdout)
70 bb.utils.nonblockingfd(sys.stderr)
71 bb.utils.nonblockingfd(sys.stdin)
72
73 _context = {
74 "os": os,
75 "bb": bb,
76 "time": time,
77 "d": d,
78 }
79
80 ps1 = "pydevshell> "
81 ps2 = "... "
82 buf = []
83 more = False
84
85 i = code.InteractiveInterpreter(locals=_context)
86 print("OE PyShell (PN = %s)\n" % d.getVar("PN", True))
87
88 def prompt(more):
89 if more:
90 prompt = ps2
91 else:
92 prompt = ps1
93 sys.stdout.write(prompt)
94
95 # Restore Ctrl+C since bitbake masks this
96 def signal_handler(signal, frame):
97 raise KeyboardInterrupt
98 signal.signal(signal.SIGINT, signal_handler)
99
100 child = None
101
102 prompt(more)
103 while True:
104 try:
105 try:
106 (r, _, _) = select.select([sys.stdin], [], [], 1)
107 if not r:
108 continue
109 line = sys.stdin.readline().strip()
110 if not line:
111 prompt(more)
112 continue
113 except EOFError as e:
114 sys.stdout.write("\n")
115 except (OSError, IOError) as e:
116 if e.errno == 11:
117 continue
118 if e.errno == 5:
119 return
120 raise
121 else:
122 if not child:
123 child = int(line)
124 continue
125 buf.append(line)
126 source = "\n".join(buf)
127 more = i.runsource(source, "<pyshell>")
128 if not more:
129 buf = []
130 prompt(more)
131 except KeyboardInterrupt:
132 i.write("\nKeyboardInterrupt\n")
133 buf = []
134 more = False
135 prompt(more)
136 except SystemExit:
137 # Easiest way to ensure everything exits
138 os.kill(child, signal.SIGTERM)
139 break
140
141python do_devpyshell() {
142 import signal
143
144 try:
145 devpyshell(d)
146 except SystemExit:
147 # Stop the SIGTERM above causing an error exit code
148 return
149 finally:
150 return
151}
152addtask devpyshell after do_patch
153
154do_devpyshell[nostamp] = "1"