Merge pull request #8085 from danepowell/issue-8065-2
Fixes #8065: Sort plugins deterministically before loading.pull/8178/head
commit
9d642fe9af
|
@ -21,6 +21,7 @@ use Composer\Package\PackageInterface;
|
||||||
use Composer\Repository\InstalledRepositoryInterface;
|
use Composer\Repository\InstalledRepositoryInterface;
|
||||||
use Composer\Util\Filesystem;
|
use Composer\Util\Filesystem;
|
||||||
use Composer\Script\ScriptEvents;
|
use Composer\Script\ScriptEvents;
|
||||||
|
use Composer\Util\PackageSorter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Igor Wiedler <igor@wiedler.ch>
|
* @author Igor Wiedler <igor@wiedler.ch>
|
||||||
|
@ -973,80 +974,21 @@ INITIALIZER;
|
||||||
{
|
{
|
||||||
$packages = array();
|
$packages = array();
|
||||||
$paths = array();
|
$paths = array();
|
||||||
$usageList = array();
|
|
||||||
|
|
||||||
foreach ($packageMap as $item) {
|
foreach ($packageMap as $item) {
|
||||||
list($package, $path) = $item;
|
list($package, $path) = $item;
|
||||||
$name = $package->getName();
|
$name = $package->getName();
|
||||||
$packages[$name] = $package;
|
$packages[$name] = $package;
|
||||||
$paths[$name] = $path;
|
$paths[$name] = $path;
|
||||||
|
|
||||||
foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) {
|
|
||||||
$target = $link->getTarget();
|
|
||||||
$usageList[$target][] = $name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$computing = array();
|
$sortedPackages = PackageSorter::sortPackages($packages);
|
||||||
$computed = array();
|
|
||||||
$computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList) {
|
|
||||||
// reusing computed importance
|
|
||||||
if (isset($computed[$name])) {
|
|
||||||
return $computed[$name];
|
|
||||||
}
|
|
||||||
|
|
||||||
// canceling circular dependency
|
|
||||||
if (isset($computing[$name])) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$computing[$name] = true;
|
|
||||||
$weight = 0;
|
|
||||||
|
|
||||||
if (isset($usageList[$name])) {
|
|
||||||
foreach ($usageList[$name] as $user) {
|
|
||||||
$weight -= 1 - $computeImportance($user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($computing[$name]);
|
|
||||||
$computed[$name] = $weight;
|
|
||||||
|
|
||||||
return $weight;
|
|
||||||
};
|
|
||||||
|
|
||||||
$weightList = array();
|
|
||||||
|
|
||||||
foreach ($packages as $name => $package) {
|
|
||||||
$weight = $computeImportance($name);
|
|
||||||
$weightList[$name] = $weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
$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, $k) {
|
|
||||||
$v = $v[3];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
array_walk($array, $transform);
|
|
||||||
asort($array);
|
|
||||||
array_walk($array, $restore);
|
|
||||||
};
|
|
||||||
|
|
||||||
$stable_sort($weightList);
|
|
||||||
|
|
||||||
$sortedPackageMap = array();
|
$sortedPackageMap = array();
|
||||||
|
|
||||||
foreach (array_keys($weightList) as $name) {
|
foreach ($sortedPackages as $package) {
|
||||||
|
$name = $package->getName();
|
||||||
$sortedPackageMap[] = array($packages[$name], $paths[$name]);
|
$sortedPackageMap[] = array($packages[$name], $paths[$name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,15 +15,16 @@ namespace Composer\Plugin;
|
||||||
use Composer\Composer;
|
use Composer\Composer;
|
||||||
use Composer\EventDispatcher\EventSubscriberInterface;
|
use Composer\EventDispatcher\EventSubscriberInterface;
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
|
use Composer\Package\CompletePackage;
|
||||||
use Composer\Package\Package;
|
use Composer\Package\Package;
|
||||||
use Composer\Package\Version\VersionParser;
|
use Composer\Package\Version\VersionParser;
|
||||||
use Composer\Repository\RepositoryInterface;
|
use Composer\Repository\RepositoryInterface;
|
||||||
use Composer\Package\AliasPackage;
|
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
use Composer\Package\Link;
|
use Composer\Package\Link;
|
||||||
use Composer\Semver\Constraint\Constraint;
|
use Composer\Semver\Constraint\Constraint;
|
||||||
use Composer\DependencyResolver\Pool;
|
use Composer\DependencyResolver\Pool;
|
||||||
use Composer\Plugin\Capability\Capability;
|
use Composer\Plugin\Capability\Capability;
|
||||||
|
use Composer\Util\PackageSorter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin manager
|
* Plugin manager
|
||||||
|
@ -253,8 +254,10 @@ class PluginManager
|
||||||
*/
|
*/
|
||||||
private function loadRepository(RepositoryInterface $repo)
|
private function loadRepository(RepositoryInterface $repo)
|
||||||
{
|
{
|
||||||
foreach ($repo->getPackages() as $package) { /** @var PackageInterface $package */
|
$packages = $repo->getPackages();
|
||||||
if ($package instanceof AliasPackage) {
|
$sortedPackages = array_reverse(PackageSorter::sortPackages($packages));
|
||||||
|
foreach ($sortedPackages as $package) {
|
||||||
|
if (!($package instanceof CompletePackage)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ('composer-plugin' === $package->getType()) {
|
if ('composer-plugin' === $package->getType()) {
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace Composer\Util;
|
||||||
|
|
||||||
|
use Composer\Package\Link;
|
||||||
|
use Composer\Package\PackageInterface;
|
||||||
|
|
||||||
|
class PackageSorter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sorts packages by dependency weight
|
||||||
|
*
|
||||||
|
* Packages of equal weight retain the original order
|
||||||
|
*
|
||||||
|
* @param array $packages
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function sortPackages(array $packages) {
|
||||||
|
$usageList = array();
|
||||||
|
|
||||||
|
foreach ($packages as $package) { /** @var PackageInterface $package */
|
||||||
|
foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) { /** @var Link $link */
|
||||||
|
$target = $link->getTarget();
|
||||||
|
$usageList[$target][] = $package->getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$computing = array();
|
||||||
|
$computed = array();
|
||||||
|
$computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList) {
|
||||||
|
// reusing computed importance
|
||||||
|
if (isset($computed[$name])) {
|
||||||
|
return $computed[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
// canceling circular dependency
|
||||||
|
if (isset($computing[$name])) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$computing[$name] = true;
|
||||||
|
$weight = 0;
|
||||||
|
|
||||||
|
if (isset($usageList[$name])) {
|
||||||
|
foreach ($usageList[$name] as $user) {
|
||||||
|
$weight -= 1 - $computeImportance($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($computing[$name]);
|
||||||
|
$computed[$name] = $weight;
|
||||||
|
|
||||||
|
return $weight;
|
||||||
|
};
|
||||||
|
|
||||||
|
$weightList = array();
|
||||||
|
|
||||||
|
foreach ($packages as $name => $package) {
|
||||||
|
$weight = $computeImportance($name);
|
||||||
|
$weightList[$name] = $weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
$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];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
array_walk($array, $transform);
|
||||||
|
asort($array);
|
||||||
|
array_walk($array, $restore);
|
||||||
|
};
|
||||||
|
|
||||||
|
$stable_sort($weightList);
|
||||||
|
|
||||||
|
$sortedPackages = array();
|
||||||
|
|
||||||
|
foreach (array_keys($weightList) as $name) {
|
||||||
|
$sortedPackages[] = $packages[$name];
|
||||||
|
}
|
||||||
|
return $sortedPackages;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue