From 1555554d9f87467e9c5165860aedc8ee48c8579e Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Fri, 25 Nov 2022 23:48:54 -0400 Subject: [PATCH 1/5] Centralize version data access Obtaining package version data from within a scoped PHAR file is a complicated topic, and it's been alternatively broken and fixed multiple times. This change moves version data access to a single class, so that we can fix it there should we need to. The rest of the code can just rely on PSALM_VERSION constant (which will be made unscoped in a further commit) or call `VersionUtils` methods. --- src/Psalm/Internal/Cli/Plugin.php | 2 +- src/Psalm/Internal/CliUtils.php | 5 +- src/Psalm/Internal/VersionUtils.php | 93 +++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 src/Psalm/Internal/VersionUtils.php diff --git a/src/Psalm/Internal/Cli/Plugin.php b/src/Psalm/Internal/Cli/Plugin.php index c4e8fe4ab8a..28a86e88a7e 100644 --- a/src/Psalm/Internal/Cli/Plugin.php +++ b/src/Psalm/Internal/Cli/Plugin.php @@ -31,7 +31,7 @@ public static function run(): void $vendor_dir = CliUtils::getVendorDir($current_dir); CliUtils::requireAutoloaders($current_dir, false, $vendor_dir); - $app = new Application('psalm-plugin', Versions::getVersion('vimeo/psalm')); + $app = new Application('psalm-plugin', PSALM_VERSION); $psalm_root = dirname(__DIR__, 4) . DIRECTORY_SEPARATOR; diff --git a/src/Psalm/Internal/CliUtils.php b/src/Psalm/Internal/CliUtils.php index 05dea134a7a..c3d536eeb5d 100644 --- a/src/Psalm/Internal/CliUtils.php +++ b/src/Psalm/Internal/CliUtils.php @@ -4,7 +4,6 @@ use Composer\Autoload\ClassLoader; use JsonException; -use PackageVersions\Versions; use Phar; use Psalm\Config; use Psalm\Config\Creator; @@ -158,8 +157,8 @@ public static function requireAutoloaders( exit(1); } - define('PSALM_VERSION', Versions::getVersion('vimeo/psalm')); - define('PHP_PARSER_VERSION', Versions::getVersion('nikic/php-parser')); + define('PSALM_VERSION', VersionUtils::getPsalmVersion()); + define('PHP_PARSER_VERSION', VersionUtils::getPhpParserVersion()); return $first_autoloader; } diff --git a/src/Psalm/Internal/VersionUtils.php b/src/Psalm/Internal/VersionUtils.php new file mode 100644 index 00000000000..d269a0835c3 --- /dev/null +++ b/src/Psalm/Internal/VersionUtils.php @@ -0,0 +1,93 @@ + 'unknown', self::PHP_PARSER_PACKAGE => 'unknown']; + } + + /** @return _VersionData|null */ + private static function loadPharVersions(): ?array + { + if (!class_exists(Phar::class)) { + return null; + } + + $phar_filename = Phar::running(true); + + if (!$phar_filename) { + return null; + } + + /** @var _VersionData */ + return require($phar_filename . '/phar-versions.php'); + } + + /** @return _VersionData|null */ + private static function loadComposerVersions(): ?array + { + try { + return [ + self::PSALM_PACKAGE => Versions::getVersion(self::PSALM_PACKAGE), + self::PHP_PARSER_PACKAGE => Versions::getVersion(self::PHP_PARSER_PACKAGE), + ]; + } catch (OutOfBoundsException $ex) { + } + return null; + } +} From 369ba0635e3aec4ac669277bdaf527a5115e307f Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Fri, 25 Nov 2022 23:58:41 -0400 Subject: [PATCH 2/5] Update humbug/box It updates humbug/scoper as well, so some changes to scoper configuration are required. `PSALM_VERSION` and `PHP_PARSER_VERSION` constants are made unscoped to prevent various issues. --- scoper.inc.php | 41 ++++++++++++------------------------ vendor-bin/box/composer.json | 2 +- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/scoper.inc.php b/scoper.inc.php index 933ea320e7f..fd949abe620 100644 --- a/scoper.inc.php +++ b/scoper.inc.php @@ -4,7 +4,7 @@ return [ 'patchers' => [ - function ($filePath, $prefix, $contents) { + function (string $filePath, string $prefix, string $contents): string { // // PHP-Parser patch // @@ -20,14 +20,14 @@ function ($filePath, $prefix, $contents) { return $contents; }, - function ($filePath, $prefix, $contents) { + function (string $_filePath, string $prefix, string $contents): string { return str_replace( - '\\'.$prefix.'\Composer\Autoload\ClassLoader', + '\\' . $prefix . '\Composer\Autoload\ClassLoader', '\Composer\Autoload\ClassLoader', $contents ); }, - function ($filePath, $prefix, $contents) { + function (string $filePath, string $prefix, string $contents): string { if (strpos($filePath, 'src/Psalm') === 0) { return str_replace( [' \\PhpParser\\'], @@ -38,7 +38,7 @@ function ($filePath, $prefix, $contents) { return $contents; }, - function ($filePath, $prefix, $contents) { + function (string $filePath, string $prefix, string $contents): string { if (strpos($filePath, 'vendor/openlss') === 0) { return str_replace( $prefix . '\\DomDocument', @@ -49,32 +49,19 @@ function ($filePath, $prefix, $contents) { return $contents; }, - function ($filePath, $prefix, $contents) { - if ($filePath === 'src/Psalm/Internal/Cli/Psalm.php') { - return str_replace( - '\\' . $prefix . '\\PSALM_VERSION', - 'PSALM_VERSION', - $contents - ); - } - - return $contents; - }, - function ($filePath, $prefix, $contents) { - $ret = str_replace( - $prefix . '\\Psalm\\', - 'Psalm\\', - $contents - ); - return $ret; - }, ], - 'whitelist' => [ + 'exclude-classes' => [ ClassLoader::class, Stringable::class, - 'Psalm\*', ], - 'files-whitelist' => [ + 'exclude-namespaces' => [ + 'Psalm', + ], + 'exclude-constants' => [ + 'PSALM_VERSION', + 'PHP_PARSER_VERSION', + ], + 'exclude-files' => [ 'src/spl_object_id.php', 'vendor/symfony/polyfill-php80/Php80.php', 'vendor/symfony/polyfill-php80/PhpToken.php', diff --git a/vendor-bin/box/composer.json b/vendor-bin/box/composer.json index f0d926cb1f8..f6b05bbd5cd 100644 --- a/vendor-bin/box/composer.json +++ b/vendor-bin/box/composer.json @@ -2,7 +2,7 @@ "minimum-stability": "dev", "prefer-stable": true, "require": { - "humbug/box": "3.10.*" + "humbug/box": "^3.16.0" }, "config": { "allow-plugins": { From 683fe2f4c6695bf209ee9395f2bce4142db52d9d Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Sat, 26 Nov 2022 00:00:43 -0400 Subject: [PATCH 3/5] Bake version data into PHAR file Compatibility between `ocramius/package-versions`, `composer/package-versions-deprecated`, `composer-runtime-api` and `humbug/box` (with `humbug/scoper` further complicating things)has been always a problematic area. So instead of trying to keep up with all the changes in all of those packages, we will now bake the version data (for the packages we need) into the PHAR file itself. Fixes vimeo/psalm#7606 Fixes vimeo/psalm#5399 --- bin/build-phar.sh | 6 ++++++ box.json.dist | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bin/build-phar.sh b/bin/build-phar.sh index 0a55d0e5d12..aa442102f20 100755 --- a/bin/build-phar.sh +++ b/bin/build-phar.sh @@ -8,6 +8,12 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" php $DIR/improve_class_alias.php +php -r 'require "vendor/autoload.php"; Psalm\Internal\VersionUtils::dump();' +if [[ ! -f build/phar-versions.php ]] ; then + echo "failed to dump versions"; + exit; +fi + vendor/bin/box compile if [[ "$GPG_SIGNING" != '' ]] ; then diff --git a/box.json.dist b/box.json.dist index 97d99cddc50..1e3d29e86da 100644 --- a/box.json.dist +++ b/box.json.dist @@ -1,7 +1,11 @@ { "output" : "build/psalm.phar", "files": [ - "psalm" + "psalm", + "build/phar-versions.php" + ], + "map": [ + {"build/phar-versions.php" : "phar-versions.php"} ], "files-bin": ["config.xsd"], "directories-bin" : [ From ee34d15b4d49e751b3c4d26a54ab0737914b4e47 Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Sat, 26 Nov 2022 00:18:45 -0400 Subject: [PATCH 4/5] SA and CS fixes --- src/Psalm/Internal/Cli/Plugin.php | 1 - src/Psalm/Internal/VersionUtils.php | 12 +++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Psalm/Internal/Cli/Plugin.php b/src/Psalm/Internal/Cli/Plugin.php index 28a86e88a7e..cafaf4597cb 100644 --- a/src/Psalm/Internal/Cli/Plugin.php +++ b/src/Psalm/Internal/Cli/Plugin.php @@ -2,7 +2,6 @@ namespace Psalm\Internal\Cli; -use PackageVersions\Versions; use Psalm\Internal\CliUtils; use Psalm\Internal\PluginManager\Command\DisableCommand; use Psalm\Internal\PluginManager\Command\EnableCommand; diff --git a/src/Psalm/Internal/VersionUtils.php b/src/Psalm/Internal/VersionUtils.php index d269a0835c3..c175b0ad581 100644 --- a/src/Psalm/Internal/VersionUtils.php +++ b/src/Psalm/Internal/VersionUtils.php @@ -7,8 +7,9 @@ use Phar; use function class_exists; -use function is_array; -use function is_string; +use function dirname; +use function file_put_contents; +use function var_export; /** * @internal @@ -22,6 +23,7 @@ final class VersionUtils /** @var null|_VersionData */ private static $versions = null; + /** @psalm-suppress UnusedConstructor it's here to prevent instantiations */ private function __construct() { } @@ -36,6 +38,7 @@ public static function getPhpParserVersion(): string return self::getVersions()[self::PHP_PARSER_PACKAGE]; } + /** @psalm-suppress UnusedMethod called from bin/build-phar.sh */ public static function dump(): void { $versions = self::loadComposerVersions(); @@ -74,7 +77,10 @@ private static function loadPharVersions(): ?array return null; } - /** @var _VersionData */ + /** + * @psalm-suppress UnresolvableInclude + * @var _VersionData + */ return require($phar_filename . '/phar-versions.php'); } From 5cbe2414936e5ca4e5959c3a01d34e0e31f04a27 Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Sat, 26 Nov 2022 00:36:47 -0400 Subject: [PATCH 5/5] Disable parallel PHAR build This is an attempt to fix CirleCI issue in this build: https://app.circleci.com/pipelines/github/weirdan/psalm/666/workflows/33476cb1-d753-4e2d-b067-a5c92808d725/jobs/2457 --- bin/build-phar.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build-phar.sh b/bin/build-phar.sh index aa442102f20..e15205f6571 100755 --- a/bin/build-phar.sh +++ b/bin/build-phar.sh @@ -14,7 +14,7 @@ if [[ ! -f build/phar-versions.php ]] ; then exit; fi -vendor/bin/box compile +vendor/bin/box compile --no-parallel if [[ "$GPG_SIGNING" != '' ]] ; then if [[ "$GPG_SECRET_KEY" != '' ]] ; then