Make SpackCommand a bit more testable

- add fail_on_error argument
- record exception and return code when the command fails
This commit is contained in:
Todd Gamblin 2017-08-14 03:57:46 -07:00
parent e77c1a20c5
commit e0dd55e090

View File

@ -369,13 +369,15 @@ class SpackCommand(object):
Use this to invoke Spack commands directly from Python and check Use this to invoke Spack commands directly from Python and check
their stdout and stderr. their stdout and stderr.
""" """
def __init__(self, command, fail_on_error=True): def __init__(self, command):
"""Create a new SpackCommand that invokes ``command`` when called.""" """Create a new SpackCommand that invokes ``command`` when called."""
self.parser = make_argument_parser() self.parser = make_argument_parser()
self.parser.add_command(command) self.parser.add_command(command)
self.command_name = command self.command_name = command
self.command = spack.cmd.get_command(command) self.command = spack.cmd.get_command(command)
self.fail_on_error = fail_on_error
self.returncode = None
self.error = None
def __call__(self, *argv, **kwargs): def __call__(self, *argv, **kwargs):
"""Invoke this SpackCommand. """Invoke this SpackCommand.
@ -384,17 +386,20 @@ def __call__(self, *argv, **kwargs):
argv (list of str): command line arguments. argv (list of str): command line arguments.
Keyword Args: Keyword Args:
color (optional bool): force-disable or force-enable color fail_on_error (optional bool): Don't raise an exception on error
Returns: Returns:
(str, str): output and error as a strings (str, str): output and error as a strings
On return, if ``fail_on_error`` is False, return value of comman On return, if ``fail_on_error`` is False, return value of comman
is set in ``returncode`` property. Otherwise, raise an error. is set in ``returncode`` property, and the error is set in the
``error`` property. Otherwise, raise an error.
""" """
args, unknown = self.parser.parse_known_args( args, unknown = self.parser.parse_known_args(
[self.command_name] + list(argv)) [self.command_name] + list(argv))
fail_on_error = kwargs.get('fail_on_error', True)
out, err = sys.stdout, sys.stderr out, err = sys.stdout, sys.stderr
ofd, ofn = tempfile.mkstemp() ofd, ofn = tempfile.mkstemp()
efd, efn = tempfile.mkstemp() efd, efn = tempfile.mkstemp()
@ -408,6 +413,11 @@ def __call__(self, *argv, **kwargs):
except SystemExit as e: except SystemExit as e:
self.returncode = e.code self.returncode = e.code
except:
self.error = sys.exc_info()[1]
if fail_on_error:
raise
finally: finally:
sys.stdout.flush() sys.stdout.flush()
sys.stdout.close() sys.stdout.close()
@ -420,7 +430,7 @@ def __call__(self, *argv, **kwargs):
os.unlink(ofn) os.unlink(ofn)
os.unlink(efn) os.unlink(efn)
if self.fail_on_error and self.returncode != 0: if fail_on_error and self.returncode not in (None, 0):
raise SpackCommandError( raise SpackCommandError(
"Command exited with code %d: %s(%s)" % ( "Command exited with code %d: %s(%s)" % (
self.returncode, self.command_name, self.returncode, self.command_name,