TestRunner.py revision bd2499a0b128ca15e97d8d67e72f8c9024d3310b
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
116bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbarclass InternalShellError(Exception):
126bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar    def __init__(self, command, message):
136bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        self.command = command
146bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        self.message = message
156bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar
16f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel DunbarkIsWindows = platform.system() == 'Windows'
17f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar
1858c661ced16cd07c796bc867b1db0997c15db69fDaniel Dunbar# Don't use close_fds on Windows.
19f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel DunbarkUseCloseFDs = not kIsWindows
206efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar
216efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar# Use temporary files to replace /dev/null on Windows.
22f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel DunbarkAvoidDevNull = kIsWindows
236efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar
24be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeCommand(command, cwd=None, env=None):
25be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    p = subprocess.Popen(command, cwd=cwd,
26be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                         stdin=subprocess.PIPE,
27be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                         stdout=subprocess.PIPE,
28be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                         stderr=subprocess.PIPE,
29be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                         env=env)
30be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out,err = p.communicate()
31be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    exitCode = p.wait()
32be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
33be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Detect Ctrl-C in subprocess.
34be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if exitCode == -signal.SIGINT:
35be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        raise KeyboardInterrupt
36be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
37be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return out, err, exitCode
38be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
39be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeShCmd(cmd, cfg, cwd, results):
40be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if isinstance(cmd, ShUtil.Seq):
41be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == ';':
42be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            res = executeShCmd(cmd.lhs, cfg, cwd, results)
43be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return executeShCmd(cmd.rhs, cfg, cwd, results)
44be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
45be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == '&':
46be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            raise NotImplementedError,"unsupported test command: '&'"
47be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
48be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == '||':
49be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            res = executeShCmd(cmd.lhs, cfg, cwd, results)
50be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res != 0:
51be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                res = executeShCmd(cmd.rhs, cfg, cwd, results)
52be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return res
53be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == '&&':
54be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            res = executeShCmd(cmd.lhs, cfg, cwd, results)
55be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res is None:
56be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                return res
57be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
58be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res == 0:
59be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                res = executeShCmd(cmd.rhs, cfg, cwd, results)
60be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return res
61be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
62be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        raise ValueError,'Unknown shell command: %r' % cmd.op
63be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
64be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    assert isinstance(cmd, ShUtil.Pipeline)
65be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    procs = []
66be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    input = subprocess.PIPE
675a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    stderrTempFiles = []
68c3681d334af978e066c4fdbfcadda492585ef338Daniel Dunbar    opened_files = []
691befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar    named_temp_files = []
705a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # To avoid deadlock, we use a single stderr stream for piped
715a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # output. This is null until we have seen some output using
725a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # stderr.
735a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    for i,j in enumerate(cmd.commands):
74a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # Apply the redirections, we use (N,) as a sentinal to indicate stdin,
75a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # stdout, stderr for N equal to 0, 1, or 2 respectively. Redirects to or
76a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # from a file are represented with a list [file, mode, file-object]
77a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # where file-object is initially None.
78be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        redirects = [(0,), (1,), (2,)]
79be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        for r in j.redirects:
80be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if r[0] == ('>',2):
81be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[2] = [r[1], 'w', None]
82a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar            elif r[0] == ('>>',2):
83a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar                redirects[2] = [r[1], 'a', None]
84be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('>&',2) and r[1] in '012':
85be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[2] = redirects[int(r[1])]
86be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('>&',) or r[0] == ('&>',):
87be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[1] = redirects[2] = [r[1], 'w', None]
88be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('>',):
89be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[1] = [r[1], 'w', None]
90a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar            elif r[0] == ('>>',):
91a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar                redirects[1] = [r[1], 'a', None]
92be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('<',):
93be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[0] = [r[1], 'r', None]
94be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
95be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                raise NotImplementedError,"Unsupported redirect: %r" % (r,)
96be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
97a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # Map from the final redirections to something subprocess can handle.
98be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        final_redirects = []
99be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        for index,r in enumerate(redirects):
100be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if r == (0,):
101be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                result = input
102be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r == (1,):
103be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                if index == 0:
104be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                    raise NotImplementedError,"Unsupported redirect for stdin"
105be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                elif index == 1:
106be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                    result = subprocess.PIPE
107be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                else:
108be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                    result = subprocess.STDOUT
109be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r == (2,):
110be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                if index != 2:
111be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                    raise NotImplementedError,"Unsupported redirect on stdout"
112be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                result = subprocess.PIPE
113be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
114be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                if r[2] is None:
1156efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                    if kAvoidDevNull and r[0] == '/dev/null':
1166efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                        r[2] = tempfile.TemporaryFile(mode=r[1])
1176efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                    else:
1186efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                        r[2] = open(r[0], r[1])
119474f0df3ac86691fc2aaa201cacc7b5d0005d236Daniel Dunbar                    # Workaround a Win32 and/or subprocess bug when appending.
120e09ccab0ce2986d1ba6950f2eccc46fd1935ae68Daniel Dunbar                    #
121e09ccab0ce2986d1ba6950f2eccc46fd1935ae68Daniel Dunbar                    # FIXME: Actually, this is probably an instance of PR6753.
122474f0df3ac86691fc2aaa201cacc7b5d0005d236Daniel Dunbar                    if r[1] == 'a':
123bf477df346b12ae5f6e7af165862575c15905e20Daniel Dunbar                        r[2].seek(0, 2)
124c3681d334af978e066c4fdbfcadda492585ef338Daniel Dunbar                    opened_files.append(r[2])
125be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                result = r[2]
126be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            final_redirects.append(result)
127be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
128be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        stdin, stdout, stderr = final_redirects
129be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
130be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # If stderr wants to come from stdout, but stdout isn't a pipe, then put
131be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # stderr on a pipe and treat it as stdout.
132be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if (stderr == subprocess.STDOUT and stdout != subprocess.PIPE):
133be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            stderr = subprocess.PIPE
134be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            stderrIsStdout = True
135be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
136be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            stderrIsStdout = False
1376bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar
1385a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            # Don't allow stderr on a PIPE except for the last
1395a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            # process, this could deadlock.
1405a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            #
1415a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            # FIXME: This is slow, but so is deadlock.
1425a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            if stderr == subprocess.PIPE and j != cmd.commands[-1]:
1435a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar                stderr = tempfile.TemporaryFile(mode='w+b')
1445a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar                stderrTempFiles.append((i, stderr))
1455a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar
1466bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        # Resolve the executable path ourselves.
1476bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        args = list(j.args)
1486bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        args[0] = Util.which(args[0], cfg.environment['PATH'])
1496bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        if not args[0]:
1506bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar            raise InternalShellError(j, '%r: command not found' % j.args[0])
1516bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar
1521befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar        # Replace uses of /dev/null with temporary files.
1531befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar        if kAvoidDevNull:
1541befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar            for i,arg in enumerate(args):
1551befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar                if arg == "/dev/null":
1561befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar                    f = tempfile.NamedTemporaryFile(delete=False)
1571befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar                    f.close()
1581befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar                    named_temp_files.append(f.name)
1591befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar                    args[i] = f.name
1601befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar
1614b78aa3f56e6dae484f1282cef4ff5237f10f9d8Daniel Dunbar        procs.append(subprocess.Popen(args, cwd=cwd,
162be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      stdin = stdin,
163be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      stdout = stdout,
164be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      stderr = stderr,
165be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      env = cfg.environment,
16658c661ced16cd07c796bc867b1db0997c15db69fDaniel Dunbar                                      close_fds = kUseCloseFDs))
167be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
168be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Immediately close stdin for any process taking stdin from us.
169be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if stdin == subprocess.PIPE:
170be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            procs[-1].stdin.close()
171be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            procs[-1].stdin = None
172be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
173be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Update the current stdin source.
174be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if stdout == subprocess.PIPE:
175be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            input = procs[-1].stdout
176be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        elif stderrIsStdout:
177be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            input = procs[-1].stderr
178be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
179be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            input = subprocess.PIPE
180be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
1815a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # FIXME: There is probably still deadlock potential here. Yawn.
182be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    procData = [None] * len(procs)
183be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    procData[-1] = procs[-1].communicate()
1845a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar
185be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for i in range(len(procs) - 1):
186be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if procs[i].stdout is not None:
187be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            out = procs[i].stdout.read()
188be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
189be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            out = ''
190be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if procs[i].stderr is not None:
191be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            err = procs[i].stderr.read()
192be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
193be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            err = ''
194be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        procData[i] = (out,err)
195c3681d334af978e066c4fdbfcadda492585ef338Daniel Dunbar
1965a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # Read stderr out of the temp files.
1975a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    for i,f in stderrTempFiles:
1985a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar        f.seek(0, 0)
1995a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar        procData[i] = (procData[i][0], f.read())
200be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
201be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    exitCode = None
202be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for i,(out,err) in enumerate(procData):
203be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        res = procs[i].wait()
204be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Detect Ctrl-C in subprocess.
205be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if res == -signal.SIGINT:
206be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            raise KeyboardInterrupt
207be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
208be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        results.append((cmd.commands[i], out, err, res))
209be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.pipe_err:
210be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Python treats the exit code as a signed char.
211be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res < 0:
212be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                exitCode = min(exitCode, res)
213be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
214be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                exitCode = max(exitCode, res)
215be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
216be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            exitCode = res
217be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
218c3681d334af978e066c4fdbfcadda492585ef338Daniel Dunbar    # Explicitly close any redirected files.
219c3681d334af978e066c4fdbfcadda492585ef338Daniel Dunbar    for f in opened_files:
220c3681d334af978e066c4fdbfcadda492585ef338Daniel Dunbar        f.close()
221c3681d334af978e066c4fdbfcadda492585ef338Daniel Dunbar
2221befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar    # Remove any named temporary files we created.
2231befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar    for f in named_temp_files:
2241befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar        try:
2251befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar            os.remove(f)
2261befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar        except OSError:
2271befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar            pass
2281befb9b2df7b287872021518cedce4a0aeca3b95Daniel Dunbar
229be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if cmd.negate:
230be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        exitCode = not exitCode
231be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
232be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return exitCode
233be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
234be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeScriptInternal(test, litConfig, tmpBase, commands, cwd):
235be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    ln = ' &&\n'.join(commands)
236be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    try:
237be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        cmd = ShUtil.ShParser(ln, litConfig.isWindows).parse()
238be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    except:
239be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.FAIL, "shell parser error on: %r" % ln)
240be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
241be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    results = []
2426bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar    try:
2436bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        exitCode = executeShCmd(cmd, test.config, cwd, results)
2446bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar    except InternalShellError,e:
2456bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        out = ''
2466bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        err = e.message
2476bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        exitCode = 255
248be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
249be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out = err = ''
250be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for i,(cmd, cmd_out,cmd_err,res) in enumerate(results):
251be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d: %s\n' % (i, ' '.join('"%s"' % s for s in cmd.args))
252be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Result: %r\n' % (i, res)
253be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Output:\n%s\n\n' % (i, cmd_out)
254be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Stderr:\n%s\n\n' % (i, cmd_err)
255be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
256be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return out, err, exitCode
257be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
258be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeTclScriptInternal(test, litConfig, tmpBase, commands, cwd):
259be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    import TclUtil
260be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    cmds = []
261be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for ln in commands:
262be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Given the unfortunate way LLVM's test are written, the line gets
263be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # backslash substitution done twice.
264be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        ln = TclUtil.TclLexer(ln).lex_unquoted(process_all = True)
265be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
266be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        try:
267be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            tokens = list(TclUtil.TclLexer(ln).lex())
268be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        except:
269be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return (Test.FAIL, "Tcl lexer error on: %r" % ln)
270be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
271be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Validate there are no control tokens.
272be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        for t in tokens:
273be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if not isinstance(t, str):
274be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                return (Test.FAIL,
275be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                        "Invalid test line: %r containing %r" % (ln, t))
276be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
277be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        try:
278be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            cmds.append(TclUtil.TclExecCommand(tokens).parse_pipeline())
279be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        except:
2802c0a49c8cba8b7a6624d9c0b96f7d94231e10d22Daniel Dunbar            return (Test.FAIL, "Tcl 'exec' parse error on: %r" % ln)
281be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
282b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin    if litConfig.useValgrind:
283b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin        for pipeline in cmds:
284b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin            if pipeline.commands:
285b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin                # Only valgrind the first command in each pipeline, to avoid
286b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin                # valgrinding things like grep, not, and FileCheck.
287b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin                cmd = pipeline.commands[0]
28832989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin                cmd.args = litConfig.valgrindArgs + cmd.args
289b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin
290be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    cmd = cmds[0]
291be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for c in cmds[1:]:
292be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        cmd = ShUtil.Seq(cmd, '&&', c)
293be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
2947723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar    # FIXME: This is lame, we shouldn't need bash. See PR5240.
2957723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar    bashPath = litConfig.getBashPath()
2967723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar    if litConfig.useTclAsSh and bashPath:
297be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        script = tmpBase + '.script'
298be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
299be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Write script file
300be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        f = open(script,'w')
301be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        print >>f, 'set -o pipefail'
302be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        cmd.toShell(f, pipefail = True)
303be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        f.close()
304be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
305be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if 0:
306be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            print >>sys.stdout, cmd
307be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            print >>sys.stdout, open(script).read()
308be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            print >>sys.stdout
309be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return '', '', 0
310be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
3117723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar        command = [litConfig.getBashPath(), script]
312be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out,err,exitCode = executeCommand(command, cwd=cwd,
313be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                          env=test.config.environment)
314be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
315be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return out,err,exitCode
316be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
317be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        results = []
3186bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        try:
3196bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar            exitCode = executeShCmd(cmd, test.config, cwd, results)
3206bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        except InternalShellError,e:
3216bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar            results.append((e.command, '', e.message + '\n', 255))
3226bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar            exitCode = 255
323be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
324be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out = err = ''
325be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
326be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for i,(cmd, cmd_out, cmd_err, res) in enumerate(results):
327be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d: %s\n' % (i, ' '.join('"%s"' % s for s in cmd.args))
328be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Result: %r\n' % (i, res)
329be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Output:\n%s\n\n' % (i, cmd_out)
330be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Stderr:\n%s\n\n' % (i, cmd_err)
331be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
332be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return out, err, exitCode
333be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
334be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeScript(test, litConfig, tmpBase, commands, cwd):
335be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    script = tmpBase + '.script'
336be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if litConfig.isWindows:
337be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        script += '.bat'
338be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
339be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Write script file
340be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    f = open(script,'w')
341be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if litConfig.isWindows:
342be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        f.write('\nif %ERRORLEVEL% NEQ 0 EXIT\n'.join(commands))
343be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
344be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        f.write(' &&\n'.join(commands))
345be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    f.write('\n')
346be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    f.close()
347be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
348be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if litConfig.isWindows:
349be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        command = ['cmd','/c', script]
350be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
351be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        command = ['/bin/sh', script]
352be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if litConfig.useValgrind:
353be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # FIXME: Running valgrind on sh is overkill. We probably could just
354be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # run on clang with no real loss.
35532989deb9641cf3878686b5634311a7a125f8f02Jeffrey Yasskin            command = litConfig.valgrindArgs + command
356be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
357be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return executeCommand(command, cwd=cwd, env=test.config.environment)
358be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
35942543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbardef isExpectedFail(xfails, xtargets, target_triple):
36042543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    # Check if any xfail matches this target.
36142543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    for item in xfails:
36242543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar        if item == '*' or item in target_triple:
36342543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar            break
36442543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    else:
36542543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar        return False
36642543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar
36742543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    # If so, see if it is expected to pass on this target.
36842543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    #
36942543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    # FIXME: Rename XTARGET to something that makes sense, like XPASS.
37042543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    for item in xtargets:
37142543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar        if item == '*' or item in target_triple:
37242543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar            return False
37342543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar
37442543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    return True
37542543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar
376771d90ff4316d3557bfb1d6d500529d290b808d0Daniel Dunbardef parseIntegratedTestScript(test, normalize_slashes=False):
377be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    """parseIntegratedTestScript - Scan an LLVM/Clang style integrated test
378be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    script and extract the lines to 'RUN' as well as 'XFAIL' and 'XTARGET'
379be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    information. The RUN lines also will have variable substitution performed.
380be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    """
381be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
382be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Get the temporary location, this is always relative to the test suite
383be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # root, not test source root.
384be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    #
385be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # FIXME: This should not be here?
386be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    sourcepath = test.getSourcePath()
387f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar    sourcedir = os.path.dirname(sourcepath)
388be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    execpath = test.getExecPath()
389be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    execdir,execbase = os.path.split(execpath)
390be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    tmpBase = os.path.join(execdir, 'Output', execbase)
39140c67b5832877935a555fc63bfaa735332c79700Daniel Dunbar    if test.index is not None:
39240c67b5832877935a555fc63bfaa735332c79700Daniel Dunbar        tmpBase += '_%d' % test.index
393be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
394f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar    # Normalize slashes, if requested.
395f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar    if normalize_slashes:
396f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar        sourcepath = sourcepath.replace('\\', '/')
397f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar        sourcedir = sourcedir.replace('\\', '/')
398f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar        tmpBase = tmpBase.replace('\\', '/')
399f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar
400be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # We use #_MARKER_# to hide %% while we do the other substitutions.
401be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    substitutions = [('%%', '#_MARKER_#')]
402be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    substitutions.extend(test.config.substitutions)
403be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    substitutions.extend([('%s', sourcepath),
404f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar                          ('%S', sourcedir),
405f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar                          ('%p', sourcedir),
406be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                          ('%t', tmpBase + '.tmp'),
4075110609ceb901f20e1d8b38530e09f9e9017386cDaniel Dunbar                          # FIXME: Remove this once we kill DejaGNU.
4085110609ceb901f20e1d8b38530e09f9e9017386cDaniel Dunbar                          ('%abs_tmp', tmpBase + '.tmp'),
409be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                          ('#_MARKER_#', '%')])
410be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
411be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Collect the test lines from the script.
412be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    script = []
413be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    xfails = []
414be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    xtargets = []
415b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar    requires = []
416be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for ln in open(sourcepath):
417be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if 'RUN:' in ln:
418be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Isolate the command to run.
419be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            index = ln.index('RUN:')
420be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            ln = ln[index+4:]
421be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
422be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Trim trailing whitespace.
423be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            ln = ln.rstrip()
424be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
425be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Collapse lines with trailing '\\'.
426be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if script and script[-1][-1] == '\\':
427be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                script[-1] = script[-1][:-1] + ln
428be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
429be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                script.append(ln)
43042543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar        elif 'XFAIL:' in ln:
431be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            items = ln[ln.index('XFAIL:') + 6:].split(',')
432be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            xfails.extend([s.strip() for s in items])
433be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        elif 'XTARGET:' in ln:
434be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            items = ln[ln.index('XTARGET:') + 8:].split(',')
435be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            xtargets.extend([s.strip() for s in items])
436b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar        elif 'REQUIRES:' in ln:
437b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar            items = ln[ln.index('REQUIRES:') + 9:].split(',')
438b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar            requires.extend([s.strip() for s in items])
439be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        elif 'END.' in ln:
440be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Check for END. lines.
441be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if ln[ln.index('END.'):].strip() == 'END.':
442be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                break
443be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
444be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Apply substitutions to the script.
445be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    def processLine(ln):
446be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Apply substitutions
447be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        for a,b in substitutions:
448be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            ln = ln.replace(a,b)
449be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
450be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Strip the trailing newline and any extra whitespace.
451be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return ln.strip()
452be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    script = map(processLine, script)
453be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
454be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Verify the script contains a run line.
455be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if not script:
456be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.UNRESOLVED, "Test has no run line!")
457be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
458b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar    # Check for unterminated run lines.
459be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if script[-1][-1] == '\\':
460be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.UNRESOLVED, "Test has unterminated run lines (with '\\')")
461be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
462b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar    # Check that we have the required features:
463b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar    missing_required_features = [f for f in requires
464b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar                                 if f not in test.config.available_features]
465b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar    if missing_required_features:
466b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar        msg = ', '.join(missing_required_features)
467b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar        return (Test.UNSUPPORTED,
468b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar                "Test requires the following features: %s" % msg)
469b937549e517fcb03032bab3441d6ced37fc4db8dDaniel Dunbar
47042543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    isXFail = isExpectedFail(xfails, xtargets, test.suite.config.target_triple)
47142543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    return script,isXFail,tmpBase,execdir
472be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
47334f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohmandef formatTestOutput(status, out, err, exitCode, failDueToStderr, script):
474be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    output = StringIO.StringIO()
475be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "Script:"
476be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "--"
477be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, '\n'.join(script)
478be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "--"
47934f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    print >>output, "Exit Code: %r" % exitCode,
48034f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    if failDueToStderr:
48134f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman        print >>output, "(but there was output on stderr)"
48234f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    else:
48334f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman        print >>output
4848a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman    if out:
4858a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "Command Output (stdout):"
4868a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "--"
4878a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        output.write(out)
4888a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "--"
4898a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman    if err:
4908a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "Command Output (stderr):"
4918a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "--"
4928a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        output.write(err)
4938a7ffe651f706a6819e94e6a99bbb2c1bb1d4391Dan Gohman        print >>output, "--"
494be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return (status, output.getvalue())
495be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
496be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeTclTest(test, litConfig):
497be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if test.config.unsupported:
498be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.UNSUPPORTED, 'Test is unsupported')
499be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
500f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar    # Parse the test script, normalizing slashes in substitutions on Windows
501f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar    # (since otherwise Tcl style lexing will treat them as escapes).
502f32a41a7e6df8ff5f78c673e3a73303bdba759ffDaniel Dunbar    res = parseIntegratedTestScript(test, normalize_slashes=kIsWindows)
503be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if len(res) == 2:
504be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return res
505be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
50642543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    script, isXFail, tmpBase, execdir = res
507be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
508be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if litConfig.noExecute:
509be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.PASS, '')
510be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
511be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Create the output directory if it does not already exist.
512be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    Util.mkdir_p(os.path.dirname(tmpBase))
513be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
514be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    res = executeTclScriptInternal(test, litConfig, tmpBase, script, execdir)
515be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if len(res) == 2:
516be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return res
517be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
51834f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    # Test for failure. In addition to the exit code, Tcl commands are
51934f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    # considered to fail if there is any standard error output.
520be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out,err,exitCode = res
521be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if isXFail:
522e1e5746476745cfea4051324c89836bc4b581530Dan Gohman        ok = exitCode != 0 or err
523bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        if ok:
524bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.XFAIL
525bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        else:
526bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.XPASS
527be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
528e1e5746476745cfea4051324c89836bc4b581530Dan Gohman        ok = exitCode == 0 and not err
529bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        if ok:
530bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.PASS
531bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        else:
532bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.FAIL
533be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
534be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if ok:
535be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (status,'')
536be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
53734f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    # Set a flag for formatTestOutput so it can explain why the test was
53834f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    # considered to have failed, despite having an exit code of 0.
53934f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    failDueToStderr = exitCode == 0 and err
54034f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman
54134f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    return formatTestOutput(status, out, err, exitCode, failDueToStderr, script)
542be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
543ee504b8cd78f5d54e4ae6ed2cfff88a9e8226771Daniel Dunbardef executeShTest(test, litConfig, useExternalSh):
544be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if test.config.unsupported:
545be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.UNSUPPORTED, 'Test is unsupported')
546be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
547ee504b8cd78f5d54e4ae6ed2cfff88a9e8226771Daniel Dunbar    res = parseIntegratedTestScript(test)
548be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if len(res) == 2:
549be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return res
550be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
55142543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    script, isXFail, tmpBase, execdir = res
552be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
553be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if litConfig.noExecute:
554be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.PASS, '')
555be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
556be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Create the output directory if it does not already exist.
557be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    Util.mkdir_p(os.path.dirname(tmpBase))
558be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
559be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if useExternalSh:
560be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        res = executeScript(test, litConfig, tmpBase, script, execdir)
561be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
562be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        res = executeScriptInternal(test, litConfig, tmpBase, script, execdir)
563be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if len(res) == 2:
564be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return res
565be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
566be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out,err,exitCode = res
56742543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    if isXFail:
568be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        ok = exitCode != 0
569bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        if ok:
570bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.XFAIL
571bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        else:
572bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.XPASS
573be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
574be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        ok = exitCode == 0
575bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        if ok:
576bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.PASS
577bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman        else:
578bd2499a0b128ca15e97d8d67e72f8c9024d3310bDan Gohman            status = Test.FAIL
579be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
580be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if ok:
581be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (status,'')
582be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
58334f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    # Sh tests are not considered to fail just from stderr output.
58434f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    failDueToStderr = False
58534f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman
58634f68fc040a920b32ee11c5a8f63ba8a75240f26Dan Gohman    return formatTestOutput(status, out, err, exitCode, failDueToStderr, script)
587