diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index f810a9ba..549c691b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -486,18 +486,6 @@ parameters: count: 1 path: test/unit/Installing/InstallForPhpProject/InstallSelectedPackageTest.php - - - message: '#^Parameter \#1 \$filename of function file_exists expects string, string\|false given\.$#' - identifier: argument.type - count: 1 - path: test/unit/Platform/TargetPhp/PhpBinaryPathTest.php - - - - message: '#^Parameter \#1 \$filename of function is_dir expects string, string\|false given\.$#' - identifier: argument.type - count: 1 - path: test/unit/Platform/TargetPhp/PhpBinaryPathTest.php - - message: '#^Method Php\\PieUnitTest\\SelfManage\\Verify\\FallbackVerificationUsingOpenSslTest\:\:prepareCertificateAndSignature\(\) should return array\{string, string\} but returns array\{mixed, mixed\}\.$#' identifier: return.type diff --git a/src/Building/WindowsBuild.php b/src/Building/WindowsBuild.php index 39bb2a1b..c724accf 100644 --- a/src/Building/WindowsBuild.php +++ b/src/Building/WindowsBuild.php @@ -26,10 +26,13 @@ public function __invoke( ): BinaryFile { $prebuiltDll = WindowsExtensionAssetName::determineDllName($targetPlatform, $downloadedPackage); - $io->write(sprintf( - 'Nothing to do on Windows, prebuilt DLL found: %s', - $prebuiltDll, - )); + $io->write( + sprintf( + 'Nothing to build on Windows, prebuilt DLL found: %s', + $prebuiltDll, + ), + verbosity: IOInterface::VERBOSE, + ); return BinaryFile::fromFileWithSha256Checksum($prebuiltDll); } diff --git a/src/Platform/TargetPhp/PhpBinaryPath.php b/src/Platform/TargetPhp/PhpBinaryPath.php index 61216ccc..9f4a5579 100644 --- a/src/Platform/TargetPhp/PhpBinaryPath.php +++ b/src/Platform/TargetPhp/PhpBinaryPath.php @@ -107,18 +107,20 @@ public function extensionPath(): string return $extensionPath; } + // `extension_dir` may be a relative URL on Windows, so resolve it according to the location of PHP + if (self::operatingSystem() === OperatingSystem::Windows) { + $phpPath = dirname($this->phpBinaryPath); + $attemptExtensionPath = $phpPath . DIRECTORY_SEPARATOR . $extensionPath; + + if (file_exists($attemptExtensionPath) && is_dir($attemptExtensionPath)) { + return $attemptExtensionPath; + } + } + // if the path is absolute, try to create it if (mkdir($extensionPath, 0777, true) && file_exists($extensionPath) && is_dir($extensionPath)) { return $extensionPath; } - - // `extension_dir` may be a relative URL on Windows, so resolve it according to the location of PHP - $phpPath = dirname($this->phpBinaryPath); - $attemptExtensionPath = $phpPath . DIRECTORY_SEPARATOR . $extensionPath; - - if (file_exists($attemptExtensionPath) && is_dir($attemptExtensionPath)) { - return $attemptExtensionPath; - } } throw new RuntimeException('Could not determine extension path for ' . $this->phpBinaryPath); diff --git a/test/integration/Command/BuildCommandTest.php b/test/integration/Command/BuildCommandTest.php index 7e8d7010..07123e58 100644 --- a/test/integration/Command/BuildCommandTest.php +++ b/test/integration/Command/BuildCommandTest.php @@ -31,7 +31,7 @@ public function testBuildCommandWillBuildTheExtension(): void $outputString = $this->commandTester->getDisplay(); if (Platform::isWindows()) { - self::assertStringContainsString('Nothing to do on Windows', $outputString); + self::assertStringContainsString('Found prebuilt archive', $outputString); return; } diff --git a/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php b/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php index acd93e7f..064139e4 100644 --- a/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php +++ b/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php @@ -16,7 +16,9 @@ use Php\Pie\Util\Process; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily; use PHPUnit\Framework\TestCase; +use ReflectionMethod; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\PhpExecutableFinder; @@ -35,11 +37,13 @@ use function ini_get; use function is_dir; use function is_executable; +use function mkdir; use function php_uname; use function phpversion; use function sprintf; use function strtolower; use function sys_get_temp_dir; +use function trim; use function uniqid; use const DIRECTORY_SEPARATOR; @@ -235,11 +239,28 @@ public function testPhpIntSize(): void ); } - public function testExtensionPath(): void + #[RequiresOperatingSystemFamily('Linux')] + public function testExtensionPathOnLinuxThatAlreadyExists(): void { $phpBinary = PhpBinaryPath::fromCurrentProcess(); - $expectedExtensionDir = ini_get('extension_dir'); + $expectedExtensionDir = (string) ini_get('extension_dir'); + self::assertNotEmpty($expectedExtensionDir); + self::assertDirectoryExists($expectedExtensionDir); + + self::assertSame( + $expectedExtensionDir, + $phpBinary->extensionPath(), + ); + } + + #[RequiresOperatingSystemFamily('Windows')] + public function testExtensionPathOnWindows(): void + { + $phpBinary = PhpBinaryPath::fromCurrentProcess(); + + $expectedExtensionDir = (string) ini_get('extension_dir'); + self::assertNotEmpty($expectedExtensionDir); // `extension_dir` may be a relative URL on Windows (e.g. "ext"), so resolve it according to the location of PHP if (! file_exists($expectedExtensionDir) || ! is_dir($expectedExtensionDir)) { @@ -255,9 +276,32 @@ public function testExtensionPath(): void ); } + #[RequiresOperatingSystemFamily('Windows')] + public function testRelativeExtensionPathOnWindowsIsFilled(): void + { + $phpBinary = $this->createPartialMock(PhpBinaryPath::class, ['phpinfo']); + (new ReflectionMethod($phpBinary, '__construct')) + ->invoke($phpBinary, trim((string) (new PhpExecutableFinder())->find()), null); + + $configuredExtensionPath = 'foo'; + self::assertDirectoryDoesNotExist($configuredExtensionPath, 'test cannot run if the same-named extension dir already exists in cwd'); + + $fullExtensionPath = dirname($phpBinary->phpBinaryPath) . DIRECTORY_SEPARATOR . $configuredExtensionPath; + mkdir($fullExtensionPath, 0777, true); + self::assertDirectoryExists($fullExtensionPath); + + $phpBinary->expects(self::once()) + ->method('phpinfo') + ->willReturn(sprintf('extension_dir => %s => %s', $configuredExtensionPath, $configuredExtensionPath)); + + self::assertSame($fullExtensionPath, $phpBinary->extensionPath()); + } + public function testExtensionPathIsImplicitlyCreated(): void { $phpBinary = $this->createPartialMock(PhpBinaryPath::class, ['phpinfo']); + (new ReflectionMethod($phpBinary, '__construct')) + ->invoke($phpBinary, trim((string) (new PhpExecutableFinder())->find()), null); $configuredExtensionPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('PIE_non_existent_extension_path', true); self::assertDirectoryDoesNotExist($configuredExtensionPath);