1# 2# Copyright OpenEmbedded Contributors 3# 4# SPDX-License-Identifier: MIT 5# 6 7inherit terminal 8 9DEVSHELL = "${SHELL}" 10 11python 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" 165