diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 62d1ac7f74fa..ed2e6cf2bae8 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -71,7 +71,7 @@ 'random_api_migration' => true, 'ternary_to_null_coalescing' => true, 'phpdoc_to_param_type' => true, - //'declare_strict_types' => true, + 'declare_strict_types' => true, // TODO php 7.4 migration (one day..) // 'phpdoc_to_property_type' => true, diff --git a/phpstan/baseline-8.1.neon b/phpstan/baseline-8.1.neon index 792be138f133..ee7346d3a8bd 100644 --- a/phpstan/baseline-8.1.neon +++ b/phpstan/baseline-8.1.neon @@ -130,11 +130,6 @@ parameters: count: 1 path: ../src/Composer/EventDispatcher/EventDispatcher.php - - - message: "#^Parameter \\#1 \\$string of function trim expects string, string\\|false given\\.$#" - count: 1 - path: ../src/Composer/Factory.php - - message: "#^Parameter \\#1 \\$stream of function fwrite expects resource, resource\\|false given\\.$#" count: 1 @@ -215,31 +210,6 @@ parameters: count: 1 path: ../src/Composer/Util/AuthHelper.php - - - message: "#^Parameter \\#1 \\$from of function stream_copy_to_stream expects resource, resource\\|false given\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#" - count: 4 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Parameter \\#1 \\$stream of function feof expects resource, resource\\|false given\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Parameter \\#1 \\$stream of function fread expects resource, resource\\|false given\\.$#" - count: 2 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Parameter \\#2 \\$to of function stream_copy_to_stream expects resource, resource\\|false given\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - message: "#^Parameter \\#1 \\$string of function rawurlencode expects string, string\\|null given\\.$#" count: 15 diff --git a/phpstan/baseline.neon b/phpstan/baseline.neon index f2e9f63da0e2..7eced10576a5 100644 --- a/phpstan/baseline.neon +++ b/phpstan/baseline.neon @@ -1575,11 +1575,6 @@ parameters: count: 1 path: ../src/Composer/Console/Application.php - - - message: "#^Only booleans are allowed in a negated boolean, string given\\.$#" - count: 1 - path: ../src/Composer/Console/Application.php - - message: "#^Only booleans are allowed in a negated boolean, string\\|false given\\.$#" count: 2 @@ -1595,11 +1590,6 @@ parameters: count: 1 path: ../src/Composer/Console/Application.php - - - message: "#^Only booleans are allowed in an if condition, string given\\.$#" - count: 1 - path: ../src/Composer/Console/Application.php - - message: "#^Only booleans are allowed in an if condition, string\\|null given\\.$#" count: 2 @@ -2295,11 +2285,6 @@ parameters: count: 1 path: ../src/Composer/Downloader/FileDownloader.php - - - message: "#^Parameter \\#1 \\$url of function parse_url expects string, string\\|null given\\.$#" - count: 2 - path: ../src/Composer/Downloader/FileDownloader.php - - message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#" count: 4 @@ -2395,11 +2380,6 @@ parameters: count: 1 path: ../src/Composer/Downloader/GzipDownloader.php - - - message: "#^Parameter \\#1 \\$url of function parse_url expects string, string\\|null given\\.$#" - count: 1 - path: ../src/Composer/Downloader/GzipDownloader.php - - message: "#^Parameter \\#1 \\$zp of function gzclose expects resource, resource\\|false given\\.$#" count: 1 @@ -3515,11 +3495,6 @@ parameters: count: 10 path: ../src/Composer/Package/Loader/ArrayLoader.php - - - message: "#^Instanceof between Composer\\\\Package\\\\CompletePackage and Composer\\\\Package\\\\CompletePackage will always evaluate to true\\.$#" - count: 1 - path: ../src/Composer/Package/Loader/ArrayLoader.php - - message: "#^Instanceof between Composer\\\\Package\\\\CompletePackage and Composer\\\\Package\\\\CompletePackageInterface will always evaluate to true\\.$#" count: 1 @@ -3555,11 +3530,6 @@ parameters: count: 1 path: ../src/Composer/Package/Loader/ArrayLoader.php - - - message: "#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#" - count: 1 - path: ../src/Composer/Package/Loader/JsonLoader.php - - message: "#^Parameter \\#1 \\$json of static method Composer\\\\Json\\\\JsonFile\\:\\:parseJson\\(\\) expects string\\|null, string\\|false given\\.$#" count: 1 @@ -4305,16 +4275,6 @@ parameters: count: 1 path: ../src/Composer/Repository/FilesystemRepository.php - - - message: "#^Call to function is_array\\(\\) with array\\ will always evaluate to true\\.$#" - count: 2 - path: ../src/Composer/Repository/FilterRepository.php - - - - message: "#^Call to function is_bool\\(\\) with bool will always evaluate to true\\.$#" - count: 1 - path: ../src/Composer/Repository/FilterRepository.php - - message: "#^Only booleans are allowed in &&, string\\|null given on the left side\\.$#" count: 1 @@ -4503,11 +4463,6 @@ parameters: count: 1 path: ../src/Composer/Repository/RepositoryFactory.php - - - message: "#^Parameter \\#3 \\$name of method Composer\\\\Repository\\\\RepositoryManager\\:\\:createRepository\\(\\) expects string\\|null, int\\|string given\\.$#" - count: 1 - path: ../src/Composer/Repository/RepositoryFactory.php - - message: "#^Only booleans are allowed in an if condition, Composer\\\\Package\\\\BasePackage\\|null given\\.$#" count: 1 @@ -4793,21 +4748,11 @@ parameters: count: 3 path: ../src/Composer/Repository/Vcs/GitLabDriver.php - - - message: "#^Parameter \\#1 \\$haystack of function strpos expects string, string\\|false given\\.$#" - count: 2 - path: ../src/Composer/Repository/Vcs/GitLabDriver.php - - message: "#^Parameter \\#2 \\$str of function explode expects string, string\\|null given\\.$#" count: 1 path: ../src/Composer/Repository/Vcs/GitLabDriver.php - - - message: "#^Property Composer\\\\Repository\\\\Vcs\\\\VcsDriver\\:\\:\\$originUrl \\(string\\) does not accept string\\|false\\.$#" - count: 1 - path: ../src/Composer/Repository/Vcs/GitLabDriver.php - - message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#" count: 2 @@ -5183,96 +5128,11 @@ parameters: count: 1 path: ../src/Composer/Util/ErrorHandler.php - - - message: "#^Cannot call method getPathname\\(\\) on SplFileInfo\\|string\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Cannot call method isDir\\(\\) on SplFileInfo\\|string\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - message: "#^Casting to string something that's already string\\.$#" - count: 2 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Method Composer\\\\Util\\\\Filesystem\\:\\:size\\(\\) should return int but returns int\\<0, max\\>\\|false\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Offset 'message' does not exist on array\\{type\\: int, message\\: string, file\\: string, line\\: int\\}\\|null\\.$#" - count: 2 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Only booleans are allowed in a negated boolean, Composer\\\\Util\\\\ProcessExecutor\\|null given\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Only booleans are allowed in a negated boolean, int\\<0, max\\> given\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Only booleans are allowed in a negated boolean, string\\|false given\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Only booleans are allowed in a ternary operator condition, array\\\\|false given\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Only booleans are allowed in a ternary operator condition, int\\<0, max\\> given\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Only numeric types are allowed in \\+, bool given on the right side\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Parameter \\#1 \\$fp of function fclose expects resource, resource\\|false given\\.$#" count: 4 path: ../src/Composer/Util/Filesystem.php - - - message: "#^Parameter \\#1 \\$fp of function feof expects resource, resource\\|false given\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Parameter \\#1 \\$fp of function fread expects resource, resource\\|false given\\.$#" - count: 2 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Parameter \\#1 \\$source of function stream_copy_to_stream expects resource, resource\\|false given\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Parameter \\#2 \\$dest of function stream_copy_to_stream expects resource, resource\\|false given\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - - - message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#" - count: 1 - path: ../src/Composer/Util/Filesystem.php - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" count: 1 @@ -5385,7 +5245,7 @@ parameters: - message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#" - count: 4 + count: 3 path: ../src/Composer/Util/Http/CurlDownloader.php - @@ -6283,11 +6143,6 @@ parameters: count: 1 path: ../tests/Composer/Test/AllFunctionalTest.php - - - message: "#^Method Composer\\\\Test\\\\AllFunctionalTest\\:\\:getTestFiles\\(\\) should return array\\\\> but returns array\\\\>\\.$#" - count: 1 - path: ../tests/Composer/Test/AllFunctionalTest.php - - message: "#^Only booleans are allowed in an if condition, string\\|false given\\.$#" count: 1 @@ -6438,11 +6293,6 @@ parameters: count: 1 path: ../tests/Composer/Test/DependencyResolver/PoolBuilderTest.php - - - message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" - count: 1 - path: ../tests/Composer/Test/DependencyResolver/PoolBuilderTest.php - - message: "#^Parameter \\#2 \\$fixturesDir of method Composer\\\\Test\\\\DependencyResolver\\\\PoolBuilderTest\\:\\:readTestFile\\(\\) expects string, string\\|false given\\.$#" count: 1 @@ -6458,11 +6308,6 @@ parameters: count: 1 path: ../tests/Composer/Test/DependencyResolver/PoolBuilderTest.php - - - message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, array\\|string given\\.$#" - count: 2 - path: ../tests/Composer/Test/DependencyResolver/PoolBuilderTest.php - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" count: 1 @@ -6478,11 +6323,6 @@ parameters: count: 1 path: ../tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php - - - message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" - count: 1 - path: ../tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php - - message: "#^Parameter \\#2 \\$fixturesDir of method Composer\\\\Test\\\\DependencyResolver\\\\PoolOptimizerTest\\:\\:readTestFile\\(\\) expects string, string\\|false given\\.$#" count: 1 @@ -6493,11 +6333,6 @@ parameters: count: 1 path: ../tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php - - - message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, array\\|string given\\.$#" - count: 2 - path: ../tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php - - message: "#^Parameter \\#1 \\$packages of class Composer\\\\DependencyResolver\\\\Pool constructor expects array\\, array\\\\|null given\\.$#" count: 1 @@ -6696,11 +6531,6 @@ parameters: count: 1 path: ../tests/Composer/Test/InstallerTest.php - - - message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" - count: 1 - path: ../tests/Composer/Test/InstallerTest.php - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false\\|null given\\.$#" count: 1 @@ -6726,11 +6556,6 @@ parameters: count: 1 path: ../tests/Composer/Test/InstallerTest.php - - - message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, array\\|string given\\.$#" - count: 2 - path: ../tests/Composer/Test/InstallerTest.php - - message: "#^Parameter \\#4 \\$composerFileContents of class Composer\\\\Package\\\\Locker constructor expects string, string\\|false given\\.$#" count: 1 @@ -6791,11 +6616,6 @@ parameters: count: 1 path: ../tests/Composer/Test/Mock/ProcessExecutorMock.php - - - message: "#^Offset 'return' on array\\{return\\: int, stdout\\?\\: string, stderr\\?\\: string\\} on left side of \\?\\? always exists and is not nullable\\.$#" - count: 1 - path: ../tests/Composer/Test/Mock/ProcessExecutorMock.php - - message: "#^Offset 'stderr' does not exist on array\\{cmd\\: array\\\\|string, return\\?\\: int, stdout\\?\\: string, stderr\\?\\: string, callback\\?\\: callable\\(\\)\\: mixed\\}\\.$#" count: 1 diff --git a/phpstan/config.neon b/phpstan/config.neon index e5469b6a7364..5ac2cd37b1ca 100644 --- a/phpstan/config.neon +++ b/phpstan/config.neon @@ -17,6 +17,7 @@ parameters: - '../tests/Composer/Test/PolyfillTestCase.php' reportUnmatchedIgnoredErrors: false + treatPhpDocTypesAsCertain: false ignoreErrors: # unused parameters diff --git a/phpstan/ignore-by-php-version.neon.php b/phpstan/ignore-by-php-version.neon.php index a88d63bced28..21212110c723 100644 --- a/phpstan/ignore-by-php-version.neon.php +++ b/phpstan/ignore-by-php-version.neon.php @@ -1,14 +1,12 @@ = 80000) { - $config = array_merge_recursive($config, $adapter->load(__DIR__ . '/baseline-8.1.neon')); + $includes[] = __DIR__ . '/baseline-8.1.neon'; } + +$config['includes'] = $includes; $config['parameters']['phpVersion'] = PHP_VERSION_ID; return $config; diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 5485565e0dd0..ffb0cd83cfa5 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -1,4 +1,4 @@ - $packageMap - * @param bool $checkPlatform + * @param bool|'php-only' $checkPlatform * @param string[] $devPackageNames * @return ?string */ - protected function getPlatformCheck(array $packageMap, bool $checkPlatform, array $devPackageNames) + protected function getPlatformCheck(array $packageMap, $checkPlatform, array $devPackageNames) { $lowestPhpVersion = Bound::zero(); $requiredExtensions = array(); diff --git a/src/Composer/Autoload/ClassMapGenerator.php b/src/Composer/Autoload/ClassMapGenerator.php index 84f946440963..fa687d101f3a 100644 --- a/src/Composer/Autoload/ClassMapGenerator.php +++ b/src/Composer/Autoload/ClassMapGenerator.php @@ -1,4 +1,4 @@ -removeDirectory($dir)) { + if (!$fs->removeDirectory((string) $dir)) { throw new \RuntimeException('Could not remove '.$dir); } } diff --git a/src/Composer/Command/DependsCommand.php b/src/Composer/Command/DependsCommand.php index 54fda17a598c..0dbbb03f2cf7 100644 --- a/src/Composer/Command/DependsCommand.php +++ b/src/Composer/Command/DependsCommand.php @@ -1,4 +1,4 @@ -getBasename(self::OLD_INSTALL_EXT); } return false; diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php index 8b11a8e33156..b115a7f88cce 100644 --- a/src/Composer/Command/ShowCommand.php +++ b/src/Composer/Command/ShowCommand.php @@ -1,4 +1,4 @@ -getRealPath(), $extraFiles, true))) { + unset($extraFiles[$index]); + } elseif (!Preg::isMatch('{(^LICENSE$|\.php$)}', $file->getFilename())) { $unexpectedFiles[] = (string) $file; } - if (Preg::isMatch('{\.php[\d.]*$}', $file)) { + if (Preg::isMatch('{\.php[\d.]*$}', $file->getFilename())) { $this->addFile($phar, $file); } else { $this->addFile($phar, $file, false); @@ -220,10 +220,10 @@ private function getRelativeFilePath(\SplFileInfo $file): string private function addFile(\Phar $phar, \SplFileInfo $file, bool $strip = true): void { $path = $this->getRelativeFilePath($file); - $content = file_get_contents($file); + $content = file_get_contents((string) $file); if ($strip) { $content = $this->stripWhitespace($content); - } elseif ('LICENSE' === basename($file)) { + } elseif ('LICENSE' === $file->getFilename()) { $content = "\n".$content."\n"; } diff --git a/src/Composer/Composer.php b/src/Composer/Composer.php index a4b769ee2207..93e8c0a6f5d6 100644 --- a/src/Composer/Composer.php +++ b/src/Composer/Composer.php @@ -1,4 +1,4 @@ -getNewWorkingDir($input)) { + $newWorkDir = $this->getNewWorkingDir($input); + if (null !== $newWorkDir) { $oldWorkingDir = Platform::getCwd(true); chdir($newWorkDir); $this->initialWorkingDirectory = $newWorkDir; @@ -171,7 +172,7 @@ public function doRun(InputInterface $input, OutputInterface $output): int } // prompt user for dir change if no composer.json is present in current dir - if ($io->isInteractive() && !$newWorkDir && !in_array($commandName, array('', 'list', 'init', 'about', 'help', 'diagnose', 'self-update', 'global', 'create-project', 'outdated'), true) && !file_exists(Factory::getComposerFile()) && ($useParentDirIfNoJsonAvailable = $this->getUseParentDirConfigValue()) !== false) { + if ($io->isInteractive() && null === $newWorkDir && !in_array($commandName, array('', 'list', 'init', 'about', 'help', 'diagnose', 'self-update', 'global', 'create-project', 'outdated'), true) && !file_exists(Factory::getComposerFile()) && ($useParentDirIfNoJsonAvailable = $this->getUseParentDirConfigValue()) !== false) { $dir = dirname(Platform::getCwd(true)); $home = realpath(Platform::getEnv('HOME') ?: Platform::getEnv('USERPROFILE') ?: '/'); @@ -357,12 +358,13 @@ function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknow /** * @param InputInterface $input * @throws \RuntimeException - * @return string + * @return ?string */ - private function getNewWorkingDir(InputInterface $input): string + private function getNewWorkingDir(InputInterface $input): ?string { - $workingDir = $input->getParameterOption(array('--working-dir', '-d')); - if (false !== $workingDir && !is_dir($workingDir)) { + /** @var string|null $workingDir */ + $workingDir = $input->getParameterOption(array('--working-dir', '-d'), null, true); + if (null !== $workingDir && !is_dir($workingDir)) { throw new \RuntimeException('Invalid working directory specified, '.$workingDir.' does not exist.'); } diff --git a/src/Composer/Console/GithubActionError.php b/src/Composer/Console/GithubActionError.php index d73b55851618..7489a9a389ef 100644 --- a/src/Composer/Console/GithubActionError.php +++ b/src/Composer/Console/GithubActionError.php @@ -1,4 +1,4 @@ -filesystem->emptyDirectory($path); $this->filesystem->ensureDirectoryExists($path); - $this->filesystem->rename($this->getFileName($package, $path), $path . '/' . pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME)); + $this->filesystem->rename($this->getFileName($package, $path), $path . '/' . pathinfo(parse_url(strtr((string) $package->getDistUrl(), '\\', '/'), PHP_URL_PATH), PATHINFO_BASENAME)); if ($package->getBinaries()) { // Single files can not have a mode set like files in archives @@ -436,7 +436,7 @@ public function remove(PackageInterface $package, string $path, bool $output = t */ protected function getFileName(PackageInterface $package, string $path): string { - return rtrim($this->config->get('vendor-dir').'/composer/tmp-'.md5($package.spl_object_hash($package)).'.'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_EXTENSION), '.'); + return rtrim($this->config->get('vendor-dir').'/composer/tmp-'.md5($package.spl_object_hash($package)).'.'.pathinfo(parse_url(strtr((string) $package->getDistUrl(), '\\', '/'), PHP_URL_PATH), PATHINFO_EXTENSION), '.'); } /** diff --git a/src/Composer/Downloader/FilesystemException.php b/src/Composer/Downloader/FilesystemException.php index f9d4e6fbece4..5aff2f089bb5 100644 --- a/src/Composer/Downloader/FilesystemException.php +++ b/src/Composer/Downloader/FilesystemException.php @@ -1,4 +1,4 @@ -getDistUrl(), PHP_URL_PATH), PATHINFO_FILENAME); + $filename = pathinfo(parse_url(strtr((string) $package->getDistUrl(), '\\', '/'), PHP_URL_PATH), PATHINFO_FILENAME); $targetFilepath = $path . DIRECTORY_SEPARATOR . $filename; // Try to use gunzip on *nix diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php index 0537103b1073..c32375c970be 100644 --- a/src/Composer/Downloader/HgDownloader.php +++ b/src/Composer/Downloader/HgDownloader.php @@ -1,4 +1,4 @@ -writeError(''.$message.''); } elseif ($level === LogLevel::WARNING) { diff --git a/src/Composer/IO/BufferIO.php b/src/Composer/IO/BufferIO.php index 0e9b44a2594f..ecbb4a3032de 100644 --- a/src/Composer/IO/BufferIO.php +++ b/src/Composer/IO/BufferIO.php @@ -1,4 +1,4 @@ -valid(); } diff --git a/src/Composer/Package/Archiver/ArchiveManager.php b/src/Composer/Package/Archiver/ArchiveManager.php index c7f5def613b1..75d010a1eb6c 100644 --- a/src/Composer/Package/Archiver/ArchiveManager.php +++ b/src/Composer/Package/Archiver/ArchiveManager.php @@ -1,4 +1,4 @@ -flags & self::CHECK_STRICT_CONSTRAINTS) && 'require' === $linkType - && strpos($linkConstraint, '=') === 0 - && $stableConstraint->versionCompare($stableConstraint, $linkConstraint, '<=') + && $linkConstraint instanceof Constraint && in_array($linkConstraint->getOperator(), ['==', '='], true) + && (new Constraint('>=', '1.0.0.0-dev'))->matches($linkConstraint) ) { $this->warnings[] = $linkType.'.'.$package.' : exact version constraints ('.$constraint.') should be avoided if the package follows semantic versioning'; } diff --git a/src/Composer/Package/Locker.php b/src/Composer/Package/Locker.php index 6dc77cf5bfad..bb780bb54fef 100644 --- a/src/Composer/Package/Locker.php +++ b/src/Composer/Package/Locker.php @@ -1,4 +1,4 @@ -url); + $jsonUrlParts = parse_url(strtr($this->url, '\\', '/')); if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '.json')) { return $this->url; diff --git a/src/Composer/Repository/CompositeRepository.php b/src/Composer/Repository/CompositeRepository.php index 3d31aa1debdc..d10815c35730 100644 --- a/src/Composer/Repository/CompositeRepository.php +++ b/src/Composer/Repository/CompositeRepository.php @@ -1,4 +1,4 @@ - (?\d+)$/im', $info, $libxpmMatches)) { - $this->addLibrary($name.'-libxpm', Version::convertLibxpmVersionId($libxpmMatches['versionId']), 'libxpm version for gd'); + $this->addLibrary($name.'-libxpm', Version::convertLibxpmVersionId((int) $libxpmMatches['versionId']), 'libxpm version for gd'); } break; @@ -363,7 +363,7 @@ protected function initialize(): void $info = $this->runtime->getExtensionInfo($name); if (Preg::isMatch('/^Vendor Version => (?\d+)$/im', $info, $matches) && Preg::isMatch('/^Vendor Name => (?.+)$/im', $info, $vendorMatches)) { - $this->addLibrary($name.'-'.strtolower($vendorMatches['vendor']), Version::convertOpenldapVersionId($matches['versionId']), $vendorMatches['vendor'].' version of ldap'); + $this->addLibrary($name.'-'.strtolower($vendorMatches['vendor']), Version::convertOpenldapVersionId((int) $matches['versionId']), $vendorMatches['vendor'].' version of ldap'); } break; diff --git a/src/Composer/Repository/RepositoryFactory.php b/src/Composer/Repository/RepositoryFactory.php index 80e03eff89c3..b31f77530689 100644 --- a/src/Composer/Repository/RepositoryFactory.php +++ b/src/Composer/Repository/RepositoryFactory.php @@ -1,4 +1,4 @@ -createRepository($repo['type'], $repo, $index); + $repos[$name] = $rm->createRepository($repo['type'], $repo, (string) $index); } } diff --git a/src/Composer/Repository/RepositoryInterface.php b/src/Composer/Repository/RepositoryInterface.php index 129a0949879a..9b612f610890 100644 --- a/src/Composer/Repository/RepositoryInterface.php +++ b/src/Composer/Repository/RepositoryInterface.php @@ -1,4 +1,4 @@ -repoConfig['secure-http']) && $this->repoConfig['secure-http'] === false ? 'http' : 'https') ; - $this->originUrl = self::determineOrigin($configuredDomains, $guessedDomain, $urlParts, $match['port']); + $origin = self::determineOrigin($configuredDomains, $guessedDomain, $urlParts, $match['port']); + if (false === $origin) { + throw new \LogicException('It should not be possible to create a gitlab driver with an unparseable origin URL ('.$this->url.')'); + } + $this->originUrl = $origin; if ($protocol = $this->config->get('gitlab-protocol')) { // https treated as a synonym for http. diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php index 1faa3c3e3b55..70f69cbb3a1a 100644 --- a/src/Composer/Repository/Vcs/HgDriver.php +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -1,4 +1,4 @@ -ensureDirectoryExists($target); $result = true; - /** @var RecursiveDirectoryIterator $ri */ foreach ($ri as $file) { $targetPath = $target . DIRECTORY_SEPARATOR . $ri->getSubPathname(); if ($file->isDir()) { @@ -451,8 +450,8 @@ public function findShortestPath(string $from, string $to, bool $directories = f throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to)); } - $from = lcfirst($this->normalizePath($from)); - $to = lcfirst($this->normalizePath($to)); + $from = $this->normalizePath($from); + $to = $this->normalizePath($to); if ($directories) { $from = rtrim($from, '/') . '/dummy_file'; @@ -463,7 +462,7 @@ public function findShortestPath(string $from, string $to, bool $directories = f } $commonPath = $to; - while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !Preg::isMatch('{^[a-z]:/?$}i', $commonPath)) { + while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !Preg::isMatch('{^[A-Z]:/?$}i', $commonPath)) { $commonPath = strtr(\dirname($commonPath), '\\', '/'); } @@ -472,10 +471,15 @@ public function findShortestPath(string $from, string $to, bool $directories = f } $commonPath = rtrim($commonPath, '/') . '/'; - $sourcePathDepth = substr_count(substr($from, \strlen($commonPath)), '/'); + $sourcePathDepth = substr_count((string) substr($from, \strlen($commonPath)), '/'); $commonPathCode = str_repeat('../', $sourcePathDepth); - return ($commonPathCode . substr($to, \strlen($commonPath))) ?: './'; + $result = $commonPathCode . substr($to, \strlen($commonPath)); + if (\strlen($result) === 0) { + return './'; + } + + return $result; } /** @@ -494,15 +498,15 @@ public function findShortestPathCode(string $from, string $to, bool $directories throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to)); } - $from = lcfirst($this->normalizePath($from)); - $to = lcfirst($this->normalizePath($to)); + $from = $this->normalizePath($from); + $to = $this->normalizePath($to); if ($from === $to) { return $directories ? '__DIR__' : '__FILE__'; } $commonPath = $to; - while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !Preg::isMatch('{^[a-z]:/?$}i', $commonPath) && '.' !== $commonPath) { + while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !Preg::isMatch('{^[A-Z]:/?$}i', $commonPath) && '.' !== $commonPath) { $commonPath = strtr(\dirname($commonPath), '\\', '/'); } @@ -512,17 +516,17 @@ public function findShortestPathCode(string $from, string $to, bool $directories $commonPath = rtrim($commonPath, '/') . '/'; if (strpos($to, $from.'/') === 0) { - return '__DIR__ . '.var_export(substr($to, \strlen($from)), true); + return '__DIR__ . '.var_export((string) substr($to, \strlen($from)), true); } - $sourcePathDepth = substr_count(substr($from, \strlen($commonPath)), '/') + $directories; + $sourcePathDepth = substr_count((string) substr($from, \strlen($commonPath)), '/') + (int) $directories; if ($staticCode) { $commonPathCode = "__DIR__ . '".str_repeat('/..', $sourcePathDepth)."'"; } else { $commonPathCode = str_repeat('dirname(', $sourcePathDepth).'__DIR__'.str_repeat(')', $sourcePathDepth); } - $relTarget = substr($to, \strlen($commonPath)); + $relTarget = (string) substr($to, \strlen($commonPath)); - return $commonPathCode . (\strlen($relTarget) ? '.' . var_export('/' . $relTarget, true) : ''); + return $commonPathCode . (\strlen($relTarget) > 0 ? '.' . var_export('/' . $relTarget, true) : ''); } /** @@ -553,7 +557,7 @@ public function size(string $path) return $this->directorySize($path); } - return filesize($path); + return (int) filesize($path); } /** @@ -589,16 +593,19 @@ public function normalizePath(string $path) $up = false; foreach (explode('/', $path) as $chunk) { - if ('..' === $chunk && ($absolute !== '' || $up)) { + if ('..' === $chunk && (\strlen($absolute) > 0 || $up)) { array_pop($parts); - $up = !(empty($parts) || '..' === end($parts)); + $up = !(\count($parts) === 0 || '..' === end($parts)); } elseif ('.' !== $chunk && '' !== $chunk) { $parts[] = $chunk; $up = '..' !== $chunk; } } - return $prefix.((string) $absolute).implode('/', $parts); + // ensure c: is normalized to C: + $prefix = Preg::replaceCallback('{(^|://)[a-z]:$}i', function (array $m) { return strtoupper($m[0]); }, $prefix); + + return $prefix.$absolute.implode('/', $parts); } /** @@ -640,7 +647,7 @@ public static function getPlatformPath(string $path) $path = Preg::replace('{^(?:file:///([a-z]):?/)}i', 'file://$1:/', $path); } - return (string) Preg::replace('{^file://}i', '', $path); + return Preg::replace('{^file://}i', '', $path); } /** @@ -695,7 +702,7 @@ protected function directorySize(string $directory) */ protected function getProcess() { - if (!$this->processExecutor) { + if (null === $this->processExecutor) { $this->processExecutor = new ProcessExecutor(); } @@ -789,7 +796,7 @@ private function resolveSymlinkedDirectorySymlink(string $pathname): string $resolved = rtrim($pathname, '/'); - if (!\strlen($resolved)) { + if (0 === \strlen($resolved)) { return $pathname; } @@ -859,7 +866,7 @@ public function isJunction(string $junction) $stat = lstat($junction); // S_ISDIR test (S_IFDIR is 0x4000, S_IFMT is 0xF000 bitmask) - return $stat ? 0x4000 !== ($stat['mode'] & 0xF000) : false; + return is_array($stat) ? 0x4000 !== ($stat['mode'] & 0xF000) : false; } /** @@ -889,8 +896,8 @@ public function removeJunction(string $junction) */ public function filePutContentsIfModified(string $path, string $content) { - $currentContent = @file_get_contents($path); - if (!$currentContent || ($currentContent != $content)) { + $currentContent = Silencer::call('file_get_contents', $path); + if (false === $currentContent || $currentContent !== $content) { return file_put_contents($path, $content); } @@ -908,23 +915,20 @@ public function filePutContentsIfModified(string $path, string $content) public function safeCopy(string $source, string $target) { if (!file_exists($target) || !file_exists($source) || !$this->filesAreEqual($source, $target)) { - $source = fopen($source, 'r'); - $target = fopen($target, 'w+'); + $sourceHandle = fopen($source, 'r'); + assert($sourceHandle !== false, 'Could not open "'.$source.'" for reading.'); + $targetHandle = fopen($target, 'w+'); + assert($targetHandle !== false, 'Could not open "'.$target.'" for writing.'); - stream_copy_to_stream($source, $target); - fclose($source); - fclose($target); + stream_copy_to_stream($sourceHandle, $targetHandle); + fclose($sourceHandle); + fclose($targetHandle); } } /** * compare 2 files * https://stackoverflow.com/questions/3060125/can-i-use-file-get-contents-to-compare-two-files - * - * @param string $a - * @param string $b - * - * @return bool */ private function filesAreEqual(string $a, string $b): bool { @@ -934,19 +938,21 @@ private function filesAreEqual(string $a, string $b): bool } // Check if content is different - $ah = fopen($a, 'rb'); - $bh = fopen($b, 'rb'); + $aHandle = fopen($a, 'rb'); + assert($aHandle !== false, 'Could not open "'.$a.'" for reading.'); + $bHandle = fopen($b, 'rb'); + assert($bHandle !== false, 'Could not open "'.$b.'" for reading.'); $result = true; - while (!feof($ah)) { - if (fread($ah, 8192) != fread($bh, 8192)) { + while (!feof($aHandle)) { + if (fread($aHandle, 8192) !== fread($bHandle, 8192)) { $result = false; break; } } - fclose($ah); - fclose($bh); + fclose($aHandle); + fclose($bHandle); return $result; } diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index f28271c74e10..2c9167f56391 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -1,4 +1,4 @@ -scheme = parse_url($fileUrl, PHP_URL_SCHEME); + $this->scheme = parse_url(strtr($fileUrl, '\\', '/'), PHP_URL_SCHEME); $this->bytesMax = 0; $this->originUrl = $originUrl; $this->fileUrl = $fileUrl; diff --git a/src/Composer/Util/Silencer.php b/src/Composer/Util/Silencer.php index 484b5a5c7a6c..c01404be6265 100644 --- a/src/Composer/Util/Silencer.php +++ b/src/Composer/Util/Silencer.php @@ -1,4 +1,4 @@ -in(__DIR__.'/Fixtures/functional')->name('*.test')->files() as $file) { - $tests[basename($file)] = array($file->getRealPath()); + $tests[$file->getFilename()] = array((string) $file); } return $tests; diff --git a/tests/Composer/Test/ApplicationTest.php b/tests/Composer/Test/ApplicationTest.php index e0674c4faad5..8effc0684b45 100644 --- a/tests/Composer/Test/ApplicationTest.php +++ b/tests/Composer/Test/ApplicationTest.php @@ -1,4 +1,4 @@ -expects($this->once()) ->method('getParameterOption') - ->with($this->equalTo(array('--working-dir', '-d'))) - ->will($this->returnValue(false)); + ->with($this->equalTo(array('--working-dir', '-d')), $this->equalTo(null)) + ->will($this->returnValue(null)); $inputMock->expects($this->any()) ->method('getFirstArgument') @@ -116,8 +116,8 @@ public function ensureNoDevWarning(string $command): void $inputMock->expects($this->once()) ->method('getParameterOption') - ->with($this->equalTo(array('--working-dir', '-d'))) - ->will($this->returnValue(false)); + ->with($this->equalTo(array('--working-dir', '-d')), $this->equalTo(null)) + ->will($this->returnValue(null)); $inputMock->expects($this->any()) ->method('getFirstArgument') diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index 6a3fbec83a2f..27c444bec187 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -1,4 +1,4 @@ - */ private $files; /** @var string */ private $root; diff --git a/tests/Composer/Test/Command/ArchiveCommandTest.php b/tests/Composer/Test/Command/ArchiveCommandTest.php index 9ad7bf73f320..0d7b074012dd 100644 --- a/tests/Composer/Test/Command/ArchiveCommandTest.php +++ b/tests/Composer/Test/Command/ArchiveCommandTest.php @@ -1,4 +1,4 @@ - */ - protected function readTestFile(\SplFileInfo $file, string $fixturesDir): array + protected function readTestFile(string $file, string $fixturesDir): array { - $tokens = Preg::split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file->getRealPath()), -1, PREG_SPLIT_DELIM_CAPTURE); + $tokens = Preg::split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file), -1, PREG_SPLIT_DELIM_CAPTURE); $sectionInfo = array( 'TEST' => true, diff --git a/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php b/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php index a9f87feaadb1..18ef95dc378f 100644 --- a/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php +++ b/tests/Composer/Test/DependencyResolver/PoolOptimizerTest.php @@ -1,4 +1,4 @@ -getRealPath()), -1, PREG_SPLIT_DELIM_CAPTURE); + $tokens = Preg::split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file), -1, PREG_SPLIT_DELIM_CAPTURE); /** @var array $sectionInfo */ $sectionInfo = array( diff --git a/tests/Composer/Test/DependencyResolver/PoolTest.php b/tests/Composer/Test/DependencyResolver/PoolTest.php index 3d24f9fdfb14..6952955d86c2 100644 --- a/tests/Composer/Test/DependencyResolver/PoolTest.php +++ b/tests/Composer/Test/DependencyResolver/PoolTest.php @@ -1,4 +1,4 @@ -> $expected + * @param array $expected * @return void */ protected function checkSolverResult(array $expected): void diff --git a/tests/Composer/Test/DependencyResolver/TransactionTest.php b/tests/Composer/Test/DependencyResolver/TransactionTest.php index 703fecf5630a..0cb73d3fc821 100644 --- a/tests/Composer/Test/DependencyResolver/TransactionTest.php +++ b/tests/Composer/Test/DependencyResolver/TransactionTest.php @@ -1,4 +1,4 @@ -> $expected + * @param array $expected * @return void */ protected function checkTransactionOperations(Transaction $transaction, array $expected): void diff --git a/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php b/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php index 4b95b2bd919e..c0d4d7ee7477 100644 --- a/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php +++ b/tests/Composer/Test/Downloader/ArchiveDownloaderTest.php @@ -1,4 +1,4 @@ -getDownloaderMock(); - $downloader->install($packageMock, '/path'); + $downloader->install($packageMock, $this->workingDir . '/path'); } public function testInstall(): void @@ -77,13 +77,13 @@ public function testInstall(): void $process = $this->getProcessExecutorMock(); $process->expects(array( - $this->getCmd('fossil clone -- \'http://fossil.kd2.org/kd2fw/\' \'repo.fossil\''), - $this->getCmd('fossil open --nested -- \'repo.fossil\''), + $this->getCmd('fossil clone -- \'http://fossil.kd2.org/kd2fw/\' \''.$this->workingDir.'.fossil\''), + $this->getCmd('fossil open --nested -- \''.$this->workingDir.'.fossil\''), $this->getCmd('fossil update -- \'trunk\''), ), true); $downloader = $this->getDownloaderMock(null, null, $process); - $downloader->install($packageMock, 'repo'); + $downloader->install($packageMock, $this->workingDir); } public function testUpdateforPackageWithoutSourceReference(): void diff --git a/tests/Composer/Test/Downloader/GitDownloaderTest.php b/tests/Composer/Test/Downloader/GitDownloaderTest.php index 91b90b369e42..8a65686d635f 100644 --- a/tests/Composer/Test/Downloader/GitDownloaderTest.php +++ b/tests/Composer/Test/Downloader/GitDownloaderTest.php @@ -1,4 +1,4 @@ -getProcessExecutorMock(); $process->expects(array( - $this->getCmd('hg clone -- \'https://mercurial.dev/l3l0/composer\' \'composerPath\''), + $this->getCmd('hg clone -- \'https://mercurial.dev/l3l0/composer\' \''.$this->workingDir.'\''), $this->getCmd('hg up -- \'ref\''), ), true); $downloader = $this->getDownloaderMock(null, null, $process); - $downloader->install($packageMock, 'composerPath'); + $downloader->install($packageMock, $this->workingDir); } public function testUpdateforPackageWithoutSourceReference(): void diff --git a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php index f8a8e16c6323..f814861066e5 100644 --- a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php +++ b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php @@ -1,4 +1,4 @@ -getRealPath()), -1, PREG_SPLIT_DELIM_CAPTURE); + $tokens = Preg::split('#(?:^|\n*)--([A-Z-]+)--\n#', file_get_contents($file), -1, PREG_SPLIT_DELIM_CAPTURE); $sectionInfo = array( 'TEST' => true, diff --git a/tests/Composer/Test/Json/ComposerSchemaTest.php b/tests/Composer/Test/Json/ComposerSchemaTest.php index e6aea2271b7b..a458ef1a0dc2 100644 --- a/tests/Composer/Test/Json/ComposerSchemaTest.php +++ b/tests/Composer/Test/Json/ComposerSchemaTest.php @@ -1,4 +1,4 @@ - 1) { @@ -113,7 +113,7 @@ public function execute($command, &$output = null, $cwd = null): int return $this->doExecute($command, $cwd, false); } - public function executeTty($command, $cwd = null): int + public function executeTty($command, ?string $cwd = null): int { $cwd = $cwd ?? Platform::getCwd(); if (Platform::isTty()) { diff --git a/tests/Composer/Test/Mock/VersionGuesserMock.php b/tests/Composer/Test/Mock/VersionGuesserMock.php index b634b0297f73..c8a0c95d0955 100644 --- a/tests/Composer/Test/Mock/VersionGuesserMock.php +++ b/tests/Composer/Test/Mock/VersionGuesserMock.php @@ -1,4 +1,4 @@ -sources, '#').'/archive\.zip/archive#', '', $this->fs->normalizePath($file)); + $files[] = Preg::replace('#^phar://'.preg_quote($this->sources, '#').'/archive\.zip/archive#', '', $this->fs->normalizePath((string) $file)); } unset($archive, $iterator, $file); diff --git a/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php b/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php index 04f098355bdf..5a898694b0ff 100644 --- a/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php +++ b/tests/Composer/Test/Package/Archiver/ArchiveManagerTest.php @@ -1,4 +1,4 @@ -home = $this->getUniqueTmpDirectory(); - $this->config = new Config(); - $this->config->merge(array( - 'config' => array( - 'home' => $this->home, - 'gitlab-domains' => array( - 'mycompany.com/gitlab', - 'gitlab.mycompany.com', - 'othercompany.com/nested/gitlab', - 'gitlab.com', - ), + $this->config = $this->getConfig([ + 'home' => $this->home, + 'gitlab-domains' => array( + 'mycompany.com/gitlab', + 'gitlab.mycompany.com', + 'othercompany.com/nested/gitlab', + 'gitlab.com', + 'gitlab.mycompany.local', ), - )); + ]); $this->io = $this->getMockBuilder('Composer\IO\IOInterface')->disableOriginalConstructor()->getMock(); $this->process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); @@ -593,7 +591,7 @@ public function testForwardsOptions(): void JSON; $this->httpDownloader->expects( - [['url' => 'https:///api/v4/projects/%2Fmyproject', 'body' => $projectData]], + [['url' => 'https://gitlab.mycompany.local/api/v4/projects/mygroup%2Fmyproject', 'body' => $projectData]], true ); diff --git a/tests/Composer/Test/Repository/Vcs/HgDriverTest.php b/tests/Composer/Test/Repository/Vcs/HgDriverTest.php index 0d6948415c9d..58cac0c1646e 100644 --- a/tests/Composer/Test/Repository/Vcs/HgDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/HgDriverTest.php @@ -1,4 +1,4 @@ -