Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for os-families-exclude in extensions composer.json #116

Merged
merged 5 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 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
Loading