'Run this executable in a subprocess.
Parameters:
*args (str): Command-line arguments to the executable to run
Keyword Arguments:
env (dict): The environment to run the executable with
fail_on_error (bool): Raise an exception if the subprocess returns
an error. Default is True. The return code is available as
``exe.returncode``
ignore_errors (int or list): A list of error codes to ignore.
If these codes are returned, this process will not raise
an exception even if ``fail_on_error`` is set to ``True``
input: Where to read stdin from
output: Where to send stdout
error: Where to send stderr
Accepted values for input, output, and error:
* python streams, e.g. open Python file objects, or ``os.devnull``
* filenames, which will be automatically opened for writing
* ``str``, as in the Python string type. If you set these to ``str``,
output and error will be written to pipes and returned as a string.
If both ``output`` and ``error`` are set to ``str``, then one string
is returned containing output concatenated with error. Not valid
for ``input``
By default, the subprocess inherits the parent\'s file descriptors.'

def __call__(self, *args, **kwargs):

    env_arg = kwargs.get('env', None)
    if (env_arg is None):
        env = os.environ.copy()
        env.update(self.default_env)
    else:
        env = self.default_env.copy()
        env.update(env_arg)
    fail_on_error = kwargs.pop('fail_on_error', True)
    ignore_errors = kwargs.pop('ignore_errors', ())
    if isinstance(ignore_errors, int):
        ignore_errors = (ignore_errors,)
    input = kwargs.pop('input', None)
    output = kwargs.pop('output', None)
    error = kwargs.pop('error', None)
    if (input is str):
        raise ValueError('Cannot    use    `str`    as    input    stream.')
    def streamify(arg, mode):
        if isinstance(arg, string_types):
            return (open(arg, mode), True)
        elif (arg is str):
            return (subprocess.PIPE, False)
        else:
            return (arg, False)
    (ostream, close_ostream) = streamify(output, 'w')
    (estream, close_estream) = streamify(error, 'w')
    (istream, close_istream) = streamify(input, 'r')
    quoted_args = [arg for arg in args if re.search('^"|^\\\'|"$|\\\'$', arg)]
    if quoted_args:
        tty.warn('Quotes    in    command    arguments    can    confuse    scripts    like    configure.', 'The    following    arguments    may    cause    problems    when    executed:', str('\n'.join([('                ' + arg) for arg in quoted_args])), "Quotes    aren't    needed    because    spack    doesn't    use    a    shell.", 'Consider    removing    them')
    cmd = (self.exe + list(args))
    cmd_line = ("'%s'" % "'    '".join(map((lambda arg: arg.replace("'", '\'"\'"\'')), cmd)))
    tty.debug(cmd_line)
    try:
        proc = subprocess.Popen(cmd, stdin=istream, stderr=estream, stdout=ostream, env=env)
        (out, err) = proc.communicate()
        rc = self.returncode = proc.returncode
        if (fail_on_error and (rc != 0) and (rc not in ignore_errors)):
            raise ProcessError(('Command    exited    with    status    %d:' % proc.returncode), cmd_line)
        if ((output is str) or (error is str)):
            result = ''
            if (output is str):
                result += out.decode('utf-8')
            if (error is str):
                result += err.decode('utf-8')
            return result
    except OSError as e:
        raise ProcessError(('%s:    %s' % (self.exe[0], e.strerror)), ('Command:    ' + cmd_line))
    except subprocess.CalledProcessError as e:
        if fail_on_error:
            raise ProcessError(str(e), ('\nExit    status    %d    when    invoking    command:    %s' % (proc.returncode, cmd_line)))
    finally:
        if close_ostream:
            ostream.close()
        if close_estream:
            estream.close()
        if close_istream:
            istream.close()
