Run a shell command and wait for the response. The result object will
    resolve to True if result.code == 0 and output/error results can be
    retrieved from result.stdout and result.stderr variables.

      >>> result = run('echo ${content}', content='Some $%^$## "" + \' content')
      >>> result.code
      0
      >>> if result:
      ...     print('Stdout: %s' % result.stdout)
      ... else:
      ...     print('Stderr: %s' % result.stderr)
      Stdout: Some $%^$## "" + ' content
      >>> print(result.command)
      echo 'Some $%^$## "" + '"'"' content'

def run(command, **kwargs):
    """Run a shell command and wait for the response. The result object will
    resolve to True if result.code == 0 and output/error results can be
    retrieved from result.stdout and result.stderr variables.

      >>> result = run('echo ${content}', content='Some $%^$## "" + \' content')
      >>> result.code
      0
      >>> if result:
      ...     print('Stdout: %s' % result.stdout)
      ... else:
      ...     print('Stderr: %s' % result.stderr)
      Stdout: Some $%^$## "" + ' content
      >>> print(result.command)
      echo 'Some $%^$## "" + '"'"' content'
    """
    env = None
    if 'env' in kwargs:
        if kwargs.get('env_empty'):
            env = {}
        else:
            env = copy.deepcopy(os.environ)
        env.update(kwargs['env'])
    stdin = kwargs.get('stdin')
    stdout = kwargs.get('stdout', False)
    stderr = kwargs.get('stderr', False)
    combine = kwargs.get('combine', False)
    if stdout is True:
        stdout = sys.stdout.write
    if stderr is True:
        stderr = sys.stderr.write
    if kwargs:
        args = {}
        q = pipes.quote
        for name, value in kwargs.items():
            if isinstance(value, basestring_type):
                args[name] = q(value)
            elif isinstance(value, (list, tuple)):
                args[name] = u' '.join([q(unicode_type(v)) for v in value])
            elif isinstance(value, dict):
                args[name] = u' '.join([u'%s %s' % (q(n), q(v)) for n, v in value.items()])
            else:
                args[name] = pipes.quote(unicode_type(value))
        command = string.Template(command).safe_substitute(args)
    log.debug('run: %s' % command)
    ref = subprocess.Popen(
        command,
        stdin=None if stdin is None else subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT if combine is True else subprocess.PIPE,
        shell=kwargs.get('shell', True),
        close_fds=kwargs.get('close_fds', True),
        env=env,
        cwd=kwargs.get('cwd', tempfile.gettempdir()),
    )
    if stdin is not None:
        if not isinstance(stdin, basestring_type):
            stdin = unicode_type(stdin)
        if not isinstance(stdin, bytes_type):
            stdin = stdin.encode('utf-8')
        ref.stdin.write(stdin)
        ref.stdin.flush()
        ref.stdin.close()
    fds = [ref.stdout]
    if combine is not True:
        fds.append(ref.stderr)
    stdout_result = b''
    stderr_result = b''
    while fds:
        for fd in select.select(fds, tuple(), tuple())[0]:
            line = fd.readline()
            if line:
                if fd == ref.stdout:
                    if stdout:
                        stdout(line)
                    stdout_result += line
                elif fd == ref.stderr:
                    if stderr:
                        stderr(line)
                    stderr_result += line
            else:
                fds.remove(fd)
    ref.wait()
    return obj({
        'code': ref.returncode,
        'command': command,
        'stdout': stdout_result,
        'stderr': stderr_result,
    }, bool=ref.returncode == 0, grow=False)