diff --git a/src/Installing/UnixInstall.php b/src/Installing/UnixInstall.php
index a58c14db..0084655b 100644
--- a/src/Installing/UnixInstall.php
+++ b/src/Installing/UnixInstall.php
@@ -5,6 +5,7 @@
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 @@ public function __invoke(
IOInterface $io,
bool $attemptToSetupIniFile,
): BinaryFile {
- $targetExtensionPath = $targetPlatform->phpBinaryPath->extensionPath();
+ $env = [];
+ $installRoot = (string) ComposerPlatform::getEnv('INSTALL_ROOT');
+ if ($installRoot !== '') {
+ $io->write(sprintf('Using INSTALL_ROOT=%s', $installRoot));
+ $env['INSTALL_ROOT'] = $installRoot;
+ }
+
+ $targetExtensionPath = $targetPlatform->phpBinaryPath->extensionPath($installRoot);
$sharedObjectName = $downloadedPackage->package->extensionName()->name() . '.so';
$expectedSharedObjectLocation = sprintf(
@@ -93,6 +101,7 @@ public function __invoke(
$installCommand,
$downloadedPackage->extractedSourcePath,
self::MAKE_INSTALL_TIMEOUT_SECS,
+ env: $env,
);
$io->write($makeInstallOutput, verbosity: IOInterface::VERY_VERBOSE);
diff --git a/src/Platform/TargetPhp/PhpBinaryPath.php b/src/Platform/TargetPhp/PhpBinaryPath.php
index 32108921..f0f231c9 100644
--- a/src/Platform/TargetPhp/PhpBinaryPath.php
+++ b/src/Platform/TargetPhp/PhpBinaryPath.php
@@ -30,9 +30,11 @@
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 @@ public function debugMode(): DebugBuild
}
/** @return non-empty-string */
- public function extensionPath(): string
+ public function extensionPath(string|null $prefixInstallRoot = null): string
{
$phpinfo = $this->phpinfo();
@@ -116,6 +118,10 @@ public function extensionPath(): string
$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;
}
diff --git a/src/Util/Process.php b/src/Util/Process.php
index 329ce5f2..8e32df16 100644
--- a/src/Util/Process.php
+++ b/src/Util/Process.php
@@ -30,6 +30,7 @@ private function __construct()
*
* @param list $command
* @param callable(SymfonyProcess::ERR|SymfonyProcess::OUT, string): void|null $outputCallback
+ * @param array|null $env
*
* @throws ProcessFailedException
*/
@@ -38,8 +39,9 @@ public static function run(
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());
}
diff --git a/test/integration/Installing/UnixInstallTest.php b/test/integration/Installing/UnixInstallTest.php
index f80e21d8..820146ed 100644
--- a/test/integration/Installing/UnixInstallTest.php
+++ b/test/integration/Installing/UnixInstallTest.php
@@ -6,6 +6,7 @@
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_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 @@ public static function phpPathProvider(): array
#[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 @@ public function testUnixInstallCanInstallExtensionBuiltFromSource(string $phpCon
$output = new BufferIO();
$targetPlatform = TargetPlatform::fromPhpBinaryPath(PhpBinaryPath::fromPhpConfigExecutable($phpConfig), null);
- $extensionPath = $targetPlatform->phpBinaryPath->extensionPath();
+ $extensionPath = $targetPlatform->phpBinaryPath->extensionPath($installRoot);
$composerPackage = $this->createMock(CompletePackageInterface::class);
$composerPackage
@@ -136,11 +143,17 @@ public function testUnixInstallCanInstallExtensionBuiltFromSource(string $phpCon
(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');
@@ -148,7 +161,8 @@ public function testUnixInstallCanInstallPrePackagedBinary(string $phpConfig): v
$output = new BufferIO();
$targetPlatform = TargetPlatform::fromPhpBinaryPath(PhpBinaryPath::fromPhpConfigExecutable($phpConfig), 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);
@@ -220,6 +234,8 @@ public function testUnixInstallCanInstallPrePackagedBinary(string $phpConfig): v
}
(new Process($rmCommand))->mustRun();
- unlink($prebuiltBinaryFile->filePath);
+ (new Filesystem())->remove($prebuiltBinaryFile->filePath);
+ (new Filesystem())->remove($installRoot);
+ putenv('INSTALL_ROOT=' . $oldInstallRoot);
}
}
diff --git a/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php b/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php
index 321ac7d8..eeeda371 100644
--- a/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php
+++ b/test/unit/Platform/TargetPhp/PhpBinaryPathTest.php
@@ -276,6 +276,22 @@ public function testExtensionPathOnLinuxThatAlreadyExists(): void
);
}
+ #[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 @@ public function testExtensionPathIsImplicitlyCreated(): void
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 */
public static function phpPathProvider(): array
{