forked from php/pie
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathResolveDependencyWithComposer.php
More file actions
178 lines (151 loc) · 7.44 KB
/
Copy pathResolveDependencyWithComposer.php
File metadata and controls
178 lines (151 loc) · 7.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
<?php
declare(strict_types=1);
namespace Php\Pie\DependencyResolver;
use Composer\Composer;
use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory;
use Composer\IO\IOInterface;
use Composer\Package\CompletePackageInterface;
use Php\Pie\ComposerIntegration\QuieterConsoleIO;
use Php\Pie\ComposerIntegration\VersionSelectorFactory;
use Php\Pie\ExtensionType;
use Php\Pie\Platform\TargetPlatform;
use Php\Pie\Platform\ThreadSafetyMode;
use function in_array;
use function Safe\preg_match;
use function sprintf;
use function str_ends_with;
/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
final class ResolveDependencyWithComposer implements DependencyResolver
{
public function __construct(
private readonly IOInterface $io,
private readonly QuieterConsoleIO $arrayCollectionIo,
) {
}
public function __invoke(
Composer $composer,
TargetPlatform $targetPlatform,
RequestedPackageAndVersion $requestedPackageAndVersion,
bool $forceInstallPackageVersion,
): ResolvedPackageRequest {
$versionSelector = VersionSelectorFactory::make($composer, $requestedPackageAndVersion, $targetPlatform);
$package = $versionSelector->findBestCandidate(
$requestedPackageAndVersion->package,
$requestedPackageAndVersion->version,
platformRequirementFilter: PlatformRequirementFilterFactory::fromBoolOrList($forceInstallPackageVersion),
io: $this->arrayCollectionIo,
);
if (! $package instanceof CompletePackageInterface) {
throw UnableToResolveRequirement::fromRequirement($requestedPackageAndVersion, $this->arrayCollectionIo);
}
/**
* If a specific commit hash is requested, override the references in the package. This is approximately what
* Composer does anyway:
*
* > ArrayLoader::parseLinks is in charge of this, it drops commit refs, for package resolution purposes we
* > only use dev-main, but we ensure in the PoolBuilder that root references (#...) are set so the dev-main
* > package has its source and dist refs overridden to be whatever you specify and that applies at install
* > time then but package metadata is only read from the branch's head
*/
if ($requestedPackageAndVersion->version !== null && preg_match('/#([a-f0-9]{40})$/', $requestedPackageAndVersion->version, $matches)) {
$package->setSourceDistReferences($matches[1]);
}
if (! ExtensionType::isValid($package->getType())) {
throw UnableToResolveRequirement::toPhpOrZendExtension($package, $requestedPackageAndVersion);
}
$piePackage = Package::fromComposerCompletePackage($package);
$this->assertBuildProviderProvidersBundledExtensions($targetPlatform, $piePackage, $forceInstallPackageVersion);
if (! $forceInstallPackageVersion) {
$this->assertCompatibleOsFamily($targetPlatform, $piePackage);
$this->assertCompatibleThreadSafetyMode($targetPlatform->threadSafety, $piePackage);
}
return new ResolvedPackageRequest($piePackage, $requestedPackageAndVersion);
}
private function assertCompatibleThreadSafetyMode(ThreadSafetyMode $threadSafetyMode, Package $resolvedPackage): void
{
if ($threadSafetyMode === ThreadSafetyMode::NonThreadSafe && ! $resolvedPackage->supportNts()) {
throw IncompatibleThreadSafetyMode::ztsExtensionOnNtsPlatform();
}
if ($threadSafetyMode === ThreadSafetyMode::ThreadSafe && ! $resolvedPackage->supportZts()) {
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,
);
}
}
private function assertBuildProviderProvidersBundledExtensions(TargetPlatform $targetPlatform, Package $piePackage, bool $forceInstallPackageVersion): void
{
if (! $piePackage->isBundledPhpExtension()) {
return;
}
if (str_ends_with($targetPlatform->phpBinaryPath->phpVersionWithExtra(), '-dev')) {
throw BundledPhpExtensionRefusal::forPhpExtraVersion($targetPlatform->phpBinaryPath);
}
$buildProvider = $targetPlatform->phpBinaryPath->buildProvider();
if (! $buildProvider) {
return;
}
$identifiedBuildProvider = false;
$note = '<options=bold,underscore;fg=red>Note:</> ';
if ($buildProvider === 'https://github.com/docker-library/php') {
$identifiedBuildProvider = true;
$this->io->write(sprintf(
'<comment>%sYou should probably use "docker-php-ext-install %s" instead</comment>',
$note,
$piePackage->extensionName()->name(),
));
}
if ($buildProvider === 'Debian') {
$identifiedBuildProvider = true;
$this->io->write(sprintf(
'<comment>%sYou should probably use "apt install php%s-%s" or "apt install php-%s" (or similar) instead</comment>',
$note,
$targetPlatform->phpBinaryPath->majorMinorVersion(),
$piePackage->extensionName()->name(),
$piePackage->extensionName()->name(),
));
}
$rpmProviders = [
'AlmaLinux',
'CentOS',
'Fedora Project',
'Red Hat, Inc.',
'|^Remi\'s RPM repository <https://rpms.remirepo.net/>|',
'Rocky Enterprise Software Foundation',
];
foreach ($rpmProviders as $rpmProvider) {
if ($buildProvider === $rpmProvider || ($rpmProvider[0] === '|' && preg_match($rpmProvider, $buildProvider))) {
$identifiedBuildProvider = true;
$this->io->write(sprintf(
'<comment>%sYou should probably use "dnf install php-%s" instead</comment>',
$note,
$piePackage->extensionName()->name(),
));
break;
}
}
if ($buildProvider === 'Homebrew') {
$identifiedBuildProvider = true;
$this->io->write(sprintf(
'<comment>%sThe bundled extension %s is likely already installed with Homebrew, and you should use that version.</comment>',
$note,
$piePackage->extensionName()->name(),
));
}
if ($identifiedBuildProvider && ! $forceInstallPackageVersion) {
throw BundledPhpExtensionRefusal::forPackage($piePackage);
}
}
}