def _run_command(args, stdout=_PIPE, stderr=_PIPE, encoding=None, stream=0):
    # regarding the shell argument, see: http://bugs.python.org/issue8557
    try:
        proc = _Popen(args, stdout=stdout, stderr=stderr, shell=(sys.platform == "win32"))

        data = proc.communicate()[stream]
    except OSError:
        return 1, ""

    # doubled checked and
    data = decode_as_string(data, encoding)

    # communciate calls wait()
    return proc.returncode, data
Example #2
0
def _run_command(args, stdout=_PIPE, stderr=_PIPE):
    # regarding the shell argument, see: http://bugs.python.org/issue8557
    try:
        args = [fsdecode(x) for x in args]
        proc = _Popen(args, stdout=stdout, stderr=stderr, shell=(sys.platform == "win32"))

        data = proc.communicate()[0]
    except OSError:
        return 1, ""

    data = consoledecode(data)

    # communciate calls wait()
    return proc.returncode, data
Example #3
0
def run_setup_py(cmd, pypath=None, path=None,
                 data_stream=0, env=None):
    """
    Execution command for tests, separate from those used by the
    code directly to prevent accidental behavior issues
    """
    if env is None:
        env = dict()
        for envname in os.environ:
            env[envname] = os.environ[envname]

    # override the python path if needed
    if pypath is not None:
        env["PYTHONPATH"] = pypath

    # overide the execution path if needed
    if path is not None:
        env["PATH"] = path
    if not env.get("PATH", ""):
        env["PATH"] = _which_dirs("tar").union(_which_dirs("gzip"))
        env["PATH"] = os.pathsep.join(env["PATH"])

    cmd = [sys.executable, "setup.py"] + list(cmd)

    # http://bugs.python.org/issue8557
    shell = sys.platform == 'win32'

    try:
        proc = _Popen(
            cmd, stdout=_PIPE, stderr=_PIPE, shell=shell, env=env,
        )

        data = proc.communicate()[data_stream]
    except OSError:
        return 1, ''

    # decode the console string if needed
    if hasattr(data,  "decode"):
        # use the default encoding
        data = data.decode()
        data = unicodedata.normalize('NFC', data)

    # communciate calls wait()
    return proc.returncode, data
Example #4
0
File: task.py Project: gwk/pithy
def run(cmd, cwd=None, stdin=None, out=None, err=None, env=None, timeout=None, exp=0):
    """
  Run a command and return (exit_code, std_out, std_err).
  Cmd: str or list of str.
  Cwd: str path.
  Stdin: str, bytes, open binary file (including value of dev_null()).
  Out, err: open binary file or _pipe special.
  Env: dict of str.
  Timeout: numeric or None.
  Exp: expected exit code can be None (accept any value), an integer code,
    or `...` (Ellipsis) to indicate any nonzero code.

  The special ellipsis notation is used because a bool expectation is confusing;
  nonzero implies True in Python, but False in Unix.

  The underlying Subprocess shell option is not supported
  because the rules regarding splitting strings are complex.
  User code is made clearer by just specifying the complete shell command;
  lists are used as is, while strings are split by shlex.split.
  """

    if isinstance(cmd, str):
        cmd = _shlex.split(cmd)

    if isinstance(stdin, str):
        f_in = _pipe
        input_bytes = stdin.encode("utf-8")
    elif isinstance(stdin, bytes):
        f_in = _pipe
        input_bytes = stdin
    else:
        f_in = stdin  # presume None, _pipe, or file, which includes dev_null().
        input_bytes = None

    proc = _Popen(cmd, cwd=cwd, stdin=f_in, stdout=out, stderr=err, shell=False, env=env)

    # timeout alarm handler.
    timed_out = False
    if timeout is not None:

        def alarm_handler(signum, current_stack_frame):
            # since signal handlers carry reentrancy concerns, do not do any IO within the handler.
            nonlocal timed_out
            timed_out = True
            proc.kill()

        signal.signal(signal.SIGALRM, alarm_handler)  # set handler.
        signal.alarm(timeout)  # set alarm.

    p_out, p_err = proc.communicate(input_bytes)  # waits for process to complete.

    if timeout is not None:
        signal.alarm(0)  # disable alarm.
        if timed_out:
            raise ProcessTimeout(cmd, timeout)

    code = proc.returncode
    if exp is None:
        pass
    elif exp is Ellipsis:
        if code == 0:
            raise ProcessExpectation(cmd, "!= 0", code)
    else:
        if code != exp:  # otherwise expect exact numeric code.
            raise ProcessExpectation(cmd, exp, code)

    return code, _decode(p_out), _decode(p_err)
Example #5
0
def shell_run(cmd,
              cin=None, cwd=None, timeout=10, critical=True, verbose=True):
    '''
    Runs a shell command within a controlled environment.

    .. note:: |use_photon_m|

    :param cmd: The command to run

        * A string one would type into a console like \
        :command:`git push -u origin master`.

        * Will be split using :py:func:`shlex.split`.

        * It is possible to use a list here, but then no splitting is done.

    :param cin:
        Add something to stdin of `cmd`
    :param cwd:
        Run `cmd` insde specified current working directory
    :param timeout:
        Catch infinite loops (e.g. ``ping``).
        Exit after `timeout` seconds
    :param critical:
        If set to ``True``: |appteardown| on failure of `cmd`
    :param verbose:
        Show messages and warnings
    :returns:
        A dictionary containing the results from
        running `cmd` with the following:

        * 'command': `cmd`

        * 'stdin': `cin` (If data was set in `cin`)

        * 'cwd': `cwd` (If `cwd` was set)

        * 'exception': exception message (If an exception was thrown)

        * 'timeout': `timeout` (If a timeout exception was thrown)

        * 'stdout': List from stdout (If any)

        * 'stderr': List from stderr (If any)

        * 'returncode': The returncode (If not any exception)

        * 'out': The most urgent message as joined string. \
        ('exception' > 'stderr' > 'stdout')
    '''

    res = dict(command=cmd)
    if cin:
        cin = str(cin)
        res.update(dict(stdin=cin))
    if cwd:
        res.update(dict(cwd=cwd))

    if isinstance(cmd, str):
        cmd = _split(cmd)

    try:
        p = _Popen(
            cmd, stdin=_PIPE, stdout=_PIPE, stderr=_PIPE,
            bufsize=1, cwd=cwd, universal_newlines=True
        )
    except Exception as ex:
        res.update(dict(exception=str(ex)))
    else:

        try:
            out, err = p.communicate(input=cin, timeout=timeout)
            if out:
                res.update(dict(
                    stdout=[o for o in out.split('\n') if o]
                ))
            if err:
                res.update(dict(
                    stderr=[e for e in err.split('\n') if e]
                ))
            res.update(dict(returncode=p.returncode))

        except _TimeoutExpired as ex:
            res.update(dict(exception=str(ex), timeout=timeout))
            p.kill()
        except Exception as ex:
            res.update(dict(exception=str(ex)))

    res.update(
        out=(
            res.get('exception') or
            '\n'.join(res.get('stderr') or res.get('stdout', ''))
        )
    )

    if res.get('returncode', -1) != 0:
        res.update(dict(critical=critical))

        shell_notify(
            'error in shell command \'%s\'' % (res.get('command')),
            state=True if critical else None,
            more=res,
            verbose=verbose
        )

    return res
Example #6
0
def verify_python3_env():
    """Ensures that the environment is good for unicode on Python 3."""
    try:
        fs_enc = _codecs.lookup(_locale.getpreferredencoding()).name
    except Exception:
        fs_enc = 'ascii'
    if fs_enc != 'ascii':
        return

    extra = ''
    if _os.name == 'posix':
        rv = _Popen(
            ['locale', '-a'], stdout=_PIPE, stderr=_PIPE).communicate()[0]
        good_locales = set()
        has_c_utf8 = False

        # Make sure we're operating on text here.
        if isinstance(rv, bytes):
            rv = rv.decode('ascii', 'replace')

        for line in rv.splitlines():
            locale = line.strip()
            if locale.lower().endswith(('.utf-8', '.utf8')):
                good_locales.add(locale)
                if locale.lower() in ('c.utf8', 'c.utf-8'):
                    has_c_utf8 = True

        extra += '\n\n'
        if not good_locales:
            extra += (
                'Additional information: on this system no suitable UTF-8\n'
                'locales were discovered.  This most likely requires resolving\n'
                'by reconfiguring the locale system.')
        elif has_c_utf8:
            extra += (
                'This system supports the C.UTF-8 locale which is recommended.\n'
                'You might be able to resolve your issue by exporting the\n'
                'following environment variables:\n\n'
                '    export LC_ALL=C.UTF-8\n'
                '    export LANG=C.UTF-8')
        else:
            extra += (
                'This system lists a couple of UTF-8 supporting locales that\n'
                'you can pick from.  The following suitable locales were\n'
                'discovered: %s') % ', '.join(sorted(good_locales))

        bad_locale = None
        for locale in _os.environ.get('LC_ALL'), _os.environ.get('LANG'):
            if locale and locale.lower().endswith(('.utf-8', '.utf8')):
                bad_locale = locale
            if locale is not None:
                break
        if bad_locale is not None:
            extra += (
                '\n\nnpm2deb discovered that you exported a UTF-8 locale\n'
                'but the locale system could not pick up from it because\n'
                'it does not exist.  The exported locale is "%s" but it\n'
                'is not supported') % bad_locale

    raise RuntimeError('npm2deb will abort further execution because Python 3 '
                       'was configured to use ASCII as encoding for the '
                       'environment.' + extra)