annotate vendor/symfony/process/Pipes/AbstractPipes.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\Process\Pipes;
Chris@0 13
Chris@0 14 use Symfony\Component\Process\Exception\InvalidArgumentException;
Chris@0 15
Chris@0 16 /**
Chris@0 17 * @author Romain Neutron <imprec@gmail.com>
Chris@0 18 *
Chris@0 19 * @internal
Chris@0 20 */
Chris@0 21 abstract class AbstractPipes implements PipesInterface
Chris@0 22 {
Chris@0 23 /** @var array */
Chris@0 24 public $pipes = array();
Chris@0 25
Chris@0 26 /** @var string */
Chris@0 27 private $inputBuffer = '';
Chris@0 28 /** @var resource|scalar|\Iterator|null */
Chris@0 29 private $input;
Chris@0 30 /** @var bool */
Chris@0 31 private $blocked = true;
Chris@0 32
Chris@0 33 public function __construct($input)
Chris@0 34 {
Chris@0 35 if (is_resource($input) || $input instanceof \Iterator) {
Chris@0 36 $this->input = $input;
Chris@0 37 } elseif (is_string($input)) {
Chris@0 38 $this->inputBuffer = $input;
Chris@0 39 } else {
Chris@0 40 $this->inputBuffer = (string) $input;
Chris@0 41 }
Chris@0 42 }
Chris@0 43
Chris@0 44 /**
Chris@0 45 * {@inheritdoc}
Chris@0 46 */
Chris@0 47 public function close()
Chris@0 48 {
Chris@0 49 foreach ($this->pipes as $pipe) {
Chris@0 50 fclose($pipe);
Chris@0 51 }
Chris@0 52 $this->pipes = array();
Chris@0 53 }
Chris@0 54
Chris@0 55 /**
Chris@0 56 * Returns true if a system call has been interrupted.
Chris@0 57 *
Chris@0 58 * @return bool
Chris@0 59 */
Chris@0 60 protected function hasSystemCallBeenInterrupted()
Chris@0 61 {
Chris@0 62 $lastError = error_get_last();
Chris@0 63
Chris@0 64 // stream_select returns false when the `select` system call is interrupted by an incoming signal
Chris@0 65 return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call');
Chris@0 66 }
Chris@0 67
Chris@0 68 /**
Chris@0 69 * Unblocks streams.
Chris@0 70 */
Chris@0 71 protected function unblock()
Chris@0 72 {
Chris@0 73 if (!$this->blocked) {
Chris@0 74 return;
Chris@0 75 }
Chris@0 76
Chris@0 77 foreach ($this->pipes as $pipe) {
Chris@0 78 stream_set_blocking($pipe, 0);
Chris@0 79 }
Chris@0 80 if (is_resource($this->input)) {
Chris@0 81 stream_set_blocking($this->input, 0);
Chris@0 82 }
Chris@0 83
Chris@0 84 $this->blocked = false;
Chris@0 85 }
Chris@0 86
Chris@0 87 /**
Chris@0 88 * Writes input to stdin.
Chris@0 89 *
Chris@0 90 * @throws InvalidArgumentException When an input iterator yields a non supported value
Chris@0 91 */
Chris@0 92 protected function write()
Chris@0 93 {
Chris@0 94 if (!isset($this->pipes[0])) {
Chris@0 95 return;
Chris@0 96 }
Chris@0 97 $input = $this->input;
Chris@0 98
Chris@0 99 if ($input instanceof \Iterator) {
Chris@0 100 if (!$input->valid()) {
Chris@0 101 $input = null;
Chris@0 102 } elseif (is_resource($input = $input->current())) {
Chris@0 103 stream_set_blocking($input, 0);
Chris@0 104 } elseif (!isset($this->inputBuffer[0])) {
Chris@0 105 if (!is_string($input)) {
Chris@0 106 if (!is_scalar($input)) {
Chris@0 107 throw new InvalidArgumentException(sprintf('%s yielded a value of type "%s", but only scalars and stream resources are supported', get_class($this->input), gettype($input)));
Chris@0 108 }
Chris@0 109 $input = (string) $input;
Chris@0 110 }
Chris@0 111 $this->inputBuffer = $input;
Chris@0 112 $this->input->next();
Chris@0 113 $input = null;
Chris@0 114 } else {
Chris@0 115 $input = null;
Chris@0 116 }
Chris@0 117 }
Chris@0 118
Chris@0 119 $r = $e = array();
Chris@0 120 $w = array($this->pipes[0]);
Chris@0 121
Chris@0 122 // let's have a look if something changed in streams
Chris@0 123 if (false === $n = @stream_select($r, $w, $e, 0, 0)) {
Chris@0 124 return;
Chris@0 125 }
Chris@0 126
Chris@0 127 foreach ($w as $stdin) {
Chris@0 128 if (isset($this->inputBuffer[0])) {
Chris@0 129 $written = fwrite($stdin, $this->inputBuffer);
Chris@0 130 $this->inputBuffer = substr($this->inputBuffer, $written);
Chris@0 131 if (isset($this->inputBuffer[0])) {
Chris@0 132 return array($this->pipes[0]);
Chris@0 133 }
Chris@0 134 }
Chris@0 135
Chris@0 136 if ($input) {
Chris@0 137 for (;;) {
Chris@0 138 $data = fread($input, self::CHUNK_SIZE);
Chris@0 139 if (!isset($data[0])) {
Chris@0 140 break;
Chris@0 141 }
Chris@0 142 $written = fwrite($stdin, $data);
Chris@0 143 $data = substr($data, $written);
Chris@0 144 if (isset($data[0])) {
Chris@0 145 $this->inputBuffer = $data;
Chris@0 146
Chris@0 147 return array($this->pipes[0]);
Chris@0 148 }
Chris@0 149 }
Chris@0 150 if (feof($input)) {
Chris@0 151 if ($this->input instanceof \Iterator) {
Chris@0 152 $this->input->next();
Chris@0 153 } else {
Chris@0 154 $this->input = null;
Chris@0 155 }
Chris@0 156 }
Chris@0 157 }
Chris@0 158 }
Chris@0 159
Chris@0 160 // no input to read on resource, buffer is empty
Chris@0 161 if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) {
Chris@0 162 $this->input = null;
Chris@0 163 fclose($this->pipes[0]);
Chris@0 164 unset($this->pipes[0]);
Chris@0 165 } elseif (!$w) {
Chris@0 166 return array($this->pipes[0]);
Chris@0 167 }
Chris@0 168 }
Chris@0 169 }