Skip to content

Commit

Permalink
Add support for os-families in extensions composer.json
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandre-daubois committed Nov 20, 2024
1 parent e312977 commit 93521d0
Show file tree
Hide file tree
Showing 14 changed files with 149 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/Command/BuildCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public function execute(InputInterface $input, OutputInterface $output): int
$package = ($this->dependencyResolver)($composer, $targetPlatform, $requestedNameAndVersion);
$output->writeln(sprintf('<info>Found package:</info> %s which provides <info>%s</info>', $package->prettyNameAndVersion(), $package->extensionName->nameWithExtPrefix()));

CommandHelper::ensureOsFamilyCompatibilityFromPackage($package);

// Now we know what package we have, we can validate the configure options for the command and re-create the
// Composer instance with the populated configure options
CommandHelper::bindConfigureOptionsFromPackage($this, $package, $input);
Expand Down
17 changes: 17 additions & 0 deletions src/Command/CommandHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@
use Webmozart\Assert\Assert;

use function array_key_exists;
use function in_array;
use function is_array;
use function is_string;
use function reset;
use function sprintf;
use function strtolower;
use function trim;

use const PHP_OS_FAMILY;
use const PHP_VERSION;

/** @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 @@ -210,6 +212,21 @@ public static function bindConfigureOptionsFromPackage(Command $command, Package
self::validateInput($input, $command);
}

public static function ensureOsFamilyCompatibilityFromPackage(Package $package): void
{
if ($package->osFamilies === [] || in_array('*', $package->osFamilies, true)) {
return;
}

if (! in_array(PHP_OS_FAMILY, $package->osFamilies, true)) {
throw new InvalidArgumentException(sprintf(
'The package "%s" is not compatible with the "%s" operating system family',
$package->prettyNameAndVersion(),
PHP_OS_FAMILY,
));
}
}

/** @return list<non-empty-string> */
public static function processConfigureOptionsFromInput(Package $package, InputInterface $input): array
{
Expand Down
2 changes: 2 additions & 0 deletions src/Command/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public function execute(InputInterface $input, OutputInterface $output): int
$package = ($this->dependencyResolver)($composer, $targetPlatform, $requestedNameAndVersion);
$output->writeln(sprintf('<info>Found package:</info> %s which provides <info>%s</info>', $package->prettyNameAndVersion(), $package->extensionName->nameWithExtPrefix()));

CommandHelper::ensureOsFamilyCompatibilityFromPackage($package);

// Now we know what package we have, we can validate the configure options for the command and re-create the
// Composer instance with the populated configure options
CommandHelper::bindConfigureOptionsFromPackage($this, $package, $input);
Expand Down
19 changes: 18 additions & 1 deletion src/DependencyResolver/Package.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use function array_slice;
use function explode;
use function implode;
use function is_string;
use function parse_url;
use function str_contains;
use function str_starts_with;
Expand All @@ -25,7 +26,10 @@
*/
final class Package
{
/** @param list<ConfigureOption> $configureOptions */
/**
* @param list<ConfigureOption> $configureOptions
* @param list<string> $osFamilies
*/
public function __construct(
public readonly CompletePackageInterface $composerPackage,
public readonly ExtensionType $extensionType,
Expand All @@ -36,6 +40,7 @@ public function __construct(
public readonly array $configureOptions,
public readonly bool $supportZts,
public readonly bool $supportNts,
public readonly array $osFamilies,
) {
}

Expand All @@ -58,6 +63,17 @@ public static function fromComposerCompletePackage(CompletePackageInterface $com
? $phpExtOptions['support-nts']
: true;

/** @var list<string>|string $osFamilies */
$osFamilies = $phpExtOptions !== null && array_key_exists('os-families', $phpExtOptions)
? $phpExtOptions['os-families']
: [];

if (is_string($osFamilies)) {
$osFamilies = [$osFamilies];
}

$osFamilies = array_map('strtolower', $osFamilies);

return new self(
$completePackage,
ExtensionType::tryFrom($completePackage->getType()) ?? ExtensionType::PhpModule,
Expand All @@ -68,6 +84,7 @@ public static function fromComposerCompletePackage(CompletePackageInterface $com
$configureOptions,
$supportZts,
$supportNts,
$osFamilies,
);
}

Expand Down
2 changes: 2 additions & 0 deletions test/integration/Building/UnixBuildTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public function testUnixBuildCanBuildExtension(): void
[ConfigureOption::fromComposerJsonDefinition(['name' => 'enable-pie_test_ext'])],
true,
true,
[],
),
self::TEST_EXTENSION_PATH,
);
Expand Down Expand Up @@ -96,6 +97,7 @@ public function testUnixBuildWillThrowExceptionWhenExpectedBinaryNameMismatches(
[ConfigureOption::fromComposerJsonDefinition(['name' => 'enable-pie_test_ext'])],
true,
true,
[],
),
self::TEST_EXTENSION_PATH,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public function testDeterminingReleaseAssetUrlForWindows(): void
[],
true,
true,
[],
);

$io = $this->createMock(IOInterface::class);
Expand Down
1 change: 1 addition & 0 deletions test/integration/Installing/UnixInstallTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ public function testUnixInstallCanInstallExtension(string $phpConfig): void
[ConfigureOption::fromComposerJsonDefinition(['name' => 'enable-pie_test_ext'])],
true,
true,
[],
),
self::TEST_EXTENSION_PATH,
);
Expand Down
1 change: 1 addition & 0 deletions test/integration/Installing/WindowsInstallTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public function testWindowsInstallCanInstallExtension(): void
[],
true,
true,
[],
),
self::TEST_EXTENSION_PATH,
);
Expand Down
69 changes: 69 additions & 0 deletions test/unit/Command/CommandHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Composer\Package\CompletePackage;
use Composer\Util\Platform;
use Generator;
use InvalidArgumentException;
use Php\Pie\Command\CommandHelper;
use Php\Pie\ConfigureOption;
Expand All @@ -27,6 +28,8 @@
use function array_combine;
use function array_map;

use const PHP_OS_FAMILY;

#[CoversClass(CommandHelper::class)]
final class CommandHelperTest extends TestCase
{
Expand Down Expand Up @@ -109,6 +112,7 @@ public function testProcessingConfigureOptionsFromInput(): void
],
true,
true,
[],
);
$inputDefinition = new InputDefinition();
$inputDefinition->addOption(new InputOption('with-stuff', null, InputOption::VALUE_REQUIRED));
Expand Down Expand Up @@ -171,4 +175,69 @@ public function testWindowsMachinesCannotUseWithPhpizePathOption(): void
$this->expectExceptionMessage('The --with-phpize-path=/path/to/phpize cannot be used on Windows.');
CommandHelper::determineTargetPlatformFromInputs($input, $output);
}

/** @param list<string> $allowedOsFamilies */
#[DataProvider('provideOsFamilies')]
public function testEnsureOsFamilyCompatibilityFromPackage(array $allowedOsFamilies): void
{
CommandHelper::ensureOsFamilyCompatibilityFromPackage($this->createCompletePackage($allowedOsFamilies));

self::expectNotToPerformAssertions();
}

/** @return Generator<int, list<list{0?: string}>, mixed, void> */

Check failure on line 188 in test/unit/Command/CommandHelperTest.php

View workflow job for this annotation

GitHub Actions / static-analysis

InvalidReturnType

test/unit/Command/CommandHelperTest.php:188:17: InvalidReturnType: The declared return type 'Generator<int, list<list{0?: string}>, mixed, void>' for Php\PieUnitTest\Command\CommandHelperTest::provideOsFamilies is incorrect, got 'Generator<int, list{list{0?: string, 1?: '*'}}, mixed, void>' (see https://psalm.dev/011)
public static function provideOsFamilies(): Generator

Check failure on line 189 in test/unit/Command/CommandHelperTest.php

View workflow job for this annotation

GitHub Actions / static-analysis

PossiblyUnusedMethod

test/unit/Command/CommandHelperTest.php:189:28: PossiblyUnusedMethod: Cannot find any calls to method Php\PieUnitTest\Command\CommandHelperTest::provideOsFamilies (see https://psalm.dev/087)
{
yield [[PHP_OS_FAMILY]];

yield [[]];

yield [['*']];

yield [['Solaris', '*']];
}

#[RequiresOperatingSystemFamily('Windows')]
public function testEnsureOsFamilyCompatibilityFromPackageOnWindowsThrows(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The package "foo/bar" is not compatible with the "Windows" operating system family');

CommandHelper::ensureOsFamilyCompatibilityFromPackage($this->createCompletePackage(['Linux']));
}

#[RequiresOperatingSystemFamily('Darwin')]
public function testEnsureOsFamilyCompatibilityFromPackageOnDarwinThrows(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The package "foo/bar:1.0.0" is not compatible with the "Darwin" operating system family');

CommandHelper::ensureOsFamilyCompatibilityFromPackage($this->createCompletePackage(['Windows']));
}

#[RequiresOperatingSystemFamily('Linux')]
public function testEnsureOsFamilyCompatibilityFromPackageOnLinuxThrows(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The package "foo/bar:1.0.0" is not compatible with the "Linux" operating system family');

CommandHelper::ensureOsFamilyCompatibilityFromPackage($this->createCompletePackage(['Windows', 'Darwin']));
}

/** @param list<string> $allowedOsFamilies */
private function createCompletePackage(array $allowedOsFamilies): Package
{
return new Package(
new CompletePackage('foo/bar', '1.0.0.0', '1.0.0'),
ExtensionType::PhpModule,
ExtensionName::normaliseFromString('ext-foo'),
'foo/bar',
'1.0.0',
null,
[],
true,
true,
$allowedOsFamilies,
);
}
}
29 changes: 29 additions & 0 deletions test/unit/DependencyResolver/PackageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,34 @@ public function testFromComposerCompletePackageWithExtensionName(): void
self::assertNull($package->downloadUrl);
}

public function testFromComposerCompletePackageWithOsFamilies(): void
{
$composerCompletePackage = new CompletePackage('vendor/foo', '1.2.3.0', '1.2.3');
$composerCompletePackage->setPhpExt(['os-families' => ['WINDOWS', 'Darwin']]);

Check failure on line 48 in test/unit/DependencyResolver/PackageTest.php

View workflow job for this annotation

GitHub Actions / static-analysis

InvalidArgument

test/unit/DependencyResolver/PackageTest.php:48:45: InvalidArgument: Argument 1 of Composer\Package\CompletePackage::setPhpExt expects array{'configure-options'?: list<array{description?: string, name: string}>, 'extension-name'?: string, 'support-nts'?: bool, 'support-zts'?: bool, priority?: int}|null, but array{'os-families': list{'WINDOWS', 'Darwin'}} with additional array shape fields (os-families) was provided (see https://psalm.dev/004)

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

self::assertSame(['windows', 'darwin'], $package->osFamilies);
self::assertSame('vendor/foo', $package->name);
self::assertSame('1.2.3', $package->version);
self::assertSame('vendor/foo:1.2.3', $package->prettyNameAndVersion());
self::assertNull($package->downloadUrl);
}

public function testFromComposerCompletePackageWithOsFamiliesWildcard(): void
{
$composerCompletePackage = new CompletePackage('vendor/foo', '1.2.3.0', '1.2.3');
$composerCompletePackage->setPhpExt(['os-families' => ['*']]);

Check failure on line 62 in test/unit/DependencyResolver/PackageTest.php

View workflow job for this annotation

GitHub Actions / static-analysis

InvalidArgument

test/unit/DependencyResolver/PackageTest.php:62:45: InvalidArgument: Argument 1 of Composer\Package\CompletePackage::setPhpExt expects array{'configure-options'?: list<array{description?: string, name: string}>, 'extension-name'?: string, 'support-nts'?: bool, 'support-zts'?: bool, priority?: int}|null, but array{'os-families': list{'*'}} with additional array shape fields (os-families) was provided (see https://psalm.dev/004)

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

self::assertSame(['*'], $package->osFamilies);
self::assertSame('vendor/foo', $package->name);
self::assertSame('1.2.3', $package->version);
self::assertSame('vendor/foo:1.2.3', $package->prettyNameAndVersion());
self::assertNull($package->downloadUrl);
}

/**
* @return array<string, array{0: string, 1: string|null, 2: string}>
*
Expand Down Expand Up @@ -72,6 +100,7 @@ public function testGithubOrgAndRepo(string $composerPackageName, string|null $d
[],
true,
true,
[],
);

self::assertSame($expectedGithubOrgAndRepo, $package->githubOrgAndRepository());
Expand Down
1 change: 1 addition & 0 deletions test/unit/Downloading/DownloadedPackageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public function testFromPackageAndExtractedPath(): void
[],
true,
true,
[],
);

$extractedSourcePath = uniqid('/path/to/downloaded/package', true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public function testForPackage(): void
[],
true,
true,
[],
);

$exception = CouldNotFindReleaseAsset::forPackage($package, ['something.zip', 'something2.zip']);
Expand All @@ -51,6 +52,7 @@ public function testForPackageWithMissingTag(): void
[],
true,
true,
[],
);

$exception = CouldNotFindReleaseAsset::forPackageWithMissingTag($package);
Expand Down
3 changes: 3 additions & 0 deletions test/unit/Downloading/GithubPackageReleaseAssetsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public function testUrlIsReturnedWhenFindingWindowsDownloadUrl(): void
[],
true,
true,
[],
);

$releaseAssets = new GithubPackageReleaseAssets('https://test-github-api-base-url.thephp.foundation');
Expand Down Expand Up @@ -137,6 +138,7 @@ public function testUrlIsReturnedWhenFindingWindowsDownloadUrlWithCompilerAndThr
[],
true,
true,
[],
);

$releaseAssets = new GithubPackageReleaseAssets('https://test-github-api-base-url.thephp.foundation');
Expand Down Expand Up @@ -176,6 +178,7 @@ public function testFindWindowsDownloadUrlForPackageThrowsExceptionWhenAssetNotF
[],
true,
true,
[],
);

$releaseAssets = new GithubPackageReleaseAssets('https://test-github-api-base-url.thephp.foundation');
Expand Down
1 change: 1 addition & 0 deletions test/unit/Platform/WindowsExtensionAssetNameTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public function setUp(): void
[],
true,
true,
[],
);
}

Expand Down

0 comments on commit 93521d0

Please sign in to comment.