1010use Php \Pie \ComposerIntegration \PieComposerRequest ;
1111use Php \Pie \ComposerIntegration \PieInstalledJsonMetadataKeys ;
1212use Php \Pie \DependencyResolver \BundledPhpExtensionRefusal ;
13+ use Php \Pie \DependencyResolver \Package ;
1314use Php \Pie \DependencyResolver \RequestedPackageAndVersion ;
1415use Php \Pie \DependencyResolver \ResolveDependencyWithComposer ;
1516use Php \Pie \DependencyResolver \UnableToResolveRequirement ;
16- use Php \Pie \File \BinaryFile ;
17- use Php \Pie \File \BinaryFileFailedVerification ;
1817use Php \Pie \Platform as PiePlatform ;
1918use Php \Pie \Platform \InstalledPiePackages ;
20- use Php \Pie \Platform \OperatingSystem ;
2119use Php \Pie \Util \Emoji ;
20+ use Php \Pie \Util \PackageVerificationStatus ;
2221use Psr \Container \ContainerInterface ;
2322use Symfony \Component \Console \Attribute \AsCommand ;
2423use Symfony \Component \Console \Command \Command ;
2827use Webmozart \Assert \Assert ;
2928
3029use function array_diff ;
31- use function array_key_exists ;
32- use function array_keys ;
30+ use function array_map ;
3331use function array_walk ;
3432use function count ;
35- use function file_exists ;
33+ use function rtrim ;
3634use function sprintf ;
37- use function substr ;
38-
39- use const DIRECTORY_SEPARATOR ;
4035
4136/** @phpstan-import-type PieMetadata from PieInstalledJsonMetadataKeys */
4237#[AsCommand(
@@ -99,8 +94,6 @@ public function execute(InputInterface $input, OutputInterface $output): int
9994
10095 $ piePackages = $ this ->installedPiePackages ->allPiePackages ($ composer );
10196 $ phpEnabledExtensions = $ targetPlatform ->phpBinaryPath ->extensions ();
102- $ extensionPath = $ targetPlatform ->phpBinaryPath ->extensionPath ();
103- $ extensionEnding = $ targetPlatform ->operatingSystem === OperatingSystem::Windows ? '.dll ' : '.so ' ;
10497 $ piePackagesMatched = [];
10598 $ rootPackageRequires = $ composer ->getPackage ()->getRequires ();
10699
@@ -110,141 +103,106 @@ public function execute(InputInterface $input, OutputInterface $output): int
110103 ));
111104 array_walk (
112105 $ phpEnabledExtensions ,
113- function (string $ version , string $ phpExtensionName ) use ($ composer , $ rootPackageRequires , $ targetPlatform , $ showAll , $ piePackages , $ extensionPath , $ extensionEnding , &$ piePackagesMatched ): void {
114- if (! array_key_exists ($ phpExtensionName , $ piePackages )) {
106+ function (string $ version , string $ phpExtensionName ) use ($ composer , $ rootPackageRequires , $ targetPlatform , $ showAll , $ piePackages , &$ piePackagesMatched ): void {
107+ $ pieMatchesForExtension = $ piePackages ->findByPhpFormattedExtensionName ($ phpExtensionName );
108+
109+ if (! count ($ pieMatchesForExtension )) {
115110 if ($ showAll ) {
116111 $ this ->io ->write (sprintf (' <comment>%s:%s</comment> ' , $ phpExtensionName , $ version ));
117112 }
118113
119114 return ;
120115 }
121116
122- $ piePackage = $ piePackages [ $ phpExtensionName ];
123- $ piePackagesMatched [] = $ phpExtensionName ;
124- $ packageName = $ piePackage ->name ( );
125- $ packageRequirement = $ rootPackageRequires [$ piePackage -> name () ]->getPrettyConstraint ();
117+ foreach ( $ pieMatchesForExtension -> packages () as $ piePackage ) {
118+ $ packageName = $ piePackage -> name () ;
119+ $ verificationStatus = $ piePackage ->verifyPackageStatus ( $ targetPlatform );
120+ $ packageRequirement = $ rootPackageRequires [$ packageName ]->getPrettyConstraint ();
126121
127- try {
128- // Don't check for updates for bundled PHP extensions
129- if ($ piePackage ->isBundledPhpExtension ()) {
130- throw new BundledPhpExtensionRefusal ();
122+ if ($ verificationStatus === PackageVerificationStatus::InstalledBinaryMetadataMissing) {
123+ continue ;
131124 }
132125
133- Assert::stringNotEmpty ($ packageName );
134- Assert::stringNotEmpty ($ packageRequirement );
135-
136- $ latestConstrainedPackage = ($ this ->resolveDependencyWithComposer )(
137- $ composer ,
138- $ targetPlatform ,
139- new RequestedPackageAndVersion ($ packageName , $ packageRequirement ),
140- false ,
141- );
142-
143- $ latestPackage = ($ this ->resolveDependencyWithComposer )(
144- $ composer ,
145- $ targetPlatform ,
146- new RequestedPackageAndVersion ($ packageName , '* ' ),
147- false ,
148- );
149- } catch (UnableToResolveRequirement | BundledPhpExtensionRefusal ) {
150- $ latestConstrainedPackage = null ;
151- $ latestPackage = null ;
152- }
126+ $ piePackagesMatched [] = $ packageName ;
127+
128+ try {
129+ // Don't check for updates for bundled PHP extensions
130+ if ($ piePackage ->isBundledPhpExtension ()) {
131+ throw new BundledPhpExtensionRefusal ();
132+ }
133+
134+ Assert::stringNotEmpty ($ packageName );
135+ Assert::stringNotEmpty ($ packageRequirement );
136+
137+ $ latestConstrainedPackage = ($ this ->resolveDependencyWithComposer )(
138+ $ composer ,
139+ $ targetPlatform ,
140+ new RequestedPackageAndVersion ($ packageName , $ packageRequirement ),
141+ false ,
142+ );
143+
144+ $ latestPackage = ($ this ->resolveDependencyWithComposer )(
145+ $ composer ,
146+ $ targetPlatform ,
147+ new RequestedPackageAndVersion ($ packageName , '* ' ),
148+ false ,
149+ );
150+ } catch (UnableToResolveRequirement | BundledPhpExtensionRefusal ) {
151+ $ latestConstrainedPackage = null ;
152+ $ latestPackage = null ;
153+ }
153154
154- $ updateNotice = '' ;
155- if ($ latestConstrainedPackage !== null && $ latestConstrainedPackage ->version () !== $ piePackage ->version ()) {
156- $ updateNotice = sprintf (
157- ', upgradable to %s (within %s) ' ,
158- $ latestConstrainedPackage ->version (),
159- $ packageRequirement ,
160- );
161- }
155+ $ updateNotice = '' ;
156+ if ($ latestConstrainedPackage !== null && $ latestConstrainedPackage ->version () !== $ piePackage ->version ()) {
157+ $ updateNotice = sprintf (
158+ ', upgradable to %s (within %s) ' ,
159+ $ latestConstrainedPackage ->version (),
160+ $ packageRequirement ,
161+ );
162+ }
162163
163- if ($ latestPackage !== null && $ latestPackage ->version () !== $ latestConstrainedPackage ->version ()) {
164- $ updateNotice .= sprintf (', latest version is %s ' , $ latestPackage ->version ());
165- }
164+ if ($ latestPackage !== null && $ latestPackage ->version () !== $ latestConstrainedPackage ->version ()) {
165+ $ updateNotice .= sprintf (', latest version is %s ' , $ latestPackage ->version ());
166+ }
166167
167- $ this ->io ->write (sprintf (
168- ' <info>%s:%s</info> (from 🥧 <info>%s</info>%s)%s ' ,
169- $ phpExtensionName ,
170- $ version ,
171- $ piePackage ->prettyNameAndVersion (),
172- self ::verifyChecksumInformation (
173- $ extensionPath ,
168+ $ this ->io ->write (sprintf (
169+ ' <info>%s:%s</info> (from 🥧 <info>%s</info> %s)%s ' ,
174170 $ phpExtensionName ,
175- $ extensionEnding ,
176- PieInstalledJsonMetadataKeys::pieMetadataFromComposerPackage ($ piePackage ->composerPackage ()),
177- ),
178- $ updateNotice ,
179- ));
171+ $ version ,
172+ $ piePackage ->prettyNameAndVersion (),
173+ $ verificationStatus ->description (),
174+ $ updateNotice ,
175+ ));
176+ }
180177 },
181178 );
182179
183180 if (! $ showAll && ! count ($ piePackagesMatched )) {
184181 $ this ->io ->write ('(none) ' );
185182 }
186183
187- $ unmatchedPiePackages = array_diff (array_keys ( $ piePackages ), $ piePackagesMatched );
184+ $ unmatchedPiePackageNames = array_diff (array_map ( static fn ( Package $ piePackage ) => $ piePackage -> name (), $ piePackages-> packages () ), $ piePackagesMatched );
188185
189- if (count ($ unmatchedPiePackages )) {
186+ if (count ($ unmatchedPiePackageNames )) {
190187 $ this ->io ->write (sprintf (
191188 '%s %s <options=bold,underscore>PIE packages not loaded:</> ' ,
192189 "\n" ,
193190 Emoji::WARNING ,
194191 ));
195- $ this ->io ->write ('These extensions were installed with PIE but are not currently enabled. ' . "\n" );
192+ $ this ->io ->write ('These extensions were set up with PIE but are not currently enabled. ' . "\n" );
196193
197- foreach ($ unmatchedPiePackages as $ unmatchedPiePackage ) {
198- $ this ->io ->write (sprintf (' - %s ' , $ piePackages [$ unmatchedPiePackage ]->prettyNameAndVersion ()));
194+ foreach ($ unmatchedPiePackageNames as $ unmatchedPiePackageName ) {
195+ $ unmatchedPiePackage = $ piePackages ->findByPackageName ($ unmatchedPiePackageName );
196+
197+ $ message = match ($ unmatchedPiePackage ->verifyPackageStatus ($ targetPlatform )) {
198+ PackageVerificationStatus::ChecksumMetadataMissing => '- was built but not installed yet. ' ,
199+ PackageVerificationStatus::InstalledBinaryMetadataMissing => '- was downloaded but has not been built yet. ' ,
200+ default => '- installed but not enabled in INI file ' ,
201+ };
202+ $ this ->io ->write (rtrim (sprintf (' - %s %s ' , $ unmatchedPiePackage ->prettyNameAndVersion (), $ message )));
199203 }
200204 }
201205
202206 return Command::SUCCESS ;
203207 }
204-
205- /**
206- * @param PieMetadata $installedJsonMetadata
207- * @phpstan-param '.dll'|'.so' $extensionEnding
208- */
209- private static function verifyChecksumInformation (
210- string $ extensionPath ,
211- string $ phpExtensionName ,
212- string $ extensionEnding ,
213- array $ installedJsonMetadata ,
214- ): string {
215- $ actualBinaryPathByConvention = $ extensionPath . DIRECTORY_SEPARATOR . $ phpExtensionName . $ extensionEnding ;
216-
217- // The extension may not be in the usual path (since you can specify a full path to an extension in the INI file)
218- if (! file_exists ($ actualBinaryPathByConvention )) {
219- return '' ;
220- }
221-
222- $ pieExpectedBinaryPath = array_key_exists (PieInstalledJsonMetadataKeys::InstalledBinary->value , $ installedJsonMetadata ) ? $ installedJsonMetadata [PieInstalledJsonMetadataKeys::InstalledBinary->value ] : null ;
223- $ pieExpectedChecksum = array_key_exists (PieInstalledJsonMetadataKeys::BinaryChecksum->value , $ installedJsonMetadata ) ? $ installedJsonMetadata [PieInstalledJsonMetadataKeys::BinaryChecksum->value ] : null ;
224-
225- // Some other kind of mismatch of file path, or we don't have a stored checksum available
226- if (
227- $ pieExpectedBinaryPath === null
228- || $ pieExpectedChecksum === null
229- || $ pieExpectedBinaryPath !== $ actualBinaryPathByConvention
230- ) {
231- return '' ;
232- }
233-
234- $ expectedBinaryFileFromMetadata = new BinaryFile ($ pieExpectedBinaryPath , $ pieExpectedChecksum );
235- $ actualBinaryFile = BinaryFile::fromFileWithSha256Checksum ($ actualBinaryPathByConvention );
236-
237- try {
238- $ expectedBinaryFileFromMetadata ->verifyAgainstOther ($ actualBinaryFile );
239- } catch (BinaryFileFailedVerification ) {
240- return sprintf (
241- ' %s was %s..., expected %s... ' ,
242- Emoji::WARNING ,
243- substr ($ actualBinaryFile ->checksum , 0 , 8 ),
244- substr ($ expectedBinaryFileFromMetadata ->checksum , 0 , 8 ),
245- );
246- }
247-
248- return ' ' . Emoji::GREEN_CHECKMARK ;
249- }
250208}
0 commit comments