Skip to content

Commit

Permalink
Merge pull request #116 from alexandre-daubois/os-composer-json
Browse files Browse the repository at this point in the history
Add support for `os-families-exclude` in extensions `composer.json`
  • Loading branch information
asgrim authored Dec 9, 2024
2 parents 89379c0 + 8110e8c commit 72b239c
Show file tree
Hide file tree
Showing 26 changed files with 465 additions and 9 deletions.
14 changes: 7 additions & 7 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions src/DependencyResolver/IncompatibleOperatingSystemFamily.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Php\Pie\DependencyResolver;

use Php\Pie\Platform\OperatingSystemFamily;
use RuntimeException;

use function array_map;
use function implode;
use function sprintf;

class IncompatibleOperatingSystemFamily extends RuntimeException
{
/** @param list<OperatingSystemFamily> $required */
public static function notInCompatibleOperatingSystemFamilies(array $required, OperatingSystemFamily $current): self
{
return new self(sprintf(
'This extension does not support the "%s" operating system family. It is compatible with the following families: "%s".',
$current->value,
implode('", "', array_map(static fn (OperatingSystemFamily $osFamily): string => $osFamily->value, $required)),
));
}

/** @param list<OperatingSystemFamily> $incompatibleOsFamilies */
public static function inIncompatibleOperatingSystemFamily(array $incompatibleOsFamilies, OperatingSystemFamily $current): self
{
return new self(sprintf(
'This extension does not support the "%s" operating system family. It is incompatible with the following families: "%s".',
$current->value,
implode('", "', array_map(static fn (OperatingSystemFamily $osFamily): string => $osFamily->value, $incompatibleOsFamilies)),
));
}
}
46 changes: 45 additions & 1 deletion src/DependencyResolver/Package.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
namespace Php\Pie\DependencyResolver;

use Composer\Package\CompletePackageInterface;
use InvalidArgumentException;
use Php\Pie\ConfigureOption;
use Php\Pie\ExtensionName;
use Php\Pie\ExtensionType;
use Php\Pie\Platform\OperatingSystemFamily;
use Webmozart\Assert\Assert;

use function array_key_exists;
use function array_map;
Expand All @@ -17,6 +20,7 @@
use function parse_url;
use function str_contains;
use function str_starts_with;
use function strtolower;

/**
* @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks
Expand All @@ -25,7 +29,11 @@
*/
final class Package
{
/** @param list<ConfigureOption> $configureOptions */
/**
* @param list<ConfigureOption> $configureOptions
* @param non-empty-list<OperatingSystemFamily>|null $compatibleOsFamilies
* @param non-empty-list<OperatingSystemFamily>|null $incompatibleOsFamilies
*/
public function __construct(
public readonly CompletePackageInterface $composerPackage,
public readonly ExtensionType $extensionType,
Expand All @@ -37,6 +45,8 @@ public function __construct(
public readonly bool $supportZts,
public readonly bool $supportNts,
public readonly string|null $buildPath,
public readonly array|null $compatibleOsFamilies,
public readonly array|null $incompatibleOsFamilies,
) {
}

Expand All @@ -63,6 +73,13 @@ public static function fromComposerCompletePackage(CompletePackageInterface $com
? $phpExtOptions['build-path']
: null;

$compatibleOsFamilies = $phpExtOptions['os-families'] ?? null;
$incompatibleOsFamilies = $phpExtOptions['os-families-exclude'] ?? null;

if ($compatibleOsFamilies !== null && $incompatibleOsFamilies !== null) {
throw new InvalidArgumentException('Cannot specify both "os-families" and "os-families-exclude" in composer.json');
}

return new self(
$completePackage,
ExtensionType::tryFrom($completePackage->getType()) ?? ExtensionType::PhpModule,
Expand All @@ -74,6 +91,8 @@ public static function fromComposerCompletePackage(CompletePackageInterface $com
$supportZts,
$supportNts,
$buildPath,
self::convertInputStringsToOperatingSystemFamilies($compatibleOsFamilies),
self::convertInputStringsToOperatingSystemFamilies($incompatibleOsFamilies),
);
}

Expand All @@ -100,4 +119,29 @@ public function githubOrgAndRepository(): string
// Converts https://api.github.com/repos/<user>/<repository>/zipball/<sha>" to "<user>/<repository>"
return implode('/', array_slice(explode('/', $parsed['path']), 2, 2));
}

/**
* @param list<string>|null $input
*
* @return non-empty-list<OperatingSystemFamily>|null
*/
private static function convertInputStringsToOperatingSystemFamilies(array|null $input): array|null
{
if ($input === null) {
return null;
}

$osFamilies = [];
foreach ($input as $value) {
$valueToTry = strtolower($value);

Assert::inArray($valueToTry, OperatingSystemFamily::asValuesList(), 'Expected operating system family to be one of: %2$s. Got: %s');

$osFamilies[] = OperatingSystemFamily::from($valueToTry);
}

Assert::isNonEmptyList($osFamilies, 'Expected operating systems families to be a non-empty list.');

return $osFamilies;
}
}
19 changes: 19 additions & 0 deletions src/DependencyResolver/ResolveDependencyWithComposer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Php\Pie\Platform\TargetPlatform;
use Php\Pie\Platform\ThreadSafetyMode;

use function in_array;
use function preg_match;

/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
Expand Down Expand Up @@ -55,6 +56,7 @@ public function __invoke(Composer $composer, TargetPlatform $targetPlatform, Req

$piePackage = Package::fromComposerCompletePackage($package);

$this->assertCompatibleOsFamily($targetPlatform, $piePackage);
$this->assertCompatibleThreadSafetyMode($targetPlatform->threadSafety, $piePackage);

return $piePackage;
Expand All @@ -70,4 +72,21 @@ private function assertCompatibleThreadSafetyMode(ThreadSafetyMode $threadSafety
throw IncompatibleThreadSafetyMode::ntsExtensionOnZtsPlatform();
}
}

private function assertCompatibleOsFamily(TargetPlatform $targetPlatform, Package $resolvedPackage): void
{
if ($resolvedPackage->compatibleOsFamilies !== null && ! in_array($targetPlatform->operatingSystemFamily, $resolvedPackage->compatibleOsFamilies, true)) {
throw IncompatibleOperatingSystemFamily::notInCompatibleOperatingSystemFamilies(
$resolvedPackage->compatibleOsFamilies,
$targetPlatform->operatingSystemFamily,
);
}

if ($resolvedPackage->incompatibleOsFamilies !== null && in_array($targetPlatform->operatingSystemFamily, $resolvedPackage->incompatibleOsFamilies, true)) {
throw IncompatibleOperatingSystemFamily::inIncompatibleOperatingSystemFamily(
$resolvedPackage->incompatibleOsFamilies,
$targetPlatform->operatingSystemFamily,
);
}
}
}
27 changes: 27 additions & 0 deletions src/Platform/OperatingSystemFamily.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Php\Pie\Platform;

use function array_map;

/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
enum OperatingSystemFamily: string
{
case Windows = 'windows';
case Bsd = 'bsd';
case Darwin = 'darwin';
case Solaris = 'solaris';
case Linux = 'linux';
case Unknown = 'unknown';

/** @return non-empty-list<non-empty-string> */
public static function asValuesList(): array
{
return array_map(
static fn (OperatingSystemFamily $osFamily): string => $osFamily->value,
self::cases(),
);
}
}
16 changes: 16 additions & 0 deletions src/Platform/TargetPhp/PhpBinaryPath.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Composer\Util\Platform;
use Php\Pie\Platform\Architecture;
use Php\Pie\Platform\OperatingSystem;
use Php\Pie\Platform\OperatingSystemFamily;
use Php\Pie\Util\Process;
use RuntimeException;
use Symfony\Component\Process\PhpExecutableFinder;
Expand All @@ -24,6 +25,7 @@
use function is_executable;
use function preg_match;
use function sprintf;
use function strtolower;
use function trim;

use const DIRECTORY_SEPARATOR;
Expand Down Expand Up @@ -164,6 +166,20 @@ public function operatingSystem(): OperatingSystem
return $winOrNot === 'win' ? OperatingSystem::Windows : OperatingSystem::NonWindows;
}

public function operatingSystemFamily(): OperatingSystemFamily
{
$output = Process::run([
$this->phpBinaryPath,
'-r',
'echo PHP_OS_FAMILY;',
]);

$osFamily = OperatingSystemFamily::tryFrom(strtolower(trim($output)));
Assert::notNull($osFamily, 'Could not determine operating system family');

return $osFamily;
}

/** @return non-empty-string */
public function version(): string
{
Expand Down
5 changes: 4 additions & 1 deletion src/Platform/TargetPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class TargetPlatform
{
public function __construct(
public readonly OperatingSystem $operatingSystem,
public readonly OperatingSystemFamily $operatingSystemFamily,
public readonly PhpBinaryPath $phpBinaryPath,
public readonly Architecture $architecture,
public readonly ThreadSafetyMode $threadSafety,
Expand All @@ -38,7 +39,8 @@ public static function isRunningAsRoot(): bool

public static function fromPhpBinaryPath(PhpBinaryPath $phpBinaryPath, int|null $makeParallelJobs): self
{
$os = $phpBinaryPath->operatingSystem();
$os = $phpBinaryPath->operatingSystem();
$osFamily = $phpBinaryPath->operatingSystemFamily();

$phpinfo = $phpBinaryPath->phpinfo();

Expand Down Expand Up @@ -114,6 +116,7 @@ public static function fromPhpBinaryPath(PhpBinaryPath $phpBinaryPath, int|null

return new self(
$os,
$osFamily,
$phpBinaryPath,
$architecture,
$threadSafety,
Expand Down
10 changes: 10 additions & 0 deletions test/integration/Building/UnixBuildTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public function testUnixBuildCanBuildExtension(): void
true,
true,
null,
null,
null,
),
self::TEST_EXTENSION_PATH,
);
Expand Down Expand Up @@ -101,6 +103,8 @@ public function testUnixBuildWillThrowExceptionWhenExpectedBinaryNameMismatches(
true,
true,
null,
null,
null,
),
self::TEST_EXTENSION_PATH,
);
Expand Down Expand Up @@ -142,6 +146,8 @@ public function testUnixBuildCanBuildExtensionWithBuildPath(): void
true,
true,
'pie_test_ext',
null,
null,
),
dirname(self::TEST_EXTENSION_PATH),
);
Expand Down Expand Up @@ -199,6 +205,8 @@ public function testCleanupDoesNotCleanWhenConfigureIsMissing(): void
true,
true,
null,
null,
null,
),
self::TEST_EXTENSION_PATH,
);
Expand Down Expand Up @@ -241,6 +249,8 @@ public function testVerboseOutputShowsCleanupMessages(): void
true,
true,
null,
null,
null,
),
self::TEST_EXTENSION_PATH,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Php\Pie\ExtensionType;
use Php\Pie\Platform\Architecture;
use Php\Pie\Platform\OperatingSystem;
use Php\Pie\Platform\OperatingSystemFamily;
use Php\Pie\Platform\TargetPhp\PhpBinaryPath;
use Php\Pie\Platform\TargetPlatform;
use Php\Pie\Platform\ThreadSafetyMode;
Expand All @@ -34,6 +35,7 @@ public function testDeterminingReleaseAssetUrlForWindows(): void

$targetPlatform = new TargetPlatform(
OperatingSystem::Windows,
OperatingSystemFamily::Windows,
$phpBinaryPath,
Architecture::x86_64,
ThreadSafetyMode::ThreadSafe,
Expand All @@ -52,6 +54,8 @@ public function testDeterminingReleaseAssetUrlForWindows(): void
true,
true,
null,
null,
null,
);

$io = $this->createMock(IOInterface::class);
Expand Down
2 changes: 2 additions & 0 deletions test/integration/Installing/UnixInstallTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ public function testUnixInstallCanInstallExtension(string $phpConfig): void
true,
true,
null,
null,
null,
),
self::TEST_EXTENSION_PATH,
);
Expand Down
Loading

0 comments on commit 72b239c

Please sign in to comment.