Skip to content

Commit

Permalink
Merge pull request #59 from asgrim/fix-phpize-path
Browse files Browse the repository at this point in the history
Fix phpize path used for UnixBuild & a bunch of test fixes
  • Loading branch information
asgrim authored Oct 2, 2024
2 parents 62d2bee + 7e1321e commit c8cbc12
Show file tree
Hide file tree
Showing 12 changed files with 340 additions and 92 deletions.
42 changes: 30 additions & 12 deletions src/Building/UnixBuild.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Php\Pie\Building;

use Php\Pie\Downloading\DownloadedPackage;
use Php\Pie\Platform\TargetPhp\PhpizePath;
use Php\Pie\Platform\TargetPlatform;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
Expand All @@ -24,19 +25,33 @@ public function __invoke(
array $configureOptions,
OutputInterface $output,
): void {
$this->phpize($downloadedPackage);
$phpizeOutput = $this->phpize(
PhpizePath::guessFrom($targetPlatform->phpBinaryPath),
$downloadedPackage,
);
if ($output->isVeryVerbose()) {
$output->writeln($phpizeOutput);
}

$output->writeln('<info>phpize complete</info>.');

$phpConfigPath = $targetPlatform->phpBinaryPath->phpConfigPath();
if ($phpConfigPath !== null) {
$configureOptions[] = '--with-php-config=' . $phpConfigPath;
}

$this->configure($downloadedPackage, $configureOptions);
$configureOutput = $this->configure($downloadedPackage, $configureOptions);
if ($output->isVeryVerbose()) {
$output->writeln($configureOutput);
}

$optionsOutput = count($configureOptions) ? ' with options: ' . implode(' ', $configureOptions) : '.';
$output->writeln('<info>Configure complete</info>' . $optionsOutput);

$this->make($downloadedPackage);
$makeOutput = $this->make($downloadedPackage);
if ($output->isVeryVerbose()) {
$output->writeln($makeOutput);
}

$expectedSoFile = $downloadedPackage->extractedSourcePath . '/modules/' . $downloadedPackage->package->extensionName->name() . '.so';

Expand All @@ -55,22 +70,25 @@ public function __invoke(
));
}

private function phpize(DownloadedPackage $downloadedPackage): void
private function phpize(PhpizePath $phpize, DownloadedPackage $downloadedPackage): string
{
(new Process(['phpize'], $downloadedPackage->extractedSourcePath))
->mustRun();
return (new Process([$phpize->phpizeBinaryPath], $downloadedPackage->extractedSourcePath))
->mustRun()
->getOutput();
}

/** @param list<non-empty-string> $configureOptions */
private function configure(DownloadedPackage $downloadedPackage, array $configureOptions = []): void
private function configure(DownloadedPackage $downloadedPackage, array $configureOptions = []): string
{
(new Process(['./configure', ...$configureOptions], $downloadedPackage->extractedSourcePath))
->mustRun();
return (new Process(['./configure', ...$configureOptions], $downloadedPackage->extractedSourcePath))
->mustRun()
->getOutput();
}

private function make(DownloadedPackage $downloadedPackage): void
private function make(DownloadedPackage $downloadedPackage): string
{
(new Process(['make'], $downloadedPackage->extractedSourcePath))
->mustRun();
return (new Process(['make'], $downloadedPackage->extractedSourcePath))
->mustRun()
->getOutput();
}
}
6 changes: 5 additions & 1 deletion src/Installing/UnixInstall.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ public function __invoke(DownloadedPackage $downloadedPackage, TargetPlatform $t
array_unshift($makeInstallCommand, 'sudo');
}

(new Process($makeInstallCommand, $downloadedPackage->extractedSourcePath))
$makeInstallOutput = (new Process($makeInstallCommand, $downloadedPackage->extractedSourcePath))
->mustRun()
->getOutput();

if ($output->isVeryVerbose()) {
$output->writeln($makeInstallOutput);
}

if (! file_exists($expectedSharedObjectLocation)) {
throw new RuntimeException('Install failed, ' . $expectedSharedObjectLocation . ' was not installed.');
}
Expand Down
14 changes: 14 additions & 0 deletions src/Platform/TargetPhp/PhpBinaryPath.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,20 @@ private static function assertValidLookingPhpBinary(string $phpBinaryPath): void
}
}

/** @return non-empty-string */
public function phpApiVersion(): string
{
if (
preg_match('/PHP API([ =>\t]*)(.*)/', $this->phpinfo(), $m)
&& array_key_exists(2, $m)
&& $m[2] !== ''
) {
return $m[2];
}

throw new RuntimeException('Failed to find PHP API version...');
}

/** @return non-empty-string */
public function extensionPath(): string
{
Expand Down
72 changes: 72 additions & 0 deletions src/Platform/TargetPhp/PhpizePath.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

namespace Php\Pie\Platform\TargetPhp;

use RuntimeException;
use Symfony\Component\Process\Process;

use function array_key_exists;
use function assert;
use function file_exists;
use function is_executable;
use function preg_match;
use function preg_replace;
use function trim;

/**
* @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks
*
* @immutable
*/
final class PhpizePath
{
/** @param non-empty-string $phpizeBinaryPath */
public function __construct(public readonly string $phpizeBinaryPath)
{
}

public static function guessFrom(PhpBinaryPath $phpBinaryPath): self
{
$expectedApiVersion = $phpBinaryPath->phpApiVersion();

$phpizeAttempts = [];

// Try to add `phpize` from path
$whichPhpize = new Process(['which', 'phpize']);
if ($whichPhpize->run() === 0) {
$phpizeAttempts[] = trim($whichPhpize->getOutput());
}

// Try to guess based on the `php` path itself
$phpizeAttempts[] = preg_replace('((.*)php)', '$1phpize', $phpBinaryPath->phpBinaryPath);

foreach ($phpizeAttempts as $phpizeAttempt) {
assert($phpizeAttempt !== '');
if (! file_exists($phpizeAttempt) || ! is_executable($phpizeAttempt)) {
continue;
}

$phpizeProcess = new Process([$phpizeAttempt, '--version']);
if ($phpizeProcess->run() !== 0) {
continue;
}

if (
! preg_match('/PHP Api Version:\s*(.*)/', $phpizeProcess->getOutput(), $m)
|| ! array_key_exists(1, $m)
|| $m[1] === ''
) {
continue;
}

if ($expectedApiVersion === $m[1]) {
return new self($phpizeAttempt);
}
}

// @todo add a way to specify --phpize or similar
throw new RuntimeException('did not find a good phpize, oh');
}
}
7 changes: 0 additions & 7 deletions test/integration/Command/BuildCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandTester;

use const PHP_VERSION;
use const PHP_VERSION_ID;

#[CoversClass(BuildCommand::class)]
class BuildCommandTest extends TestCase
{
Expand All @@ -28,10 +25,6 @@ public function setUp(): void

public function testBuildCommandWillBuildTheExtension(): void
{
if (PHP_VERSION_ID < 80300 || PHP_VERSION_ID >= 80400) {
self::markTestSkipped('This test can only run on PHP 8.3 - you are running ' . PHP_VERSION);
}

$this->commandTester->execute(['requested-package-and-version' => self::TEST_PACKAGE]);

$this->commandTester->assertCommandIsSuccessful();
Expand Down
24 changes: 10 additions & 14 deletions test/integration/Command/DownloadCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,18 @@ public function setUp(): void
public static function validVersionsList(): array
{
$versionsAndExpected = [
[self::TEST_PACKAGE, self::TEST_PACKAGE . ':1.0.1'],
[self::TEST_PACKAGE . ':^1.0', self::TEST_PACKAGE . ':1.0.1'],
[self::TEST_PACKAGE . ':1.0.1-alpha.3@alpha', self::TEST_PACKAGE . ':1.0.1-alpha.3'],
[self::TEST_PACKAGE . ':*', self::TEST_PACKAGE . ':1.0.1'],
[self::TEST_PACKAGE . ':~1.0.0@alpha', self::TEST_PACKAGE . ':1.0.1'],
[self::TEST_PACKAGE . ':~1.0.0', self::TEST_PACKAGE . ':1.0.1'],
[self::TEST_PACKAGE, self::TEST_PACKAGE . ':2.0.0'],
[self::TEST_PACKAGE . ':*', self::TEST_PACKAGE . ':2.0.0'],
[self::TEST_PACKAGE . ':^2.0', self::TEST_PACKAGE . ':2.0.0'],
];

if (PHP_VERSION_ID >= 80300 && PHP_VERSION_ID <= 80400) {
$versionsAndExpected[] = [self::TEST_PACKAGE . ':^1.0', self::TEST_PACKAGE . ':1.0.1'];
$versionsAndExpected[] = [self::TEST_PACKAGE . ':1.0.1-alpha.3@alpha', self::TEST_PACKAGE . ':1.0.1-alpha.3'];
$versionsAndExpected[] = [self::TEST_PACKAGE . ':~1.0.0@alpha', self::TEST_PACKAGE . ':1.0.1'];
$versionsAndExpected[] = [self::TEST_PACKAGE . ':~1.0.0', self::TEST_PACKAGE . ':1.0.1'];
}

return array_combine(
array_map(static fn ($item) => $item[0], $versionsAndExpected),
$versionsAndExpected,
Expand All @@ -65,10 +69,6 @@ public function testDownloadCommandWillDownloadCompatibleExtension(
string $requestedVersion,
string $expectedVersion,
): void {
if (PHP_VERSION_ID < 80300 || PHP_VERSION_ID >= 80400) {
self::markTestSkipped('This test can only run on PHP 8.3 - you are running ' . PHP_VERSION);
}

$this->commandTester->execute(['requested-package-and-version' => $requestedVersion]);

$this->commandTester->assertCommandIsSuccessful();
Expand All @@ -84,10 +84,6 @@ public function testDownloadCommandWillDownloadSpecificCommits(): void
self::markTestSkipped('This test can only run on non-Windows systems');
}

if (PHP_VERSION_ID < 80300 || PHP_VERSION_ID >= 80400) {
self::markTestSkipped('This test can only run on PHP 8.3 - you are running ' . PHP_VERSION);
}

$this->commandTester->execute(['requested-package-and-version' => 'asgrim/example-pie-extension:dev-main#9b5e6c80a1e05556e4e6824f0c112a4992cee001']);

$this->commandTester->assertCommandIsSuccessful();
Expand Down
7 changes: 0 additions & 7 deletions test/integration/Command/InfoCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandTester;

use const PHP_VERSION;
use const PHP_VERSION_ID;

#[CoversClass(InfoCommand::class)]
final class InfoCommandTest extends TestCase
{
Expand All @@ -25,10 +22,6 @@ public function setUp(): void

public function testInfoCommandDisplaysInformation(): void
{
if (PHP_VERSION_ID < 80300 || PHP_VERSION_ID >= 80400) {
self::markTestSkipped('This test can only run on PHP 8.3 - you are running ' . PHP_VERSION);
}

$this->commandTester->execute(['requested-package-and-version' => 'asgrim/example-pie-extension:dev-main#9b5e6c80a1e05556e4e6824f0c112a4992cee001']);

$this->commandTester->assertCommandIsSuccessful();
Expand Down
52 changes: 41 additions & 11 deletions test/integration/Command/InstallCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,25 @@
use Php\Pie\Command\InstallCommand;
use Php\Pie\Container;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Process\Process;

use function array_combine;
use function array_filter;
use function array_key_exists;
use function array_map;
use function array_unshift;
use function assert;
use function file_exists;
use function is_executable;
use function is_file;
use function is_string;
use function is_writable;
use function preg_match;

use const PHP_VERSION;
use const PHP_VERSION_ID;

#[CoversClass(InstallCommand::class)]
class InstallCommandTest extends TestCase
{
Expand All @@ -36,17 +39,48 @@ public function setUp(): void
$this->commandTester = new CommandTester(Container::factory()->get(InstallCommand::class));
}

public function testInstallCommandWillInstallCompatibleExtensionNonWindows(): void
/**
* @return array<string, array{0: string}>
*
* @psalm-suppress PossiblyUnusedMethod https://github.com/psalm/psalm-plugin-phpunit/issues/131
*/
public static function phpPathProvider(): array
{
if (PHP_VERSION_ID < 80300 || PHP_VERSION_ID >= 80400) {
self::markTestSkipped('This test can only run on PHP 8.3 - you are running ' . PHP_VERSION);
// data providers cannot return empty, even if the test is skipped
if (Platform::isWindows()) {
return ['skip' => ['skip']];
}

$possiblePhpConfigPaths = array_filter(
[
'/usr/bin/php-config',
'/usr/bin/php-config8.3',
'/usr/bin/php-config8.2',
'/usr/bin/php-config8.1',
'/usr/bin/php-config8.0',
'/usr/bin/php-config7.4',
],
static fn (string $phpConfigPath) => file_exists($phpConfigPath)
&& is_executable($phpConfigPath),
);

return array_combine(
$possiblePhpConfigPaths,
array_map(static fn (string $phpConfigPath) => [$phpConfigPath], $possiblePhpConfigPaths),
);
}

#[DataProvider('phpPathProvider')]
public function testInstallCommandWillInstallCompatibleExtensionNonWindows(string $phpConfigPath): void
{
if (Platform::isWindows()) {
self::markTestSkipped('This test can only run on non-Windows systems');
}

$this->commandTester->execute(['requested-package-and-version' => self::TEST_PACKAGE]);
$this->commandTester->execute(
['requested-package-and-version' => self::TEST_PACKAGE, '--with-php-config' => $phpConfigPath],
['verbosity' => BufferedOutput::VERBOSITY_VERY_VERBOSE],
);

$this->commandTester->assertCommandIsSuccessful();

Expand Down Expand Up @@ -76,10 +110,6 @@ public function testInstallCommandWillInstallCompatibleExtensionNonWindows(): vo

public function testInstallCommandWillInstallCompatibleExtensionWindows(): void
{
if (PHP_VERSION_ID < 80300 || PHP_VERSION_ID >= 80400) {
self::markTestSkipped('This test can only run on PHP 8.3 - you are running ' . PHP_VERSION);
}

if (! Platform::isWindows()) {
self::markTestSkipped('This test can only run on Windows systems');
}
Expand Down
Loading

0 comments on commit c8cbc12

Please sign in to comment.