diff --git a/composer.lock b/composer.lock index e7effec98..7d19af4f9 100644 --- a/composer.lock +++ b/composer.lock @@ -1825,16 +1825,16 @@ "packages-dev": [ { "name": "phpstan/phpstan", - "version": "1.6.2", + "version": "1.6.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "becb9603a31d70f5007d505877a7b812598dfe46" + "reference": "6128620b98292e0b69ea6d799871d77163681c8e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/becb9603a31d70f5007d505877a7b812598dfe46", - "reference": "becb9603a31d70f5007d505877a7b812598dfe46", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6128620b98292e0b69ea6d799871d77163681c8e", + "reference": "6128620b98292e0b69ea6d799871d77163681c8e", "shasum": "" }, "require": { @@ -1860,7 +1860,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.6.2" + "source": "https://github.com/phpstan/phpstan/tree/1.6.3" }, "funding": [ { @@ -1880,7 +1880,7 @@ "type": "tidelift" } ], - "time": "2022-04-27T11:05:24+00:00" + "time": "2022-04-28T11:27:53+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -1986,21 +1986,21 @@ }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "afbe1e3235c51ee3f10ba4c8b32449099016ea02" + "reference": "f3ca6464eae640a556c69a02b3b77a2507475d2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/afbe1e3235c51ee3f10ba4c8b32449099016ea02", - "reference": "afbe1e3235c51ee3f10ba4c8b32449099016ea02", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/f3ca6464eae640a556c69a02b3b77a2507475d2f", + "reference": "f3ca6464eae640a556c69a02b3b77a2507475d2f", "shasum": "" }, "require": { "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.6.0" + "phpstan/phpstan": "^1.6.3" }, "require-dev": { "nikic/php-parser": "^4.13.0", @@ -2028,9 +2028,9 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.2.0" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.2.1" }, - "time": "2022-04-21T13:07:43+00:00" + "time": "2022-04-28T07:20:18+00:00" }, { "name": "phpstan/phpstan-symfony", diff --git a/src/Composer/InstalledVersions.php b/src/Composer/InstalledVersions.php index 41bc143c1..c6b54af7b 100644 --- a/src/Composer/InstalledVersions.php +++ b/src/Composer/InstalledVersions.php @@ -28,7 +28,7 @@ class InstalledVersions { /** * @var mixed[]|null - * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}|array{}|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null */ private static $installed; @@ -39,7 +39,7 @@ class InstalledVersions /** * @var array[] - * @psalm-var array}> + * @psalm-var array}> */ private static $installedByVendor = array(); @@ -243,7 +243,7 @@ class InstalledVersions /** * @return array - * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} */ public static function getRootPackage() { @@ -257,7 +257,7 @@ class InstalledVersions * * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. * @return array[] - * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} */ public static function getRawData() { @@ -280,7 +280,7 @@ class InstalledVersions * Returns the raw data of all installed.php which are currently loaded for custom implementations * * @return array[] - * @psalm-return list}> + * @psalm-return list}> */ public static function getAllRawData() { @@ -303,7 +303,7 @@ class InstalledVersions * @param array[] $data A vendor/composer/installed.php data set * @return void * - * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} $data + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data */ public static function reload($data) { @@ -313,7 +313,7 @@ class InstalledVersions /** * @return array[] - * @psalm-return list}> + * @psalm-return list}> */ private static function getInstalled() { diff --git a/src/Composer/Repository/FilesystemRepository.php b/src/Composer/Repository/FilesystemRepository.php index cd677c18f..b811dbe79 100644 --- a/src/Composer/Repository/FilesystemRepository.php +++ b/src/Composer/Repository/FilesystemRepository.php @@ -14,6 +14,8 @@ namespace Composer\Repository; use Composer\Json\JsonFile; use Composer\Package\Loader\ArrayLoader; +use Composer\Package\PackageInterface; +use Composer\Package\RootAliasPackage; use Composer\Package\RootPackageInterface; use Composer\Package\AliasPackage; use Composer\Package\Dumper\ArrayDumper; @@ -207,25 +209,26 @@ class FilesystemRepository extends WritableArrayRepository /** * @param array $installPaths - * @param bool $devMode - * @param string $repoDir * - * @return ?array + * @return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} */ - private function generateInstalledVersions(InstallationManager $installationManager, array $installPaths, bool $devMode, string $repoDir): ?array + private function generateInstalledVersions(InstallationManager $installationManager, array $installPaths, bool $devMode, string $repoDir): array { - if (!$this->dumpVersions) { - return null; - } - $devPackages = array_flip($this->devPackageNames); - $versions = array('versions' => array()); $packages = $this->getPackages(); + if (null === $this->rootPackage) { + throw new \LogicException('It should not be possible to dump packages if no root package is given'); + } $packages[] = $rootPackage = $this->rootPackage; - while ($rootPackage instanceof AliasPackage) { + + while ($rootPackage instanceof RootAliasPackage) { $rootPackage = $rootPackage->getAliasOf(); $packages[] = $rootPackage; } + $versions = [ + 'root' => $this->dumpRootPackage($rootPackage, $installPaths, $devMode, $repoDir, $devPackages), + 'versions' => [], + ]; // add real installed packages foreach ($packages as $package) { @@ -233,36 +236,7 @@ class FilesystemRepository extends WritableArrayRepository continue; } - $reference = null; - if ($package->getInstallationSource()) { - $reference = $package->getInstallationSource() === 'source' ? $package->getSourceReference() : $package->getDistReference(); - } - if (null === $reference) { - $reference = ($package->getSourceReference() ?: $package->getDistReference()) ?: null; - } - - if ($package instanceof RootPackageInterface) { - $to = $this->filesystem->normalizePath(realpath(Platform::getCwd())); - $installPath = $this->filesystem->findShortestPath($repoDir, $to, true); - } else { - $installPath = $installPaths[$package->getName()]; - } - - $versions['versions'][$package->getName()] = array( - 'pretty_version' => $package->getPrettyVersion(), - 'version' => $package->getVersion(), - 'type' => $package->getType(), - 'install_path' => $installPath, - 'aliases' => array(), - 'reference' => $reference, - 'dev_requirement' => isset($devPackages[$package->getName()]), - ); - if ($package instanceof RootPackageInterface) { - $versions['root'] = $versions['versions'][$package->getName()]; - unset($versions['root']['dev_requirement']); - $versions['root']['name'] = $package->getName(); - $versions['root']['dev'] = $devMode; - } + $versions['versions'][$package->getName()] = $this->dumpInstalledPackage($package, $installPaths, $repoDir, $devPackages); } // add provided/replaced packages @@ -322,4 +296,60 @@ class FilesystemRepository extends WritableArrayRepository return $versions; } + + /** + * @param array $installPaths + * @param array $devPackages + * @return array{pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev_requirement: bool} + */ + private function dumpInstalledPackage(PackageInterface $package, array $installPaths, string $repoDir, array $devPackages): array + { + $reference = null; + if ($package->getInstallationSource()) { + $reference = $package->getInstallationSource() === 'source' ? $package->getSourceReference() : $package->getDistReference(); + } + if (null === $reference) { + $reference = ($package->getSourceReference() ?: $package->getDistReference()) ?: null; + } + + if ($package instanceof RootPackageInterface) { + $to = $this->filesystem->normalizePath(realpath(Platform::getCwd())); + $installPath = $this->filesystem->findShortestPath($repoDir, $to, true); + } else { + $installPath = $installPaths[$package->getName()]; + } + + $data = [ + 'pretty_version' => $package->getPrettyVersion(), + 'version' => $package->getVersion(), + 'reference' => $reference, + 'type' => $package->getType(), + 'install_path' => $installPath, + 'aliases' => array(), + 'dev_requirement' => isset($devPackages[$package->getName()]), + ]; + + return $data; + } + + /** + * @param array $installPaths + * @param array $devPackages + * @return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + private function dumpRootPackage(RootPackageInterface $package, array $installPaths, bool $devMode, string $repoDir, array $devPackages) + { + $data = $this->dumpInstalledPackage($package, $installPaths, $repoDir, $devPackages); + + return [ + 'name' => $package->getName(), + 'pretty_version' => $data['pretty_version'], + 'version' => $data['version'], + 'reference' => $data['reference'], + 'type' => $data['type'], + 'install_path' => $data['install_path'], + 'aliases' => $data['aliases'], + 'dev' => $devMode, + ]; + } } diff --git a/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilterTest.php b/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilterTest.php index 239c954c1..fa4f32fdf 100644 --- a/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilterTest.php +++ b/tests/Composer/Test/Filter/PlatformRequirementFilter/IgnoreNothingPlatformRequirementFilterTest.php @@ -26,7 +26,7 @@ final class IgnoreNothingPlatformRequirementFilterTest extends TestCase { $platformRequirementFilter = new IgnoreNothingPlatformRequirementFilter(); - $this->assertFalse($platformRequirementFilter->isIgnored($req)); + $this->assertFalse($platformRequirementFilter->isIgnored($req)); // @phpstan-ignore-line } /** diff --git a/tests/Composer/Test/InstalledVersionsTest.php b/tests/Composer/Test/InstalledVersionsTest.php index 9e06f4c2c..0268d7cc5 100644 --- a/tests/Composer/Test/InstalledVersionsTest.php +++ b/tests/Composer/Test/InstalledVersionsTest.php @@ -215,15 +215,15 @@ class InstalledVersionsTest extends TestCase public function testGetRootPackage(): void { $this->assertSame(array( + 'name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', + 'reference' => 'sourceref-by-default', 'type' => 'library', 'install_path' => $this->root . '/./', 'aliases' => array( '1.10.x-dev', ), - 'reference' => 'sourceref-by-default', - 'name' => '__root__', 'dev' => true, ), InstalledVersions::getRootPackage()); } diff --git a/tests/Composer/Test/Json/JsonFileTest.php b/tests/Composer/Test/Json/JsonFileTest.php index 8e79fad6b..8f07eee57 100644 --- a/tests/Composer/Test/Json/JsonFileTest.php +++ b/tests/Composer/Test/Json/JsonFileTest.php @@ -92,9 +92,11 @@ class JsonFileTest extends TestCase public function testSchemaValidation(): void { + self::expectNotToPerformAssertions(); + $json = new JsonFile(__DIR__.'/Fixtures/composer.json'); - $this->assertTrue($json->validateSchema()); - $this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA)); + $json->validateSchema(); + $json->validateSchema(JsonFile::LAX_SCHEMA); } public function testSchemaValidationError(): void @@ -133,7 +135,7 @@ class JsonFileTest extends TestCase $this->assertEquals(sprintf('"%s" does not match the expected JSON schema', $file), $e->getMessage()); $this->assertEquals(array('The property foo is not defined and the definition does not allow additional properties'), $e->getErrors()); } - $this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA)); + $json->validateSchema(JsonFile::LAX_SCHEMA); unlink($file); } @@ -154,7 +156,7 @@ class JsonFileTest extends TestCase $this->assertContains('name : The property name is required', $errors); $this->assertContains('description : The property description is required', $errors); } - $this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA)); + $json->validateSchema(JsonFile::LAX_SCHEMA); file_put_contents($file, '{ "name": "vendor/package" }'); try { @@ -164,7 +166,7 @@ class JsonFileTest extends TestCase $this->assertEquals($expectedMessage, $e->getMessage()); $this->assertEquals(array('description : The property description is required'), $e->getErrors()); } - $this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA)); + $json->validateSchema(JsonFile::LAX_SCHEMA); file_put_contents($file, '{ "description": "generic description" }'); try { @@ -174,7 +176,7 @@ class JsonFileTest extends TestCase $this->assertEquals($expectedMessage, $e->getMessage()); $this->assertEquals(array('name : The property name is required'), $e->getErrors()); } - $this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA)); + $json->validateSchema(JsonFile::LAX_SCHEMA); file_put_contents($file, '{ "type": "library" }'); try { @@ -186,7 +188,7 @@ class JsonFileTest extends TestCase $this->assertContains('name : The property name is required', $errors); $this->assertContains('description : The property description is required', $errors); } - $this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA)); + $json->validateSchema(JsonFile::LAX_SCHEMA); file_put_contents($file, '{ "type": "project" }'); try { @@ -198,17 +200,18 @@ class JsonFileTest extends TestCase $this->assertContains('name : The property name is required', $errors); $this->assertContains('description : The property description is required', $errors); } - $this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA)); + $json->validateSchema(JsonFile::LAX_SCHEMA); file_put_contents($file, '{ "name": "vendor/package", "description": "generic description" }'); - $this->assertTrue($json->validateSchema()); - $this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA)); + $json->validateSchema(); + $json->validateSchema(JsonFile::LAX_SCHEMA); unlink($file); } public function testCustomSchemaValidationLax(): void { + self::expectNotToPerformAssertions(); $file = $this->createTempFile(); file_put_contents($file, '{ "custom": "property", "another custom": "property" }'); @@ -217,7 +220,7 @@ class JsonFileTest extends TestCase $json = new JsonFile($file); - $this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA, $schema)); + $json->validateSchema(JsonFile::LAX_SCHEMA, $schema); unlink($file); unlink($schema); @@ -225,6 +228,7 @@ class JsonFileTest extends TestCase public function testCustomSchemaValidationStrict(): void { + self::expectNotToPerformAssertions(); $file = $this->createTempFile(); file_put_contents($file, '{ "custom": "property" }'); @@ -233,7 +237,7 @@ class JsonFileTest extends TestCase $json = new JsonFile($file); - $this->assertTrue($json->validateSchema(JsonFile::STRICT_SCHEMA, $schema)); + $json->validateSchema(JsonFile::STRICT_SCHEMA, $schema); unlink($file); unlink($schema); diff --git a/tests/Composer/Test/Repository/FilesystemRepositoryTest.php b/tests/Composer/Test/Repository/FilesystemRepositoryTest.php index e16938334..3e5409853 100644 --- a/tests/Composer/Test/Repository/FilesystemRepositoryTest.php +++ b/tests/Composer/Test/Repository/FilesystemRepositoryTest.php @@ -132,11 +132,10 @@ class FilesystemRepositoryTest extends TestCase $json = new JsonFile($dir.'/installed.json'); - $rootPackage = $this->getPackage('__root__', 'dev-master', 'Composer\Package\RootPackage'); + $rootPackage = $this->getRootPackage('__root__', 'dev-master'); $rootPackage->setSourceReference('sourceref-by-default'); $rootPackage->setDistReference('distref'); $this->configureLinks($rootPackage, array('provide' => array('foo/impl' => '2.0'))); - /** @var RootAliasPackage $rootPackage */ $rootPackage = $this->getAliasPackage($rootPackage, '1.10.x-dev'); $repository = new FilesystemRepository($json, true, $rootPackage); diff --git a/tests/Composer/Test/Repository/Fixtures/installed.php b/tests/Composer/Test/Repository/Fixtures/installed.php index fb9870def..cd918997c 100644 --- a/tests/Composer/Test/Repository/Fixtures/installed.php +++ b/tests/Composer/Test/Repository/Fixtures/installed.php @@ -12,70 +12,70 @@ return array( 'root' => array( + 'name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', + 'reference' => 'sourceref-by-default', 'type' => 'library', // @phpstan-ignore-next-line 'install_path' => $dir . '/./', 'aliases' => array( '1.10.x-dev', ), - 'reference' => 'sourceref-by-default', - 'name' => '__root__', 'dev' => true, ), 'versions' => array( '__root__' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', + 'reference' => 'sourceref-by-default', 'type' => 'library', // @phpstan-ignore-next-line 'install_path' => $dir . '/./', 'aliases' => array( '1.10.x-dev', ), - 'reference' => 'sourceref-by-default', 'dev_requirement' => false, ), 'a/provider' => array( 'pretty_version' => '1.1', 'version' => '1.1.0.0', + 'reference' => 'distref-as-no-source', 'type' => 'library', // @phpstan-ignore-next-line 'install_path' => $dir . '/vendor/a/provider', 'aliases' => array(), - 'reference' => 'distref-as-no-source', 'dev_requirement' => false, ), 'a/provider2' => array( 'pretty_version' => '1.2', 'version' => '1.2.0.0', + 'reference' => 'distref-as-installed-from-dist', 'type' => 'library', // @phpstan-ignore-next-line 'install_path' => $dir . '/vendor/a/provider2', 'aliases' => array( '1.4', ), - 'reference' => 'distref-as-installed-from-dist', 'dev_requirement' => false, ), 'b/replacer' => array( 'pretty_version' => '2.2', 'version' => '2.2.0.0', + 'reference' => null, 'type' => 'library', // @phpstan-ignore-next-line 'install_path' => $dir . '/vendor/b/replacer', 'aliases' => array(), - 'reference' => null, 'dev_requirement' => false, ), 'c/c' => array( 'pretty_version' => '3.0', 'version' => '3.0.0.0', + 'reference' => null, 'type' => 'library', 'install_path' => '/foo/bar/vendor/c/c', 'aliases' => array(), - 'reference' => null, 'dev_requirement' => true, ), 'foo/impl' => array( @@ -105,10 +105,10 @@ return array( 'meta/package' => array( 'pretty_version' => '3.0', 'version' => '3.0.0.0', + 'reference' => null, 'type' => 'metapackage', 'install_path' => null, 'aliases' => array(), - 'reference' => null, 'dev_requirement' => false, ) ), diff --git a/tests/Composer/Test/TestCase.php b/tests/Composer/Test/TestCase.php index ff04e79d1..8b727f4bc 100644 --- a/tests/Composer/Test/TestCase.php +++ b/tests/Composer/Test/TestCase.php @@ -141,7 +141,7 @@ abstract class TestCase extends \PHPUnit\Framework\TestCase /** * @param string $version - * @return AliasPackage|RootAliasPackage|CompleteAliasPackage + * @return ($package is RootPackage ? RootAliasPackage : ($package is CompletePackage ? CompleteAliasPackage : AliasPackage)) */ protected function getAliasPackage(Package $package, string $version): AliasPackage {