Skip to content

Commit 72b239c

Browse files
authored
Merge pull request #116 from alexandre-daubois/os-composer-json
Add support for `os-families-exclude` in extensions `composer.json`
2 parents 89379c0 + 8110e8c commit 72b239c

26 files changed

+465
-9
lines changed

Diff for: composer.lock

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Php\Pie\DependencyResolver;
6+
7+
use Php\Pie\Platform\OperatingSystemFamily;
8+
use RuntimeException;
9+
10+
use function array_map;
11+
use function implode;
12+
use function sprintf;
13+
14+
class IncompatibleOperatingSystemFamily extends RuntimeException
15+
{
16+
/** @param list<OperatingSystemFamily> $required */
17+
public static function notInCompatibleOperatingSystemFamilies(array $required, OperatingSystemFamily $current): self
18+
{
19+
return new self(sprintf(
20+
'This extension does not support the "%s" operating system family. It is compatible with the following families: "%s".',
21+
$current->value,
22+
implode('", "', array_map(static fn (OperatingSystemFamily $osFamily): string => $osFamily->value, $required)),
23+
));
24+
}
25+
26+
/** @param list<OperatingSystemFamily> $incompatibleOsFamilies */
27+
public static function inIncompatibleOperatingSystemFamily(array $incompatibleOsFamilies, OperatingSystemFamily $current): self
28+
{
29+
return new self(sprintf(
30+
'This extension does not support the "%s" operating system family. It is incompatible with the following families: "%s".',
31+
$current->value,
32+
implode('", "', array_map(static fn (OperatingSystemFamily $osFamily): string => $osFamily->value, $incompatibleOsFamilies)),
33+
));
34+
}
35+
}

Diff for: src/DependencyResolver/Package.php

+45-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
namespace Php\Pie\DependencyResolver;
66

77
use Composer\Package\CompletePackageInterface;
8+
use InvalidArgumentException;
89
use Php\Pie\ConfigureOption;
910
use Php\Pie\ExtensionName;
1011
use Php\Pie\ExtensionType;
12+
use Php\Pie\Platform\OperatingSystemFamily;
13+
use Webmozart\Assert\Assert;
1114

1215
use function array_key_exists;
1316
use function array_map;
@@ -17,6 +20,7 @@
1720
use function parse_url;
1821
use function str_contains;
1922
use function str_starts_with;
23+
use function strtolower;
2024

2125
/**
2226
* @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks
@@ -25,7 +29,11 @@
2529
*/
2630
final class Package
2731
{
28-
/** @param list<ConfigureOption> $configureOptions */
32+
/**
33+
* @param list<ConfigureOption> $configureOptions
34+
* @param non-empty-list<OperatingSystemFamily>|null $compatibleOsFamilies
35+
* @param non-empty-list<OperatingSystemFamily>|null $incompatibleOsFamilies
36+
*/
2937
public function __construct(
3038
public readonly CompletePackageInterface $composerPackage,
3139
public readonly ExtensionType $extensionType,
@@ -37,6 +45,8 @@ public function __construct(
3745
public readonly bool $supportZts,
3846
public readonly bool $supportNts,
3947
public readonly string|null $buildPath,
48+
public readonly array|null $compatibleOsFamilies,
49+
public readonly array|null $incompatibleOsFamilies,
4050
) {
4151
}
4252

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

76+
$compatibleOsFamilies = $phpExtOptions['os-families'] ?? null;
77+
$incompatibleOsFamilies = $phpExtOptions['os-families-exclude'] ?? null;
78+
79+
if ($compatibleOsFamilies !== null && $incompatibleOsFamilies !== null) {
80+
throw new InvalidArgumentException('Cannot specify both "os-families" and "os-families-exclude" in composer.json');
81+
}
82+
6683
return new self(
6784
$completePackage,
6885
ExtensionType::tryFrom($completePackage->getType()) ?? ExtensionType::PhpModule,
@@ -74,6 +91,8 @@ public static function fromComposerCompletePackage(CompletePackageInterface $com
7491
$supportZts,
7592
$supportNts,
7693
$buildPath,
94+
self::convertInputStringsToOperatingSystemFamilies($compatibleOsFamilies),
95+
self::convertInputStringsToOperatingSystemFamilies($incompatibleOsFamilies),
7796
);
7897
}
7998

@@ -100,4 +119,29 @@ public function githubOrgAndRepository(): string
100119
// Converts https://api.github.com/repos/<user>/<repository>/zipball/<sha>" to "<user>/<repository>"
101120
return implode('/', array_slice(explode('/', $parsed['path']), 2, 2));
102121
}
122+
123+
/**
124+
* @param list<string>|null $input
125+
*
126+
* @return non-empty-list<OperatingSystemFamily>|null
127+
*/
128+
private static function convertInputStringsToOperatingSystemFamilies(array|null $input): array|null
129+
{
130+
if ($input === null) {
131+
return null;
132+
}
133+
134+
$osFamilies = [];
135+
foreach ($input as $value) {
136+
$valueToTry = strtolower($value);
137+
138+
Assert::inArray($valueToTry, OperatingSystemFamily::asValuesList(), 'Expected operating system family to be one of: %2$s. Got: %s');
139+
140+
$osFamilies[] = OperatingSystemFamily::from($valueToTry);
141+
}
142+
143+
Assert::isNonEmptyList($osFamilies, 'Expected operating systems families to be a non-empty list.');
144+
145+
return $osFamilies;
146+
}
103147
}

Diff for: src/DependencyResolver/ResolveDependencyWithComposer.php

+19
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Php\Pie\Platform\TargetPlatform;
1313
use Php\Pie\Platform\ThreadSafetyMode;
1414

15+
use function in_array;
1516
use function preg_match;
1617

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

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

59+
$this->assertCompatibleOsFamily($targetPlatform, $piePackage);
5860
$this->assertCompatibleThreadSafetyMode($targetPlatform->threadSafety, $piePackage);
5961

6062
return $piePackage;
@@ -70,4 +72,21 @@ private function assertCompatibleThreadSafetyMode(ThreadSafetyMode $threadSafety
7072
throw IncompatibleThreadSafetyMode::ntsExtensionOnZtsPlatform();
7173
}
7274
}
75+
76+
private function assertCompatibleOsFamily(TargetPlatform $targetPlatform, Package $resolvedPackage): void
77+
{
78+
if ($resolvedPackage->compatibleOsFamilies !== null && ! in_array($targetPlatform->operatingSystemFamily, $resolvedPackage->compatibleOsFamilies, true)) {
79+
throw IncompatibleOperatingSystemFamily::notInCompatibleOperatingSystemFamilies(
80+
$resolvedPackage->compatibleOsFamilies,
81+
$targetPlatform->operatingSystemFamily,
82+
);
83+
}
84+
85+
if ($resolvedPackage->incompatibleOsFamilies !== null && in_array($targetPlatform->operatingSystemFamily, $resolvedPackage->incompatibleOsFamilies, true)) {
86+
throw IncompatibleOperatingSystemFamily::inIncompatibleOperatingSystemFamily(
87+
$resolvedPackage->incompatibleOsFamilies,
88+
$targetPlatform->operatingSystemFamily,
89+
);
90+
}
91+
}
7392
}

Diff for: src/Platform/OperatingSystemFamily.php

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Php\Pie\Platform;
6+
7+
use function array_map;
8+
9+
/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
10+
enum OperatingSystemFamily: string
11+
{
12+
case Windows = 'windows';
13+
case Bsd = 'bsd';
14+
case Darwin = 'darwin';
15+
case Solaris = 'solaris';
16+
case Linux = 'linux';
17+
case Unknown = 'unknown';
18+
19+
/** @return non-empty-list<non-empty-string> */
20+
public static function asValuesList(): array
21+
{
22+
return array_map(
23+
static fn (OperatingSystemFamily $osFamily): string => $osFamily->value,
24+
self::cases(),
25+
);
26+
}
27+
}

Diff for: src/Platform/TargetPhp/PhpBinaryPath.php

+16
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Composer\Util\Platform;
99
use Php\Pie\Platform\Architecture;
1010
use Php\Pie\Platform\OperatingSystem;
11+
use Php\Pie\Platform\OperatingSystemFamily;
1112
use Php\Pie\Util\Process;
1213
use RuntimeException;
1314
use Symfony\Component\Process\PhpExecutableFinder;
@@ -24,6 +25,7 @@
2425
use function is_executable;
2526
use function preg_match;
2627
use function sprintf;
28+
use function strtolower;
2729
use function trim;
2830

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

169+
public function operatingSystemFamily(): OperatingSystemFamily
170+
{
171+
$output = Process::run([
172+
$this->phpBinaryPath,
173+
'-r',
174+
'echo PHP_OS_FAMILY;',
175+
]);
176+
177+
$osFamily = OperatingSystemFamily::tryFrom(strtolower(trim($output)));
178+
Assert::notNull($osFamily, 'Could not determine operating system family');
179+
180+
return $osFamily;
181+
}
182+
167183
/** @return non-empty-string */
168184
public function version(): string
169185
{

Diff for: src/Platform/TargetPlatform.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class TargetPlatform
2323
{
2424
public function __construct(
2525
public readonly OperatingSystem $operatingSystem,
26+
public readonly OperatingSystemFamily $operatingSystemFamily,
2627
public readonly PhpBinaryPath $phpBinaryPath,
2728
public readonly Architecture $architecture,
2829
public readonly ThreadSafetyMode $threadSafety,
@@ -38,7 +39,8 @@ public static function isRunningAsRoot(): bool
3839

3940
public static function fromPhpBinaryPath(PhpBinaryPath $phpBinaryPath, int|null $makeParallelJobs): self
4041
{
41-
$os = $phpBinaryPath->operatingSystem();
42+
$os = $phpBinaryPath->operatingSystem();
43+
$osFamily = $phpBinaryPath->operatingSystemFamily();
4244

4345
$phpinfo = $phpBinaryPath->phpinfo();
4446

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

115117
return new self(
116118
$os,
119+
$osFamily,
117120
$phpBinaryPath,
118121
$architecture,
119122
$threadSafety,

Diff for: test/integration/Building/UnixBuildTest.php

+10
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ public function testUnixBuildCanBuildExtension(): void
4848
true,
4949
true,
5050
null,
51+
null,
52+
null,
5153
),
5254
self::TEST_EXTENSION_PATH,
5355
);
@@ -101,6 +103,8 @@ public function testUnixBuildWillThrowExceptionWhenExpectedBinaryNameMismatches(
101103
true,
102104
true,
103105
null,
106+
null,
107+
null,
104108
),
105109
self::TEST_EXTENSION_PATH,
106110
);
@@ -142,6 +146,8 @@ public function testUnixBuildCanBuildExtensionWithBuildPath(): void
142146
true,
143147
true,
144148
'pie_test_ext',
149+
null,
150+
null,
145151
),
146152
dirname(self::TEST_EXTENSION_PATH),
147153
);
@@ -199,6 +205,8 @@ public function testCleanupDoesNotCleanWhenConfigureIsMissing(): void
199205
true,
200206
true,
201207
null,
208+
null,
209+
null,
202210
),
203211
self::TEST_EXTENSION_PATH,
204212
);
@@ -241,6 +249,8 @@ public function testVerboseOutputShowsCleanupMessages(): void
241249
true,
242250
true,
243251
null,
252+
null,
253+
null,
244254
),
245255
self::TEST_EXTENSION_PATH,
246256
);

Diff for: test/integration/Downloading/GithubPackageReleaseAssetsTest.php

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Php\Pie\ExtensionType;
1616
use Php\Pie\Platform\Architecture;
1717
use Php\Pie\Platform\OperatingSystem;
18+
use Php\Pie\Platform\OperatingSystemFamily;
1819
use Php\Pie\Platform\TargetPhp\PhpBinaryPath;
1920
use Php\Pie\Platform\TargetPlatform;
2021
use Php\Pie\Platform\ThreadSafetyMode;
@@ -34,6 +35,7 @@ public function testDeterminingReleaseAssetUrlForWindows(): void
3435

3536
$targetPlatform = new TargetPlatform(
3637
OperatingSystem::Windows,
38+
OperatingSystemFamily::Windows,
3739
$phpBinaryPath,
3840
Architecture::x86_64,
3941
ThreadSafetyMode::ThreadSafe,
@@ -52,6 +54,8 @@ public function testDeterminingReleaseAssetUrlForWindows(): void
5254
true,
5355
true,
5456
null,
57+
null,
58+
null,
5559
);
5660

5761
$io = $this->createMock(IOInterface::class);

Diff for: test/integration/Installing/UnixInstallTest.php

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ public function testUnixInstallCanInstallExtension(string $phpConfig): void
9191
true,
9292
true,
9393
null,
94+
null,
95+
null,
9496
),
9597
self::TEST_EXTENSION_PATH,
9698
);

0 commit comments

Comments
 (0)