Executables can optionally ignore error output.

This commit is contained in:
Todd Gamblin 2014-06-22 12:25:53 -07:00
parent ae31838193
commit f1bc65c132

View file

@ -22,7 +22,7 @@
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
############################################################################## ##############################################################################
__all__ = ['Executable', 'when'] __all__ = ['Executable', 'which', 'ProcessError']
import os import os
import sys import sys
@ -30,7 +30,7 @@
import subprocess import subprocess
import llnl.util.tty as tty import llnl.util.tty as tty
from spack.error import SpackError import spack.error
class Executable(object): class Executable(object):
"""Class representing a program that can be run on the command line.""" """Class representing a program that can be run on the command line."""
@ -52,6 +52,7 @@ def __call__(self, *args, **kwargs):
"""Run the executable with subprocess.check_output, return output.""" """Run the executable with subprocess.check_output, return output."""
return_output = kwargs.get("return_output", False) return_output = kwargs.get("return_output", False)
fail_on_error = kwargs.get("fail_on_error", True) fail_on_error = kwargs.get("fail_on_error", True)
error = kwargs.get("error", sys.stderr)
quoted_args = [arg for arg in args if re.search(r'^"|^\'|"$|\'$', arg)] quoted_args = [arg for arg in args if re.search(r'^"|^\'|"$|\'$', arg)]
if quoted_args: if quoted_args:
@ -64,22 +65,34 @@ def __call__(self, *args, **kwargs):
cmd = self.exe + list(args) cmd = self.exe + list(args)
tty.debug(" ".join(cmd)) tty.debug(" ".join(cmd))
close_error = False
try: try:
if error is None:
error = open(os.devnull, 'w')
close_error = True
proc = subprocess.Popen( proc = subprocess.Popen(
cmd, cmd,
stderr=sys.stderr, stderr=error,
stdout=subprocess.PIPE if return_output else sys.stdout) stdout=subprocess.PIPE if return_output else sys.stdout)
out, err = proc.communicate() out, err = proc.communicate()
self.returncode = proc.returncode self.returncode = proc.returncode
if fail_on_error and proc.returncode != 0: if fail_on_error and proc.returncode != 0:
raise SpackError("command '%s' returned error code %d" raise ProcessError("command '%s' returned error code %d"
% (" ".join(cmd), proc.returncode)) % (" ".join(cmd), proc.returncode))
if return_output: if return_output:
return out return out
except subprocess.CalledProcessError, e: except subprocess.CalledProcessError, e:
if fail_on_error: raise if fail_on_error:
raise ProcessError(
"command '%s' failed to run." % (
" ".join(cmd), proc.returncode), str(e))
finally:
if close_error:
error.close()
def __eq__(self, other): def __eq__(self, other):
@ -114,3 +127,8 @@ def which(name, **kwargs):
if required: if required:
tty.die("spack requires %s. Make sure it is in your path." % name) tty.die("spack requires %s. Make sure it is in your path." % name)
return None return None
class ProcessError(spack.error.SpackError):
def __init__(self, msg, *long_msg):
super(ProcessError, self).__init__(msg, *long_msg)