mirror of
https://github.com/php/pie.git
synced 2026-03-23 23:12:17 +01:00
Merge pull request #536 from asgrim/dev-php-versions-issues
Fix `-dev` php versions issues
This commit is contained in:
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Php\Pie\DependencyResolver;
|
||||
|
||||
use Php\Pie\Platform\TargetPhp\PhpBinaryPath;
|
||||
use RuntimeException;
|
||||
|
||||
use function sprintf;
|
||||
@@ -24,4 +25,12 @@ class BundledPhpExtensionRefusal extends RuntimeException
|
||||
$package->name(),
|
||||
));
|
||||
}
|
||||
|
||||
public static function forPhpExtraVersion(PhpBinaryPath $phpBinaryPath): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'Cannot install bundled PHP extension for non-stable versions of PHP (detected: %s)',
|
||||
$phpBinaryPath->phpVersionWithExtra(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ use Php\Pie\Platform\ThreadSafetyMode;
|
||||
use function in_array;
|
||||
use function 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
|
||||
@@ -109,6 +110,10 @@ final class ResolveDependencyWithComposer implements DependencyResolver
|
||||
return;
|
||||
}
|
||||
|
||||
if (str_ends_with($targetPlatform->phpBinaryPath->phpVersionWithExtra(), '-dev')) {
|
||||
throw BundledPhpExtensionRefusal::forPhpExtraVersion($targetPlatform->phpBinaryPath);
|
||||
}
|
||||
|
||||
$buildProvider = $targetPlatform->phpBinaryPath->buildProvider();
|
||||
$identifiedBuildProvider = false;
|
||||
$note = '<options=bold,underscore;fg=red>Note:</> ';
|
||||
|
||||
@@ -328,6 +328,19 @@ PHP,
|
||||
return $phpVersion;
|
||||
}
|
||||
|
||||
/** @return non-empty-string */
|
||||
public function phpVersionWithExtra(): string
|
||||
{
|
||||
$phpVersionWithExtra = self::cleanWarningAndDeprecationsFromOutput(Process::run([
|
||||
$this->phpBinaryPath,
|
||||
'-r',
|
||||
'echo PHP_VERSION;',
|
||||
]));
|
||||
Assert::stringNotEmpty($phpVersionWithExtra, 'Could not determine PHP_VERSION');
|
||||
|
||||
return $phpVersionWithExtra;
|
||||
}
|
||||
|
||||
/** @return non-empty-string */
|
||||
public function majorMinorVersion(): string
|
||||
{
|
||||
|
||||
@@ -10,12 +10,24 @@ use Composer\IO\IOInterface;
|
||||
use Composer\Package\CompletePackage;
|
||||
use Composer\Package\Link;
|
||||
use Composer\Semver\Constraint\Constraint;
|
||||
use Composer\Semver\VersionParser;
|
||||
use Php\Pie\DependencyResolver\FetchDependencyStatuses;
|
||||
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 PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
use function assert;
|
||||
|
||||
use const PHP_MAJOR_VERSION;
|
||||
use const PHP_MINOR_VERSION;
|
||||
use const PHP_RELEASE_VERSION;
|
||||
use const PHP_VERSION;
|
||||
|
||||
#[CoversClass(FetchDependencyStatuses::class)]
|
||||
final class FetchDependencyStatusesTest extends TestCase
|
||||
{
|
||||
@@ -26,15 +38,44 @@ final class FetchDependencyStatusesTest extends TestCase
|
||||
self::assertEquals([], (new FetchDependencyStatuses())(TargetPlatform::fromPhpBinaryPath(PhpBinaryPath::fromCurrentProcess(), null, null), $this->createMock(Composer::class), $package));
|
||||
}
|
||||
|
||||
public function testRequiresReturnsListOfStatuses(): void
|
||||
/** @return array<non-empty-string, array{0: non-empty-string, 1: non-empty-string}> */
|
||||
public function phpVersionProvider(): array
|
||||
{
|
||||
$php = PhpBinaryPath::fromCurrentProcess();
|
||||
return [
|
||||
'8.2.0' => ['8.2.0', '8.2.0'],
|
||||
'8.2.0-dev' => ['8.2.0', '8.2.0-dev'],
|
||||
'8.2.0-alpha' => ['8.2.0', '8.2.0-alpha'],
|
||||
'8.2.0-RC1' => ['8.2.0', '8.2.0-RC1'],
|
||||
PHP_VERSION => [PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, PHP_VERSION],
|
||||
];
|
||||
}
|
||||
|
||||
#[DataProvider('phpVersionProvider')]
|
||||
public function testRequiresReturnsListOfStatuses(string $version, string $versionWithExtra): void
|
||||
{
|
||||
$php = $this->createMock(PhpBinaryPath::class);
|
||||
$php->method('operatingSystem')->willReturn(OperatingSystem::NonWindows);
|
||||
$php->method('operatingSystemFamily')->willReturn(OperatingSystemFamily::Linux);
|
||||
$php->method('machineType')->willReturn(Architecture::x86_64);
|
||||
$php->expects(self::any())
|
||||
->method('version')
|
||||
->willReturn($version);
|
||||
$php->expects(self::any())
|
||||
->method('phpVersionWithExtra')
|
||||
->willReturn($versionWithExtra);
|
||||
$php->expects(self::any())
|
||||
->method('extensions')
|
||||
->willReturn(['Core' => $versionWithExtra, 'standard' => $versionWithExtra]);
|
||||
|
||||
$versionParser = new VersionParser();
|
||||
$parsedPhpVersion = $versionParser->parseConstraints($php->phpVersionWithExtra());
|
||||
assert($parsedPhpVersion instanceof Constraint);
|
||||
|
||||
$package = new CompletePackage('vendor/foo', '1.2.3.0', '1.2.3');
|
||||
$package->setRequires([
|
||||
'ext-core' => new Link('__root__', 'ext-core', new Constraint('=', $php->version() . '.0')),
|
||||
'ext-nonsense_extension' => new Link('__root__', 'ext-nonsense_extension', new Constraint('=', '*')),
|
||||
'ext-standard' => new Link('__root__', 'ext-standard', new Constraint('<', '1.0.0.0')),
|
||||
'ext-core' => new Link('__root__', 'ext-core', $versionParser->parseConstraints('= ' . $php->phpVersionWithExtra())),
|
||||
'ext-nonsense_extension' => new Link('__root__', 'ext-nonsense_extension', $versionParser->parseConstraints('*')),
|
||||
'ext-standard' => new Link('__root__', 'ext-standard', $versionParser->parseConstraints('< 1.0.0')),
|
||||
]);
|
||||
|
||||
$deps = (new FetchDependencyStatuses())(
|
||||
@@ -45,8 +86,8 @@ final class FetchDependencyStatusesTest extends TestCase
|
||||
|
||||
self::assertCount(3, $deps);
|
||||
|
||||
self::assertSame('ext-core: == ' . $php->version() . '.0 ✅', $deps[0]->asPrettyString());
|
||||
self::assertSame('ext-nonsense_extension: == * 🚫 (not installed)', $deps[1]->asPrettyString());
|
||||
self::assertSame('ext-standard: < 1.0.0.0 🚫 (your version is ' . $php->version() . '.0)', $deps[2]->asPrettyString());
|
||||
self::assertSame('ext-core: = ' . $php->phpVersionWithExtra() . ' ✅', $deps[0]->asPrettyString());
|
||||
self::assertSame('ext-nonsense_extension: * 🚫 (not installed)', $deps[1]->asPrettyString());
|
||||
self::assertSame('ext-standard: < 1.0.0 🚫 (your version is ' . $parsedPhpVersion->getVersion() . ')', $deps[2]->asPrettyString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,15 @@ use Composer\Repository\InstalledRepositoryInterface;
|
||||
use Composer\Repository\RepositoryFactory;
|
||||
use Composer\Repository\RepositoryManager;
|
||||
use Composer\Semver\Constraint\Constraint;
|
||||
use Php\Pie\ComposerIntegration\BundledPhpExtensionsRepository;
|
||||
use Php\Pie\ComposerIntegration\QuieterConsoleIO;
|
||||
use Php\Pie\DependencyResolver\BundledPhpExtensionRefusal;
|
||||
use Php\Pie\DependencyResolver\IncompatibleOperatingSystemFamily;
|
||||
use Php\Pie\DependencyResolver\IncompatibleThreadSafetyMode;
|
||||
use Php\Pie\DependencyResolver\RequestedPackageAndVersion;
|
||||
use Php\Pie\DependencyResolver\ResolveDependencyWithComposer;
|
||||
use Php\Pie\DependencyResolver\UnableToResolveRequirement;
|
||||
use Php\Pie\ExtensionType;
|
||||
use Php\Pie\Platform\Architecture;
|
||||
use Php\Pie\Platform\OperatingSystem;
|
||||
use Php\Pie\Platform\OperatingSystemFamily;
|
||||
@@ -49,13 +52,21 @@ final class ResolveDependencyWithComposerTest extends TestCase
|
||||
]);
|
||||
$this->localRepo = $this->createMock(InstalledRepositoryInterface::class);
|
||||
$this->localRepo->method('getPackages')->willReturn([
|
||||
new CompletePackage('already/installed1', '1.2.3.0', '1.2.3'),
|
||||
new CompletePackage('a/installed1', '1.2.3.0', '1.2.3'),
|
||||
$packageWithReplaces,
|
||||
]);
|
||||
|
||||
$bundledPhpPackage = new CompletePackage('php/bundled', '8.3.0', '8.3.0.0');
|
||||
$bundledPhpPackage->setType(ExtensionType::PhpModule->value);
|
||||
|
||||
$repoManager = $this->createMock(RepositoryManager::class);
|
||||
$repoManager->method('getRepositories')
|
||||
->willReturn([new CompositeRepository(RepositoryFactory::defaultReposWithDefaultManager(new NullIO()))]);
|
||||
->willReturn([
|
||||
new CompositeRepository([
|
||||
...RepositoryFactory::defaultReposWithDefaultManager(new NullIO()),
|
||||
new BundledPhpExtensionsRepository([$bundledPhpPackage]),
|
||||
]),
|
||||
]);
|
||||
$repoManager->method('getLocalRepository')->willReturn($this->localRepo);
|
||||
|
||||
$this->composer = $this->createMock(Composer::class);
|
||||
@@ -415,4 +426,119 @@ final class ResolveDependencyWithComposerTest extends TestCase
|
||||
self::assertSame('asgrim/example-pie-extension', $package->name());
|
||||
self::assertStringStartsWith('1.', $package->version());
|
||||
}
|
||||
|
||||
public function testBundledExtensionCannotBeInstalledOnDevPhpVersion(): void
|
||||
{
|
||||
$phpBinaryPath = $this->createMock(PhpBinaryPath::class);
|
||||
$phpBinaryPath->expects(self::any())
|
||||
->method('version')
|
||||
->willReturn('8.3.0');
|
||||
$phpBinaryPath->expects(self::any())
|
||||
->method('phpVersionWithExtra')
|
||||
->willReturn('8.3.0-dev');
|
||||
|
||||
$targetPlatform = new TargetPlatform(
|
||||
OperatingSystem::NonWindows,
|
||||
OperatingSystemFamily::Linux,
|
||||
$phpBinaryPath,
|
||||
Architecture::x86_64,
|
||||
ThreadSafetyMode::ThreadSafe,
|
||||
1,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
|
||||
$resolver = new ResolveDependencyWithComposer(
|
||||
$this->createMock(IOInterface::class),
|
||||
$this->createMock(QuieterConsoleIO::class),
|
||||
);
|
||||
$requestedPackage = new RequestedPackageAndVersion('php/bundled', null);
|
||||
|
||||
$this->expectException(BundledPhpExtensionRefusal::class);
|
||||
$this->expectExceptionMessage('Cannot install bundled PHP extension for non-stable versions of PHP');
|
||||
$resolver->__invoke($this->composer, $targetPlatform, $requestedPackage, false);
|
||||
}
|
||||
|
||||
/** @return array<non-empty-string, array{0: non-empty-string}> */
|
||||
public function buildProvidersWithBundledExtensionWarnings(): array
|
||||
{
|
||||
return [
|
||||
'Docker' => ['https://github.com/docker-library/php'],
|
||||
'Debian/Ubuntu' => ['Debian'],
|
||||
'Remi Repo' => ['Remi\'s RPM repository <https://rpms.remirepo.net/> #StandWithUkraine'],
|
||||
'Brew' => ['Homebrew'],
|
||||
];
|
||||
}
|
||||
|
||||
#[DataProvider('buildProvidersWithBundledExtensionWarnings')]
|
||||
public function testBundledExtensionWillNotInstallOnBuildProviderWithoutForce(string $buildProvider): void
|
||||
{
|
||||
$phpBinaryPath = $this->createMock(PhpBinaryPath::class);
|
||||
$phpBinaryPath->expects(self::any())
|
||||
->method('version')
|
||||
->willReturn('8.3.0');
|
||||
$phpBinaryPath->expects(self::any())
|
||||
->method('phpVersionWithExtra')
|
||||
->willReturn('8.3.0');
|
||||
$phpBinaryPath->expects(self::any())
|
||||
->method('buildProvider')
|
||||
->willReturn($buildProvider);
|
||||
|
||||
$targetPlatform = new TargetPlatform(
|
||||
OperatingSystem::NonWindows,
|
||||
OperatingSystemFamily::Linux,
|
||||
$phpBinaryPath,
|
||||
Architecture::x86_64,
|
||||
ThreadSafetyMode::ThreadSafe,
|
||||
1,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
|
||||
$resolver = new ResolveDependencyWithComposer(
|
||||
$this->createMock(IOInterface::class),
|
||||
$this->createMock(QuieterConsoleIO::class),
|
||||
);
|
||||
$requestedPackage = new RequestedPackageAndVersion('php/bundled', null);
|
||||
|
||||
$this->expectException(BundledPhpExtensionRefusal::class);
|
||||
$this->expectExceptionMessage('Bundled PHP extension php/bundled should be installed by your distribution, not by PIE');
|
||||
$resolver->__invoke($this->composer, $targetPlatform, $requestedPackage, false);
|
||||
}
|
||||
|
||||
#[DataProvider('buildProvidersWithBundledExtensionWarnings')]
|
||||
public function testBundledExtensionWillInstallOnBuildProviderWithForce(string $buildProvider): void
|
||||
{
|
||||
$phpBinaryPath = $this->createMock(PhpBinaryPath::class);
|
||||
$phpBinaryPath->expects(self::any())
|
||||
->method('version')
|
||||
->willReturn('8.3.0');
|
||||
$phpBinaryPath->expects(self::any())
|
||||
->method('phpVersionWithExtra')
|
||||
->willReturn('8.3.0');
|
||||
$phpBinaryPath->expects(self::any())
|
||||
->method('buildProvider')
|
||||
->willReturn($buildProvider);
|
||||
|
||||
$targetPlatform = new TargetPlatform(
|
||||
OperatingSystem::NonWindows,
|
||||
OperatingSystemFamily::Linux,
|
||||
$phpBinaryPath,
|
||||
Architecture::x86_64,
|
||||
ThreadSafetyMode::ThreadSafe,
|
||||
1,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
|
||||
$resolver = new ResolveDependencyWithComposer(
|
||||
$this->createMock(IOInterface::class),
|
||||
$this->createMock(QuieterConsoleIO::class),
|
||||
);
|
||||
$requestedPackage = new RequestedPackageAndVersion('php/bundled', null);
|
||||
|
||||
$package = $resolver->__invoke($this->composer, $targetPlatform, $requestedPackage, true);
|
||||
|
||||
self::assertSame('php/bundled', $package->name());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user