Prefix INSTALL_ROOT env var for UnixInstall

This commit is contained in:
James Titcumb
2026-02-12 09:12:12 +00:00
parent 682a10b9f1
commit 62361e1d46
5 changed files with 69 additions and 7 deletions

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Php\Pie\Installing;
use Composer\IO\IOInterface;
use Composer\Util\Platform as ComposerPlatform;
use Php\Pie\Downloading\DownloadedPackage;
use Php\Pie\Downloading\DownloadUrlMethod;
use Php\Pie\File\BinaryFile;
@@ -37,7 +38,14 @@ final class UnixInstall implements Install
IOInterface $io,
bool $attemptToSetupIniFile,
): BinaryFile {
$targetExtensionPath = $targetPlatform->phpBinaryPath->extensionPath();
$env = [];
$installRoot = (string) ComposerPlatform::getEnv('INSTALL_ROOT');
if ($installRoot !== '') {
$io->write(sprintf('<info>Using INSTALL_ROOT=%s</info>', $installRoot));
$env['INSTALL_ROOT'] = $installRoot;
}
$targetExtensionPath = $targetPlatform->phpBinaryPath->extensionPath($installRoot);
$sharedObjectName = $downloadedPackage->package->extensionName()->name() . '.so';
$expectedSharedObjectLocation = sprintf(
@@ -93,6 +101,7 @@ final class UnixInstall implements Install
$installCommand,
$downloadedPackage->extractedSourcePath,
self::MAKE_INSTALL_TIMEOUT_SECS,
env: $env,
);
$io->write($makeInstallOutput, verbosity: IOInterface::VERY_VERBOSE);

View File

@@ -30,9 +30,11 @@ use function implode;
use function in_array;
use function is_dir;
use function is_executable;
use function ltrim;
use function mkdir;
use function preg_match;
use function preg_replace;
use function rtrim;
use function sprintf;
use function strtolower;
use function trim;
@@ -103,7 +105,7 @@ class PhpBinaryPath
}
/** @return non-empty-string */
public function extensionPath(): string
public function extensionPath(string|null $prefixInstallRoot = null): string
{
$phpinfo = $this->phpinfo();
@@ -116,6 +118,10 @@ class PhpBinaryPath
$extensionPath = trim($matches[1]);
assert($extensionPath !== '');
if (self::operatingSystem() !== OperatingSystem::Windows && $prefixInstallRoot !== null && $prefixInstallRoot !== '') {
$extensionPath = rtrim($prefixInstallRoot, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . ltrim($extensionPath, DIRECTORY_SEPARATOR);
}
if (file_exists($extensionPath) && is_dir($extensionPath)) {
return $extensionPath;
}

View File

@@ -30,6 +30,7 @@ final class Process
*
* @param list<string> $command
* @param callable(SymfonyProcess::ERR|SymfonyProcess::OUT, string): void|null $outputCallback
* @param array<string, scalar>|null $env
*
* @throws ProcessFailedException
*/
@@ -38,8 +39,9 @@ final class Process
string|null $workingDirectory = null,
int|null $timeout = self::NO_TIMEOUT,
callable|null $outputCallback = null,
array|null $env = null,
): string {
return trim((new SymfonyProcess($command, $workingDirectory, timeout: $timeout))
return trim((new SymfonyProcess($command, $workingDirectory, $env, timeout: $timeout))
->mustRun($outputCallback)
->getOutput());
}

View File

@@ -6,6 +6,7 @@ namespace Php\PieIntegrationTest\Installing;
use Composer\IO\BufferIO;
use Composer\Package\CompletePackageInterface;
use Composer\Util\Filesystem;
use Composer\Util\Platform;
use Php\Pie\Building\UnixBuild;
use Php\Pie\DependencyResolver\Package;
@@ -30,11 +31,13 @@ use function array_map;
use function array_unshift;
use function assert;
use function file_exists;
use function getenv;
use function is_executable;
use function is_writable;
use function mkdir;
use function putenv;
use function rename;
use function unlink;
use function uniqid;
use const DIRECTORY_SEPARATOR;
@@ -79,6 +82,10 @@ final class UnixInstallTest extends TestCase
#[DataProvider('phpPathProvider')]
public function testUnixInstallCanInstallExtensionBuiltFromSource(string $phpConfig): void
{
$installRoot = '/tmp/' . uniqid('pie-test-install-root-', true);
$oldInstallRoot = getenv('INSTALL_ROOT');
putenv('INSTALL_ROOT=' . $installRoot);
assert($phpConfig !== '');
if (Platform::isWindows()) {
self::markTestSkipped('Unix build test cannot be run on Windows');
@@ -86,7 +93,7 @@ final class UnixInstallTest extends TestCase
$output = new BufferIO();
$targetPlatform = TargetPlatform::fromPhpBinaryPath(PhpBinaryPath::fromPhpConfigExecutable($phpConfig), null, null);
$extensionPath = $targetPlatform->phpBinaryPath->extensionPath();
$extensionPath = $targetPlatform->phpBinaryPath->extensionPath($installRoot);
$composerPackage = $this->createMock(CompletePackageInterface::class);
$composerPackage
@@ -135,11 +142,17 @@ final class UnixInstallTest extends TestCase
(new Process($rmCommand))->mustRun();
(new Process(['make', 'clean'], $downloadedPackage->extractedSourcePath))->mustRun();
(new Process(['phpize', '--clean'], $downloadedPackage->extractedSourcePath))->mustRun();
(new Filesystem())->remove($installRoot);
putenv('INSTALL_ROOT=' . $oldInstallRoot);
}
#[DataProvider('phpPathProvider')]
public function testUnixInstallCanInstallPrePackagedBinary(string $phpConfig): void
{
$installRoot = '/tmp/' . uniqid('pie-test-install-root-', true);
$oldInstallRoot = getenv('INSTALL_ROOT');
putenv('INSTALL_ROOT=' . $installRoot);
assert($phpConfig !== '');
if (Platform::isWindows()) {
self::markTestSkipped('Unix build test cannot be run on Windows');
@@ -147,7 +160,8 @@ final class UnixInstallTest extends TestCase
$output = new BufferIO();
$targetPlatform = TargetPlatform::fromPhpBinaryPath(PhpBinaryPath::fromPhpConfigExecutable($phpConfig), null, null);
$extensionPath = $targetPlatform->phpBinaryPath->extensionPath();
$extensionPath = $installRoot . $targetPlatform->phpBinaryPath->extensionPath();
mkdir($extensionPath, 0777, true);
// First build it (otherwise the test assets would need to have a binary for every test platform...)
$composerPackage = $this->createMock(CompletePackageInterface::class);
@@ -218,6 +232,8 @@ final class UnixInstallTest extends TestCase
}
(new Process($rmCommand))->mustRun();
unlink($prebuiltBinaryFile->filePath);
(new Filesystem())->remove($prebuiltBinaryFile->filePath);
(new Filesystem())->remove($installRoot);
putenv('INSTALL_ROOT=' . $oldInstallRoot);
}
}

View File

@@ -276,6 +276,22 @@ final class PhpBinaryPathTest extends TestCase
);
}
#[RequiresOperatingSystemFamily('Linux')]
public function testExtensionPathWithInstallRootPrefixOnLinuxThatAlreadyExists(): void
{
$installRoot = '/tmp/' . uniqid('pie-test-install-root-existing-', true);
$phpBinary = PhpBinaryPath::fromCurrentProcess();
$expectedExtensionDir = $installRoot . ini_get('extension_dir');
mkdir($expectedExtensionDir, 0777, true);
self::assertDirectoryExists($expectedExtensionDir);
self::assertSame(
$expectedExtensionDir,
$phpBinary->extensionPath($installRoot),
);
}
#[RequiresOperatingSystemFamily('Windows')]
public function testExtensionPathOnWindows(): void
{
@@ -336,6 +352,19 @@ final class PhpBinaryPathTest extends TestCase
self::assertDirectoryExists($configuredExtensionPath);
}
#[RequiresOperatingSystemFamily('Linux')]
public function testExtensionPathWithInstallRootPrefixIsImplicitlyCreated(): void
{
$installRoot = '/tmp/' . uniqid('pie-test-install-root-not-existing-', true);
$phpBinary = PhpBinaryPath::fromCurrentProcess();
$expectedExtensionDir = $installRoot . ini_get('extension_dir');
self::assertDirectoryDoesNotExist($expectedExtensionDir);
self::assertSame($expectedExtensionDir, $phpBinary->extensionPath($installRoot));
self::assertDirectoryExists($expectedExtensionDir);
}
/** @return array<string, array{0: string}> */
public static function phpPathProvider(): array
{