blob: 4c23049cf06c348550ca64b1169b4a8ffd0cd02a [file] [log] [blame]
Patrick Williams92b42cb2022-09-03 06:53:57 -05001#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: MIT
5#
6
7inherit terminal
8
9DEVSHELL = "${SHELL}"
10
Patrick Williams92b42cb2022-09-03 06:53:57 -050011python do_devshell () {
12 if d.getVarFlag("do_devshell", "manualfakeroot"):
13 d.prependVar("DEVSHELL", "pseudo ")
14 fakeenv = d.getVar("FAKEROOTENV").split()
15 for f in fakeenv:
16 k = f.split("=")
17 d.setVar(k[0], k[1])
18 d.appendVar("OE_TERMINAL_EXPORTS", " " + k[0])
19 d.delVarFlag("do_devshell", "fakeroot")
20
21 oe_terminal(d.getVar('DEVSHELL'), 'OpenEmbedded Developer Shell', d)
22}
23
24addtask devshell after do_patch do_prepare_recipe_sysroot
25
26# The directory that the terminal starts in
27DEVSHELL_STARTDIR ?= "${S}"
28do_devshell[dirs] = "${DEVSHELL_STARTDIR}"
29do_devshell[nostamp] = "1"
30do_devshell[network] = "1"
31
32# devshell and fakeroot/pseudo need careful handling since only the final
33# command should run under fakeroot emulation, any X connection should
34# be done as the normal user. We therfore carefully construct the envionment
35# manually
36python () {
37 if d.getVarFlag("do_devshell", "fakeroot"):
38 # We need to signal our code that we want fakeroot however we
39 # can't manipulate the environment and variables here yet (see YOCTO #4795)
40 d.setVarFlag("do_devshell", "manualfakeroot", "1")
41 d.delVarFlag("do_devshell", "fakeroot")
42}
43
44def pydevshell(d):
45
46 import code
47 import select
48 import signal
49 import termios
50
51 m, s = os.openpty()
52 sname = os.ttyname(s)
53
54 def noechoicanon(fd):
55 old = termios.tcgetattr(fd)
56 old[3] = old[3] &~ termios.ECHO &~ termios.ICANON
57 # &~ termios.ISIG
58 termios.tcsetattr(fd, termios.TCSADRAIN, old)
59
60 # No echo or buffering over the pty
61 noechoicanon(s)
62
63 pid = os.fork()
64 if pid:
65 os.close(m)
66 oe_terminal("oepydevshell-internal.py %s %d" % (sname, pid), 'OpenEmbedded Developer PyShell', d)
67 os._exit(0)
68 else:
69 os.close(s)
70
71 os.dup2(m, sys.stdin.fileno())
72 os.dup2(m, sys.stdout.fileno())
73 os.dup2(m, sys.stderr.fileno())
74
75 bb.utils.nonblockingfd(sys.stdout)
76 bb.utils.nonblockingfd(sys.stderr)
77 bb.utils.nonblockingfd(sys.stdin)
78
79 _context = {
80 "os": os,
81 "bb": bb,
82 "time": time,
83 "d": d,
84 }
85
86 ps1 = "pydevshell> "
87 ps2 = "... "
88 buf = []
89 more = False
90
91 i = code.InteractiveInterpreter(locals=_context)
92 print("OE PyShell (PN = %s)\n" % d.getVar("PN"))
93
94 def prompt(more):
95 if more:
96 prompt = ps2
97 else:
98 prompt = ps1
99 sys.stdout.write(prompt)
100 sys.stdout.flush()
101
102 # Restore Ctrl+C since bitbake masks this
103 def signal_handler(signal, frame):
104 raise KeyboardInterrupt
105 signal.signal(signal.SIGINT, signal_handler)
106
107 child = None
108
109 prompt(more)
110 while True:
111 try:
112 try:
113 (r, _, _) = select.select([sys.stdin], [], [], 1)
114 if not r:
115 continue
116 line = sys.stdin.readline().strip()
117 if not line:
118 prompt(more)
119 continue
120 except EOFError as e:
121 sys.stdout.write("\n")
122 sys.stdout.flush()
123 except (OSError, IOError) as e:
124 if e.errno == 11:
125 continue
126 if e.errno == 5:
127 return
128 raise
129 else:
130 if not child:
131 child = int(line)
132 continue
133 buf.append(line)
134 source = "\n".join(buf)
135 more = i.runsource(source, "<pyshell>")
136 if not more:
137 buf = []
138 sys.stderr.flush()
139 prompt(more)
140 except KeyboardInterrupt:
141 i.write("\nKeyboardInterrupt\n")
142 buf = []
143 more = False
144 prompt(more)
145 except SystemExit:
146 # Easiest way to ensure everything exits
147 os.kill(child, signal.SIGTERM)
148 break
149
150python do_pydevshell() {
151 import signal
152
153 try:
154 pydevshell(d)
155 except SystemExit:
156 # Stop the SIGTERM above causing an error exit code
157 return
158 finally:
159 return
160}
161addtask pydevshell after do_patch
162
163do_pydevshell[nostamp] = "1"
164do_pydevshell[network] = "1"