annotate vendor/symfony/process/Pipes/AbstractPipes.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
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@17 23 public $pipes = [];
Chris@0 24
Chris@0 25 private $inputBuffer = '';
Chris@0 26 private $input;
Chris@0 27 private $blocked = true;
Chris@16 28 private $lastError;
Chris@0 29
Chris@14 30 /**
Chris@14 31 * @param resource|string|int|float|bool|\Iterator|null $input
Chris@14 32 */
Chris@0 33 public function __construct($input)
Chris@0 34 {
Chris@17 35 if (\is_resource($input) || $input instanceof \Iterator) {
Chris@0 36 $this->input = $input;
Chris@17 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@17 52 $this->pipes = [];
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@16 62 $lastError = $this->lastError;
Chris@16 63 $this->lastError = null;
Chris@0 64
Chris@0 65 // stream_select returns false when the `select` system call is interrupted by an incoming signal
Chris@16 66 return null !== $lastError && false !== stripos($lastError, 'interrupted system call');
Chris@0 67 }
Chris@0 68
Chris@0 69 /**
Chris@0 70 * Unblocks streams.
Chris@0 71 */
Chris@0 72 protected function unblock()
Chris@0 73 {
Chris@0 74 if (!$this->blocked) {
Chris@0 75 return;
Chris@0 76 }
Chris@0 77
Chris@0 78 foreach ($this->pipes as $pipe) {
Chris@0 79 stream_set_blocking($pipe, 0);
Chris@0 80 }
Chris@17 81 if (\is_resource($this->input)) {
Chris@0 82 stream_set_blocking($this->input, 0);
Chris@0 83 }
Chris@0 84
Chris@0 85 $this->blocked = false;
Chris@0 86 }
Chris@0 87
Chris@0 88 /**
Chris@0 89 * Writes input to stdin.
Chris@0 90 *
Chris@0 91 * @throws InvalidArgumentException When an input iterator yields a non supported value
Chris@0 92 */
Chris@0 93 protected function write()
Chris@0 94 {
Chris@0 95 if (!isset($this->pipes[0])) {
Chris@0 96 return;
Chris@0 97 }
Chris@0 98 $input = $this->input;
Chris@0 99
Chris@0 100 if ($input instanceof \Iterator) {
Chris@0 101 if (!$input->valid()) {
Chris@0 102 $input = null;
Chris@17 103 } elseif (\is_resource($input = $input->current())) {
Chris@0 104 stream_set_blocking($input, 0);
Chris@0 105 } elseif (!isset($this->inputBuffer[0])) {
Chris@17 106 if (!\is_string($input)) {
Chris@0 107 if (!is_scalar($input)) {
Chris@17 108 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 109 }
Chris@0 110 $input = (string) $input;
Chris@0 111 }
Chris@0 112 $this->inputBuffer = $input;
Chris@0 113 $this->input->next();
Chris@0 114 $input = null;
Chris@0 115 } else {
Chris@0 116 $input = null;
Chris@0 117 }
Chris@0 118 }
Chris@0 119
Chris@17 120 $r = $e = [];
Chris@17 121 $w = [$this->pipes[0]];
Chris@0 122
Chris@0 123 // let's have a look if something changed in streams
Chris@14 124 if (false === @stream_select($r, $w, $e, 0, 0)) {
Chris@0 125 return;
Chris@0 126 }
Chris@0 127
Chris@0 128 foreach ($w as $stdin) {
Chris@0 129 if (isset($this->inputBuffer[0])) {
Chris@0 130 $written = fwrite($stdin, $this->inputBuffer);
Chris@0 131 $this->inputBuffer = substr($this->inputBuffer, $written);
Chris@0 132 if (isset($this->inputBuffer[0])) {
Chris@17 133 return [$this->pipes[0]];
Chris@0 134 }
Chris@0 135 }
Chris@0 136
Chris@0 137 if ($input) {
Chris@0 138 for (;;) {
Chris@0 139 $data = fread($input, self::CHUNK_SIZE);
Chris@0 140 if (!isset($data[0])) {
Chris@0 141 break;
Chris@0 142 }
Chris@0 143 $written = fwrite($stdin, $data);
Chris@0 144 $data = substr($data, $written);
Chris@0 145 if (isset($data[0])) {
Chris@0 146 $this->inputBuffer = $data;
Chris@0 147
Chris@17 148 return [$this->pipes[0]];
Chris@0 149 }
Chris@0 150 }
Chris@0 151 if (feof($input)) {
Chris@0 152 if ($this->input instanceof \Iterator) {
Chris@0 153 $this->input->next();
Chris@0 154 } else {
Chris@0 155 $this->input = null;
Chris@0 156 }
Chris@0 157 }
Chris@0 158 }
Chris@0 159 }
Chris@0 160
Chris@0 161 // no input to read on resource, buffer is empty
Chris@0 162 if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) {
Chris@0 163 $this->input = null;
Chris@0 164 fclose($this->pipes[0]);
Chris@0 165 unset($this->pipes[0]);
Chris@0 166 } elseif (!$w) {
Chris@17 167 return [$this->pipes[0]];
Chris@0 168 }
Chris@0 169 }
Chris@16 170
Chris@16 171 /**
Chris@16 172 * @internal
Chris@16 173 */
Chris@16 174 public function handleError($type, $msg)
Chris@16 175 {
Chris@16 176 $this->lastError = $msg;
Chris@16 177 }
Chris@0 178 }