1# 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" 167