From f31700bf1983879a6f519ca6e50fc5591845de3b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 15 Mar 2022 11:04:30 +0100 Subject: [PATCH] Sort packages with the same weight alphabetically to have a completely stable sort not dependent on input order, fixes #10614 --- src/Composer/Autoload/AutoloadGenerator.php | 2 +- src/Composer/Util/PackageSorter.php | 37 ++++++------------- .../Test/Autoload/AutoloadGeneratorTest.php | 8 ++++ .../autoload_static_files_by_dependency.php | 2 +- .../Composer/Test/Util/PackageSorterTest.php | 14 +++++++ 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index efb8c7cefa2f..b31f9ed678b3 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -1379,7 +1379,7 @@ function ($item) use ($include) { /** * Sorts packages by dependency weight * - * Packages of equal weight retain the original order + * Packages of equal weight are sorted alphabetically * * @param array $packageMap * @return array diff --git a/src/Composer/Util/PackageSorter.php b/src/Composer/Util/PackageSorter.php index 01aabfc74ff0..63e4a93cbf12 100644 --- a/src/Composer/Util/PackageSorter.php +++ b/src/Composer/Util/PackageSorter.php @@ -20,7 +20,7 @@ class PackageSorter /** * Sorts packages by dependency weight * - * Packages of equal weight retain the original order + * Packages of equal weight are sorted alphabetically * * @param PackageInterface[] $packages * @return PackageInterface[] sorted array @@ -67,39 +67,26 @@ public static function sortPackages(array $packages) return $weight; }; - $weightList = array(); + $weightedPackages = array(); foreach ($packages as $index => $package) { - $weight = $computeImportance($package->getName()); - $weightList[$index] = $weight; + $name = $package->getName(); + $weight = $computeImportance($name); + $weightedPackages[] = array('name' => $name, 'weight' => $weight, 'index' => $index); } - $stable_sort = function (&$array) { - static $transform, $restore; - - $i = 0; - - if (!$transform) { - $transform = function (&$v, $k) use (&$i) { - $v = array($v, ++$i, $k, $v); - }; - - $restore = function (&$v) { - $v = $v[3]; - }; + usort($weightedPackages, function ($a, $b) { + if ($a['weight'] !== $b['weight']) { + return $a['weight'] - $b['weight']; } - array_walk($array, $transform); - asort($array); - array_walk($array, $restore); - }; - - $stable_sort($weightList); + return strnatcasecmp($a['name'], $b['name']); + }); $sortedPackages = array(); - foreach (array_keys($weightList) as $index) { - $sortedPackages[] = $packages[$index]; + foreach ($weightedPackages as $pkg) { + $sortedPackages[] = $packages[$pkg['index']]; } return $sortedPackages; diff --git a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php index 0a801ad63c83..c29121f215bb 100644 --- a/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php +++ b/tests/Composer/Test/Autoload/AutoloadGeneratorTest.php @@ -1017,6 +1017,14 @@ public function testFilesAutoloadOrderByDependencies() $packages[] = $c = new Package('c/lorem', '1.0', '1.0'); $packages[] = $e = new Package('e/e', '1.0', '1.0'); + // expected order: + // c requires nothing + // d requires c + // b requires c & d + // e requires c + // z requires c + // (b, e, z ordered alphabetically) + $z->setAutoload(array('files' => array('testA.php'))); $z->setRequires(array('c/lorem' => new Link('z/foo', 'c/lorem', new MatchAllConstraint()))); diff --git a/tests/Composer/Test/Autoload/Fixtures/autoload_static_files_by_dependency.php b/tests/Composer/Test/Autoload/Fixtures/autoload_static_files_by_dependency.php index e3659aee32db..addd6cc3f578 100644 --- a/tests/Composer/Test/Autoload/Fixtures/autoload_static_files_by_dependency.php +++ b/tests/Composer/Test/Autoload/Fixtures/autoload_static_files_by_dependency.php @@ -9,9 +9,9 @@ class ComposerStaticInitFilesAutoloadOrder public static $files = array ( 'bfdd693009729d60c830ff8d79129635' => __DIR__ . '/..' . '/c/lorem/testC.php', '61e6098c8cafe404d6cf19e59fc2b788' => __DIR__ . '/..' . '/d/d/testD.php', - '8bceec6fdc149a1a6acbf7ad3cfed51c' => __DIR__ . '/..' . '/z/foo/testA.php', 'c5466e580c6c2403f225c43b6a21a96f' => __DIR__ . '/..' . '/b/bar/testB.php', '69dfc37c40a853a7cbac6c9d2367c5f4' => __DIR__ . '/..' . '/e/e/testE.php', + '8bceec6fdc149a1a6acbf7ad3cfed51c' => __DIR__ . '/..' . '/z/foo/testA.php', 'ab280164f4754f5dfdb0721de84d737f' => __DIR__ . '/../..' . '/root2.php', ); diff --git a/tests/Composer/Test/Util/PackageSorterTest.php b/tests/Composer/Test/Util/PackageSorterTest.php index 7ee94982cb4e..b4c7e2b8a2cc 100644 --- a/tests/Composer/Test/Util/PackageSorterTest.php +++ b/tests/Composer/Test/Util/PackageSorterTest.php @@ -99,6 +99,20 @@ public function sortingOrdersDependenciesHigherThanPackageDataProvider() 'foo/bar6', ), ), + 'equal weight sorted alphabetically' => array( + array( + $this->createPackage('foo/bar10', array('foo/dep')), + $this->createPackage('foo/bar2', array('foo/dep')), + $this->createPackage('foo/baz', array('foo/dep')), + $this->createPackage('foo/dep', array()), + ), + array( + 'foo/dep', + 'foo/bar2', + 'foo/bar10', + 'foo/baz', + ), + ), ); }