TestRunner.py revision b5e9770aef7176668cb1a1d97c085c061798cfd3
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
1658c661ced16cd07c796bc867b1db0997c15db69fDaniel Dunbar# Don't use close_fds on Windows.
1758c661ced16cd07c796bc867b1db0997c15db69fDaniel DunbarkUseCloseFDs = platform.system() != 'Windows'
186efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar
196efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar# Use temporary files to replace /dev/null on Windows.
206efba21342b15d7dc3185462868a606234e064f1Daniel DunbarkAvoidDevNull = platform.system() == 'Windows'
216efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar
22be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeCommand(command, cwd=None, env=None):
23be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    p = subprocess.Popen(command, cwd=cwd,
24be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                         stdin=subprocess.PIPE,
25be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                         stdout=subprocess.PIPE,
26be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                         stderr=subprocess.PIPE,
27be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                         env=env)
28be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out,err = p.communicate()
29be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    exitCode = p.wait()
30be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
31be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Detect Ctrl-C in subprocess.
32be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if exitCode == -signal.SIGINT:
33be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        raise KeyboardInterrupt
34be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
35be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return out, err, exitCode
36be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
37be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeShCmd(cmd, cfg, cwd, results):
38be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if isinstance(cmd, ShUtil.Seq):
39be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == ';':
40be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            res = executeShCmd(cmd.lhs, cfg, cwd, results)
41be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return executeShCmd(cmd.rhs, cfg, cwd, results)
42be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
43be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == '&':
44be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            raise NotImplementedError,"unsupported test command: '&'"
45be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
46be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == '||':
47be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            res = executeShCmd(cmd.lhs, cfg, cwd, results)
48be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res != 0:
49be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                res = executeShCmd(cmd.rhs, cfg, cwd, results)
50be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return res
51be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.op == '&&':
52be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            res = executeShCmd(cmd.lhs, cfg, cwd, results)
53be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res is None:
54be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                return res
55be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
56be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res == 0:
57be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                res = executeShCmd(cmd.rhs, cfg, cwd, results)
58be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return res
59be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
60be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        raise ValueError,'Unknown shell command: %r' % cmd.op
61be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
62be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    assert isinstance(cmd, ShUtil.Pipeline)
63be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    procs = []
64be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    input = subprocess.PIPE
655a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    stderrTempFiles = []
665a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # To avoid deadlock, we use a single stderr stream for piped
675a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # output. This is null until we have seen some output using
685a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # stderr.
695a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    for i,j in enumerate(cmd.commands):
70a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # Apply the redirections, we use (N,) as a sentinal to indicate stdin,
71a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # stdout, stderr for N equal to 0, 1, or 2 respectively. Redirects to or
72a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # from a file are represented with a list [file, mode, file-object]
73a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # where file-object is initially None.
74be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        redirects = [(0,), (1,), (2,)]
75be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        for r in j.redirects:
76be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if r[0] == ('>',2):
77be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[2] = [r[1], 'w', None]
78a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar            elif r[0] == ('>>',2):
79a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar                redirects[2] = [r[1], 'a', None]
80be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('>&',2) and r[1] in '012':
81be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[2] = redirects[int(r[1])]
82be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('>&',) or r[0] == ('&>',):
83be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[1] = redirects[2] = [r[1], 'w', None]
84be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('>',):
85be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[1] = [r[1], 'w', None]
86a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar            elif r[0] == ('>>',):
87a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar                redirects[1] = [r[1], 'a', None]
88be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r[0] == ('<',):
89be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                redirects[0] = [r[1], 'r', None]
90be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
91be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                raise NotImplementedError,"Unsupported redirect: %r" % (r,)
92be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
93a3f85d206a4b9f717d4dd9b53cdc280e9105c70fDaniel Dunbar        # Map from the final redirections to something subprocess can handle.
94be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        final_redirects = []
95be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        for index,r in enumerate(redirects):
96be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if r == (0,):
97be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                result = input
98be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r == (1,):
99be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                if index == 0:
100be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                    raise NotImplementedError,"Unsupported redirect for stdin"
101be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                elif index == 1:
102be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                    result = subprocess.PIPE
103be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                else:
104be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                    result = subprocess.STDOUT
105be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            elif r == (2,):
106be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                if index != 2:
107be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                    raise NotImplementedError,"Unsupported redirect on stdout"
108be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                result = subprocess.PIPE
109be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
110be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                if r[2] is None:
1116efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                    if kAvoidDevNull and r[0] == '/dev/null':
1126efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                        r[2] = tempfile.TemporaryFile(mode=r[1])
1136efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                    else:
1146efba21342b15d7dc3185462868a606234e064f1Daniel Dunbar                        r[2] = open(r[0], r[1])
115474f0df3ac86691fc2aaa201cacc7b5d0005d236Daniel Dunbar                    # Workaround a Win32 and/or subprocess bug when appending.
116474f0df3ac86691fc2aaa201cacc7b5d0005d236Daniel Dunbar                    if r[1] == 'a':
117bf477df346b12ae5f6e7af165862575c15905e20Daniel Dunbar                        r[2].seek(0, 2)
118be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                result = r[2]
119be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            final_redirects.append(result)
120be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
121be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        stdin, stdout, stderr = final_redirects
122be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
123be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # If stderr wants to come from stdout, but stdout isn't a pipe, then put
124be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # stderr on a pipe and treat it as stdout.
125be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if (stderr == subprocess.STDOUT and stdout != subprocess.PIPE):
126be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            stderr = subprocess.PIPE
127be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            stderrIsStdout = True
128be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
129be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            stderrIsStdout = False
1306bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar
1315a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            # Don't allow stderr on a PIPE except for the last
1325a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            # process, this could deadlock.
1335a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            #
1345a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            # FIXME: This is slow, but so is deadlock.
1355a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar            if stderr == subprocess.PIPE and j != cmd.commands[-1]:
1365a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar                stderr = tempfile.TemporaryFile(mode='w+b')
1375a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar                stderrTempFiles.append((i, stderr))
1385a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar
1396bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        # Resolve the executable path ourselves.
1406bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        args = list(j.args)
1416bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        args[0] = Util.which(args[0], cfg.environment['PATH'])
1426bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        if not args[0]:
1436bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar            raise InternalShellError(j, '%r: command not found' % j.args[0])
1446bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar
1454b78aa3f56e6dae484f1282cef4ff5237f10f9d8Daniel Dunbar        procs.append(subprocess.Popen(args, cwd=cwd,
146be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      stdin = stdin,
147be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      stdout = stdout,
148be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      stderr = stderr,
149be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                      env = cfg.environment,
15058c661ced16cd07c796bc867b1db0997c15db69fDaniel Dunbar                                      close_fds = kUseCloseFDs))
151be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
152be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Immediately close stdin for any process taking stdin from us.
153be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if stdin == subprocess.PIPE:
154be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            procs[-1].stdin.close()
155be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            procs[-1].stdin = None
156be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
157be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Update the current stdin source.
158be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if stdout == subprocess.PIPE:
159be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            input = procs[-1].stdout
160be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        elif stderrIsStdout:
161be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            input = procs[-1].stderr
162be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
163be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            input = subprocess.PIPE
164be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
1655a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # FIXME: There is probably still deadlock potential here. Yawn.
166be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    procData = [None] * len(procs)
167be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    procData[-1] = procs[-1].communicate()
1685a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar
169be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for i in range(len(procs) - 1):
170be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if procs[i].stdout is not None:
171be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            out = procs[i].stdout.read()
172be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
173be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            out = ''
174be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if procs[i].stderr is not None:
175be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            err = procs[i].stderr.read()
176be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
177be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            err = ''
178be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        procData[i] = (out,err)
1795a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar
1805a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    # Read stderr out of the temp files.
1815a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar    for i,f in stderrTempFiles:
1825a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar        f.seek(0, 0)
1835a461dd513dddaec6fd30196cb8f8680659a6e0dDaniel Dunbar        procData[i] = (procData[i][0], f.read())
184be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
185be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    exitCode = None
186be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for i,(out,err) in enumerate(procData):
187be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        res = procs[i].wait()
188be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Detect Ctrl-C in subprocess.
189be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if res == -signal.SIGINT:
190be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            raise KeyboardInterrupt
191be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
192be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        results.append((cmd.commands[i], out, err, res))
193be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if cmd.pipe_err:
194be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Python treats the exit code as a signed char.
195be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if res < 0:
196be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                exitCode = min(exitCode, res)
197be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
198be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                exitCode = max(exitCode, res)
199be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        else:
200be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            exitCode = res
201be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
202be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if cmd.negate:
203be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        exitCode = not exitCode
204be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
205be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return exitCode
206be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
207be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeScriptInternal(test, litConfig, tmpBase, commands, cwd):
208be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    ln = ' &&\n'.join(commands)
209be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    try:
210be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        cmd = ShUtil.ShParser(ln, litConfig.isWindows).parse()
211be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    except:
212be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.FAIL, "shell parser error on: %r" % ln)
213be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
214be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    results = []
2156bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar    try:
2166bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        exitCode = executeShCmd(cmd, test.config, cwd, results)
2176bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar    except InternalShellError,e:
2186bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        out = ''
2196bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        err = e.message
2206bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        exitCode = 255
221be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
222be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out = err = ''
223be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for i,(cmd, cmd_out,cmd_err,res) in enumerate(results):
224be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d: %s\n' % (i, ' '.join('"%s"' % s for s in cmd.args))
225be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Result: %r\n' % (i, res)
226be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Output:\n%s\n\n' % (i, cmd_out)
227be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Stderr:\n%s\n\n' % (i, cmd_err)
228be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
229be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return out, err, exitCode
230be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
231be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeTclScriptInternal(test, litConfig, tmpBase, commands, cwd):
232be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    import TclUtil
233be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    cmds = []
234be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for ln in commands:
235be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Given the unfortunate way LLVM's test are written, the line gets
236be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # backslash substitution done twice.
237be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        ln = TclUtil.TclLexer(ln).lex_unquoted(process_all = True)
238be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
239be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        try:
240be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            tokens = list(TclUtil.TclLexer(ln).lex())
241be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        except:
242be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return (Test.FAIL, "Tcl lexer error on: %r" % ln)
243be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
244be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Validate there are no control tokens.
245be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        for t in tokens:
246be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if not isinstance(t, str):
247be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                return (Test.FAIL,
248be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                        "Invalid test line: %r containing %r" % (ln, t))
249be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
250be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        try:
251be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            cmds.append(TclUtil.TclExecCommand(tokens).parse_pipeline())
252be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        except:
2532c0a49c8cba8b7a6624d9c0b96f7d94231e10d22Daniel Dunbar            return (Test.FAIL, "Tcl 'exec' parse error on: %r" % ln)
254be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
255b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin    if litConfig.useValgrind:
256b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin        valgrindArgs = ['valgrind', '-q',
257b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin                        '--tool=memcheck', '--trace-children=yes',
258b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin                        '--error-exitcode=123']
259b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin        valgrindArgs.extend(litConfig.valgrindArgs)
260b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin        for pipeline in cmds:
261b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin            if pipeline.commands:
262b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin                # Only valgrind the first command in each pipeline, to avoid
263b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin                # valgrinding things like grep, not, and FileCheck.
264b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin                cmd = pipeline.commands[0]
265b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin                cmd.args = valgrindArgs + cmd.args
266b5e9770aef7176668cb1a1d97c085c061798cfd3Jeffrey Yasskin
267be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    cmd = cmds[0]
268be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for c in cmds[1:]:
269be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        cmd = ShUtil.Seq(cmd, '&&', c)
270be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
2717723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar    # FIXME: This is lame, we shouldn't need bash. See PR5240.
2727723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar    bashPath = litConfig.getBashPath()
2737723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar    if litConfig.useTclAsSh and bashPath:
274be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        script = tmpBase + '.script'
275be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
276be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Write script file
277be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        f = open(script,'w')
278be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        print >>f, 'set -o pipefail'
279be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        cmd.toShell(f, pipefail = True)
280be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        f.close()
281be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
282be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if 0:
283be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            print >>sys.stdout, cmd
284be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            print >>sys.stdout, open(script).read()
285be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            print >>sys.stdout
286be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            return '', '', 0
287be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
2887723d45153c5610349486121e2b50b5ba60b2f5cDaniel Dunbar        command = [litConfig.getBashPath(), script]
289be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out,err,exitCode = executeCommand(command, cwd=cwd,
290be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                                          env=test.config.environment)
291be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
292be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Tcl commands fail on standard error output.
293be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if err:
294be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            exitCode = 1
295be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            out = 'Command has output on stderr!\n\n' + out
296be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
297be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return out,err,exitCode
298be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
299be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        results = []
3006bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        try:
3016bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar            exitCode = executeShCmd(cmd, test.config, cwd, results)
3026bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar        except InternalShellError,e:
3036bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar            results.append((e.command, '', e.message + '\n', 255))
3046bd2b2e9a27df118951d2fdc88df249d56a4d8feDaniel Dunbar            exitCode = 255
305be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
306be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out = err = ''
307be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
308be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Tcl commands fail on standard error output.
309be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if [True for _,_,err,res in results if err]:
310be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        exitCode = 1
311be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command has output on stderr!\n\n'
312be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
313be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for i,(cmd, cmd_out, cmd_err, res) in enumerate(results):
314be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d: %s\n' % (i, ' '.join('"%s"' % s for s in cmd.args))
315be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Result: %r\n' % (i, res)
316be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Output:\n%s\n\n' % (i, cmd_out)
317be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        out += 'Command %d Stderr:\n%s\n\n' % (i, cmd_err)
318be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
319be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return out, err, exitCode
320be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
321be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeScript(test, litConfig, tmpBase, commands, cwd):
322be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    script = tmpBase + '.script'
323be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if litConfig.isWindows:
324be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        script += '.bat'
325be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
326be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Write script file
327be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    f = open(script,'w')
328be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if litConfig.isWindows:
329be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        f.write('\nif %ERRORLEVEL% NEQ 0 EXIT\n'.join(commands))
330be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
331be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        f.write(' &&\n'.join(commands))
332be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    f.write('\n')
333be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    f.close()
334be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
335be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if litConfig.isWindows:
336be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        command = ['cmd','/c', script]
337be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
338be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        command = ['/bin/sh', script]
339be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if litConfig.useValgrind:
340be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # FIXME: Running valgrind on sh is overkill. We probably could just
341be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # run on clang with no real loss.
342be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            valgrindArgs = ['valgrind', '-q',
343be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                            '--tool=memcheck', '--trace-children=yes',
344be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                            '--error-exitcode=123']
345be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            valgrindArgs.extend(litConfig.valgrindArgs)
346be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
347be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            command = valgrindArgs + command
348be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
349be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return executeCommand(command, cwd=cwd, env=test.config.environment)
350be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
35142543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbardef isExpectedFail(xfails, xtargets, target_triple):
35242543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    # Check if any xfail matches this target.
35342543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    for item in xfails:
35442543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar        if item == '*' or item in target_triple:
35542543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar            break
35642543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    else:
35742543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar        return False
35842543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar
35942543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    # If so, see if it is expected to pass on this target.
36042543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    #
36142543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    # FIXME: Rename XTARGET to something that makes sense, like XPASS.
36242543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    for item in xtargets:
36342543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar        if item == '*' or item in target_triple:
36442543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar            return False
36542543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar
36642543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    return True
36742543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar
368ee504b8cd78f5d54e4ae6ed2cfff88a9e8226771Daniel Dunbardef parseIntegratedTestScript(test):
369be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    """parseIntegratedTestScript - Scan an LLVM/Clang style integrated test
370be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    script and extract the lines to 'RUN' as well as 'XFAIL' and 'XTARGET'
371be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    information. The RUN lines also will have variable substitution performed.
372be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    """
373be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
374be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Get the temporary location, this is always relative to the test suite
375be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # root, not test source root.
376be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    #
377be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # FIXME: This should not be here?
378be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    sourcepath = test.getSourcePath()
379be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    execpath = test.getExecPath()
380be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    execdir,execbase = os.path.split(execpath)
381be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    tmpBase = os.path.join(execdir, 'Output', execbase)
38240c67b5832877935a555fc63bfaa735332c79700Daniel Dunbar    if test.index is not None:
38340c67b5832877935a555fc63bfaa735332c79700Daniel Dunbar        tmpBase += '_%d' % test.index
384be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
385be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # We use #_MARKER_# to hide %% while we do the other substitutions.
386be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    substitutions = [('%%', '#_MARKER_#')]
387be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    substitutions.extend(test.config.substitutions)
388be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    substitutions.extend([('%s', sourcepath),
389be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                          ('%S', os.path.dirname(sourcepath)),
390be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                          ('%p', os.path.dirname(sourcepath)),
391be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                          ('%t', tmpBase + '.tmp'),
3925110609ceb901f20e1d8b38530e09f9e9017386cDaniel Dunbar                          # FIXME: Remove this once we kill DejaGNU.
3935110609ceb901f20e1d8b38530e09f9e9017386cDaniel Dunbar                          ('%abs_tmp', tmpBase + '.tmp'),
394be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                          ('#_MARKER_#', '%')])
395be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
396be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Collect the test lines from the script.
397be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    script = []
398be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    xfails = []
399be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    xtargets = []
400be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    for ln in open(sourcepath):
401be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        if 'RUN:' in ln:
402be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Isolate the command to run.
403be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            index = ln.index('RUN:')
404be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            ln = ln[index+4:]
405be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
406be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Trim trailing whitespace.
407be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            ln = ln.rstrip()
408be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
409be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Collapse lines with trailing '\\'.
410be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if script and script[-1][-1] == '\\':
411be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                script[-1] = script[-1][:-1] + ln
412be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            else:
413be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                script.append(ln)
41442543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar        elif 'XFAIL:' in ln:
415be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            items = ln[ln.index('XFAIL:') + 6:].split(',')
416be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            xfails.extend([s.strip() for s in items])
417be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        elif 'XTARGET:' in ln:
418be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            items = ln[ln.index('XTARGET:') + 8:].split(',')
419be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            xtargets.extend([s.strip() for s in items])
420be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        elif 'END.' in ln:
421be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            # Check for END. lines.
422be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            if ln[ln.index('END.'):].strip() == 'END.':
423be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar                break
424be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
425be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Apply substitutions to the script.
426be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    def processLine(ln):
427be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Apply substitutions
428be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        for a,b in substitutions:
429be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar            ln = ln.replace(a,b)
430be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
431be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        # Strip the trailing newline and any extra whitespace.
432be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return ln.strip()
433be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    script = map(processLine, script)
434be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
435be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Verify the script contains a run line.
436be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if not script:
437be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.UNRESOLVED, "Test has no run line!")
438be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
439be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if script[-1][-1] == '\\':
440be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.UNRESOLVED, "Test has unterminated run lines (with '\\')")
441be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
44242543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    isXFail = isExpectedFail(xfails, xtargets, test.suite.config.target_triple)
44342543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    return script,isXFail,tmpBase,execdir
444be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
445be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef formatTestOutput(status, out, err, exitCode, script):
446be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    output = StringIO.StringIO()
447be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "Script:"
448be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "--"
449be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, '\n'.join(script)
450be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "--"
451be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "Exit Code: %r" % exitCode
452be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "Command Output (stdout):"
453be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "--"
454be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    output.write(out)
455be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "--"
456be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "Command Output (stderr):"
457be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "--"
458be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    output.write(err)
459be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    print >>output, "--"
460be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return (status, output.getvalue())
461be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
462be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbardef executeTclTest(test, litConfig):
463be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if test.config.unsupported:
464be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.UNSUPPORTED, 'Test is unsupported')
465be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
466ee504b8cd78f5d54e4ae6ed2cfff88a9e8226771Daniel Dunbar    res = parseIntegratedTestScript(test)
467be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if len(res) == 2:
468be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return res
469be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
47042543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    script, isXFail, tmpBase, execdir = res
471be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
472be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if litConfig.noExecute:
473be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.PASS, '')
474be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
475be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Create the output directory if it does not already exist.
476be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    Util.mkdir_p(os.path.dirname(tmpBase))
477be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
478be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    res = executeTclScriptInternal(test, litConfig, tmpBase, script, execdir)
479be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if len(res) == 2:
480be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return res
481be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
482be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out,err,exitCode = res
483be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if isXFail:
484be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        ok = exitCode != 0
485be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        status = (Test.XPASS, Test.XFAIL)[ok]
486be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
487be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        ok = exitCode == 0
488be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        status = (Test.FAIL, Test.PASS)[ok]
489be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
490be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if ok:
491be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (status,'')
492be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
493be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return formatTestOutput(status, out, err, exitCode, script)
494be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
495ee504b8cd78f5d54e4ae6ed2cfff88a9e8226771Daniel Dunbardef executeShTest(test, litConfig, useExternalSh):
496be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if test.config.unsupported:
497be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.UNSUPPORTED, 'Test is unsupported')
498be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
499ee504b8cd78f5d54e4ae6ed2cfff88a9e8226771Daniel Dunbar    res = parseIntegratedTestScript(test)
500be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if len(res) == 2:
501be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return res
502be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
50342543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    script, isXFail, tmpBase, execdir = res
504be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
505be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if litConfig.noExecute:
506be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (Test.PASS, '')
507be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
508be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    # Create the output directory if it does not already exist.
509be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    Util.mkdir_p(os.path.dirname(tmpBase))
510be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
511be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if useExternalSh:
512be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        res = executeScript(test, litConfig, tmpBase, script, execdir)
513be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
514be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        res = executeScriptInternal(test, litConfig, tmpBase, script, execdir)
515be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if len(res) == 2:
516be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return res
517be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
518be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    out,err,exitCode = res
51942543b7b736c9304b4877148943ff8a5fee3c22bDaniel Dunbar    if isXFail:
520be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        ok = exitCode != 0
521be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        status = (Test.XPASS, Test.XFAIL)[ok]
522be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    else:
523be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        ok = exitCode == 0
524be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        status = (Test.FAIL, Test.PASS)[ok]
525be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
526be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    if ok:
527be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar        return (status,'')
528be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar
529be7ada718139b8c840a38ba34c4af492b6a05f9fDaniel Dunbar    return formatTestOutput(status, out, err, exitCode, script)
530