Skip to content

Commit

Permalink
Merge pull request #192 from asgrim/pie-uninstall-feature
Browse files Browse the repository at this point in the history
PIE Uninstall feature
  • Loading branch information
asgrim authored Feb 28, 2025
2 parents c94c664 + 7d45866 commit 1b22e9c
Show file tree
Hide file tree
Showing 69 changed files with 1,653 additions and 118 deletions.
2 changes: 2 additions & 0 deletions bin/pie
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use Php\Pie\Command\RepositoryAddCommand;
use Php\Pie\Command\RepositoryListCommand;
use Php\Pie\Command\RepositoryRemoveCommand;
use Php\Pie\Command\ShowCommand;
use Php\Pie\Command\UninstallCommand;
use Php\Pie\Util\PieVersion;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
Expand All @@ -37,6 +38,7 @@ $application->setCommandLoader(new ContainerCommandLoader(
'repository:list' => RepositoryListCommand::class,
'repository:add' => RepositoryAddCommand::class,
'repository:remove' => RepositoryRemoveCommand::class,
'uninstall' => UninstallCommand::class,
]
));

Expand Down
8 changes: 8 additions & 0 deletions features/uninstall-extensions.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Feature: Extensions can be uninstalled with PIE

# See https://github.com/php/pie/issues/190 for why this is non-Windows
@non-windows
Example: An extension can be uninstalled
Given an extension was previously installed
When I run a command to uninstall an extension
Then the extension should not be installed anymore
1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
requireCoverageMetadata="true"
beStrictAboutOutputDuringTests="true"
displayDetailsOnSkippedTests="true"
displayDetailsOnTestsThatTriggerWarnings="true"
failOnRisky="true"
failOnWarning="true">
<testsuites>
Expand Down
2 changes: 1 addition & 1 deletion src/Building/Build.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace Php\Pie\Building;

use Php\Pie\BinaryFile;
use Php\Pie\Downloading\DownloadedPackage;
use Php\Pie\File\BinaryFile;
use Php\Pie\Platform\TargetPhp\PhpizePath;
use Php\Pie\Platform\TargetPlatform;
use Symfony\Component\Console\Output\OutputInterface;
Expand Down
2 changes: 1 addition & 1 deletion src/Building/UnixBuild.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace Php\Pie\Building;

use Php\Pie\BinaryFile;
use Php\Pie\Downloading\DownloadedPackage;
use Php\Pie\File\BinaryFile;
use Php\Pie\Platform\TargetPhp\PhpizePath;
use Php\Pie\Platform\TargetPlatform;
use Php\Pie\Util\Process;
Expand Down
2 changes: 1 addition & 1 deletion src/Building/WindowsBuild.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace Php\Pie\Building;

use Php\Pie\BinaryFile;
use Php\Pie\Downloading\DownloadedPackage;
use Php\Pie\File\BinaryFile;
use Php\Pie\Platform\TargetPhp\PhpizePath;
use Php\Pie\Platform\TargetPlatform;
use Php\Pie\Platform\WindowsExtensionAssetName;
Expand Down
2 changes: 1 addition & 1 deletion src/Command/BuildCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
);

try {
($this->composerIntegrationHandler)(
$this->composerIntegrationHandler->runInstall(
$package,
$composer,
$targetPlatform,
Expand Down
22 changes: 15 additions & 7 deletions src/Command/CommandHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use InvalidArgumentException;
use Php\Pie\DependencyResolver\Package;
use Php\Pie\DependencyResolver\RequestedPackageAndVersion;
use Php\Pie\Platform as PiePlatform;
use Php\Pie\Platform\OperatingSystem;
use Php\Pie\Platform\TargetPhp\PhpBinaryPath;
use Php\Pie\Platform\TargetPhp\PhpizePath;
Expand Down Expand Up @@ -64,27 +65,27 @@ public static function configurePhpConfigOptions(Command $command): void
InputOption::VALUE_REQUIRED,
'The path to the `php` binary to use as the target PHP platform on ' . OperatingSystem::Windows->asFriendlyName() . ', e.g. --' . self::OPTION_WITH_PHP_PATH . '=C:\usr\php7.4.33\php.exe',
);
$command->addOption(
self::OPTION_WITH_PHPIZE_PATH,
null,
InputOption::VALUE_REQUIRED,
'The path to the `phpize` binary to use as the target PHP platform, e.g. --' . self::OPTION_WITH_PHPIZE_PATH . '=/usr/bin/phpize7.4',
);
}

public static function configureDownloadBuildInstallOptions(Command $command): void
{
$command->addArgument(
self::ARG_REQUESTED_PACKAGE_AND_VERSION,
InputArgument::REQUIRED,
'The extension name and version constraint to use, in the format {ext-name}{?:{?version-constraint}{?@stability}}, for example `xdebug/xdebug:^3.4@alpha`, `xdebug/xdebug:@alpha`, `xdebug/xdebug:^3.4`, etc.',
'The PIE package name and version constraint to use, in the format {vendor/package}{?:{?version-constraint}{?@stability}}, for example `xdebug/xdebug:^3.4@alpha`, `xdebug/xdebug:@alpha`, `xdebug/xdebug:^3.4`, etc.',
);
$command->addOption(
self::OPTION_MAKE_PARALLEL_JOBS,
'j',
InputOption::VALUE_REQUIRED,
'Override many jobs to run in parallel when running compiling (this is passed to "make -jN" during build). PIE will try to detect this by default.',
);
$command->addOption(
self::OPTION_WITH_PHPIZE_PATH,
null,
InputOption::VALUE_REQUIRED,
'The path to the `phpize` binary to use as the target PHP platform, e.g. --' . self::OPTION_WITH_PHPIZE_PATH . '=/usr/bin/phpize7.4',
);
$command->addOption(
self::OPTION_SKIP_ENABLE_EXTENSION,
null,
Expand Down Expand Up @@ -168,6 +169,13 @@ public static function determineTargetPlatformFromInputs(InputInterface $input,
$targetPlatform->architecture->name,
$phpBinaryPath->phpBinaryPath,
));
$output->writeln(
sprintf(
'<info>Using pie.json:</info> %s',
PiePlatform::getPieJsonFilename($targetPlatform),
),
OutputInterface::VERBOSITY_VERBOSE,
);

return $targetPlatform;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Command/DownloadCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
$output->writeln(sprintf('<info>Found package:</info> %s which provides <info>%s</info>', $package->prettyNameAndVersion(), $package->extensionName()->nameWithExtPrefix()));

try {
($this->composerIntegrationHandler)(
$this->composerIntegrationHandler->runInstall(
$package,
$composer,
$targetPlatform,
Expand Down
2 changes: 1 addition & 1 deletion src/Command/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public function execute(InputInterface $input, OutputInterface $output): int
);

try {
($this->composerIntegrationHandler)(
$this->composerIntegrationHandler->runInstall(
$package,
$composer,
$targetPlatform,
Expand Down
81 changes: 28 additions & 53 deletions src/Command/ShowCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,21 @@

namespace Php\Pie\Command;

use Composer\Package\BasePackage;
use Composer\Package\CompletePackageInterface;
use Php\Pie\BinaryFile;
use Php\Pie\ComposerIntegration\PieComposerFactory;
use Php\Pie\ComposerIntegration\PieComposerRequest;
use Php\Pie\ComposerIntegration\PieInstalledJsonMetadataKeys;
use Php\Pie\DependencyResolver\Package;
use Php\Pie\File\BinaryFile;
use Php\Pie\File\BinaryFileFailedVerification;
use Php\Pie\Platform\InstalledPiePackages;
use Php\Pie\Platform\OperatingSystem;
use Php\Pie\Platform\TargetPlatform;
use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\OutputInterface;

use function array_combine;
use function array_filter;
use function array_key_exists;
use function array_map;
use function array_walk;
use function file_exists;
use function sprintf;
Expand All @@ -38,6 +34,7 @@
final class ShowCommand extends Command
{
public function __construct(
private readonly InstalledPiePackages $installedPiePackages,
private readonly ContainerInterface $container,
) {
parent::__construct();
Expand All @@ -54,7 +51,15 @@ public function execute(InputInterface $input, OutputInterface $output): int
{
$targetPlatform = CommandHelper::determineTargetPlatformFromInputs($input, $output);

$piePackages = $this->buildListOfPieInstalledPackages($output, $targetPlatform);
$composer = PieComposerFactory::createPieComposer(
$this->container,
PieComposerRequest::noOperation(
new NullOutput(),
$targetPlatform,
),
);

$piePackages = $this->installedPiePackages->allPiePackages($composer);
$phpEnabledExtensions = $targetPlatform->phpBinaryPath->extensions();
$extensionPath = $targetPlatform->phpBinaryPath->extensionPath();
$extensionEnding = $targetPlatform->operatingSystem === OperatingSystem::Windows ? '.dll' : '.so';
Expand Down Expand Up @@ -99,64 +104,34 @@ private static function verifyChecksumInformation(
string $extensionEnding,
array $installedJsonMetadata,
): string {
$expectedConventionalBinaryPath = $extensionPath . DIRECTORY_SEPARATOR . $phpExtensionName . $extensionEnding;
$actualBinaryPathByConvention = $extensionPath . DIRECTORY_SEPARATOR . $phpExtensionName . $extensionEnding;

// The extension may not be in the usual path (since you can specify a full path to an extension in the INI file)
if (! file_exists($expectedConventionalBinaryPath)) {
if (! file_exists($actualBinaryPathByConvention)) {
return '';
}

$pieExpectedBinaryPath = array_key_exists(PieInstalledJsonMetadataKeys::InstalledBinary->value, $installedJsonMetadata) ? $installedJsonMetadata[PieInstalledJsonMetadataKeys::InstalledBinary->value] : null;
$pieExpectedChecksum = array_key_exists(PieInstalledJsonMetadataKeys::BinaryChecksum->value, $installedJsonMetadata) ? $installedJsonMetadata[PieInstalledJsonMetadataKeys::BinaryChecksum->value] : null;

// Some other kind of mismatch of file path, or we don't have a stored checksum available
if ($expectedConventionalBinaryPath !== $pieExpectedBinaryPath || $pieExpectedChecksum === null) {
if (
$pieExpectedBinaryPath === null
|| $pieExpectedChecksum === null
|| $pieExpectedBinaryPath !== $actualBinaryPathByConvention
) {
return '';
}

$actualInstalledBinary = BinaryFile::fromFileWithSha256Checksum($expectedConventionalBinaryPath);
if ($actualInstalledBinary->checksum !== $pieExpectedChecksum) {
return ' ⚠️ was ' . substr($actualInstalledBinary->checksum, 0, 8) . '..., expected ' . substr($pieExpectedChecksum, 0, 8) . '...';
$expectedBinaryFileFromMetadata = new BinaryFile($pieExpectedBinaryPath, $pieExpectedChecksum);
$actualBinaryFile = BinaryFile::fromFileWithSha256Checksum($actualBinaryPathByConvention);

try {
$expectedBinaryFileFromMetadata->verifyAgainstOther($actualBinaryFile);
} catch (BinaryFileFailedVerification) {
return ' ⚠️ was ' . substr($actualBinaryFile->checksum, 0, 8) . '..., expected ' . substr($expectedBinaryFileFromMetadata->checksum, 0, 8) . '...';
}

return '';
}

/** @return array<non-empty-string, Package> */
private function buildListOfPieInstalledPackages(
OutputInterface $output,
TargetPlatform $targetPlatform,
): array {
$composerInstalledPackages = array_map(
static function (CompletePackageInterface $package): Package {
return Package::fromComposerCompletePackage($package);
},
array_filter(
PieComposerFactory::createPieComposer(
$this->container,
PieComposerRequest::noOperation(
$output,
$targetPlatform,
),
)
->getRepositoryManager()
->getLocalRepository()
->getPackages(),
static function (BasePackage $basePackage): bool {
return $basePackage instanceof CompletePackageInterface;
},
),
);

return array_combine(
array_map(
/** @return non-empty-string */
static function (Package $package): string {
return $package->extensionName()->name();
},
$composerInstalledPackages,
),
$composerInstalledPackages,
);
}
}
Loading

0 comments on commit 1b22e9c

Please sign in to comment.