diff --git a/lldb/packages/Python/lldbsuite/test/builders/builder.py b/lldb/packages/Python/lldbsuite/test/builders/builder.py --- a/lldb/packages/Python/lldbsuite/test/builders/builder.py +++ b/lldb/packages/Python/lldbsuite/test/builders/builder.py @@ -78,15 +78,6 @@ return cmdline - def runBuildCommands(self, commands): - try: - lldbtest.system(commands) - except subprocess.CalledProcessError as called_process_error: - # Convert to a build-specific error. - # We don't do that in lldbtest.system() since that - # is more general purpose. - raise build_exception.BuildError(called_process_error) - def getArchSpec(self, architecture): """ Helper function to return the key-value string to specify the architecture @@ -136,11 +127,11 @@ return ["MAKE_DSYM=NO", "MAKE_GMODULES=YES"] return None - def build(self, debug_info, architecture=None, compiler=None, + def getBuildCommands(self, debug_info, architecture=None, compiler=None, dictionary=None, testdir=None, testname=None): debug_info_args = self._getDebugInfoArgs(debug_info) if debug_info_args is None: - return False + return None command_parts = [ self.getMake(testdir, testname), debug_info_args, ["all"], @@ -150,8 +141,7 @@ self.getCmdLine(dictionary)] command = list(itertools.chain(*command_parts)) - self.runBuildCommands([command]) - return True + return [command] def cleanup(self, dictionary=None): """Perform a platform-specific cleanup after the test.""" diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -45,6 +45,7 @@ import re import shutil import signal +import shlex from subprocess import * import sys import time @@ -68,6 +69,7 @@ from lldbsuite.support import encoded_file from lldbsuite.support import funcutils from lldbsuite.test.builders import get_builder +from lldbsuite.test_event import build_exception # See also dotest.parseOptionsAndInitTestdirs(), where the environment variables # LLDB_COMMAND_TRACE is set from '-t' option. @@ -469,61 +471,6 @@ def terminate(self): lldb.remote_platform.Kill(self._pid) -# From 2.7's subprocess.check_output() convenience function. -# Return a tuple (stdoutdata, stderrdata). - - -def system(commands, **kwargs): - r"""Run an os command with arguments and return its output as a byte string. - - If the exit code was non-zero it raises a CalledProcessError. The - CalledProcessError object will have the return code in the returncode - attribute and output in the output attribute. - - The arguments are the same as for the Popen constructor. Example: - - >>> check_output(["ls", "-l", "/dev/null"]) - 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n' - - The stdout argument is not allowed as it is used internally. - To capture standard error in the result, use stderr=STDOUT. - - >>> check_output(["/bin/sh", "-c", - ... "ls -l non_existent_file ; exit 0"], - ... stderr=STDOUT) - 'ls: non_existent_file: No such file or directory\n' - """ - - output = "" - error = "" - for shellCommand in commands: - if 'stdout' in kwargs: - raise ValueError( - 'stdout argument not allowed, it will be overridden.') - process = Popen( - shellCommand, - stdout=PIPE, - stderr=STDOUT, - **kwargs) - pid = process.pid - this_output, this_error = process.communicate() - retcode = process.poll() - - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = shellCommand - cpe = CalledProcessError(retcode, cmd) - # Ensure caller can access the stdout/stderr. - cpe.lldb_extensions = { - "combined_output": this_output, - "command": shellCommand - } - raise cpe - output = output + this_output.decode("utf-8", errors='ignore') - return output - - def getsource_if_available(obj): """ Return the text of the source code for an object if available. Otherwise, @@ -1334,11 +1281,10 @@ Supports: llvm, clang. """ compiler = self.getCompilerBinary() - version_output = system([[compiler, "--version"]]) - for line in version_output.split(os.linesep): - m = re.search('version ([0-9.]+)', line) - if m: - return m.group(1) + version_output = check_output([compiler, "--version"], errors="replace") + m = re.search('version ([0-9.]+)', version_output) + if m: + return m.group(1) return 'unknown' def getDwarfVersion(self): @@ -1465,9 +1411,22 @@ testname = self.getBuildDirBasename() module = builder_module() - if not module.build(debug_info, architecture, compiler, dictionary, - testdir, testname): + commands = builder_module().getBuildCommands(debug_info, architecture, + compiler, dictionary, testdir, testname) + if commands is None: raise Exception("Don't know how to build binary") + + self.runBuildCommands(commands) + + def runBuildCommands(self, commands): + for cmd in commands: + self.trace(shlex.join(cmd)) + try: + output = check_output(cmd, stderr=STDOUT, errors="replace") + except CalledProcessError as cpe: + raise build_exception.BuildError(cpe) + self.trace(output) + # ================================================== # Build methods supported through a plugin interface @@ -1615,7 +1574,7 @@ if not yaml2obj_bin: self.assertTrue(False, "No valid yaml2obj executable specified") command = [yaml2obj_bin, "-o=%s" % obj_path, yaml_path] - system([command]) + self.runBuildCommands([command]) def getBuildFlags( self, diff --git a/lldb/packages/Python/lldbsuite/test_event/build_exception.py b/lldb/packages/Python/lldbsuite/test_event/build_exception.py --- a/lldb/packages/Python/lldbsuite/test_event/build_exception.py +++ b/lldb/packages/Python/lldbsuite/test_event/build_exception.py @@ -1,10 +1,11 @@ +import shlex + class BuildError(Exception): def __init__(self, called_process_error): super(BuildError, self).__init__("Error when building test subject") - self.command = called_process_error.lldb_extensions.get( - "command", "") - self.build_error = called_process_error.lldb_extensions["combined_output"] + self.command = shlex.join(called_process_error.cmd) + self.build_error = called_process_error.output def __str__(self): return self.format_build_error(self.command, self.build_error) @@ -12,4 +13,4 @@ @staticmethod def format_build_error(command, command_output): return "Error when building test subject.\n\nBuild Command:\n{}\n\nBuild Command Output:\n{}".format( - command, command_output.decode("utf-8", errors='ignore')) + command, command_output)