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