def _RunProcess(cmd, stdinput=None, env=None, cwd=None, sudo=False,
                sudo_password=None, background=False, stream_output=False,
                timeout=0, waitfor=0):
  """Executes cmd using suprocess.

  Args:
    cmd: An array of strings as the command to run
    stdinput: An optional sting as stdin
    env: An optional dictionary as the environment
    cwd: An optional string as the current working directory
    sudo: An optional boolean on whether to do the command via sudo
    sudo_password: An optional string of the password to use for sudo
    background: Launch command in background mode
    stream_output: An optional boolean on whether to send output to the screen
    timeout: An optional int or float; if >0, Exec() will stop waiting for
      output after timeout seconds and kill the process it started. Return code
      might be undefined, or -SIGTERM, use waitfor to make sure to obtain it.
      values <1 will be crudely rounded off because of select() sleep time.
    waitfor: An optional int or float, if >0, Exec() will wait waitfor seconds
      before asking for the process exit status one more time.
  Returns:
    Tuple: two strings and an integer: (stdout, stderr, returncode);
    stdout/stderr may also be None. If the process is set to launch in
    background mode, a tuple of (<subprocess.Popen object>, None, None) is
    returned, in order to be able to read from its pipes *and* use poll() to
    check when it is finished
  Raises:
    GmacpyutilException: If both stdinput and sudo_password are specified
    GmacpyutilException: If both sudo and background are specified
    GmacpyutilException: If both timeout and background, stream_output, sudo, or
      sudo_password, or stdinput are specified
    GmacpyutilException: If timeout is less than 0
    GmacpyutilException: If subprocess raises an OSError
  """
  if timeout and (background or stream_output or sudo or sudo_password or
                  stdinput):
    raise GmacpyutilException('timeout is not compatible with background, '
                              'stream_output, sudo, sudo_password, or '
                              'stdinput.')
  if waitfor and not timeout:
    raise GmacpyutilException('waitfor only valid with timeout.')
  if timeout < 0:
    raise GmacpyutilException('timeout must be greater than 0.')
  if stream_output:
    stdoutput = None
    stderror = None
  else:
    stdoutput = subprocess.PIPE
    stderror = subprocess.PIPE
  if sudo and not background:
    sudo_cmd = ['sudo']
    if sudo_password and not stdinput:
      # Set sudo to get password from stdin
      sudo_cmd.extend(['-S'])
      stdinput = sudo_password + '\n'
    elif sudo_password and stdinput:
      raise GmacpyutilException('stdinput and sudo_password are mutually '
                                'exclusive')
    else:
      sudo_cmd.extend(['-p', "%u's password is required for admin access: "])
    sudo_cmd.extend(cmd)
    cmd = sudo_cmd
  elif sudo and background:
    raise GmacpyutilException('sudo is not compatible with background.')
  environment = os.environ.copy()
  if env is not None:
    environment.update(env)
  try:
    task = subprocess.Popen(cmd, stdout=stdoutput, stderr=stderror,
                            stdin=subprocess.PIPE, env=environment, cwd=cwd)
  except __HOLE__, e:
    raise GmacpyutilException('Could not execute: %s' % e.strerror)
  if timeout == 0:
    # communicate() will wait until the process is finished, so if we are in
    # background mode, just send the input and take the pipe objects as output.
    if not background:
      (stdout, stderr) = task.communicate(input=stdinput)
      return (stdout, stderr, task.returncode)
    else:
      if stdinput:
        task.stdin.write(stdinput)
      return task
  else:
    # TODO(user): See if it's possible to pass stdinput when using a timeout
    inactive = 0
    stdoutput = []
    stderror = []
    SetFileNonBlocking(task.stdout)
    SetFileNonBlocking(task.stderr)
    returncode = None
    while returncode is None:
      rlist, _, _ = select.select([task.stdout, task.stderr], [], [], 1.0)
      if not rlist:
        inactive += 1
        if inactive >= timeout:
          logging.error('cmd has timed out: %s', cmd)
          logging.error('Sending SIGTERM to PID=%s', task.pid)
          os.kill(task.pid, signal.SIGTERM)
          break  # note: this is a hard timeout, we don't read() again
      else:
        inactive = 0
        for fd in rlist:
          if fd is task.stdout:
            stdoutput.append(fd.read())
          elif fd is task.stderr:
            stderror.append(fd.read())

      returncode = task.poll()

    # if the process was just killed, wait for waitfor seconds.
    if inactive >= timeout and waitfor > 0:
      time.sleep(waitfor)
    # attempt to obtain returncode one last chance
    returncode = task.poll()
    stdoutput = ''.join(stdoutput)
    stderror = ''.join(stderror)
    return (stdoutput, stderror, task.returncode)
dataset/ETHPy150Open google/macops/gmacpyutil/gmacpyutil/gmacpyutil.py/_RunProcess