Skip to content

Commit

Permalink
feat: Provide a non optimized requirement list (#1328)
Browse files Browse the repository at this point in the history
This is a preparatory step for #1273. The goal is to be able to provide _all_ the requirements. The idea being that one may be interested in seeing this full list for debugging purpose, rather than the strict final one where the provided extensions removed the required extensions from the calculated requirements.
  • Loading branch information
theofidry authored Mar 11, 2024
1 parent 4ae6b07 commit 879e0be
Show file tree
Hide file tree
Showing 6 changed files with 314 additions and 71 deletions.
30 changes: 29 additions & 1 deletion src/RequirementChecker/AppRequirementsFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,47 @@ final class AppRequirementsFactory
{
private const SELF_PACKAGE = null;

public function createUnfiltered(
ComposerJson $composerJson,
ComposerLock $composerLock,
CompressionAlgorithm $compressionAlgorithm,
): Requirements {
return $this
->createBuilder(
$composerJson,
$composerLock,
$compressionAlgorithm,
)
->all();
}

public function create(
ComposerJson $composerJson,
ComposerLock $composerLock,
CompressionAlgorithm $compressionAlgorithm,
): Requirements {
return $this
->createBuilder(
$composerJson,
$composerLock,
$compressionAlgorithm,
)
->build();
}

private function createBuilder(
ComposerJson $composerJson,
ComposerLock $composerLock,
CompressionAlgorithm $compressionAlgorithm,
): RequirementsBuilder {
$requirementsBuilder = new RequirementsBuilder();

self::retrievePhpVersionRequirements($requirementsBuilder, $composerJson, $composerLock);
self::collectExtensionRequirementsFromCompressionAlgorithm($requirementsBuilder, $compressionAlgorithm);
self::collectComposerLockExtensionRequirements($composerLock, $requirementsBuilder);
self::collectComposerJsonExtensionRequirements($composerJson, $requirementsBuilder);

return $requirementsBuilder->build();
return $requirementsBuilder;
}

private static function retrievePhpVersionRequirements(
Expand Down
29 changes: 29 additions & 0 deletions src/RequirementChecker/Requirement.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,35 @@ public static function forRequiredExtension(string $extension, ?string $packageN
);
}

public static function forProvidedExtension(string $extension, ?string $packageName): self
{
return new self(
RequirementType::PROVIDED_EXTENSION,
$extension,
$packageName,
null === $packageName
? sprintf(
'This application provides the extension "%s".',
$extension,
)
: sprintf(
'The package "%s" provides the extension "%s".',
$packageName,
$extension,
),
null === $packageName
? sprintf(
'This application does not require the extension "%s", it is provided by the application itself.',
$extension,
)
: sprintf(
'This application does not require the extension "%s", it is provided by the package "%s".',
$packageName,
$extension,
),
);
}

public static function forConflictingExtension(string $extension, ?string $packageName): self
{
return new self(
Expand Down
1 change: 1 addition & 0 deletions src/RequirementChecker/RequirementType.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ enum RequirementType: string
{
case PHP = 'php';
case EXTENSION = 'extension';
case PROVIDED_EXTENSION = 'provided-extension';
case EXTENSION_CONFLICT = 'extension-conflict';
}
60 changes: 60 additions & 0 deletions src/RequirementChecker/RequirementsBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,40 @@ public function addConflictingExtension(Extension $extension, ?string $source):
$this->conflictingExtensions[$extension->name][] = $source;
}

public function all(): Requirements
{
$requirements = $this->predefinedRequirements;

foreach ($this->getUnfilteredSortedRequiredExtensions() as $extensionName => $sources) {
foreach ($sources as $source) {
$requirements[] = Requirement::forRequiredExtension(
$extensionName,
$source,
);
}
}

foreach ($this->getSortedProvidedExtensions() as $extensionName => $sources) {
foreach ($sources as $source) {
$requirements[] = Requirement::forProvidedExtension(
$extensionName,
$source,
);
}
}

foreach ($this->getSortedConflictedExtensions() as $extensionName => $sources) {
foreach ($sources as $source) {
$requirements[] = Requirement::forConflictingExtension(
$extensionName,
$source,
);
}
}

return new Requirements($requirements);
}

public function build(): Requirements
{
$requirements = $this->predefinedRequirements;
Expand All @@ -74,6 +108,32 @@ public function build(): Requirements
return new Requirements($requirements);
}

/**
* @return array<string, list<string>>
*/
private function getUnfilteredSortedRequiredExtensions(): array
{
return array_map(
self::createSortedDistinctList(...),
self::sortByExtensionName(
$this->requiredExtensions,
),
);
}

/**
* @return array<string, list<string>>
*/
private function getSortedProvidedExtensions(): array
{
return array_map(
self::createSortedDistinctList(...),
self::sortByExtensionName(
$this->providedExtensions,
),
);
}

/**
* @return array<string, list<string>>
*/
Expand Down
36 changes: 36 additions & 0 deletions tests/RequirementChecker/RequirementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,42 @@ public function test_it_can_be_created_for_an_extension_constraint_for_a_package
self::assertItCanBeCreatedFromItsArrayForm($requirement, $actual);
}

public function test_it_can_be_created_for_a_provided_extension_constraint(): void
{
$requirement = Requirement::forProvidedExtension('mbstring', null);

$expected = [
'type' => 'provided-extension',
'condition' => 'mbstring',
'source' => null,
'message' => 'This application provides the extension "mbstring".',
'helpMessage' => 'This application does not require the extension "mbstring", it is provided by the application itself.',
];

$actual = $requirement->toArray();

self::assertSame($expected, $actual);
self::assertItCanBeCreatedFromItsArrayForm($requirement, $actual);
}

public function test_it_can_be_created_for_a_provided_extension_constraint_for_a_package(): void
{
$requirement = Requirement::forProvidedExtension('mbstring', 'box/test');

$expected = [
'type' => 'provided-extension',
'condition' => 'mbstring',
'source' => 'box/test',
'message' => 'The package "box/test" provides the extension "mbstring".',
'helpMessage' => 'This application does not require the extension "box/test", it is provided by the package "mbstring".',
];

$actual = $requirement->toArray();

self::assertSame($expected, $actual);
self::assertItCanBeCreatedFromItsArrayForm($requirement, $actual);
}

public function test_it_can_be_created_for_a_conflicting_extension_constraint(): void
{
$requirement = Requirement::forConflictingExtension('mbstring', null);
Expand Down
Loading

0 comments on commit 879e0be

Please sign in to comment.