TestRunner.py revision 8755ae8c69ca522a9931aab4b4951443b2f64d26
1be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarimport os, signal, subprocess, sys
2be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarimport StringIO
3be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
4be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarimport ShUtil
5be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarimport Test
6be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbarimport Util
7be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
858c661ced16cd07c796bc867b1db0997c15db69fDaniel Dunbarimport platform
95a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbarimport tempfile
1058c661ced16cd07c796bc867b1db0997c15db69fDaniel Dunbar
1118d49877530c04dd63578e6d9d0a1d3b6955502bDavid Greeneimport re
1218d49877530c04dd63578e6d9d0a1d3b6955502bDavid Greene
136bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbarclass InternalShellError(Exception):
146bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar    def __init__(self, command, message):
156bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        self.command = command
166bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        self.message = message
176bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar
18f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel DunbarkIsWindows = platform.system() == 'Windows'
19f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar
2058c661ced16cd07c796bc867b1db0997c15db69fDaniel Dunbar# Don't use close_fds on Windows.
21f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel DunbarkUseCloseFDs = not kIsWindows
226efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar
236efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar# Use temporary files to replace /dev/null on Windows.
24f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel DunbarkAvoidDevNull = kIsWindows
256efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar
26be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeCommand(command, cwd=None, env=None):
27b1a464279623768a3d04ff6726c99dce35d2f360Daniel Dunbar    # Close extra file handles on UNIX (on Windows this cannot be done while
28b1a464279623768a3d04ff6726c99dce35d2f360Daniel Dunbar    # also redirecting input).
29b1a464279623768a3d04ff6726c99dce35d2f360Daniel Dunbar    close_fds = not kIsWindows
30b1a464279623768a3d04ff6726c99dce35d2f360Daniel Dunbar
31be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    p = subprocess.Popen(command, cwd=cwd,
32be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                         stdin=subprocess.PIPE,
33be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                         stdout=subprocess.PIPE,
34be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                         stderr=subprocess.PIPE,
35b1a464279623768a3d04ff6726c99dce35d2f360Daniel Dunbar                         env=env, close_fds=close_fds)
36be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out,err = p.communicate()
37be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    exitCode = p.wait()
38be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
39be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Detect Ctrl-C in subprocess.
40be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if exitCode == -signal.SIGINT:
41be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        raise KeyboardInterrupt
42be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
43be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return out, err, exitCode
44be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
45be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeShCmd(cmd, cfg, cwd, results):
46be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if isinstance(cmd, ShUtil.Seq):
47be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == ';':
48be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            res = executeShCmd(cmd.lhs, cfg, cwd, results)
49be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return executeShCmd(cmd.rhs, cfg, cwd, results)
50be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
51be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == '&':
52a80ae9c71c361e0569af66b9885a15c3877c6c2dDaniel Dunbar            raise InternalShellError(cmd,"unsupported shell operator: '&'")
53be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
54be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == '||':
55be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            res = executeShCmd(cmd.lhs, cfg, cwd, results)
56be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res != 0:
57be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                res = executeShCmd(cmd.rhs, cfg, cwd, results)
58be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return res
59a80ae9c71c361e0569af66b9885a15c3877c6c2dDaniel Dunbar
60be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == '&&':
61be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            res = executeShCmd(cmd.lhs, cfg, cwd, results)
62be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res is None:
63be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                return res
64be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
65be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res == 0:
66be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                res = executeShCmd(cmd.rhs, cfg, cwd, results)
67be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return res
68be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
69be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        raise ValueError,'Unknown shell command: %r' % cmd.op
70be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
71be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    assert isinstance(cmd, ShUtil.Pipeline)
72be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    procs = []
73be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    input = subprocess.PIPE
745a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    stderrTempFiles = []
75c3681d334af978e066c4fdbfcadda492585ef338Daniel Dunbar    opened_files = []
761befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar    named_temp_files = []
775a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # To avoid deadlock, we use a single stderr stream for piped
785a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # output. This is null until we have seen some output using
795a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # stderr.
805a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    for i,j in enumerate(cmd.commands):
81f1a26cf9df900101b9cbea42b67f7466edc7deedEli Bendersky        # Apply the redirections, we use (N,) as a sentinel to indicate stdin,
82a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # stdout, stderr for N equal to 0, 1, or 2 respectively. Redirects to or
83a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # from a file are represented with a list [file, mode, file-object]
84a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # where file-object is initially None.
85be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        redirects = [(0,), (1,), (2,)]
86be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        for r in j.redirects:
87be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if r[0] == ('>',2):
88be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[2] = [r[1], 'w', None]
89a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar            elif r[0] == ('>>',2):
90a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar                redirects[2] = [r[1], 'a', None]
91be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('>&',2) and r[1] in '012':
92be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[2] = redirects[int(r[1])]
93be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('>&',) or r[0] == ('&>',):
94be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[1] = redirects[2] = [r[1], 'w', None]
95be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('>',):
96be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[1] = [r[1], 'w', None]
97a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar            elif r[0] == ('>>',):
98a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar                redirects[1] = [r[1], 'a', None]
99be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('<',):
100be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[0] = [r[1], 'r', None]
101be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
102a80ae9c71c361e0569af66b9885a15c3877c6c2dDaniel Dunbar                raise InternalShellError(j,"Unsupported redirect: %r" % (r,))
103be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
104a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # Map from the final redirections to something subprocess can handle.
105be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        final_redirects = []
106be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        for index,r in enumerate(redirects):
107be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if r == (0,):
108be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                result = input
109be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r == (1,):
110be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                if index == 0:
111a80ae9c71c361e0569af66b9885a15c3877c6c2dDaniel Dunbar                    raise InternalShellError(j,"Unsupported redirect for stdin")
112be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                elif index == 1:
113be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                    result = subprocess.PIPE
114be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                else:
115be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                    result = subprocess.STDOUT
116be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r == (2,):
117be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                if index != 2:
118a80ae9c71c361e0569af66b9885a15c3877c6c2dDaniel Dunbar                    raise InternalShellError(j,"Unsupported redirect on stdout")
119be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                result = subprocess.PIPE
120be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
121be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                if r[2] is None:
1226efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                    if kAvoidDevNull and r[0] == '/dev/null':
1236efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                        r[2] = tempfile.TemporaryFile(mode=r[1])
1246efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                    else:
1256efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                        r[2] = open(r[0], r[1])
126474f0df3ac86691fc2aaa201cacc7b5d0005d236Daniel Dunbar                    # Workaround a Win32 and/or subprocess bug when appending.
127e09ccab0ce2986d1ba6950f2eccc46fd1935ae68Daniel Dunbar                    #
128e09ccab0ce2986d1ba6950f2eccc46fd1935ae68Daniel Dunbar                    # FIXME: Actually, this is probably an instance of PR6753.
129474f0df3ac86691fc2aaa201cacc7b5d0005d236Daniel Dunbar                    if r[1] == 'a':
130bf477df346b12ae5f6e7af165862575c15905e20Daniel Dunbar                        r[2].seek(0, 2)
1319fae6ee6af42b7aca361deb478a212f573a0cd60NAKAMURA Takumi                    opened_files.append(r[2])
132be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                result = r[2]
133be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            final_redirects.append(result)
134be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
135be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        stdin, stdout, stderr = final_redirects
136be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
137be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # If stderr wants to come from stdout, but stdout isn't a pipe, then put
138be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # stderr on a pipe and treat it as stdout.
139be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if (stderr == subprocess.STDOUT and stdout != subprocess.PIPE):
140be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            stderr = subprocess.PIPE
141be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            stderrIsStdout = True
142be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
143be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            stderrIsStdout = False
1446bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar
1455a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            # Don't allow stderr on a PIPE except for the last
1465a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            # process, this could deadlock.
1475a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            #
1485a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            # FIXME: This is slow, but so is deadlock.
1495a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            if stderr == subprocess.PIPE and j != cmd.commands[-1]:
1505a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar                stderr = tempfile.TemporaryFile(mode='w+b')
1515a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar                stderrTempFiles.append((i, stderr))
1525a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar
1536bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        # Resolve the executable path ourselves.
1546bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        args = list(j.args)
1556bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        args[0] = Util.which(args[0], cfg.environment['PATH'])
1566bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        if not args[0]:
1576bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar            raise InternalShellError(j, '%r: command not found' % j.args[0])
1586bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar
1591befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar        # Replace uses of /dev/null with temporary files.
1601befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar        if kAvoidDevNull:
1611befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar            for i,arg in enumerate(args):
1621befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar                if arg == "/dev/null":
1631befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar                    f = tempfile.NamedTemporaryFile(delete=False)
1641befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar                    f.close()
1651befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar                    named_temp_files.append(f.name)
1661befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar                    args[i] = f.name
1671befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar
1684b78aa3f56e6dae484f1282cef4ff5237f10f9d8Daniel Dunbar        procs.append(subprocess.Popen(args, cwd=cwd,
169be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      stdin = stdin,
170be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      stdout = stdout,
171be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      stderr = stderr,
172be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      env = cfg.environment,
17358c661ced16cd07c796bc867b1db0997c15db69fDaniel Dunbar                                      close_fds = kUseCloseFDs))
174be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
175be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Immediately close stdin for any process taking stdin from us.
176be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if stdin == subprocess.PIPE:
177be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            procs[-1].stdin.close()
178be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            procs[-1].stdin = None
179be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
180be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Update the current stdin source.
181be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if stdout == subprocess.PIPE:
182be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            input = procs[-1].stdout
183be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        elif stderrIsStdout:
184be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            input = procs[-1].stderr
185be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
186be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            input = subprocess.PIPE
187be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
18869c4cbe9e878e49aa87d322c63afd809588f4cd7Daniel Dunbar    # Explicitly close any redirected files. We need to do this now because we
18969c4cbe9e878e49aa87d322c63afd809588f4cd7Daniel Dunbar    # need to release any handles we may have on the temporary files (important
19069c4cbe9e878e49aa87d322c63afd809588f4cd7Daniel Dunbar    # on Win32, for example). Since we have already spawned the subprocess, our
19169c4cbe9e878e49aa87d322c63afd809588f4cd7Daniel Dunbar    # handles have already been transferred so we do not need them anymore.
19269c4cbe9e878e49aa87d322c63afd809588f4cd7Daniel Dunbar    for f in opened_files:
1939fae6ee6af42b7aca361deb478a212f573a0cd60NAKAMURA Takumi        f.close()
19469c4cbe9e878e49aa87d322c63afd809588f4cd7Daniel Dunbar
1955a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # FIXME: There is probably still deadlock potential here. Yawn.
196be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    procData = [None] * len(procs)
197be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    procData[-1] = procs[-1].communicate()
1985a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar
199be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for i in range(len(procs) - 1):
200be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if procs[i].stdout is not None:
201be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            out = procs[i].stdout.read()
202be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
203be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            out = ''
204be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if procs[i].stderr is not None:
205be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            err = procs[i].stderr.read()
206be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
207be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            err = ''
208be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        procData[i] = (out,err)
209c3681d334af978e066c4fdbfcadda492585ef338Daniel Dunbar
2105a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # Read stderr out of the temp files.
2115a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    for i,f in stderrTempFiles:
2125a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar        f.seek(0, 0)
2135a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar        procData[i] = (procData[i][0], f.read())
214be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
215be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    exitCode = None
216be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for i,(out,err) in enumerate(procData):
217be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        res = procs[i].wait()
218be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Detect Ctrl-C in subprocess.
219be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if res == -signal.SIGINT:
220be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            raise KeyboardInterrupt
221be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
222be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        results.append((cmd.commands[i], out, err, res))
223be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.pipe_err:
224be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Python treats the exit code as a signed char.
225be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res < 0:
226be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                exitCode = min(exitCode, res)
227be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
228be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                exitCode = max(exitCode, res)
229be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
230be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            exitCode = res
231be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
2321befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar    # Remove any named temporary files we created.
2331befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar    for f in named_temp_files:
2349fae6ee6af42b7aca361deb478a212f573a0cd60NAKAMURA Takumi        try:
2359fae6ee6af42b7aca361deb478a212f573a0cd60NAKAMURA Takumi            os.remove(f)
2369fae6ee6af42b7aca361deb478a212f573a0cd60NAKAMURA Takumi        except OSError:
2379fae6ee6af42b7aca361deb478a212f573a0cd60NAKAMURA Takumi            pass
2381befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar
239be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if cmd.negate:
240be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        exitCode = not exitCode
241be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
242be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return exitCode
243be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
244be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeScriptInternal(test, litConfig, tmpBase, commands, cwd):
24500fb9c429e4400f3daeb87e6fad9498d4c73862aRichard Smith    cmds = []
24600fb9c429e4400f3daeb87e6fad9498d4c73862aRichard Smith    for ln in commands:
24700fb9c429e4400f3daeb87e6fad9498d4c73862aRichard Smith        try:
24800fb9c429e4400f3daeb87e6fad9498d4c73862aRichard Smith            cmds.append(ShUtil.ShParser(ln, litConfig.isWindows).parse())
24900fb9c429e4400f3daeb87e6fad9498d4c73862aRichard Smith        except:
25000fb9c429e4400f3daeb87e6fad9498d4c73862aRichard Smith            return (Test.FAIL, "shell parser error on: %r" % ln)
25100fb9c429e4400f3daeb87e6fad9498d4c73862aRichard Smith
25200fb9c429e4400f3daeb87e6fad9498d4c73862aRichard Smith    cmd = cmds[0]
25300fb9c429e4400f3daeb87e6fad9498d4c73862aRichard Smith    for c in cmds[1:]:
25400fb9c429e4400f3daeb87e6fad9498d4c73862aRichard Smith        cmd = ShUtil.Seq(cmd, '&&', c)
255be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
256be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    results = []
2576bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar    try:
2586bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        exitCode = executeShCmd(cmd, test.config, cwd, results)
2596bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar    except InternalShellError,e:
260b62fb4ba5cf61070486287da393ada566b4ad4edDaniel Dunbar        exitCode = 127
261b62fb4ba5cf61070486287da393ada566b4ad4edDaniel Dunbar        results.append((e.command, '', e.message, exitCode))
262be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
263be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out = err = ''
264be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for i,(cmd, cmd_out,cmd_err,res) in enumerate(results):
265be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d: %s\n' % (i, ' '.join('"%s"' % s for s in cmd.args))
266be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Result: %r\n' % (i, res)
267be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Output:\n%s\n\n' % (i, cmd_out)
268be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Stderr:\n%s\n\n' % (i, cmd_err)
269be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
270be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return out, err, exitCode
271be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
272be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeScript(test, litConfig, tmpBase, commands, cwd):
2739869c2f71744821d77fca2d0596cd9f27f84c5d2NAKAMURA Takumi    bashPath = litConfig.getBashPath();
2749869c2f71744821d77fca2d0596cd9f27f84c5d2NAKAMURA Takumi    isWin32CMDEXE = (litConfig.isWindows and not bashPath)
275be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    script = tmpBase + '.script'
2769869c2f71744821d77fca2d0596cd9f27f84c5d2NAKAMURA Takumi    if isWin32CMDEXE:
277be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        script += '.bat'
278be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
279be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Write script file
2808755ae8c69ca522a9931aab4b4951443b2f64d26Reid Kleckner    mode = 'w'
2818755ae8c69ca522a9931aab4b4951443b2f64d26Reid Kleckner    if litConfig.isWindows and not isWin32CMDEXE:
2828755ae8c69ca522a9931aab4b4951443b2f64d26Reid Kleckner      mode += 'b'  # Avoid CRLFs when writing bash scripts.
2838755ae8c69ca522a9931aab4b4951443b2f64d26Reid Kleckner    f = open(script, mode)
2849869c2f71744821d77fca2d0596cd9f27f84c5d2NAKAMURA Takumi    if isWin32CMDEXE:
285be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        f.write('\nif %ERRORLEVEL% NEQ 0 EXIT\n'.join(commands))
286be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
287c15e5b0a0dbdaf8612bdcbba1deedcb77bed1045Richard Smith        f.write('{ ' + '; } &&\n{ '.join(commands) + '; }')
288be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    f.write('\n')
289be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    f.close()
290be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
2919869c2f71744821d77fca2d0596cd9f27f84c5d2NAKAMURA Takumi    if isWin32CMDEXE:
292be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        command = ['cmd','/c', script]
293be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
2949869c2f71744821d77fca2d0596cd9f27f84c5d2NAKAMURA Takumi        if bashPath:
2959869c2f71744821d77fca2d0596cd9f27f84c5d2NAKAMURA Takumi            command = [bashPath, script]
2969869c2f71744821d77fca2d0596cd9f27f84c5d2NAKAMURA Takumi        else:
2979869c2f71744821d77fca2d0596cd9f27f84c5d2NAKAMURA Takumi            command = ['/bin/sh', script]
298be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if litConfig.useValgrind:
299be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # FIXME: Running valgrind on sh is overkill. We probably could just
300be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # run on clang with no real loss.
30132989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin            command = litConfig.valgrindArgs + command
302be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
303be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return executeCommand(command, cwd=cwd, env=test.config.environment)
304be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
305f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbardef isExpectedFail(test, xfails):
306f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar    # Check if any of the xfails match an available feature or the target.
30742543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    for item in xfails:
308f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar        # If this is the wildcard, it always fails.
309f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar        if item == '*':
31044a83f092029fa76bce05ff0c0598afc55215767Daniel Dunbar            return True
31144a83f092029fa76bce05ff0c0598afc55215767Daniel Dunbar
312f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar        # If this is an exact match for one of the features, it fails.
313f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar        if item in test.config.available_features:
314f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar            return True
31542543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar
316f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar        # If this is a part of the target triple, it fails.
317f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar        if item in test.suite.config.target_triple:
318f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar            return True
31942543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar
320f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar    return False
32142543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar
3222d4a5bf817ba0d85ddeb34a3c7fc2bc07fda32bdDaniel Dunbardef parseIntegratedTestScript(test, normalize_slashes=False,
3232d4a5bf817ba0d85ddeb34a3c7fc2bc07fda32bdDaniel Dunbar                              extra_substitutions=[]):
324be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    """parseIntegratedTestScript - Scan an LLVM/Clang style integrated test
325f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar    script and extract the lines to 'RUN' as well as 'XFAIL' and 'REQUIRES'
326be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    information. The RUN lines also will have variable substitution performed.
327be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    """
328be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
329be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Get the temporary location, this is always relative to the test suite
330be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # root, not test source root.
331be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    #
332be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # FIXME: This should not be here?
333be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    sourcepath = test.getSourcePath()
334f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar    sourcedir = os.path.dirname(sourcepath)
335be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    execpath = test.getExecPath()
336be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    execdir,execbase = os.path.split(execpath)
3370f9d34c71d4f4ea83912c45f99ed286557ea189cDouglas Gregor    tmpDir = os.path.join(execdir, 'Output')
3380f9d34c71d4f4ea83912c45f99ed286557ea189cDouglas Gregor    tmpBase = os.path.join(tmpDir, execbase)
33940c67b5832877935a555fc63bfaa735332c79700Daniel Dunbar    if test.index is not None:
34040c67b5832877935a555fc63bfaa735332c79700Daniel Dunbar        tmpBase += '_%d' % test.index
341be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
342f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar    # Normalize slashes, if requested.
343f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar    if normalize_slashes:
344f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar        sourcepath = sourcepath.replace('\\', '/')
345f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar        sourcedir = sourcedir.replace('\\', '/')
346bbbc283d86a911ccf3bdecdc78a7a8f71f31683fNAKAMURA Takumi        tmpDir = tmpDir.replace('\\', '/')
347f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar        tmpBase = tmpBase.replace('\\', '/')
348f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar
349be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # We use #_MARKER_# to hide %% while we do the other substitutions.
3502d4a5bf817ba0d85ddeb34a3c7fc2bc07fda32bdDaniel Dunbar    substitutions = list(extra_substitutions)
3512d4a5bf817ba0d85ddeb34a3c7fc2bc07fda32bdDaniel Dunbar    substitutions.extend([('%%', '#_MARKER_#')])
352be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    substitutions.extend(test.config.substitutions)
353be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    substitutions.extend([('%s', sourcepath),
354f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar                          ('%S', sourcedir),
355f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar                          ('%p', sourcedir),
3560191bfcf7a5ae1ccfad7afe8ced59a14ffaca2a6Nico Weber                          ('%{pathsep}', os.pathsep),
357be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                          ('%t', tmpBase + '.tmp'),
3580f9d34c71d4f4ea83912c45f99ed286557ea189cDouglas Gregor                          ('%T', tmpDir),
359be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                          ('#_MARKER_#', '%')])
360be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
361be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Collect the test lines from the script.
362be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    script = []
363be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    xfails = []
364b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar    requires = []
36508639983ded4250c18614c62450e70ba653aac4cAlexander Kornienko    line_number = 0
366be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for ln in open(sourcepath):
36708639983ded4250c18614c62450e70ba653aac4cAlexander Kornienko        line_number += 1
368be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if 'RUN:' in ln:
369be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Isolate the command to run.
370be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            index = ln.index('RUN:')
371be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            ln = ln[index+4:]
372be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
373be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Trim trailing whitespace.
374be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            ln = ln.rstrip()
375be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
37608639983ded4250c18614c62450e70ba653aac4cAlexander Kornienko            # Substitute line number expressions
37708639983ded4250c18614c62450e70ba653aac4cAlexander Kornienko            ln = re.sub('%\(line\)', str(line_number), ln)
37808639983ded4250c18614c62450e70ba653aac4cAlexander Kornienko            def replace_line_number(match):
37908639983ded4250c18614c62450e70ba653aac4cAlexander Kornienko                if match.group(1) == '+':
38008639983ded4250c18614c62450e70ba653aac4cAlexander Kornienko                    return str(line_number + int(match.group(2)))
38108639983ded4250c18614c62450e70ba653aac4cAlexander Kornienko                if match.group(1) == '-':
38208639983ded4250c18614c62450e70ba653aac4cAlexander Kornienko                    return str(line_number - int(match.group(2)))
38308639983ded4250c18614c62450e70ba653aac4cAlexander Kornienko            ln = re.sub('%\(line *([\+-]) *(\d+)\)', replace_line_number, ln)
38408639983ded4250c18614c62450e70ba653aac4cAlexander Kornienko
385be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Collapse lines with trailing '\\'.
386be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if script and script[-1][-1] == '\\':
387be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                script[-1] = script[-1][:-1] + ln
388be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
389be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                script.append(ln)
39042543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar        elif 'XFAIL:' in ln:
391be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            items = ln[ln.index('XFAIL:') + 6:].split(',')
392be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            xfails.extend([s.strip() for s in items])
393b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar        elif 'REQUIRES:' in ln:
394b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar            items = ln[ln.index('REQUIRES:') + 9:].split(',')
395b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar            requires.extend([s.strip() for s in items])
396be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        elif 'END.' in ln:
397be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Check for END. lines.
398be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if ln[ln.index('END.'):].strip() == 'END.':
399be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                break
400be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
40118d49877530c04dd63578e6d9d0a1d3b6955502bDavid Greene    # Apply substitutions to the script.  Allow full regular
40218d49877530c04dd63578e6d9d0a1d3b6955502bDavid Greene    # expression syntax.  Replace each matching occurrence of regular
40318d49877530c04dd63578e6d9d0a1d3b6955502bDavid Greene    # expression pattern a with substitution b in line ln.
404be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    def processLine(ln):
405be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Apply substitutions
406be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        for a,b in substitutions:
407ba69d3f6d448ca0a3a56b71fa65e85712bf76512Francois Pichet            if kIsWindows:
4087a0be17c087ad7723e0ec65e63f4eb80ce9b5cefFrancois Pichet                b = b.replace("\\","\\\\")
4097a0be17c087ad7723e0ec65e63f4eb80ce9b5cefFrancois Pichet            ln = re.sub(a, b, ln)
410be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
411be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Strip the trailing newline and any extra whitespace.
412be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return ln.strip()
413be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    script = map(processLine, script)
414be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
415be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Verify the script contains a run line.
416be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if not script:
417be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.UNRESOLVED, "Test has no run line!")
418be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
419b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar    # Check for unterminated run lines.
420be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if script[-1][-1] == '\\':
421be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.UNRESOLVED, "Test has unterminated run lines (with '\\')")
422be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
423f2a58425cd2a288b1d9fc3d2484ac774d361a0d7Andrew Trick    # Check that we have the required features:
424b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar    missing_required_features = [f for f in requires
425f2a58425cd2a288b1d9fc3d2484ac774d361a0d7Andrew Trick                                 if f not in test.config.available_features]
426b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar    if missing_required_features:
427b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar        msg = ', '.join(missing_required_features)
428b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar        return (Test.UNSUPPORTED,
429b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar                "Test requires the following features: %s" % msg)
430b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar
431f793fbc5698263e045661cab3fb06144c66cc1dbDaniel Dunbar    isXFail = isExpectedFail(test, xfails)
43242543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    return script,isXFail,tmpBase,execdir
433be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
434213a789a711724c864defdc2c3e1208d6c5b7fd4Daniel Dunbardef formatTestOutput(status, out, err, exitCode, script):
435be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    output = StringIO.StringIO()
436be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "Script:"
437be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "--"
438be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, '\n'.join(script)
439be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "--"
44034f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    print >>output, "Exit Code: %r" % exitCode,
441213a789a711724c864defdc2c3e1208d6c5b7fd4Daniel Dunbar    print >>output
4428a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman    if out:
4438a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "Command Output (stdout):"
4448a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "--"
4458a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        output.write(out)
4468a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "--"
4478a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman    if err:
4488a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "Command Output (stderr):"
4498a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "--"
4508a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        output.write(err)
4518a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "--"
452be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return (status, output.getvalue())
453be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
4542d4a5bf817ba0d85ddeb34a3c7fc2bc07fda32bdDaniel Dunbardef executeShTest(test, litConfig, useExternalSh,
4552d4a5bf817ba0d85ddeb34a3c7fc2bc07fda32bdDaniel Dunbar                  extra_substitutions=[]):
456be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if test.config.unsupported:
457be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.UNSUPPORTED, 'Test is unsupported')
458be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
4592d4a5bf817ba0d85ddeb34a3c7fc2bc07fda32bdDaniel Dunbar    res = parseIntegratedTestScript(test, useExternalSh, extra_substitutions)
460be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if len(res) == 2:
461be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return res
462be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
46342543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    script, isXFail, tmpBase, execdir = res
464be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
465be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if litConfig.noExecute:
466be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.PASS, '')
467be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
468be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Create the output directory if it does not already exist.
469be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    Util.mkdir_p(os.path.dirname(tmpBase))
470be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
471be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if useExternalSh:
472be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        res = executeScript(test, litConfig, tmpBase, script, execdir)
473be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
474be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        res = executeScriptInternal(test, litConfig, tmpBase, script, execdir)
475be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if len(res) == 2:
476be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return res
477be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
478be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out,err,exitCode = res
47942543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    if isXFail:
480be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        ok = exitCode != 0
481bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        if ok:
482bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.XFAIL
483bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        else:
484bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.XPASS
485be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
486be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        ok = exitCode == 0
487bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        if ok:
488bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.PASS
489bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        else:
490bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.FAIL
491be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
492be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if ok:
493be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (status,'')
494be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
495213a789a711724c864defdc2c3e1208d6c5b7fd4Daniel Dunbar    return formatTestOutput(status, out, err, exitCode, script)
496