Skip to content

Commit

Permalink
Added INI enable approach for phpenmod
Browse files Browse the repository at this point in the history
  • Loading branch information
asgrim committed Dec 23, 2024
1 parent 1827440 commit 5329ebe
Show file tree
Hide file tree
Showing 5 changed files with 668 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ static function (ContainerInterface $container): Build {
static function (ContainerInterface $container): Ini\SetupIniApproach {
return new Ini\PickBestSetupIniApproach([
$container->get(Ini\PreCheckExtensionAlreadyLoaded::class),
$container->get(Ini\OndrejPhpenmod::class),
$container->get(Ini\DockerPhpExtEnable::class),
$container->get(Ini\StandardAdditionalPhpIniDirectory::class),
$container->get(Ini\StandardSinglePhpIni::class),
Expand Down
194 changes: 194 additions & 0 deletions src/Installing/Ini/OndrejPhpenmod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<?php

declare(strict_types=1);

namespace Php\Pie\Installing\Ini;

use Composer\Util\Platform;
use Php\Pie\BinaryFile;
use Php\Pie\Downloading\DownloadedPackage;
use Php\Pie\Platform\TargetPlatform;
use Php\Pie\Util\Process;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Exception\ProcessFailedException;

use function file_exists;
use function is_dir;
use function is_writable;
use function preg_match;
use function rtrim;
use function sprintf;
use function touch;
use function unlink;

use const DIRECTORY_SEPARATOR;

/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
final class OndrejPhpenmod implements SetupIniApproach
{
private const DEFAULT_PHPENMOD = 'phpenmod';
private const DEFAULT_MODS_AVAILABLE_PATH = '/etc/php/%s/mods-available';

public function __construct(
private readonly CheckAndAddExtensionToIniIfNeeded $checkAndAddExtensionToIniIfNeeded,
private readonly string $phpenmod = self::DEFAULT_PHPENMOD,
private readonly string $modsAvailablePath = self::DEFAULT_MODS_AVAILABLE_PATH,
) {
}

public function canBeUsed(TargetPlatform $targetPlatform): bool
{
return $this->phpenmodPath() !== null;
}

public function setup(
TargetPlatform $targetPlatform,
DownloadedPackage $downloadedPackage,
BinaryFile $binaryFile,
OutputInterface $output,
): bool {
$phpenmodPath = $this->phpenmodPath();

/** In practice, this shouldn't happen since {@see canBeUsed()} checks this */
if ($phpenmodPath === null) {
return false;
}

// the Ondrej repo uses an additional php.ini directory, if this isn't set, we may not actually be using Ondrej repo for this particular PHP install
$additionalPhpIniPath = $targetPlatform->phpBinaryPath->additionalIniDirectory();

if ($additionalPhpIniPath === null) {
$output->writeln(
'Additional INI file path was not set - may not be Ondrej PHP repo',
OutputInterface::VERBOSITY_VERBOSE,
);

return false;
}

// Cursory check for the expected PHP INI directory; this is another indication we're using the Ondrej repo
if (preg_match('#/etc/php/\d\.\d/[a-z-_]+/conf.d#', $additionalPhpIniPath) !== 1) {
$output->writeln(
sprintf(
'Warning: additional INI file path was not in the expected format (/etc/php/{version}/{sapi}/conf.d). Path was: %s',
$additionalPhpIniPath,
),
OutputInterface::VERBOSITY_VERY_VERBOSE,
);
}

$expectedModsAvailablePath = sprintf($this->modsAvailablePath, $targetPlatform->phpBinaryPath->majorMinorVersion());

if (! file_exists($expectedModsAvailablePath)) {
$output->writeln(
sprintf(
'Mods available path %s does not exist',
$expectedModsAvailablePath,
),
OutputInterface::VERBOSITY_VERBOSE,
);

return false;
}

if (! is_dir($expectedModsAvailablePath)) {
$output->writeln(
sprintf(
'Mods available path %s is not a directory',
$expectedModsAvailablePath,
),
OutputInterface::VERBOSITY_VERBOSE,
);

return false;
}

if (! is_writable($expectedModsAvailablePath)) {
$output->writeln(
sprintf(
'Mods available path %s is not writable',
$expectedModsAvailablePath,
),
OutputInterface::VERBOSITY_VERBOSE,
);

return false;
}

$expectedIniFile = sprintf(
'%s%s%s.ini',
rtrim($expectedModsAvailablePath, DIRECTORY_SEPARATOR),
DIRECTORY_SEPARATOR,
$downloadedPackage->package->extensionName->name(),
);

$pieCreatedTheIniFile = false;
if (! file_exists($expectedIniFile)) {
$output->writeln(
sprintf(
'Creating new INI file based on extension priority: %s',
$expectedIniFile,
),
OutputInterface::VERBOSITY_VERY_VERBOSE,
);
$pieCreatedTheIniFile = true;
touch($expectedIniFile);
}

$addingExtensionWasSuccessful = ($this->checkAndAddExtensionToIniIfNeeded)(
$expectedIniFile,
$targetPlatform,
$downloadedPackage,
$output,
static function () use ($phpenmodPath, $targetPlatform, $downloadedPackage, $output): bool {
try {
Process::run([
$phpenmodPath,
'-v',
$targetPlatform->phpBinaryPath->majorMinorVersion(),
'-s',
'ALL',
$downloadedPackage->package->extensionName->name(),
]);

return true;
} catch (ProcessFailedException $processFailedException) {
$output->writeln(
sprintf(
'Failed to use %s to enable %s for PHP %s: %s',
$phpenmodPath,
$downloadedPackage->package->extensionName->name(),
$targetPlatform->phpBinaryPath->majorMinorVersion(),
$processFailedException->getMessage(),
),
OutputInterface::VERBOSITY_VERBOSE,
);

return false;
}
},
);

if (! $addingExtensionWasSuccessful && $pieCreatedTheIniFile) {
unlink($expectedIniFile);
}

return $addingExtensionWasSuccessful;
}

/** @return non-empty-string|null */
private function phpenmodPath(): string|null
{
if (Platform::isWindows()) {
return null;
}

try {
$phpenmodPath = Process::run(['which', $this->phpenmod]);

return $phpenmodPath !== '' ? $phpenmodPath : null;
} catch (ProcessFailedException) {
return null;
}
}
}
4 changes: 4 additions & 0 deletions test/assets/phpenmod/bad
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash

echo "something bad happened"
exit 1
4 changes: 4 additions & 0 deletions test/assets/phpenmod/good
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash

echo "hi"
exit 0
Loading

0 comments on commit 5329ebe

Please sign in to comment.