From e7016b00a9d7f5be76655e82c6968fc289fb9768 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 20 Jul 2023 12:52:28 +0200 Subject: [PATCH] Upgrade to react/promise 3.0.0 (#10429) --- composer.json | 2 +- composer.lock | 29 ++++++++++--------- phpstan/baseline.neon | 10 +++---- src/Composer/Downloader/ArchiveDownloader.php | 1 + src/Composer/Downloader/DownloadManager.php | 6 ++++ .../Downloader/DownloaderInterface.php | 6 ++++ src/Composer/Downloader/GitDownloader.php | 2 ++ src/Composer/Downloader/SvnDownloader.php | 3 ++ src/Composer/Downloader/VcsDownloader.php | 4 +++ src/Composer/Downloader/ZipDownloader.php | 2 ++ .../Installer/InstallationManager.php | 19 +++++++----- src/Composer/Installer/InstallerInterface.php | 6 ++++ src/Composer/Installer/LibraryInstaller.php | 3 ++ .../Package/Version/VersionGuesser.php | 5 ++-- .../Repository/ComposerRepository.php | 11 ++++++- src/Composer/Util/Filesystem.php | 1 + src/Composer/Util/HttpDownloader.php | 5 +++- src/Composer/Util/Loop.php | 16 +++++----- src/Composer/Util/ProcessExecutor.php | 1 + src/Composer/Util/SyncHelper.php | 1 + .../Test/Downloader/ZipDownloaderTest.php | 4 +-- .../Test/Util/ProcessExecutorTest.php | 1 - 22 files changed, 93 insertions(+), 45 deletions(-) diff --git a/composer.json b/composer.json index 36dbfe22d..70f488506 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,7 @@ "symfony/filesystem": "^5.4 || ^6.0 || ^7", "symfony/finder": "^5.4 || ^6.0 || ^7", "symfony/process": "^5.4 || ^6.0 || ^7", - "react/promise": "^2.8", + "react/promise": "^2.8 || ^3", "composer/pcre": "^2.1 || ^3.1", "symfony/polyfill-php73": "^1.24", "symfony/polyfill-php80": "^1.24", diff --git a/composer.lock b/composer.lock index 39b48033b..6b3ca48a6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c50c89580fa044b7523cb55c2d557c87", + "content-hash": "4bceaf933dcf6bc05808134e78d21496", "packages": [ { "name": "composer/ca-bundle", @@ -692,23 +692,24 @@ }, { "name": "react/promise", - "version": "v2.10.0", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38" + "reference": "c86753c76fd3be465d93b308f18d189f01a22be4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", - "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", + "url": "https://api.github.com/repos/reactphp/promise/zipball/c86753c76fd3be465d93b308f18d189f01a22be4", + "reference": "c86753c76fd3be465d93b308f18d189f01a22be4", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": ">=7.1.0" }, "require-dev": { - "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.36" + "phpstan/phpstan": "1.10.20 || 1.4.10", + "phpunit/phpunit": "^9.5 || ^7.5" }, "type": "library", "autoload": { @@ -752,7 +753,7 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v2.10.0" + "source": "https://github.com/reactphp/promise/tree/v3.0.0" }, "funding": [ { @@ -760,7 +761,7 @@ "type": "open_collective" } ], - "time": "2023-05-02T15:15:43+00:00" + "time": "2023-07-11T16:12:49+00:00" }, { "name": "seld/jsonlint", @@ -2034,16 +2035,16 @@ "packages-dev": [ { "name": "phpstan/phpstan", - "version": "1.10.25", + "version": "1.10.26", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "578f4e70d117f9a90699324c555922800ac38d8c" + "reference": "5d660cbb7e1b89253a47147ae44044f49832351f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/578f4e70d117f9a90699324c555922800ac38d8c", - "reference": "578f4e70d117f9a90699324c555922800ac38d8c", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5d660cbb7e1b89253a47147ae44044f49832351f", + "reference": "5d660cbb7e1b89253a47147ae44044f49832351f", "shasum": "" }, "require": { @@ -2092,7 +2093,7 @@ "type": "tidelift" } ], - "time": "2023-07-06T12:11:37+00:00" + "time": "2023-07-19T12:44:37+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", diff --git a/phpstan/baseline.neon b/phpstan/baseline.neon index 19f0d228f..cad1d17ff 100644 --- a/phpstan/baseline.neon +++ b/phpstan/baseline.neon @@ -1665,6 +1665,11 @@ parameters: count: 3 path: ../src/Composer/Downloader/FileDownloader.php + - + message: "#^Strict comparison using \\=\\=\\= between null and Composer\\\\Util\\\\Http\\\\Response will always evaluate to false\\.$#" + count: 1 + path: ../src/Composer/Downloader/FileDownloader.php + - message: "#^Parameter \\#3 \\$cwd of method Composer\\\\Util\\\\ProcessExecutor\\:\\:execute\\(\\) expects string\\|null, string\\|false given\\.$#" count: 5 @@ -2305,11 +2310,6 @@ parameters: count: 1 path: ../src/Composer/Installer/InstallationManager.php - - - message: "#^Only booleans are allowed in an if condition, React\\\\Promise\\\\PromiseInterface\\|null given\\.$#" - count: 1 - path: ../src/Composer/Installer/InstallationManager.php - - message: "#^Only booleans are allowed in an if condition, Symfony\\\\Component\\\\Console\\\\Helper\\\\ProgressBar\\|null given\\.$#" count: 1 diff --git a/src/Composer/Downloader/ArchiveDownloader.php b/src/Composer/Downloader/ArchiveDownloader.php index a6648bcdf..6de51ee58 100644 --- a/src/Composer/Downloader/ArchiveDownloader.php +++ b/src/Composer/Downloader/ArchiveDownloader.php @@ -216,6 +216,7 @@ abstract class ArchiveDownloader extends FileDownloader * * @param string $file Extracted file * @param string $path Directory + * @phpstan-return PromiseInterface * * @throws \UnexpectedValueException If can not extract downloaded file to path */ diff --git a/src/Composer/Downloader/DownloadManager.php b/src/Composer/Downloader/DownloadManager.php index 7f7ad2c3a..e4adfdf37 100644 --- a/src/Composer/Downloader/DownloadManager.php +++ b/src/Composer/Downloader/DownloadManager.php @@ -174,6 +174,7 @@ class DownloadManager * @param PackageInterface $package package instance * @param string $targetDir target dir * @param PackageInterface|null $prevPackage previous package instance in case of updates + * @phpstan-return PromiseInterface * * @throws \InvalidArgumentException if package have no urls to download from * @throws \RuntimeException @@ -241,6 +242,7 @@ class DownloadManager * @param PackageInterface $package package instance * @param string $targetDir target dir * @param PackageInterface|null $prevPackage previous package instance in case of updates + * @phpstan-return PromiseInterface */ public function prepare(string $type, PackageInterface $package, string $targetDir, ?PackageInterface $prevPackage = null): PromiseInterface { @@ -258,6 +260,7 @@ class DownloadManager * * @param PackageInterface $package package instance * @param string $targetDir target dir + * @phpstan-return PromiseInterface * * @throws \InvalidArgumentException if package have no urls to download from * @throws \RuntimeException @@ -279,6 +282,7 @@ class DownloadManager * @param PackageInterface $initial initial package version * @param PackageInterface $target target package version * @param string $targetDir target dir + * @phpstan-return PromiseInterface * * @throws \InvalidArgumentException if initial package is not installed */ @@ -328,6 +332,7 @@ class DownloadManager * * @param PackageInterface $package package instance * @param string $targetDir target dir + * @phpstan-return PromiseInterface */ public function remove(PackageInterface $package, string $targetDir): PromiseInterface { @@ -347,6 +352,7 @@ class DownloadManager * @param PackageInterface $package package instance * @param string $targetDir target dir * @param PackageInterface|null $prevPackage previous package instance in case of updates + * @phpstan-return PromiseInterface */ public function cleanup(string $type, PackageInterface $package, string $targetDir, ?PackageInterface $prevPackage = null): PromiseInterface { diff --git a/src/Composer/Downloader/DownloaderInterface.php b/src/Composer/Downloader/DownloaderInterface.php index 8e135d725..8cb86cdbb 100644 --- a/src/Composer/Downloader/DownloaderInterface.php +++ b/src/Composer/Downloader/DownloaderInterface.php @@ -34,6 +34,7 @@ interface DownloaderInterface * This should do any network-related tasks to prepare for an upcoming install/update * * @param string $path download path + * @phpstan-return PromiseInterface */ public function download(PackageInterface $package, string $path, ?PackageInterface $prevPackage = null): PromiseInterface; @@ -49,6 +50,7 @@ interface DownloaderInterface * @param PackageInterface $package package instance * @param string $path download path * @param PackageInterface $prevPackage previous package instance in case of an update + * @phpstan-return PromiseInterface */ public function prepare(string $type, PackageInterface $package, string $path, ?PackageInterface $prevPackage = null): PromiseInterface; @@ -57,6 +59,7 @@ interface DownloaderInterface * * @param PackageInterface $package package instance * @param string $path download path + * @phpstan-return PromiseInterface */ public function install(PackageInterface $package, string $path): PromiseInterface; @@ -66,6 +69,7 @@ interface DownloaderInterface * @param PackageInterface $initial initial package * @param PackageInterface $target updated package * @param string $path download path + * @phpstan-return PromiseInterface */ public function update(PackageInterface $initial, PackageInterface $target, string $path): PromiseInterface; @@ -74,6 +78,7 @@ interface DownloaderInterface * * @param PackageInterface $package package instance * @param string $path download path + * @phpstan-return PromiseInterface */ public function remove(PackageInterface $package, string $path): PromiseInterface; @@ -88,6 +93,7 @@ interface DownloaderInterface * @param PackageInterface $package package instance * @param string $path download path * @param PackageInterface $prevPackage previous package instance in case of an update + * @phpstan-return PromiseInterface */ public function cleanup(string $type, PackageInterface $package, string $path, ?PackageInterface $prevPackage = null): PromiseInterface; } diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index 05901a9b2..0840219d0 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -536,6 +536,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface } /** + * @phpstan-return PromiseInterface * @throws \RuntimeException */ protected function discardChanges(string $path): PromiseInterface @@ -551,6 +552,7 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface } /** + * @phpstan-return PromiseInterface * @throws \RuntimeException */ protected function stashChanges(string $path): PromiseInterface diff --git a/src/Composer/Downloader/SvnDownloader.php b/src/Composer/Downloader/SvnDownloader.php index daa93dfe9..be180d63d 100644 --- a/src/Composer/Downloader/SvnDownloader.php +++ b/src/Composer/Downloader/SvnDownloader.php @@ -230,6 +230,9 @@ class SvnDownloader extends VcsDownloader return "Could not retrieve changes between $fromReference and $toReference due to missing revision information"; } + /** + * @phpstan-return PromiseInterface + */ protected function discardChanges(string $path): PromiseInterface { if (0 !== $this->process->execute('svn revert -R .', $output, $path)) { diff --git a/src/Composer/Downloader/VcsDownloader.php b/src/Composer/Downloader/VcsDownloader.php index 15f3aeccd..a1c5979d5 100644 --- a/src/Composer/Downloader/VcsDownloader.php +++ b/src/Composer/Downloader/VcsDownloader.php @@ -259,6 +259,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa * if false (remove) the changes should be assumed to be lost if the operation is not aborted * * @throws \RuntimeException in case the operation must be aborted + * @phpstan-return PromiseInterface */ protected function cleanChanges(PackageInterface $package, string $path, bool $update): PromiseInterface { @@ -286,6 +287,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa * @param string $path download path * @param string $url package url * @param PackageInterface|null $prevPackage previous package (in case of an update) + * @phpstan-return PromiseInterface */ abstract protected function doDownload(PackageInterface $package, string $path, string $url, ?PackageInterface $prevPackage = null): PromiseInterface; @@ -295,6 +297,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa * @param PackageInterface $package package instance * @param string $path download path * @param string $url package url + * @phpstan-return PromiseInterface */ abstract protected function doInstall(PackageInterface $package, string $path, string $url): PromiseInterface; @@ -305,6 +308,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa * @param PackageInterface $target updated package * @param string $path download path * @param string $url package url + * @phpstan-return PromiseInterface */ abstract protected function doUpdate(PackageInterface $initial, PackageInterface $target, string $path, string $url): PromiseInterface; diff --git a/src/Composer/Downloader/ZipDownloader.php b/src/Composer/Downloader/ZipDownloader.php index 851e70de1..9d0f35353 100644 --- a/src/Composer/Downloader/ZipDownloader.php +++ b/src/Composer/Downloader/ZipDownloader.php @@ -105,6 +105,7 @@ class ZipDownloader extends ArchiveDownloader * * @param string $file File to extract * @param string $path Path where to extract file + * @phpstan-return PromiseInterface */ private function extractWithSystemUnzip(PackageInterface $package, string $file, string $path): PromiseInterface { @@ -194,6 +195,7 @@ class ZipDownloader extends ArchiveDownloader * * @param string $file File to extract * @param string $path Path where to extract file + * @phpstan-return PromiseInterface */ private function extractWithZipArchive(PackageInterface $package, string $file, string $path): PromiseInterface { diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php index d171139e9..f92a117ba 100644 --- a/src/Composer/Installer/InstallationManager.php +++ b/src/Composer/Installer/InstallationManager.php @@ -180,7 +180,7 @@ class InstallationManager */ public function execute(InstalledRepositoryInterface $repo, array $operations, bool $devMode = true, bool $runScripts = true, bool $downloadOnly = false): void { - /** @var array */ + /** @var array> */ $cleanupPromises = []; $signalHandler = SignalHandler::create([SignalHandler::SIGINT, SignalHandler::SIGTERM, SignalHandler::SIGHUP], function (string $signal, SignalHandler $handler) use (&$cleanupPromises) { @@ -237,8 +237,8 @@ class InstallationManager /** * @param OperationInterface[] $operations List of operations to execute in this batch - * @param array $cleanupPromises * @param OperationInterface[] $allOperations Complete list of operations to be executed in the install job, used for event listeners + * @phpstan-param array> $cleanupPromises */ private function downloadAndExecuteBatch(InstalledRepositoryInterface $repo, array $operations, array &$cleanupPromises, bool $devMode, bool $runScripts, bool $downloadOnly, array $allOperations): void { @@ -275,7 +275,7 @@ class InstallationManager if ($opType !== 'uninstall') { $promise = $installer->download($package, $initialPackage); - if ($promise) { + if (null !== $promise) { $promises[] = $promise; } } @@ -322,8 +322,8 @@ class InstallationManager /** * @param OperationInterface[] $operations List of operations to execute in this batch - * @param array $cleanupPromises * @param OperationInterface[] $allOperations Complete list of operations to be executed in the install job, used for event listeners + * @phpstan-param array> $cleanupPromises */ private function executeBatch(InstalledRepositoryInterface $repo, array $operations, array $cleanupPromises, bool $devMode, bool $runScripts, array $allOperations): void { @@ -413,7 +413,7 @@ class InstallationManager } /** - * @param PromiseInterface[] $promises + * @param array> $promises */ private function waitOnPromises(array $promises): void { @@ -440,7 +440,7 @@ class InstallationManager /** * Executes download operation. * - * $param PackageInterface $package + * @phpstan-return PromiseInterface|null */ public function download(PackageInterface $package): ?PromiseInterface { @@ -455,6 +455,7 @@ class InstallationManager * * @param InstalledRepositoryInterface $repo repository in which to check * @param InstallOperation $operation operation instance + * @phpstan-return PromiseInterface|null */ public function install(InstalledRepositoryInterface $repo, InstallOperation $operation): ?PromiseInterface { @@ -471,6 +472,7 @@ class InstallationManager * * @param InstalledRepositoryInterface $repo repository in which to check * @param UpdateOperation $operation operation instance + * @phpstan-return PromiseInterface|null */ public function update(InstalledRepositoryInterface $repo, UpdateOperation $operation): ?PromiseInterface { @@ -509,6 +511,7 @@ class InstallationManager * * @param InstalledRepositoryInterface $repo repository in which to check * @param UninstallOperation $operation operation instance + * @phpstan-return PromiseInterface|null */ public function uninstall(InstalledRepositoryInterface $repo, UninstallOperation $operation): ?PromiseInterface { @@ -638,8 +641,8 @@ class InstallationManager } /** - * @param array $cleanupPromises * @return void + * @phpstan-param array> $cleanupPromises */ private function runCleanup(array $cleanupPromises): void { @@ -648,7 +651,7 @@ class InstallationManager $this->loop->abortJobs(); foreach ($cleanupPromises as $cleanup) { - $promises[] = new \React\Promise\Promise(static function ($resolve, $reject) use ($cleanup): void { + $promises[] = new \React\Promise\Promise(static function ($resolve) use ($cleanup): void { $promise = $cleanup(); if (!$promise instanceof PromiseInterface) { $resolve(); diff --git a/src/Composer/Installer/InstallerInterface.php b/src/Composer/Installer/InstallerInterface.php index bdf42ec42..7c92e91d4 100644 --- a/src/Composer/Installer/InstallerInterface.php +++ b/src/Composer/Installer/InstallerInterface.php @@ -48,6 +48,7 @@ interface InstallerInterface * @param PackageInterface $package package instance * @param PackageInterface $prevPackage previous package instance in case of an update * @return PromiseInterface|null + * @phpstan-return PromiseInterface|null */ public function download(PackageInterface $package, ?PackageInterface $prevPackage = null); @@ -63,6 +64,7 @@ interface InstallerInterface * @param PackageInterface $package package instance * @param PackageInterface $prevPackage previous package instance in case of an update * @return PromiseInterface|null + * @phpstan-return PromiseInterface|null */ public function prepare(string $type, PackageInterface $package, ?PackageInterface $prevPackage = null); @@ -72,6 +74,7 @@ interface InstallerInterface * @param InstalledRepositoryInterface $repo repository in which to check * @param PackageInterface $package package instance * @return PromiseInterface|null + * @phpstan-return PromiseInterface|null */ public function install(InstalledRepositoryInterface $repo, PackageInterface $package); @@ -83,6 +86,7 @@ interface InstallerInterface * @param PackageInterface $target updated version * @throws InvalidArgumentException if $initial package is not installed * @return PromiseInterface|null + * @phpstan-return PromiseInterface|null */ public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target); @@ -92,6 +96,7 @@ interface InstallerInterface * @param InstalledRepositoryInterface $repo repository in which to check * @param PackageInterface $package package instance * @return PromiseInterface|null + * @phpstan-return PromiseInterface|null */ public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package); @@ -106,6 +111,7 @@ interface InstallerInterface * @param PackageInterface $package package instance * @param PackageInterface $prevPackage previous package instance in case of an update * @return PromiseInterface|null + * @phpstan-return PromiseInterface|null */ public function cleanup(string $type, PackageInterface $package, ?PackageInterface $prevPackage = null); diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index d87c6e3dc..0626fb189 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -272,6 +272,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface /** * @return PromiseInterface|null + * @phpstan-return PromiseInterface|null */ protected function installCode(PackageInterface $package) { @@ -282,6 +283,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface /** * @return PromiseInterface|null + * @phpstan-return PromiseInterface|null */ protected function updateCode(PackageInterface $initial, PackageInterface $target) { @@ -316,6 +318,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface /** * @return PromiseInterface|null + * @phpstan-return PromiseInterface|null */ protected function removeCode(PackageInterface $package) { diff --git a/src/Composer/Package/Version/VersionGuesser.php b/src/Composer/Package/Version/VersionGuesser.php index 46116f0b7..2b2b19706 100644 --- a/src/Composer/Package/Version/VersionGuesser.php +++ b/src/Composer/Package/Version/VersionGuesser.php @@ -322,9 +322,8 @@ class VersionGuesser $prettyVersion = 'dev-' . $candidateVersion; if ($length === 0) { foreach ($promises as $promise) { - if ($promise instanceof CancellablePromiseInterface) { - $promise->cancel(); - } + // to support react/promise 2.x we wrap the promise in a resolve() call for safety + \React\Promise\resolve($promise)->cancel(); } } } diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 0efb02e96..f06fcf5c2 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -1070,6 +1070,9 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito return ['namesFound' => $namesFound, 'packages' => $packages]; } + /** + * @phpstan-return PromiseInterface + */ private function startCachedAsyncDownload(string $fileName, ?string $packageName = null): PromiseInterface { if (null === $this->lazyProvidersUrl) { @@ -1598,6 +1601,9 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito } } + /** + * @phpstan-return PromiseInterface|true> true if the response was a 304 and the cache is fresh, otherwise it returns the decoded json + */ private function asyncFetchFile(string $filename, string $cacheKey, ?string $lastModifiedTime = null): PromiseInterface { if ('' === $filename) { @@ -1610,7 +1616,10 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito if (isset($this->freshMetadataUrls[$filename]) && $lastModifiedTime) { // make it look like we got a 304 response - return \React\Promise\resolve(true); + /** @var PromiseInterface $promise */ + $promise = \React\Promise\resolve(true); + + return $promise; } $httpDownloader = $this->httpDownloader; diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index e0f008d14..d5ec81050 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -133,6 +133,7 @@ class Filesystem * * @throws \RuntimeException * @return PromiseInterface + * @phpstan-return PromiseInterface */ public function removeDirectoryAsync(string $directory) { diff --git a/src/Composer/Util/HttpDownloader.php b/src/Composer/Util/HttpDownloader.php index 58a64b663..e4034d2ae 100644 --- a/src/Composer/Util/HttpDownloader.php +++ b/src/Composer/Util/HttpDownloader.php @@ -28,7 +28,7 @@ use React\Promise\PromiseInterface; /** * @author Jordi Boggiano * @phpstan-type Request array{url: non-empty-string, options: mixed[], copyTo: string|null} - * @phpstan-type Job array{id: int, status: int, request: Request, sync: bool, origin: string, resolve?: callable, reject?: callable, curl_id?: int, response?: Response, exception?: TransportException} + * @phpstan-type Job array{id: int, status: int, request: Request, sync: bool, origin: string, resolve?: callable, reject?: callable, curl_id?: int, response?: Response, exception?: \Throwable} */ class HttpDownloader { @@ -123,6 +123,7 @@ class HttpDownloader * although not all options are supported when using the default curl downloader * @throws TransportException * @return PromiseInterface + * @phpstan-return PromiseInterface */ public function add(string $url, array $options = []) { @@ -164,6 +165,7 @@ class HttpDownloader * although not all options are supported when using the default curl downloader * @throws TransportException * @return PromiseInterface + * @phpstan-return PromiseInterface */ public function addCopy(string $url, string $to, array $options = []) { @@ -199,6 +201,7 @@ class HttpDownloader /** * @phpstan-param Request $request * @return array{Job, PromiseInterface} + * @phpstan-return array{Job, PromiseInterface} */ private function addJob(array $request, bool $sync = false): array { diff --git a/src/Composer/Util/Loop.php b/src/Composer/Util/Loop.php index a1abed9a5..ca24e69b4 100644 --- a/src/Composer/Util/Loop.php +++ b/src/Composer/Util/Loop.php @@ -25,7 +25,7 @@ class Loop private $httpDownloader; /** @var ProcessExecutor|null */ private $processExecutor; - /** @var PromiseInterface[][] */ + /** @var array>> */ private $currentPromises = []; /** @var int */ private $waitIndex = 0; @@ -52,18 +52,17 @@ class Loop } /** - * @param PromiseInterface[] $promises - * @param ?ProgressBar $progress + * @param array> $promises + * @param ProgressBar|null $progress */ public function wait(array $promises, ?ProgressBar $progress = null): void { - /** @var \Exception|null */ $uncaught = null; \React\Promise\all($promises)->then( static function (): void { }, - static function ($e) use (&$uncaught): void { + static function (\Throwable $e) use (&$uncaught): void { $uncaught = $e; } ); @@ -107,7 +106,7 @@ class Loop } unset($this->currentPromises[$waitIndex]); - if ($uncaught) { + if (null !== $uncaught) { throw $uncaught; } } @@ -116,9 +115,8 @@ class Loop { foreach ($this->currentPromises as $promiseGroup) { foreach ($promiseGroup as $promise) { - if ($promise instanceof CancellablePromiseInterface) { - $promise->cancel(); - } + // to support react/promise 2.x we wrap the promise in a resolve() call for safety + \React\Promise\resolve($promise)->cancel(); } } } diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php index a8f69eceb..25e4c903b 100644 --- a/src/Composer/Util/ProcessExecutor.php +++ b/src/Composer/Util/ProcessExecutor.php @@ -155,6 +155,7 @@ class ProcessExecutor * * @param string|list $command the command to execute * @param string $cwd the working directory + * @phpstan-return PromiseInterface */ public function executeAsync($command, ?string $cwd = null): PromiseInterface { diff --git a/src/Composer/Util/SyncHelper.php b/src/Composer/Util/SyncHelper.php index ffb51af6d..9a7398cc0 100644 --- a/src/Composer/Util/SyncHelper.php +++ b/src/Composer/Util/SyncHelper.php @@ -58,6 +58,7 @@ class SyncHelper * Waits for a promise to resolve * * @param Loop $loop Loop instance which you can get from $composer->getLoop() + * @phpstan-param PromiseInterface|null $promise */ public static function await(Loop $loop, ?PromiseInterface $promise = null): void { diff --git a/tests/Composer/Test/Downloader/ZipDownloaderTest.php b/tests/Composer/Test/Downloader/ZipDownloaderTest.php index 56aa7a04d..ced6c0992 100644 --- a/tests/Composer/Test/Downloader/ZipDownloaderTest.php +++ b/tests/Composer/Test/Downloader/ZipDownloaderTest.php @@ -314,7 +314,7 @@ class ZipDownloaderTest extends TestCase } /** - * @param ?\React\Promise\PromiseInterface $promise + * @param ?\React\Promise\PromiseInterface $promise */ private function wait($promise): void { @@ -329,7 +329,7 @@ class ZipDownloaderTest extends TestCase $e = $ex; }); - if ($e) { + if ($e !== null) { throw $e; } } diff --git a/tests/Composer/Test/Util/ProcessExecutorTest.php b/tests/Composer/Test/Util/ProcessExecutorTest.php index c42f7de1d..a8455c7ab 100644 --- a/tests/Composer/Test/Util/ProcessExecutorTest.php +++ b/tests/Composer/Test/Util/ProcessExecutorTest.php @@ -120,7 +120,6 @@ class ProcessExecutorTest extends TestCase $process = new ProcessExecutor($buffer = new BufferIO('', StreamOutput::VERBOSITY_DEBUG)); $process->enableAsync(); $start = microtime(true); - /** @var Promise $promise */ $promise = $process->executeAsync('sleep 2'); $this->assertEquals(1, $process->countActiveJobs()); $promise->cancel();