Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
rt-framework / rt / lexec.py
Size: Mime:
#
# Copyright (C) 2016 Rolf Neugebauer <rolf.neugebauer@docker.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#

"""Execute a command and re-direct stdout/stderr to a log"""

import os
import subprocess
import threading
import time

import rt.local
import rt.log

_WIN_BASH = None


def _get_win_bash():
    """On Windows, we can't use the WSL bash.exe which may be in the
    path before the MSYS bash.exe. This function tries to find
    the right bash.exe and stashes the result in _WIN_BASH"""
    global _WIN_BASH
    if _WIN_BASH:
        return _WIN_BASH

    for p in os.environ["PATH"].split(';'):
        if os.path.isfile(os.path.join(p, "bash.exe")):
            if "system32" not in p:
                _WIN_BASH = os.path.join(p, "bash.exe")
    if not _WIN_BASH:
        _WIN_BASH = "bash.exe"
    return _WIN_BASH


def _run(cmd, cwd=None, env=None):
    """Run a command and return the return code"""

    rt.log.logger.debug("Executing: %s in %s" % (cmd, cwd))

    # exec the command
    p = subprocess.Popen(cmd, cwd=cwd, env=env,
                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    def log(stream, cb):
        """Executed by a Thread to log either stdout or stderr to log"""
        while True:
            out = stream.readline()
            if out:
                cb(out.rstrip())
            else:
                break
        return

    logger = rt.log.logger

    # kick off a thread per output stream
    out_thd = threading.Thread(
        target=log,
        args=(p.stdout, lambda s: logger.log(rt.log.LOG_LVL_STDOUT, s)))
    err_thd = threading.Thread(
        target=log,
        args=(p.stderr, lambda s: logger.log(rt.log.LOG_LVL_STDERR, s)))

    # kick the threads
    out_thd.start()
    err_thd.start()

    # wait till they terminate
    out_thd.join()
    err_thd.join()

    # wait for process to terminate (it should have) and return code
    while p.poll() is None:
        time.sleep(0.5)
    return p.returncode


def shexec(script, args=[], cwd=None, name=None, labels=[]):
    """Execute a shell script in directory. args is a list of arguments"""

    # Add RT environment variables
    env = os.environ
    env["RT_ROOT"] = rt.local.ENV_RT_ROOT
    env["RT_UTILS"] = rt.local.ENV_RT_UTILS
    env["RT_PROJECT_ROOT"] = rt.local.ENV_RT_PROJECT_ROOT
    env["RT_OS"] = rt.local.ENV_RT_OS
    env["RT_OS_VER"] = rt.local.ENV_RT_OS_VER
    env["RT_LABELS"] = ":".join(labels)
    env["RT_TEST_NAME"] = name if name else "UNKNOWN"
    env["RT_LIB"] = rt.local.ENV_RT_LIB

    for k in rt.local.ENV_VARS:
        env[k] = rt.local.ENV_VARS[k]

    if rt.log.ENV_RT_RESULTS:
        env["RT_RESULTS"] = rt.log.ENV_RT_RESULTS

    if os.name == 'nt':
        # On Windows execute bash.exe with the command as argument
        cmd = [_get_win_bash()]
        env["MSYS_NO_PATHCONV"] = "1"
    else:
        cmd = ['/bin/sh']

    if rt.local.ENV_EXTRA_DEBUG:
        cmd.append('-x')

    cmd.append(script)
    cmd.extend(args)

    return _run(cmd, cwd, env)