Skip to content

Commit

Permalink
Merge pull request #1001 from fredden/sort/repository-filtering
Browse files Browse the repository at this point in the history
Sort repository filtering lists (only, exclude)
  • Loading branch information
localheinz authored Dec 13, 2023
2 parents fe9f378 + 022bbd7 commit eba9b55
Show file tree
Hide file tree
Showing 36 changed files with 811 additions and 66 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ For a full diff see [`4.3.0...main`][4.3.0...main].
### Changed

- Started removing `v` prefixes from version constraints ([#1027]), by [@fredden]
- Started sorting items in the `exclude` and `only` properties of items listed in the `repositories` section ([#1001]), by [@fredden]

## [`4.3.0`][4.3.0]

Expand Down Expand Up @@ -655,6 +656,7 @@ For a full diff see [`5d8b3e2...0.1.0`][5d8b3e2...0.1.0].
[#989]: https://github.com/ergebnis/json-normalizer/pull/989
[#991]: https://github.com/ergebnis/json-normalizer/pull/991
[#992]: https://github.com/ergebnis/json-normalizer/pull/992
[#1001]: https://github.com/ergebnis/json-normalizer/pull/1001
[#1027]: https://github.com/ergebnis/json-normalizer/pull/1027

[@alexis-saransig-lullabot]: https://github.com/alexis-saransig-lullabot
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ It composes the following normalizers:
- [`Ergebnis\Composer\Json\Normalizer\Vendor\Composer\BinNormalizer`](#vendorcomposerbinnormalizer)
- [`Ergebnis\Composer\Json\Normalizer\Vendor\Composer\ConfigHashNormalizer`](#vendorcomposerconfighashnormalizer)
- [`Ergebnis\Composer\Json\Normalizer\Vendor\Composer\PackageHashNormalizer`](#vendorcomposerpackagehashnormalizer)
- [`Ergebnis\Composer\Json\Normalizer\Vendor\Composer\RepositoriesHashNormalizer`](#vendorcomposerrepositorieshashnormalizer)
- [`Ergebnis\Composer\Json\Normalizer\Vendor\Composer\VersionConstraintNormalizer`](#vendorcomposerversionconstraintnormalizer)
- [`Ergebnis\Composer\Json\Normalizer\Vendor\WithFinalNewLineNormalizer`](#withfinalnewlinenormalizer)

Expand Down Expand Up @@ -452,6 +453,14 @@ sections, the `Vendor\Composer\PackageHashNormalizer` will sort the packages in

:bulb: This transfers the behaviour from using the [`--sort-packages`](https://getcomposer.org/doc/03-cli.md#require) or [`sort-packages`](https://getcomposer.org/doc/06-config.md#sort-packages) configuration flag in `require` and `require-dev` to other sections.

#### `Vendor\Composer\RepositoriesHashNormalizer`

When `composer.json` contains any configuration in the

- [`repositories`](https://getcomposer.org/doc/04-schema.md#repositories)

section, the `Vendor\Composer\RepositoriesHashNormalizer` will sort the repositories listed in the [`exclude` and `only` properties of repositories](https://getcomposer.org/doc/articles/repository-priorities.md#filtering-packages).

#### `Vendor\Composer\VersionConstraintNormalizer`

When `composer.json` contains version constraints in the
Expand Down
10 changes: 10 additions & 0 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,21 @@
<code>$value</code>
</MixedAssignment>
</file>
<file src="src/Vendor/Composer/RepositoriesHashNormalizer.php">
<MixedAssignment>
<code>$repository</code>
</MixedAssignment>
</file>
<file src="src/Vendor/Composer/VersionConstraintNormalizer.php">
<MixedAssignment>
<code>$value</code>
</MixedAssignment>
</file>
<file src="src/Vendor/Composer/WildcardSorter.php">
<MixedAssignment>
<code>$package</code>
</MixedAssignment>
</file>
<file src="test/Fixture/FormatNormalizer/NormalizeNormalizesJson/Scenario.php">
<PossiblyUnusedMethod>
<code>key</code>
Expand Down
1 change: 1 addition & 0 deletions src/Vendor/Composer/ComposerJsonNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public function __construct(string $schemaUri)
new BinNormalizer(),
new ConfigHashNormalizer(),
new PackageHashNormalizer(),
new RepositoriesHashNormalizer(),
new VersionConstraintNormalizer(new Semver\VersionParser()),
new Normalizer\WithFinalNewLineNormalizer(),
);
Expand Down
63 changes: 7 additions & 56 deletions src/Vendor/Composer/ConfigHashNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ final class ConfigHashNormalizer implements Normalizer
*/
'preferred-install',
];
private readonly WildcardSorter $wildcardSorter;

public function __construct()
{
$this->wildcardSorter = new WildcardSorter();
}

public function normalize(Json $json): Json
{
Expand Down Expand Up @@ -56,7 +62,7 @@ public function normalize(Json $json): Json
\ksort($config);

foreach (self::PROPERTIES_WITH_WILDCARDS as $property) {
self::sortPropertyWithWildcard(
$this->wildcardSorter->sortPropertyWithWildcard(
$config,
$property,
);
Expand All @@ -72,59 +78,4 @@ public function normalize(Json $json): Json

return Json::fromString($encoded);
}

/**
* When sorting with wildcards, special care needs to be taken.
*
* @see https://github.com/ergebnis/json-normalizer/pull/775#issuecomment-1346095415
* @see https://github.com/composer/composer/blob/2.6.5/src/Composer/Plugin/PluginManager.php#L85-L86
* @see https://github.com/composer/composer/blob/2.6.5/src/Composer/Plugin/PluginManager.php#L626-L646
* @see https://github.com/composer/composer/blob/2.6.5/src/Composer/Package/BasePackage.php#L252-L257
* @see https://github.com/composer/composer/blob/2.6.5/src/Composer/Plugin/PluginManager.php#L687-L691
*/
private static function sortPropertyWithWildcard(
array &$config,
string $property,
): void {
if (!\array_key_exists($property, $config)) {
return;
}

if (!\is_object($config[$property])) {
return;
}

$value = (array) $config[$property];

if ([] === $value) {
return;
}

foreach (\array_keys($value) as $package) {
/** @var string $package */
if (\str_contains(\rtrim($package, '*'), '*')) {
// We cannot reliably sort allow-plugins when there's a wildcard other than at the end of the string.
return;
}
}

$normalize = static function (string $package): string {
// Any key with an asterisk needs to be the last entry in its group
return \str_replace(
'*',
'~',
$package,
);
};

/** @var array<string, mixed> $value */
\uksort($value, static function (string $a, string $b) use ($normalize): int {
return \strcmp(
$normalize($a),
$normalize($b),
);
});

$config[$property] = $value;
}
}
81 changes: 81 additions & 0 deletions src/Vendor/Composer/RepositoriesHashNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2018-2023 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/json-normalizer
*/

namespace Ergebnis\Json\Normalizer\Vendor\Composer;

use Ergebnis\Json\Json;
use Ergebnis\Json\Normalizer\Format;
use Ergebnis\Json\Normalizer\Normalizer;

final class RepositoriesHashNormalizer implements Normalizer
{
private const PROPERTIES_WITH_WILDCARDS = [
/**
* @see https://getcomposer.org/doc/articles/repository-priorities.md#filtering-packages
*/
'exclude',
'only',
];
private readonly WildcardSorter $wildcardSorter;

public function __construct()
{
$this->wildcardSorter = new WildcardSorter();
}

public function normalize(Json $json): Json
{
$decoded = $json->decoded();

if (!\is_object($decoded)) {
return $json;
}

if (!\property_exists($decoded, 'repositories')) {
return $json;
}

if (!\is_object($decoded->repositories) && !\is_array($decoded->repositories)) {
return $json;
}

/** @var array<string, mixed> $repositories */
$repositories = (array) $decoded->repositories;

if ([] === $repositories) {
return $json;
}

foreach ($repositories as &$repository) {
$repository = (array) $repository;

foreach (self::PROPERTIES_WITH_WILDCARDS as $property) {
$this->wildcardSorter->sortPropertyWithWildcard(
$repository,
$property,
false,
);
}
}

$decoded->repositories = $repositories;

/** @var string $encoded */
$encoded = \json_encode(
$decoded,
Format\JsonEncodeOptions::default()->toInt(),
);

return Json::fromString($encoded);
}
}
85 changes: 85 additions & 0 deletions src/Vendor/Composer/WildcardSorter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2018-2023 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/json-normalizer
*/

namespace Ergebnis\Json\Normalizer\Vendor\Composer;

/**
* @internal
*/
final class WildcardSorter
{
/**
* When sorting with wildcards, special care needs to be taken.
*
* @see https://github.com/ergebnis/json-normalizer/pull/775#issuecomment-1346095415
* @see https://github.com/composer/composer/blob/2.6.5/src/Composer/Plugin/PluginManager.php#L85-L86
* @see https://github.com/composer/composer/blob/2.6.5/src/Composer/Plugin/PluginManager.php#L626-L646
* @see https://github.com/composer/composer/blob/2.6.5/src/Composer/Package/BasePackage.php#L252-L257
* @see https://github.com/composer/composer/blob/2.6.5/src/Composer/Plugin/PluginManager.php#L687-L691
*/
public function sortPropertyWithWildcard(
array &$config,
string $property,
bool $sortByKey = true,
): void {
if (!\array_key_exists($property, $config)) {
return;
}

if (!\is_object($config[$property]) && !\is_array($config[$property])) {
return;
}

$value = (array) $config[$property];

if ([] === $value) {
return;
}

$packages = $sortByKey ? \array_keys($value) : \array_values($value);

foreach ($packages as $package) {
/** @var string $package */
if (\str_contains(\rtrim($package, '*'), '*')) {
// We cannot reliably sort allow-plugins when there's a wildcard other than at the end of the string.
return;
}
}

$normalize = static function (string $package): string {
// Any key with an asterisk needs to be the last entry in its group
return \str_replace(
'*',
'~',
$package,
);
};

$callback = static function (string $a, string $b) use ($normalize): int {
return \strcmp(
$normalize($a),
$normalize($b),
);
};

if ($sortByKey) {
/** @var array<string, mixed> $value */
\uksort($value, $callback);
} else {
/** @var array<mixed, string> $value */
\usort($value, $callback);
}

$config[$property] = $value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
"repositories": [
{
"type": "composer",
"url": "http://packages.example.com",
"only": [
"example/*"
]
"url": "http://packages.example.com"
},
{
"type": "composer",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"repositories": [
{
"url": "http://packages.example.com",
"only": [ "example/*" ],
"type": "composer"
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "ergebnis/json-normalizer",
"description": "Provides generic and vendor-specific normalizers for normalizing JSON documents.",
"license": "MIT",
"type": "library",
"keywords": [
"json",
"normalizer"
],
"authors": [
{
"name": "Andreas Möller",
"email": "[email protected]"
}
],
"homepage": "https://getcomposer.org/doc/04-schema.md#repositories",
"repositories": [
{
"type": "composer",
"url": "http://packages.foo.com",
"exclude": [
"vendor/one",
"vendor/two"
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "ergebnis/json-normalizer",
"description": "Provides generic and vendor-specific normalizers for normalizing JSON documents.",
"license": "MIT",
"type": "library",
"keywords": [
"json",
"normalizer"
],
"authors": [
{
"name": "Andreas Möller",
"email": "[email protected]"
}
],
"homepage": "https://getcomposer.org/doc/04-schema.md#repositories",
"repositories": [
{
"url": "http://packages.foo.com",
"exclude": ["vendor/two","vendor/one"],
"type": "composer"
}
]
}
Loading

0 comments on commit eba9b55

Please sign in to comment.