Skip to content

Commit 67ad173

Browse files
authored
Merge pull request #610 from asgrim/merge-up-596-597-fixes-to-1-5-x
Merge up fixes for #596 and #597 to 1.5.x
2 parents 11653f8 + 97933f9 commit 67ad173

17 files changed

Lines changed: 349 additions & 213 deletions

.github/workflows/build-assets.yml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ jobs:
6868
needs:
6969
- build-phar
7070
runs-on: ${{ matrix.operating-system }}
71+
env:
72+
SPC_VERSION: 2.8.5
7173
strategy:
7274
fail-fast: false
7375
matrix:
@@ -76,7 +78,7 @@ jobs:
7678
- ubuntu-24.04-arm
7779
- macos-15-intel
7880
- macos-26
79-
- windows-2025
81+
# - windows-2025 - disabled for now, seems broken
8082
permissions:
8183
# id-token:write is required for build provenance attestation.
8284
id-token: write
@@ -92,33 +94,34 @@ jobs:
9294
# Source URL: https://static-php.dev/en/guide/manual-build.html#build-locally-using-spc-binary-recommended
9395
case "${{ matrix.operating-system }}" in
9496
ubuntu-24.04)
95-
curl -fsSL -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-x86_64
97+
curl -fsSL -o spc.tgz https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-linux-x86_64.tar.gz
9698
;;
9799
98100
ubuntu-24.04-arm)
99-
curl -fsSL -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-aarch64
101+
curl -fsSL -o spc.tgz https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-linux-aarch64.tar.gz
100102
;;
101103
102104
macos-15-intel)
103-
curl -fsSL -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-x86_64
105+
curl -fsSL -o spc.tgz https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-macos-x86_64.tar.gz
104106
;;
105107
106108
macos-26)
107-
curl -fsSL -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-macos-aarch64
109+
curl -fsSL -o spc.tgz https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-macos-aarch64.tar.gz
108110
;;
109111
110112
*)
111113
echo "unsupported operating system: ${{ matrix.operating-system }}"
112114
exit 1
113115
;;
114116
esac
117+
tar zxvf spc.tgz
115118
chmod +x spc
116119
echo "SPC_BINARY=./spc" >> $GITHUB_ENV
117120
echo "PIE_BINARY_OUTPUT=pie-${{ runner.os }}-${{ runner.arch }}" >> $GITHUB_ENV
118121
- name: Download SPC (Windows)
119122
if: runner.os == 'Windows'
120123
run: |
121-
curl.exe -fsSL -o spc.exe https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-windows-x64.exe
124+
curl.exe -fsSL -o spc.exe https://github.com/crazywhalecc/static-php-cli/releases/download/${{ env.SPC_VERSION }}/spc-windows-x64.exe
122125
chmod +x spc.exe
123126
echo "SPC_BINARY=.\spc.exe" >> $env:GITHUB_ENV
124127
echo "PIE_BINARY_OUTPUT=pie-${{ runner.os }}-${{ runner.arch }}.exe" >> $env:GITHUB_ENV

src/Command/InstallExtensionsForProjectCommand.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,18 @@ public function execute(InputInterface $input, OutputInterface $output): int
167167

168168
array_walk(
169169
$extensionsRequired,
170-
function (Link $link) use ($pieComposer, $phpEnabledExtensions, $installedPiePackages, $input, &$anyErrorsHappened): void {
170+
function (Link $link) use ($pieComposer, $phpEnabledExtensions, $installedPiePackages, $input, &$anyErrorsHappened, $targetPlatform): void {
171171
$extension = ExtensionName::normaliseFromString($link->getTarget());
172172
$linkRequiresConstraint = $link->getPrettyConstraint();
173173

174+
$piePackagesForExtension = $installedPiePackages
175+
->findByPhpFormattedExtensionName($extension->phpFormattedExtensionName())
176+
->onlyVerifiedFor($targetPlatform);
177+
174178
$piePackageVersion = null;
175-
if (in_array($extension->name(), array_keys($installedPiePackages))) {
176-
$piePackageVersion = $installedPiePackages[$extension->name()]->version();
179+
180+
if (count($piePackagesForExtension) === 1) {
181+
$piePackageVersion = $piePackagesForExtension->onlyOne()->version();
177182
}
178183

179184
$piePackageVersionMatchesLinkConstraint = null;

src/Command/ShowCommand.php

Lines changed: 73 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,14 @@
1010
use Php\Pie\ComposerIntegration\PieComposerRequest;
1111
use Php\Pie\ComposerIntegration\PieInstalledJsonMetadataKeys;
1212
use Php\Pie\DependencyResolver\BundledPhpExtensionRefusal;
13+
use Php\Pie\DependencyResolver\Package;
1314
use Php\Pie\DependencyResolver\RequestedPackageAndVersion;
1415
use Php\Pie\DependencyResolver\ResolveDependencyWithComposer;
1516
use Php\Pie\DependencyResolver\UnableToResolveRequirement;
16-
use Php\Pie\File\BinaryFile;
17-
use Php\Pie\File\BinaryFileFailedVerification;
1817
use Php\Pie\Platform as PiePlatform;
1918
use Php\Pie\Platform\InstalledPiePackages;
20-
use Php\Pie\Platform\OperatingSystem;
2119
use Php\Pie\Util\Emoji;
20+
use Php\Pie\Util\PackageVerificationStatus;
2221
use Psr\Container\ContainerInterface;
2322
use Symfony\Component\Console\Attribute\AsCommand;
2423
use Symfony\Component\Console\Command\Command;
@@ -28,15 +27,11 @@
2827
use Webmozart\Assert\Assert;
2928

3029
use function array_diff;
31-
use function array_key_exists;
32-
use function array_keys;
30+
use function array_map;
3331
use function array_walk;
3432
use function count;
35-
use function file_exists;
33+
use function rtrim;
3634
use 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
}

src/Command/UninstallCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ private function findPiePackageByPackageName(string $packageToRemove, Composer $
109109
{
110110
$piePackages = $this->installedPiePackages->allPiePackages($composer);
111111

112-
foreach ($piePackages as $piePackage) {
112+
foreach ($piePackages->packages() as $piePackage) {
113113
if ($piePackage->name() === $packageToRemove) {
114114
return $piePackage;
115115
}

src/ComposerIntegration/PhpBinaryPathBasedPlatformRepository.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function __construct(PhpBinaryPath $phpBinaryPath, Composer $composer, In
4444

4545
$piePackages = $installedPiePackages->allPiePackages($composer);
4646
$extensionsBeingReplacedByPiePackages = [];
47-
foreach ($piePackages as $piePackage) {
47+
foreach ($piePackages->packages() as $piePackage) {
4848
foreach ($piePackage->composerPackage()->getReplaces() as $replaceLink) {
4949
$target = $replaceLink->getTarget();
5050
if (

0 commit comments

Comments
 (0)