Understanding Sismo Processes Part I

Update: By the comments from @stof I made exit($return_var) and system(…,$return_var) takes a second argument as shown. So it works now like it should have been. Thanks!

What am I trying to do? Yes I am trying to understand this process method with which sismo personal ci runs my behat tests. The issue here is because I am running a script and not a simple command the process seems to end simply in a green result whereas I could still have some steps failing while on behat but sismo would not want to color my commit with red.

So that said we give credits for the code below to SensioLabs. How then are we going to change this method to allow for our examination of behat results? passing or failing?

The problem:

  /**
   * Runs the process.
   *
   * The callback receives the type of output (out or err) and
   * some bytes from the output in real-time. It allows to have feedback
   * from the independent process during execution.
   *
   * The STDOUT and STDERR are also available after the process is finished
   * via the getOutput() and getErrorOutput() methods.
   *
   * @param Closure|string|array $callback A PHP callback to run whenever there is some
   *                                       output available on STDOUT or STDERR
   *
   * @return integer The exit status code
   *
   * @throws \RuntimeException When process can't be launch or is stopped
   *
   * @api
   */

So right from here we see there could be potential hooks from where we can insert our telling the system when it is an error or when it is a passing test/description/etc.

    public function run($callback = null)
    {
        $this->stdout = '';
        $this->stderr = '';
        $that = $this;
        $callback = function ($type, $data) use ($that, $callback)
        {
            if ('out' == $type) {
                $that->addOutput($data);
            } else {
                $that->addErrorOutput($data);
            }
 
            if (null !== $callback) {
                call_user_func($callback, $type, $data);
            }
        };
 
        $descriptors = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w'));
 
        $process = proc_open($this->commandline, $descriptors, $pipes, $this->cwd, $this->env, $this->options);
 
        if (!is_resource($process)) {
            throw new \RuntimeException('Unable to launch a new process.');
        }
 
        foreach ($pipes as $pipe) {
            stream_set_blocking($pipe, false);
        }
 
        if (null === $this->stdin) {
            fclose($pipes[0]);
            $writePipes = null;
        } else {
            $writePipes = array($pipes[0]);
            $stdinLen = strlen($this->stdin);
            $stdinOffset = 0;
        }
        unset($pipes[0]);
 
        while ($pipes || $writePipes) {
            $r = $pipes;
            $w = $writePipes;
            $e = null;
 
            $n = @stream_select($r, $w, $e, $this->timeout);
 
            if (false === $n) {
                break;
            } elseif ($n === 0) {
                proc_terminate($process);
 
                throw new \RuntimeException('The process timed out.');
            }
 
            if ($w) {
                $written = fwrite($writePipes[0], (binary) substr($this->stdin, $stdinOffset), 8192);
                if (false !== $written) {
                    $stdinOffset += $written;
                }
                if ($stdinOffset >= $stdinLen) {
                    fclose($writePipes[0]);
                    $writePipes = null;
                }
            }
 
            foreach ($r as $pipe) {
                $type = array_search($pipe, $pipes);
                $data = fread($pipe, 8192);
                if (strlen($data) > 0) {
                    call_user_func($callback, $type == 1 ? 'out' : 'err', $data);
                }
                if (false === $data || feof($pipe)) {
                    fclose($pipe);
                    unset($pipes[$type]);
                }
            }
        }
 
        $this->status = proc_get_status($process);
 
        $time = 0;
        while (1 == $this->status['running'] && $time < 1000000) {
            $time += 1000;
            usleep(1000);
            $this->status = proc_get_status($process);
        }
 
        $exitcode = proc_close($process);
 
        if ($this->status['signaled']) {
            throw new \RuntimeException(sprintf('The process stopped because of a "%s" signal.', $this->status['stopsig']));
        }
 
        return $this->exitcode = $this->status['running'] ? $exitcode : $this->status['exitcode'];
    }

Leave a Reply

Your email address will not be published. Required fields are marked *