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