devshell.bbclass 4.6 KB

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