1
0
mirror of https://github.com/php/pie.git synced 2026-03-23 23:12:17 +01:00

Added docker-php-ext-enable INI method

This commit is contained in:
James Titcumb
2024-12-17 20:17:42 +00:00
parent f331578f1f
commit 294a529d77
5 changed files with 274 additions and 0 deletions

View File

@@ -77,6 +77,7 @@ final class Container
static function (ContainerInterface $container): Ini\SetupIniApproach {
return new Ini\PickBestSetupIniApproach([
$container->get(Ini\PreCheckExtensionAlreadyLoaded::class),
$container->get(Ini\DockerPhpExtEnable::class),
$container->get(Ini\StandardAdditionalPhpIniDirectory::class),
$container->get(Ini\StandardSinglePhpIni::class),
]);

View File

@@ -0,0 +1,89 @@
<?php
declare(strict_types=1);
namespace Php\Pie\Installing\Ini;
use Php\Pie\BinaryFile;
use Php\Pie\Downloading\DownloadedPackage;
use Php\Pie\Platform\TargetPhp\Exception\ExtensionIsNotLoaded;
use Php\Pie\Platform\TargetPlatform;
use Php\Pie\Util\Process;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Exception\ProcessFailedException;
use function sprintf;
/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
final class DockerPhpExtEnable implements SetupIniApproach
{
private const DOCKER_PHP_EXT_ENABLE = 'docker-php-ext-enable';
public function __construct(private readonly string $dockerPhpExtEnableName = self::DOCKER_PHP_EXT_ENABLE)
{
}
public function canBeUsed(TargetPlatform $targetPlatform): bool
{
return $this->dockerPhpExtEnablePath() !== null;
}
public function setup(
TargetPlatform $targetPlatform,
DownloadedPackage $downloadedPackage,
BinaryFile $binaryFile,
OutputInterface $output,
): bool {
$dockerPhpExtEnable = $this->dockerPhpExtEnablePath();
if ($dockerPhpExtEnable === null) {
return false;
}
try {
$enableOutput = Process::run([$dockerPhpExtEnable, $downloadedPackage->package->extensionName->name()]);
} catch (ProcessFailedException $processFailed) {
$output->writeln(
sprintf(
'Could not enable extension %s using %s. Exception was: %s',
$downloadedPackage->package->extensionName->name(),
$this->dockerPhpExtEnableName,
$processFailed->getMessage(),
),
OutputInterface::VERBOSITY_VERBOSE,
);
return false;
}
try {
$targetPlatform->phpBinaryPath->assertExtensionIsLoadedInRuntime(
$downloadedPackage->package->extensionName,
$output,
);
return true;
} catch (ExtensionIsNotLoaded) {
$output->writeln(
sprintf(
'Asserting that extension %s was enabled using %s failed. Output was: %s',
$downloadedPackage->package->extensionName->name(),
$this->dockerPhpExtEnableName,
$enableOutput !== '' ? $enableOutput : '(empty)',
),
OutputInterface::VERBOSITY_VERBOSE,
);
return false;
}
}
private function dockerPhpExtEnablePath(): string|null
{
try {
return Process::run(['which', $this->dockerPhpExtEnableName]);
} catch (ProcessFailedException) {
return null;
}
}
}

View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
echo "something bad happened"
exit 1

View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
echo "hi"
exit 0

View File

@@ -0,0 +1,176 @@
<?php
declare(strict_types=1);
namespace Php\PieUnitTest\Installing\Ini;
use Composer\Package\CompletePackageInterface;
use Php\Pie\BinaryFile;
use Php\Pie\DependencyResolver\Package;
use Php\Pie\Downloading\DownloadedPackage;
use Php\Pie\ExtensionName;
use Php\Pie\ExtensionType;
use Php\Pie\Installing\Ini\DockerPhpExtEnable;
use Php\Pie\Platform\Architecture;
use Php\Pie\Platform\OperatingSystem;
use Php\Pie\Platform\OperatingSystemFamily;
use Php\Pie\Platform\TargetPhp\Exception\ExtensionIsNotLoaded;
use Php\Pie\Platform\TargetPhp\PhpBinaryPath;
use Php\Pie\Platform\TargetPlatform;
use Php\Pie\Platform\ThreadSafetyMode;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Output\BufferedOutput;
#[RequiresOperatingSystemFamily('Linux')]
#[CoversClass(DockerPhpExtEnable::class)]
final class DockerPhpExtEnableTest extends TestCase
{
private const NON_EXISTENT_DOCKER_PHP_EXT_ENABLE = 'something-that-should-not-be-in-path';
private const GOOD_DOCKER_PHP_EXT_ENABLE = __DIR__ . '/../../../assets/docker-php-ext-enable/good';
private const BAD_DOCKER_PHP_EXT_ENABLE = __DIR__ . '/../../../assets/docker-php-ext-enable/bad';
private BufferedOutput $output;
private PhpBinaryPath&MockObject $mockPhpBinary;
private TargetPlatform $targetPlatform;
private DownloadedPackage $downloadedPackage;
private BinaryFile $binaryFile;
public function setUp(): void
{
parent::setUp();
$this->output = new BufferedOutput(BufferedOutput::VERBOSITY_VERBOSE);
$this->mockPhpBinary = $this->createMock(PhpBinaryPath::class);
/**
* @psalm-suppress PossiblyNullFunctionCall
* @psalm-suppress UndefinedThisPropertyAssignment
*/
(fn () => $this->phpBinaryPath = '/path/to/php')
->bindTo($this->mockPhpBinary, PhpBinaryPath::class)();
$this->targetPlatform = new TargetPlatform(
OperatingSystem::NonWindows,
OperatingSystemFamily::Linux,
$this->mockPhpBinary,
Architecture::x86_64,
ThreadSafetyMode::ThreadSafe,
1,
null,
);
$this->downloadedPackage = DownloadedPackage::fromPackageAndExtractedPath(
new Package(
$this->createMock(CompletePackageInterface::class),
ExtensionType::PhpModule,
ExtensionName::normaliseFromString('foobar'),
'foo/bar',
'1.2.3',
null,
[],
true,
true,
null,
null,
null,
99,
),
'/path/to/extracted/source',
);
$this->binaryFile = new BinaryFile('/path/to/compiled/extension.so', 'fake checksum');
}
public function testCannotBeUsedWhenDockerPhpExtEnableIsNotInPath(): void
{
self::assertFalse(
(new DockerPhpExtEnable(self::NON_EXISTENT_DOCKER_PHP_EXT_ENABLE))
->canBeUsed($this->targetPlatform),
);
}
public function testCanBeUsedWhenDockerPhpExtEnableIsInPath(): void
{
self::assertTrue(
(new DockerPhpExtEnable(self::GOOD_DOCKER_PHP_EXT_ENABLE))
->canBeUsed($this->targetPlatform),
);
}
public function testSetupReturnsFalseWhenWhenDockerPhpExtEnableIsNotInPath(): void
{
$this->mockPhpBinary
->expects(self::never())
->method('assertExtensionIsLoadedInRuntime');
self::assertFalse(
(new DockerPhpExtEnable(self::NON_EXISTENT_DOCKER_PHP_EXT_ENABLE))
->setup(
$this->targetPlatform,
$this->downloadedPackage,
$this->binaryFile,
$this->output,
),
);
}
public function testReturnsTrueWhenDockerPhpExtEnableSuccessfullyEnablesExtension(): void
{
$this->mockPhpBinary
->expects(self::once())
->method('assertExtensionIsLoadedInRuntime')
->with($this->downloadedPackage->package->extensionName, $this->output);
self::assertTrue(
(new DockerPhpExtEnable(self::GOOD_DOCKER_PHP_EXT_ENABLE))
->setup(
$this->targetPlatform,
$this->downloadedPackage,
$this->binaryFile,
$this->output,
),
);
}
public function testReturnsFalseWhenDockerPhpExtEnableFailsToBeRun(): void
{
$this->mockPhpBinary
->expects(self::never())
->method('assertExtensionIsLoadedInRuntime');
self::assertFalse(
(new DockerPhpExtEnable(self::BAD_DOCKER_PHP_EXT_ENABLE))
->setup(
$this->targetPlatform,
$this->downloadedPackage,
$this->binaryFile,
$this->output,
),
);
}
public function testReturnsFalseWhenDockerPhpExtEnableFailsToAssertExtensionWasEnabled(): void
{
$this->mockPhpBinary
->expects(self::once())
->method('assertExtensionIsLoadedInRuntime')
->with($this->downloadedPackage->package->extensionName, $this->output)
->willThrowException(ExtensionIsNotLoaded::fromExpectedExtension(
$this->mockPhpBinary,
$this->downloadedPackage->package->extensionName,
));
self::assertFalse(
(new DockerPhpExtEnable(self::GOOD_DOCKER_PHP_EXT_ENABLE))
->setup(
$this->targetPlatform,
$this->downloadedPackage,
$this->binaryFile,
$this->output,
),
);
}
}