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