diff --git a/features/uninstall-extensions.feature b/features/uninstall-extensions.feature index 154c10cf..1167897e 100644 --- a/features/uninstall-extensions.feature +++ b/features/uninstall-extensions.feature @@ -1,7 +1,5 @@ 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 diff --git a/src/Command/UninstallCommand.php b/src/Command/UninstallCommand.php index 0e6997bf..0cd46dc9 100644 --- a/src/Command/UninstallCommand.php +++ b/src/Command/UninstallCommand.php @@ -5,7 +5,6 @@ namespace Php\Pie\Command; use Composer\Composer; -use Composer\Util\Platform; use Php\Pie\ComposerIntegration\ComposerIntegrationHandler; use Php\Pie\ComposerIntegration\PieComposerFactory; use Php\Pie\ComposerIntegration\PieComposerRequest; @@ -54,16 +53,6 @@ public function configure(): void public function execute(InputInterface $input, OutputInterface $output): int { - if (Platform::isWindows()) { - /** - * @todo add support for uninstalling in Windows - see - * {@link https://github.com/php/pie/issues/190} for details - */ - $output->writeln('Uninstalling extensions on Windows is not currently supported.'); - - return 1; - } - if (! TargetPlatform::isRunningAsRoot()) { $output->writeln('This command may need elevated privileges, and may prompt you for your password.'); } diff --git a/src/Downloading/DownloadUrlMethod.php b/src/Downloading/DownloadUrlMethod.php index 397de170..6a5a95d8 100644 --- a/src/Downloading/DownloadUrlMethod.php +++ b/src/Downloading/DownloadUrlMethod.php @@ -10,6 +10,7 @@ use Php\Pie\Platform\TargetPlatform; use Php\Pie\Platform\WindowsExtensionAssetName; +/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ enum DownloadUrlMethod: string { case ComposerDefaultDownload = 'composer-default'; diff --git a/src/File/SudoCreate.php b/src/File/SudoCreate.php index e7ba4899..9a58c003 100644 --- a/src/File/SudoCreate.php +++ b/src/File/SudoCreate.php @@ -13,6 +13,7 @@ use function is_writable; use function touch; +/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ final class SudoCreate { public static function file(string $filename): void diff --git a/src/File/SudoUnlink.php b/src/File/SudoUnlink.php index 4f1bb542..1cfe33a6 100644 --- a/src/File/SudoUnlink.php +++ b/src/File/SudoUnlink.php @@ -4,6 +4,7 @@ namespace Php\Pie\File; +use Composer\Util\Platform; use Php\Pie\Util\CaptureErrors; use Php\Pie\Util\Process; use Symfony\Component\Process\Exception\ProcessFailedException; @@ -12,6 +13,7 @@ use function is_writable; use function unlink; +/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ final class SudoUnlink { public static function singleFile(string $filename): void @@ -20,7 +22,7 @@ public static function singleFile(string $filename): void return; } - if (is_writable($filename)) { + if (! Platform::isWindows() && is_writable($filename)) { $capturedErrors = []; $unlinkSuccessful = CaptureErrors::for( static fn () => unlink($filename), @@ -34,6 +36,12 @@ public static function singleFile(string $filename): void return; } + if (Platform::isWindows()) { + WindowsDelete::usingMoveToTemp($filename); + + return; + } + if (! Sudo::exists()) { throw FailedToUnlinkFile::fromNoPermissions($filename); } diff --git a/src/File/WindowsDelete.php b/src/File/WindowsDelete.php new file mode 100644 index 00000000..edae1ac5 --- /dev/null +++ b/src/File/WindowsDelete.php @@ -0,0 +1,47 @@ +extensionType() === ExtensionType::PhpModule ? 'extension' : 'zend_extension', $package->extensionName()->name(), ); diff --git a/src/Installing/WindowsInstall.php b/src/Installing/WindowsInstall.php index 23c8f2a9..a97f0f54 100644 --- a/src/Installing/WindowsInstall.php +++ b/src/Installing/WindowsInstall.php @@ -5,8 +5,8 @@ namespace Php\Pie\Installing; use Php\Pie\Downloading\DownloadedPackage; -use Php\Pie\ExtensionType; use Php\Pie\File\BinaryFile; +use Php\Pie\File\WindowsDelete; use Php\Pie\Platform\TargetPlatform; use Php\Pie\Platform\WindowsExtensionAssetName; use RecursiveDirectoryIterator; @@ -21,7 +21,6 @@ use function file_exists; use function is_file; use function mkdir; -use function sprintf; use function str_replace; use function strlen; use function substr; @@ -79,17 +78,6 @@ public function __invoke( $output->writeln('Copied extras: ' . $destinationPathname); } - /** - * @link https://github.com/php/pie/issues/20 - * - * @todo this should be improved in future to try to automatically set up the ext - */ - $output->writeln(sprintf( - 'You must now add "%s=%s" to your php.ini', - $downloadedPackage->package->extensionType() === ExtensionType::PhpModule ? 'extension' : 'zend_extension', - $downloadedPackage->package->extensionName()->name(), - )); - $binaryFile = BinaryFile::fromFileWithSha256Checksum($destinationDllName); ($this->setupIniFile)( @@ -124,6 +112,10 @@ private function copyExtensionDll(TargetPlatform $targetPlatform, DownloadedPack $destinationDllName = $targetPlatform->phpBinaryPath->extensionPath() . DIRECTORY_SEPARATOR . 'php_' . $downloadedPackage->package->extensionName()->name() . '.dll'; + if (file_exists($destinationDllName)) { + WindowsDelete::usingMoveToTemp($destinationDllName); + } + if (! copy($sourceDllName, $destinationDllName) || ! file_exists($destinationDllName) && ! is_file($destinationDllName)) { throw new RuntimeException('Failed to install DLL to ' . $destinationDllName); }