Updated Rector to commit 91f9f3057c2d51018228ed89273a76da991d3f45

91f9f3057c Use symfony/console ~6.3.9 to fix downgrade build (#5302)
This commit is contained in:
Tomas Votruba 2023-11-30 10:06:33 +00:00
parent f8dc5ef396
commit 35f86a2fad
33 changed files with 595 additions and 103 deletions

View File

@ -7,6 +7,8 @@ use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\BinaryOp\BooleanAnd;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Break_;
use PhpParser\Node\Stmt\ClassMethod;
@ -128,6 +130,9 @@ CODE_SAMPLE
continue;
}
$nextStmt = $stmts[$key + 1] ?? null;
if ($this->isComplexReturn($nextStmt)) {
return null;
}
if ($this->shouldSkip($stmt, $nextStmt)) {
$newStmts[] = $stmt;
continue;
@ -222,4 +227,17 @@ CODE_SAMPLE
}
return $nextStmt instanceof Return_;
}
private function isComplexReturn(?Stmt $stmt) : bool
{
if (!$stmt instanceof Return_) {
return \false;
}
if (!$stmt->expr instanceof Expr) {
return \false;
}
if ($stmt->expr instanceof ConstFetch) {
return \false;
}
return !$stmt->expr instanceof Scalar;
}
}

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = '84bcfebdf7e9f522c8f9f9e97814c82d3d5d3315';
public const PACKAGE_VERSION = '91f9f3057c2d51018228ed89273a76da991d3f45';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2023-11-28 21:17:42';
public const RELEASE_DATE = '2023-11-30 17:03:56';
/**
* @var int
*/

2
vendor/autoload.php vendored
View File

@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInita55c41c7fa52abd86138c6f32df1d185::getLoader();
return ComposerAutoloaderInit6ee5b17c87a6bea7c9006b4ba8060b02::getLoader();

View File

@ -893,11 +893,16 @@ return array(
'RectorPrefix202311\\Symfony\\Component\\Process\\Exception\\ProcessFailedException' => $vendorDir . '/symfony/process/Exception/ProcessFailedException.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => $vendorDir . '/symfony/process/Exception/ProcessSignaledException.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => $vendorDir . '/symfony/process/Exception/ProcessTimedOutException.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Exception\\RunProcessFailedException' => $vendorDir . '/symfony/process/Exception/RunProcessFailedException.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Exception\\RuntimeException' => $vendorDir . '/symfony/process/Exception/RuntimeException.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\ExecutableFinder' => $vendorDir . '/symfony/process/ExecutableFinder.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\InputStream' => $vendorDir . '/symfony/process/InputStream.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Messenger\\RunProcessContext' => $vendorDir . '/symfony/process/Messenger/RunProcessContext.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Messenger\\RunProcessMessage' => $vendorDir . '/symfony/process/Messenger/RunProcessMessage.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Messenger\\RunProcessMessageHandler' => $vendorDir . '/symfony/process/Messenger/RunProcessMessageHandler.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\PhpExecutableFinder' => $vendorDir . '/symfony/process/PhpExecutableFinder.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\PhpProcess' => $vendorDir . '/symfony/process/PhpProcess.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\PhpSubprocess' => $vendorDir . '/symfony/process/PhpSubprocess.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Pipes\\AbstractPipes' => $vendorDir . '/symfony/process/Pipes/AbstractPipes.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Pipes\\PipesInterface' => $vendorDir . '/symfony/process/Pipes/PipesInterface.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Pipes\\UnixPipes' => $vendorDir . '/symfony/process/Pipes/UnixPipes.php',

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInita55c41c7fa52abd86138c6f32df1d185
class ComposerAutoloaderInit6ee5b17c87a6bea7c9006b4ba8060b02
{
private static $loader;
@ -22,17 +22,17 @@ class ComposerAutoloaderInita55c41c7fa52abd86138c6f32df1d185
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInita55c41c7fa52abd86138c6f32df1d185', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInit6ee5b17c87a6bea7c9006b4ba8060b02', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInita55c41c7fa52abd86138c6f32df1d185', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInit6ee5b17c87a6bea7c9006b4ba8060b02', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInita55c41c7fa52abd86138c6f32df1d185::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInit6ee5b17c87a6bea7c9006b4ba8060b02::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
$filesToLoad = \Composer\Autoload\ComposerStaticInita55c41c7fa52abd86138c6f32df1d185::$files;
$filesToLoad = \Composer\Autoload\ComposerStaticInit6ee5b17c87a6bea7c9006b4ba8060b02::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

View File

@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInita55c41c7fa52abd86138c6f32df1d185
class ComposerStaticInit6ee5b17c87a6bea7c9006b4ba8060b02
{
public static $files = array (
'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
@ -1111,11 +1111,16 @@ class ComposerStaticInita55c41c7fa52abd86138c6f32df1d185
'RectorPrefix202311\\Symfony\\Component\\Process\\Exception\\ProcessFailedException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessFailedException.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessSignaledException.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessTimedOutException.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Exception\\RunProcessFailedException' => __DIR__ . '/..' . '/symfony/process/Exception/RunProcessFailedException.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/process/Exception/RuntimeException.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\ExecutableFinder' => __DIR__ . '/..' . '/symfony/process/ExecutableFinder.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\InputStream' => __DIR__ . '/..' . '/symfony/process/InputStream.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Messenger\\RunProcessContext' => __DIR__ . '/..' . '/symfony/process/Messenger/RunProcessContext.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Messenger\\RunProcessMessage' => __DIR__ . '/..' . '/symfony/process/Messenger/RunProcessMessage.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Messenger\\RunProcessMessageHandler' => __DIR__ . '/..' . '/symfony/process/Messenger/RunProcessMessageHandler.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\PhpExecutableFinder' => __DIR__ . '/..' . '/symfony/process/PhpExecutableFinder.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\PhpProcess' => __DIR__ . '/..' . '/symfony/process/PhpProcess.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\PhpSubprocess' => __DIR__ . '/..' . '/symfony/process/PhpSubprocess.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Pipes\\AbstractPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/AbstractPipes.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Pipes\\PipesInterface' => __DIR__ . '/..' . '/symfony/process/Pipes/PipesInterface.php',
'RectorPrefix202311\\Symfony\\Component\\Process\\Pipes\\UnixPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/UnixPipes.php',
@ -2601,9 +2606,9 @@ class ComposerStaticInita55c41c7fa52abd86138c6f32df1d185
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInita55c41c7fa52abd86138c6f32df1d185::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInita55c41c7fa52abd86138c6f32df1d185::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInita55c41c7fa52abd86138c6f32df1d185::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInit6ee5b17c87a6bea7c9006b4ba8060b02::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit6ee5b17c87a6bea7c9006b4ba8060b02::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit6ee5b17c87a6bea7c9006b4ba8060b02::$classMap;
}, null, ClassLoader::class);
}

View File

@ -1228,17 +1228,17 @@
},
{
"name": "react\/dns",
"version": "v1.11.0",
"version_normalized": "1.11.0.0",
"version": "v1.12.0",
"version_normalized": "1.12.0.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/reactphp\/dns.git",
"reference": "3be0fc8f1eb37d6875cd6f0c6c7d0be81435de9f"
"reference": "c134600642fa615b46b41237ef243daa65bb64ec"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/reactphp\/dns\/zipball\/3be0fc8f1eb37d6875cd6f0c6c7d0be81435de9f",
"reference": "3be0fc8f1eb37d6875cd6f0c6c7d0be81435de9f",
"url": "https:\/\/api.github.com\/repos\/reactphp\/dns\/zipball\/c134600642fa615b46b41237ef243daa65bb64ec",
"reference": "c134600642fa615b46b41237ef243daa65bb64ec",
"shasum": ""
},
"require": {
@ -1248,11 +1248,11 @@
"react\/promise": "^3.0 || ^2.7 || ^1.2.1"
},
"require-dev": {
"phpunit\/phpunit": "^9.5 || ^4.8.35",
"phpunit\/phpunit": "^9.6 || ^5.7 || ^4.8.36",
"react\/async": "^4 || ^3 || ^2",
"react\/promise-timer": "^1.9"
},
"time": "2023-06-02T12:45:26+00:00",
"time": "2023-11-29T12:41:06+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -1295,7 +1295,7 @@
],
"support": {
"issues": "https:\/\/github.com\/reactphp\/dns\/issues",
"source": "https:\/\/github.com\/reactphp\/dns\/tree\/v1.11.0"
"source": "https:\/\/github.com\/reactphp\/dns\/tree\/v1.12.0"
},
"funding": [
{
@ -2015,17 +2015,17 @@
},
{
"name": "symfony\/console",
"version": "v6.3.8",
"version_normalized": "6.3.8.0",
"version": "v6.3.9",
"version_normalized": "6.3.9.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/symfony\/console.git",
"reference": "0d14a9f6d04d4ac38a8cea1171f4554e325dae92"
"reference": "0566dbd051f8648d980592c7849f5d90d2c7c60c"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/symfony\/console\/zipball\/0d14a9f6d04d4ac38a8cea1171f4554e325dae92",
"reference": "0d14a9f6d04d4ac38a8cea1171f4554e325dae92",
"url": "https:\/\/api.github.com\/repos\/symfony\/console\/zipball\/0566dbd051f8648d980592c7849f5d90d2c7c60c",
"reference": "0566dbd051f8648d980592c7849f5d90d2c7c60c",
"shasum": ""
},
"require": {
@ -2054,7 +2054,7 @@
"symfony\/process": "^5.4|^6.0",
"symfony\/var-dumper": "^5.4|^6.0"
},
"time": "2023-10-31T08:09:35+00:00",
"time": "2023-11-20T16:36:29+00:00",
"type": "library",
"extra": {
"patches_applied": [
@ -2093,7 +2093,7 @@
"terminal"
],
"support": {
"source": "https:\/\/github.com\/symfony\/console\/tree\/v6.3.8"
"source": "https:\/\/github.com\/symfony\/console\/tree\/v6.3.9"
},
"funding": [
{
@ -2113,17 +2113,17 @@
},
{
"name": "symfony\/filesystem",
"version": "v6.3.1",
"version_normalized": "6.3.1.0",
"version": "v6.4.0",
"version_normalized": "6.4.0.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/symfony\/filesystem.git",
"reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae"
"reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/symfony\/filesystem\/zipball\/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae",
"reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae",
"url": "https:\/\/api.github.com\/repos\/symfony\/filesystem\/zipball\/952a8cb588c3bc6ce76f6023000fb932f16a6e59",
"reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59",
"shasum": ""
},
"require": {
@ -2131,7 +2131,7 @@
"symfony\/polyfill-ctype": "~1.8",
"symfony\/polyfill-mbstring": "~1.8"
},
"time": "2023-06-01T08:30:39+00:00",
"time": "2023-07-26T17:27:13+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -2159,7 +2159,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https:\/\/symfony.com",
"support": {
"source": "https:\/\/github.com\/symfony\/filesystem\/tree\/v6.3.1"
"source": "https:\/\/github.com\/symfony\/filesystem\/tree\/v6.4.0"
},
"funding": [
{
@ -2179,26 +2179,26 @@
},
{
"name": "symfony\/finder",
"version": "v6.3.5",
"version_normalized": "6.3.5.0",
"version": "v6.4.0",
"version_normalized": "6.4.0.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/symfony\/finder.git",
"reference": "a1b31d88c0e998168ca7792f222cbecee47428c4"
"reference": "11d736e97f116ac375a81f96e662911a34cd50ce"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/symfony\/finder\/zipball\/a1b31d88c0e998168ca7792f222cbecee47428c4",
"reference": "a1b31d88c0e998168ca7792f222cbecee47428c4",
"url": "https:\/\/api.github.com\/repos\/symfony\/finder\/zipball\/11d736e97f116ac375a81f96e662911a34cd50ce",
"reference": "11d736e97f116ac375a81f96e662911a34cd50ce",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"require-dev": {
"symfony\/filesystem": "^6.0"
"symfony\/filesystem": "^6.0|^7.0"
},
"time": "2023-09-26T12:56:25+00:00",
"time": "2023-10-31T17:30:12+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -2226,7 +2226,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https:\/\/symfony.com",
"support": {
"source": "https:\/\/github.com\/symfony\/finder\/tree\/v6.3.5"
"source": "https:\/\/github.com\/symfony\/finder\/tree\/v6.4.0"
},
"funding": [
{
@ -2332,23 +2332,23 @@
},
{
"name": "symfony\/process",
"version": "v6.3.4",
"version_normalized": "6.3.4.0",
"version": "v6.4.0",
"version_normalized": "6.4.0.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/symfony\/process.git",
"reference": "0b5c29118f2e980d455d2e34a5659f4579847c54"
"reference": "191703b1566d97a5425dc969e4350d32b8ef17aa"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/symfony\/process\/zipball\/0b5c29118f2e980d455d2e34a5659f4579847c54",
"reference": "0b5c29118f2e980d455d2e34a5659f4579847c54",
"url": "https:\/\/api.github.com\/repos\/symfony\/process\/zipball\/191703b1566d97a5425dc969e4350d32b8ef17aa",
"reference": "191703b1566d97a5425dc969e4350d32b8ef17aa",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"time": "2023-08-07T10:39:22+00:00",
"time": "2023-11-17T21:06:49+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -2376,7 +2376,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https:\/\/symfony.com",
"support": {
"source": "https:\/\/github.com\/symfony\/process\/tree\/v6.3.4"
"source": "https:\/\/github.com\/symfony\/process\/tree\/v6.4.0"
},
"funding": [
{

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,13 @@
# Changelog
## 1.12.0 (2023-11-29)
* Feature: Full PHP 8.3 compatibility.
(#217 by @sergiy-petrov)
* Update test environment and avoid unhandled promise rejections.
(#215, #216 and #218 by @clue)
## 1.11.0 (2023-06-02)
* Feature: Include timeout logic to avoid dependency on reactphp/promise-timer.

View File

@ -410,7 +410,7 @@ This project follows [SemVer](https://semver.org/).
This will install the latest supported version:
```bash
composer require react/dns:^1.11
composer require react/dns:^1.12
```
See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.

View File

@ -37,7 +37,7 @@
"react\/promise": "^3.0 || ^2.7 || ^1.2.1"
},
"require-dev": {
"phpunit\/phpunit": "^9.5 || ^4.8.35",
"phpunit\/phpunit": "^9.6 || ^5.7 || ^4.8.36",
"react\/async": "^4 || ^3 || ^2",
"react\/promise-timer": "^1.9"
},

View File

@ -20,6 +20,9 @@ use RectorPrefix202311\Symfony\Component\Filesystem\Exception\IOException;
*/
class Filesystem
{
/**
* @var string|null
*/
private static $lastError;
/**
* Copies a file.
@ -650,7 +653,7 @@ class Filesystem
{
self::assertFunctionExists($func);
self::$lastError = null;
\set_error_handler(__CLASS__ . '::handleError');
\set_error_handler(\Closure::fromCallable([self::class, 'handleError']));
try {
return $func(...$args);
} finally {

View File

@ -1,6 +1,11 @@
CHANGELOG
=========
6.4
---
* Add early directory pruning to `Finder::filter()`
6.2
---

View File

@ -62,6 +62,10 @@ class Finder implements \IteratorAggregate, \Countable
* @var mixed[]
*/
private $filters = [];
/**
* @var mixed[]
*/
private $pruneFilters = [];
/**
* @var mixed[]
*/
@ -582,13 +586,20 @@ class Finder implements \IteratorAggregate, \Countable
* The anonymous function receives a \SplFileInfo and must return false
* to remove files.
*
* @param \Closure(SplFileInfo): bool $closure
* @param bool $prune Whether to skip traversing directories further
*
* @return $this
*
* @see CustomFilterIterator
*/
public function filter(\Closure $closure)
{
$prune = 1 < \func_num_args() ? \func_get_arg(1) : \false;
$this->filters[] = $closure;
if ($prune) {
$this->pruneFilters[] = $closure;
}
return $this;
}
/**
@ -721,6 +732,9 @@ class Finder implements \IteratorAggregate, \Countable
{
$exclude = $this->exclude;
$notPaths = $this->notPaths;
if ($this->pruneFilters) {
$exclude = \array_merge($exclude, $this->pruneFilters);
}
if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
$exclude = \array_merge($exclude, self::$vcsPatterns);
}

View File

@ -28,17 +28,17 @@ class ExcludeDirectoryFilterIterator extends \FilterIterator implements \Recursi
* @var bool
*/
private $isRecursive;
/**
* @var mixed[]
*/
/** @var array<string, true> */
private $excludedDirs = [];
/**
* @var string|null
*/
private $excludedPattern;
/** @var list<callable(SplFileInfo):bool> */
private $pruneFilters = [];
/**
* @param \Iterator<string, SplFileInfo> $iterator The Iterator to filter
* @param string[] $directories An array of directories to exclude
* @param \Iterator<string, SplFileInfo> $iterator The Iterator to filter
* @param list<string|callable(SplFileInfo):bool> $directories An array of directories to exclude
*/
public function __construct(\Iterator $iterator, array $directories)
{
@ -46,6 +46,13 @@ class ExcludeDirectoryFilterIterator extends \FilterIterator implements \Recursi
$this->isRecursive = $iterator instanceof \RecursiveIterator;
$patterns = [];
foreach ($directories as $directory) {
if (!\is_string($directory)) {
if (!\is_callable($directory)) {
throw new \InvalidArgumentException('Invalid PHP callback.');
}
$this->pruneFilters[] = $directory;
continue;
}
$directory = \rtrim($directory, '/');
if (!$this->isRecursive || \strpos($directory, '/') !== \false) {
$patterns[] = \preg_quote($directory, '#');
@ -71,6 +78,13 @@ class ExcludeDirectoryFilterIterator extends \FilterIterator implements \Recursi
$path = \str_replace('\\', '/', $path);
return !\preg_match($this->excludedPattern, $path);
}
if ($this->pruneFilters && $this->hasChildren()) {
foreach ($this->pruneFilters as $pruneFilter) {
if (!$pruneFilter($this->current())) {
return \false;
}
}
}
return \true;
}
public function hasChildren() : bool

View File

@ -19,7 +19,7 @@
"php": ">=8.1"
},
"require-dev": {
"symfony\/filesystem": "^6.0"
"symfony\/filesystem": "^6.0|^7.0"
},
"autoload": {
"psr-4": {

View File

@ -1,6 +1,14 @@
CHANGELOG
=========
6.4
---
* Add `PhpSubprocess` to handle PHP subprocesses that take over the
configuration from their parent
* Add `RunProcessMessage` and `RunProcessMessageHandler`
* Support using `Process::findExecutable()` independently of `open_basedir`
5.2.0
-----

View File

@ -18,6 +18,9 @@ use RectorPrefix202311\Symfony\Component\Process\Process;
*/
class ProcessFailedException extends RuntimeException
{
/**
* @var \Symfony\Component\Process\Process
*/
private $process;
public function __construct(Process $process)
{

View File

@ -18,6 +18,9 @@ use RectorPrefix202311\Symfony\Component\Process\Process;
*/
final class ProcessSignaledException extends RuntimeException
{
/**
* @var \Symfony\Component\Process\Process
*/
private $process;
public function __construct(Process $process)
{

View File

@ -20,7 +20,13 @@ class ProcessTimedOutException extends RuntimeException
{
public const TYPE_GENERAL = 1;
public const TYPE_IDLE = 2;
/**
* @var \Symfony\Component\Process\Process
*/
private $process;
/**
* @var int
*/
private $timeoutType;
public function __construct(Process $process, int $timeoutType)
{

View File

@ -0,0 +1,29 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RectorPrefix202311\Symfony\Component\Process\Exception;
use RectorPrefix202311\Symfony\Component\Process\Messenger\RunProcessContext;
/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
final class RunProcessFailedException extends RuntimeException
{
/**
* @readonly
* @var \Symfony\Component\Process\Messenger\RunProcessContext
*/
public $context;
public function __construct(ProcessFailedException $exception, RunProcessContext $context)
{
$this->context = $context;
parent::__construct($exception->getMessage(), $exception->getCode());
}
}

View File

@ -18,6 +18,9 @@ namespace RectorPrefix202311\Symfony\Component\Process;
*/
class ExecutableFinder
{
/**
* @var mixed[]
*/
private $suffixes = ['.exe', '.bat', '.cmd', '.com'];
/**
* Replaces default suffixes of executable.
@ -46,22 +49,7 @@ class ExecutableFinder
*/
public function find(string $name, string $default = null, array $extraDirs = []) : ?string
{
if (\ini_get('open_basedir')) {
$searchPath = \array_merge(\explode(\PATH_SEPARATOR, \ini_get('open_basedir')), $extraDirs);
$dirs = [];
foreach ($searchPath as $path) {
// Silencing against https://bugs.php.net/69240
if (@\is_dir($path)) {
$dirs[] = $path;
} else {
if (\basename($path) == $name && @\is_executable($path)) {
return $path;
}
}
}
} else {
$dirs = \array_merge(\explode(\PATH_SEPARATOR, \getenv('PATH') ?: \getenv('Path')), $extraDirs);
}
$dirs = \array_merge(\explode(\PATH_SEPARATOR, \getenv('PATH') ?: \getenv('Path')), $extraDirs);
$suffixes = [''];
if ('\\' === \DIRECTORY_SEPARATOR) {
$pathExt = \getenv('PATHEXT');
@ -72,8 +60,15 @@ class ExecutableFinder
if (@\is_file($file = $dir . \DIRECTORY_SEPARATOR . $name . $suffix) && ('\\' === \DIRECTORY_SEPARATOR || @\is_executable($file))) {
return $file;
}
if (!@\is_dir($dir) && \basename($dir) === $name . $suffix && @\is_executable($dir)) {
return $dir;
}
}
}
$command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v';
if (\function_exists('exec') && ($executablePath = \strtok(@\exec($command . ' ' . \escapeshellarg($name)), \PHP_EOL)) && \is_executable($executablePath)) {
return $executablePath;
}
return $default;
}
}

View File

@ -20,9 +20,17 @@ use RectorPrefix202311\Symfony\Component\Process\Exception\RuntimeException;
*/
class InputStream implements \IteratorAggregate
{
/** @var callable|null */
/**
* @var \Closure|null
*/
private $onEmpty;
/**
* @var mixed[]
*/
private $input = [];
/**
* @var bool
*/
private $open = \true;
/**
* Sets a callback that is called when the write buffer becomes empty.
@ -31,7 +39,7 @@ class InputStream implements \IteratorAggregate
*/
public function onEmpty(callable $onEmpty = null)
{
$this->onEmpty = $onEmpty;
$this->onEmpty = null !== $onEmpty ? \Closure::fromCallable($onEmpty) : null;
}
/**
* Appends an input to the write buffer.

View File

@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RectorPrefix202311\Symfony\Component\Process\Messenger;
use RectorPrefix202311\Symfony\Component\Process\Process;
/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
final class RunProcessContext
{
/**
* @readonly
* @var \Symfony\Component\Process\Messenger\RunProcessMessage
*/
public $message;
/**
* @readonly
* @var int|null
*/
public $exitCode;
/**
* @readonly
* @var string|null
*/
public $output;
/**
* @readonly
* @var string|null
*/
public $errorOutput;
public function __construct(RunProcessMessage $message, Process $process)
{
$this->message = $message;
$this->exitCode = $process->getExitCode();
$this->output = $process->isOutputDisabled() ? null : $process->getOutput();
$this->errorOutput = $process->isOutputDisabled() ? null : $process->getErrorOutput();
}
}

View File

@ -0,0 +1,58 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RectorPrefix202311\Symfony\Component\Process\Messenger;
/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
class RunProcessMessage
{
/**
* @readonly
* @var mixed[]
*/
public $command;
/**
* @readonly
* @var string|null
*/
public $cwd;
/**
* @readonly
* @var mixed[]|null
*/
public $env;
/**
* @readonly
* @var mixed
*/
public $input = null;
/**
* @readonly
* @var float|null
*/
public $timeout = 60.0;
/**
* @param mixed $input
*/
public function __construct(array $command, ?string $cwd = null, ?array $env = null, $input = null, ?float $timeout = 60.0)
{
$this->command = $command;
$this->cwd = $cwd;
$this->env = $env;
$this->input = $input;
$this->timeout = $timeout;
}
public function __toString() : string
{
return \implode(' ', $this->command);
}
}

View File

@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RectorPrefix202311\Symfony\Component\Process\Messenger;
use RectorPrefix202311\Symfony\Component\Process\Exception\ProcessFailedException;
use RectorPrefix202311\Symfony\Component\Process\Exception\RunProcessFailedException;
use RectorPrefix202311\Symfony\Component\Process\Process;
/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
final class RunProcessMessageHandler
{
public function __invoke(RunProcessMessage $message) : RunProcessContext
{
$process = new Process($message->command, $message->cwd, $message->env, $message->input, $message->timeout);
try {
return new RunProcessContext($message, $process->mustRun());
} catch (ProcessFailedException $e) {
throw new RunProcessFailedException($e, new RunProcessContext($message, $e->getProcess()));
}
}
}

View File

@ -18,6 +18,9 @@ namespace RectorPrefix202311\Symfony\Component\Process;
*/
class PhpExecutableFinder
{
/**
* @var \Symfony\Component\Process\ExecutableFinder
*/
private $executableFinder;
public function __construct()
{
@ -32,7 +35,7 @@ class PhpExecutableFinder
if ($php = \getenv('PHP_BINARY')) {
if (!\is_executable($php)) {
$command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v';
if ($php = \strtok(\exec($command . ' ' . \escapeshellarg($php)), \PHP_EOL)) {
if (\function_exists('exec') && ($php = \strtok(\exec($command . ' ' . \escapeshellarg($php)), \PHP_EOL))) {
if (!\is_executable($php)) {
return \false;
}

140
vendor/symfony/process/PhpSubprocess.php vendored Normal file
View File

@ -0,0 +1,140 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace RectorPrefix202311\Symfony\Component\Process;
use RectorPrefix202311\Symfony\Component\Process\Exception\LogicException;
use RectorPrefix202311\Symfony\Component\Process\Exception\RuntimeException;
/**
* PhpSubprocess runs a PHP command as a subprocess while keeping the original php.ini settings.
*
* For this, it generates a temporary php.ini file taking over all the current settings and disables
* loading additional .ini files. Basically, your command gets prefixed using "php -n -c /tmp/temp.ini".
*
* Given your php.ini contains "memory_limit=-1" and you have a "MemoryTest.php" with the following content:
*
* <?php var_dump(ini_get('memory_limit'));
*
* These are the differences between the regular Process and PhpSubprocess classes:
*
* $p = new Process(['php', '-d', 'memory_limit=256M', 'MemoryTest.php']);
* $p->run();
* print $p->getOutput()."\n";
*
* This will output "string(2) "-1", because the process is started with the default php.ini settings.
*
* $p = new PhpSubprocess(['MemoryTest.php'], null, null, 60, ['php', '-d', 'memory_limit=256M']);
* $p->run();
* print $p->getOutput()."\n";
*
* This will output "string(4) "256M"", because the process is started with the temporarily created php.ini settings.
*
* @author Yanick Witschi <yanick.witschi@terminal42.ch>
* @author Partially copied and heavily inspired from composer/xdebug-handler by John Stevenson <john-stevenson@blueyonder.co.uk>
*/
class PhpSubprocess extends Process
{
/**
* @param array $command The command to run and its arguments listed as separate entries. They will automatically
* get prefixed with the PHP binary
* @param string|null $cwd The working directory or null to use the working dir of the current PHP process
* @param array|null $env The environment variables or null to use the same environment as the current PHP process
* @param int $timeout The timeout in seconds
* @param array|null $php Path to the PHP binary to use with any additional arguments
*/
public function __construct(array $command, string $cwd = null, array $env = null, int $timeout = 60, array $php = null)
{
if (null === $php) {
$executableFinder = new PhpExecutableFinder();
$php = $executableFinder->find(\false);
$php = \false === $php ? null : \array_merge([$php], $executableFinder->findArguments());
}
if (null === $php) {
throw new RuntimeException('Unable to find PHP binary.');
}
$tmpIni = $this->writeTmpIni($this->getAllIniFiles(), \sys_get_temp_dir());
$php = \array_merge($php, ['-n', '-c', $tmpIni]);
\register_shutdown_function('unlink', $tmpIni);
$command = \array_merge($php, $command);
parent::__construct($command, $cwd, $env, null, $timeout);
}
/**
* @param mixed $input
* @return static
*/
public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
{
throw new LogicException(\sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
}
public function start(callable $callback = null, array $env = []) : void
{
if (null === $this->getCommandLine()) {
throw new RuntimeException('Unable to find the PHP executable.');
}
parent::start($callback, $env);
}
private function writeTmpIni(array $iniFiles, string $tmpDir) : string
{
if (\false === ($tmpfile = @\tempnam($tmpDir, ''))) {
throw new RuntimeException('Unable to create temporary ini file.');
}
// $iniFiles has at least one item and it may be empty
if ('' === $iniFiles[0]) {
\array_shift($iniFiles);
}
$content = '';
foreach ($iniFiles as $file) {
// Check for inaccessible ini files
if (($data = @\file_get_contents($file)) === \false) {
throw new RuntimeException('Unable to read ini: ' . $file);
}
// Check and remove directives after HOST and PATH sections
if (\preg_match('/^\\s*\\[(?:PATH|HOST)\\s*=/mi', $data, $matches)) {
$data = \substr($data, 0, $matches[0][1]);
}
$content .= $data . "\n";
}
// Merge loaded settings into our ini content, if it is valid
$config = \parse_ini_string($content);
$loaded = \ini_get_all(null, \false);
if (\false === $config || \false === $loaded) {
throw new RuntimeException('Unable to parse ini data.');
}
$content .= $this->mergeLoadedConfig($loaded, $config);
// Work-around for https://bugs.php.net/bug.php?id=75932
$content .= "opcache.enable_cli=0\n";
if (\false === @\file_put_contents($tmpfile, $content)) {
throw new RuntimeException('Unable to write temporary ini file.');
}
return $tmpfile;
}
private function mergeLoadedConfig(array $loadedConfig, array $iniConfig) : string
{
$content = '';
foreach ($loadedConfig as $name => $value) {
if (!\is_string($value)) {
continue;
}
if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) {
// Double-quote escape each value
$content .= $name . '="' . \addcslashes($value, '\\"') . "\"\n";
}
}
return $content;
}
private function getAllIniFiles() : array
{
$paths = [(string) \php_ini_loaded_file()];
if (\false !== ($scanned = \php_ini_scanned_files())) {
$paths = \array_merge($paths, \array_map('trim', \explode(',', $scanned)));
}
return $paths;
}
}

View File

@ -22,19 +22,27 @@ abstract class AbstractPipes implements PipesInterface
* @var mixed[]
*/
public $pipes = [];
/**
* @var string
*/
private $inputBuffer = '';
/** @var resource|string|\Iterator */
private $input;
/**
* @var bool
*/
private $blocked = \true;
/**
* @var string|null
*/
private $lastError;
/**
* @param mixed $input
* @param resource|string|\Iterator $input
*/
public function __construct($input)
{
if (\is_resource($input) || $input instanceof \Iterator) {
$this->input = $input;
} elseif (\is_string($input)) {
$this->inputBuffer = $input;
} else {
$this->inputBuffer = (string) $input;
}

View File

@ -20,8 +20,17 @@ use RectorPrefix202311\Symfony\Component\Process\Process;
*/
class UnixPipes extends AbstractPipes
{
/**
* @var bool|null
*/
private $ttyMode;
/**
* @var bool
*/
private $ptyMode;
/**
* @var bool
*/
private $haveReadSupport;
/**
* @param mixed $input
@ -37,7 +46,7 @@ class UnixPipes extends AbstractPipes
{
throw new \BadMethodCallException('Cannot serialize ' . __CLASS__);
}
public function __wakeup()
public function __wakeup() : void
{
throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
}

View File

@ -24,10 +24,25 @@ use RectorPrefix202311\Symfony\Component\Process\Process;
*/
class WindowsPipes extends AbstractPipes
{
/**
* @var mixed[]
*/
private $files = [];
/**
* @var mixed[]
*/
private $fileHandles = [];
/**
* @var mixed[]
*/
private $lockHandles = [];
/**
* @var mixed[]
*/
private $readBytes = [Process::STDOUT => 0, Process::STDERR => 0];
/**
* @var bool
*/
private $haveReadSupport;
/**
* @param mixed $input
@ -83,7 +98,7 @@ class WindowsPipes extends AbstractPipes
{
throw new \BadMethodCallException('Cannot serialize ' . __CLASS__);
}
public function __wakeup()
public function __wakeup() : void
{
throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
}

View File

@ -16,7 +16,6 @@ use RectorPrefix202311\Symfony\Component\Process\Exception\ProcessFailedExceptio
use RectorPrefix202311\Symfony\Component\Process\Exception\ProcessSignaledException;
use RectorPrefix202311\Symfony\Component\Process\Exception\ProcessTimedOutException;
use RectorPrefix202311\Symfony\Component\Process\Exception\RuntimeException;
use RectorPrefix202311\Symfony\Component\Process\Pipes\PipesInterface;
use RectorPrefix202311\Symfony\Component\Process\Pipes\UnixPipes;
use RectorPrefix202311\Symfony\Component\Process\Pipes\WindowsPipes;
/**
@ -48,33 +47,97 @@ class Process implements \IteratorAggregate
// Use this flag to skip STDOUT while iterating
public const ITER_SKIP_ERR = 8;
// Use this flag to skip STDERR while iterating
/**
* @var \Closure|null
*/
private $callback;
private $hasCallback = \false;
/**
* @var mixed[]|string
*/
private $commandline;
/**
* @var string|null
*/
private $cwd;
/**
* @var mixed[]
*/
private $env = [];
/** @var resource|string|\Iterator|null */
private $input;
/**
* @var float|null
*/
private $starttime;
/**
* @var float|null
*/
private $lastOutputTime;
/**
* @var float|null
*/
private $timeout;
/**
* @var float|null
*/
private $idleTimeout;
/**
* @var int|null
*/
private $exitcode;
/**
* @var mixed[]
*/
private $fallbackStatus = [];
/**
* @var mixed[]
*/
private $processInformation;
/**
* @var bool
*/
private $outputDisabled = \false;
/** @var resource */
private $stdout;
/** @var resource */
private $stderr;
/** @var resource|null */
private $process;
/**
* @var string
*/
private $status = self::STATUS_READY;
/**
* @var int
*/
private $incrementalOutputOffset = 0;
/**
* @var int
*/
private $incrementalErrorOutputOffset = 0;
/**
* @var bool
*/
private $tty = \false;
/**
* @var bool
*/
private $pty;
/**
* @var mixed[]
*/
private $options = ['suppress_errors' => \true, 'bypass_shell' => \true];
private $useFileHandles = \false;
/** @var PipesInterface */
/**
* @var \Symfony\Component\Process\Pipes\WindowsPipes|\Symfony\Component\Process\Pipes\UnixPipes
*/
private $processPipes;
/**
* @var int|null
*/
private $latestSignal;
/**
* @var bool|null
*/
private static $sigchild;
/**
* Exit codes translation table.
@ -149,7 +212,6 @@ class Process implements \IteratorAggregate
}
$this->setInput($input);
$this->setTimeout($timeout);
$this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR;
$this->pty = \false;
}
/**
@ -184,6 +246,9 @@ class Process implements \IteratorAggregate
{
throw new \BadMethodCallException('Cannot serialize ' . __CLASS__);
}
/**
* @return void
*/
public function __wakeup()
{
throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
@ -276,8 +341,7 @@ class Process implements \IteratorAggregate
$this->resetProcessData();
$this->starttime = $this->lastOutputTime = \microtime(\true);
$this->callback = $this->buildCallback($callback);
$this->hasCallback = null !== $callback;
$descriptors = $this->getDescriptors();
$descriptors = $this->getDescriptors(null !== $callback);
if ($this->env) {
$env += '\\' === \DIRECTORY_SEPARATOR ? \array_diff_ukey($this->env, $env, 'strcasecmp') : $this->env;
}
@ -293,15 +357,12 @@ class Process implements \IteratorAggregate
}
if ('\\' === \DIRECTORY_SEPARATOR) {
$commandline = $this->prepareWindowsCommandLine($commandline, $env);
} elseif (!$this->useFileHandles && $this->isSigchildEnabled()) {
} elseif ($this->isSigchildEnabled()) {
// last exit code is output on the fourth pipe and caught to work around --enable-sigchild
$descriptors[3] = ['pipe', 'w'];
// See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
$commandline = '{ (' . $commandline . ') <&3 3<&- 3>/dev/null & } 3<&0;';
$commandline .= 'pid=$!; echo $pid >&3; wait $pid 2>/dev/null; code=$?; echo $code >&3; exit $code';
// Workaround for the bug, when PTS functionality is enabled.
// @see : https://bugs.php.net/69442
$ptsWorkaround = \fopen(__FILE__, 'r');
}
$envPairs = [];
foreach ($env as $k => $v) {
@ -312,10 +373,11 @@ class Process implements \IteratorAggregate
if (!\is_dir($this->cwd)) {
throw new RuntimeException(\sprintf('The provided cwd "%s" does not exist.', $this->cwd));
}
$this->process = @\proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
if (!\is_resource($this->process)) {
$process = @\proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
if (!\is_resource($process)) {
throw new RuntimeException('Unable to launch a new process.');
}
$this->process = $process;
$this->status = self::STATUS_STARTED;
if (isset($descriptors[3])) {
$this->fallbackStatus['pid'] = (int) \fgets($this->processPipes->pipes[3]);
@ -1070,15 +1132,15 @@ class Process implements \IteratorAggregate
/**
* Creates the descriptors needed by the proc_open.
*/
private function getDescriptors() : array
private function getDescriptors(bool $hasCallback) : array
{
if ($this->input instanceof \Iterator) {
$this->input->rewind();
}
if ('\\' === \DIRECTORY_SEPARATOR) {
$this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback);
$this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $hasCallback);
} else {
$this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback);
$this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $hasCallback);
}
return $this->processPipes->getDescriptors();
}
@ -1230,7 +1292,7 @@ class Process implements \IteratorAggregate
$this->callback = null;
$this->exitcode = null;
$this->fallbackStatus = [];
$this->processInformation = null;
$this->processInformation = [];
$this->stdout = \fopen('php://temp/maxmemory:' . 1024 * 1024, 'w+');
$this->stderr = \fopen('php://temp/maxmemory:' . 1024 * 1024, 'w+');
$this->process = null;

View File

@ -41,9 +41,6 @@ class ProcessUtils
if (\is_resource($input)) {
return $input;
}
if (\is_string($input)) {
return $input;
}
if (\is_scalar($input)) {
return (string) $input;
}