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);
}