Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load plugins which modify install path early #10621

Merged
merged 1 commit into from Mar 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions doc/articles/plugins.md
Expand Up @@ -323,6 +323,15 @@ hint to Composer that the plugin should be installed on its own before proceedin
the rest of the package downloads. This slightly slows down the overall installation
process however, so do not use it in plugins which do not absolutely require it.

### plugin-modifies-install-path

Some special plugins modify the install path of packages.

As of Composer 2.2.9, you can specify `{"extra": {"plugin-modifies-install-path": true}}`
in your composer.json to hint to Composer that the plugin should be activated as soon
as possible to prevent any bad side-effects from Composer assuming packages are installed
in another location than they actually are.

## Plugin Autoloading

Due to plugins being loaded by Composer at runtime, and to ensure that plugins which
Expand Down
13 changes: 12 additions & 1 deletion src/Composer/Plugin/PluginManager.php
Expand Up @@ -477,7 +477,18 @@ public function uninstallPlugin(PluginInterface $plugin)
private function loadRepository(RepositoryInterface $repo, $isGlobalRepo)
{
$packages = $repo->getPackages();
$sortedPackages = PackageSorter::sortPackages($packages);

$weights = array();
foreach ($packages as $package) {
if ($package->getType() === 'composer-plugin') {
$extra = $package->getExtra();
if ($package->getName() === 'composer/installers' || (isset($extra['plugin-modifies-install-path']) && $extra['plugin-modifies-install-path'] === true)) {
$weights[$package->getName()] = -10000;
}
}
}

$sortedPackages = PackageSorter::sortPackages($packages, $weights);
foreach ($sortedPackages as $package) {
if (!($package instanceof CompletePackage)) {
continue;
Expand Down
7 changes: 4 additions & 3 deletions src/Composer/Util/PackageSorter.php
Expand Up @@ -23,9 +23,10 @@ class PackageSorter
* Packages of equal weight are sorted alphabetically
*
* @param PackageInterface[] $packages
* @param array<string, int> $weights Pre-set weights for some packages to give them more (negative number) or less (positive) weight offsets
* @return PackageInterface[] sorted array
*/
public static function sortPackages(array $packages)
public static function sortPackages(array $packages, array $weights = array())
{
$usageList = array();

Expand All @@ -41,7 +42,7 @@ public static function sortPackages(array $packages)
}
$computing = array();
$computed = array();
$computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList) {
$computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList, $weights) {
// reusing computed importance
if (isset($computed[$name])) {
return $computed[$name];
Expand All @@ -53,7 +54,7 @@ public static function sortPackages(array $packages)
}

$computing[$name] = true;
$weight = 0;
$weight = isset($weights[$name]) ? $weights[$name] : 0;

if (isset($usageList[$name])) {
foreach ($usageList[$name] as $user) {
Expand Down
22 changes: 20 additions & 2 deletions tests/Composer/Test/Util/PackageSorterTest.php
Expand Up @@ -127,6 +127,23 @@ public function sortingOrdersDependenciesHigherThanPackageDataProvider()
'foo/baz',
),
),
'pre-weighted packages bumped to top incl their deps' => array(
array(
$this->createPackage('foo/bar', array('foo/dep')),
$this->createPackage('foo/bar2', array('foo/dep2')),
$this->createPackage('foo/dep', array()),
$this->createPackage('foo/dep2', array()),
),
array(
'foo/dep',
'foo/bar',
'foo/dep2',
'foo/bar2',
),
array(
'foo/bar' => -1000
)
),
);
}

Expand All @@ -135,10 +152,11 @@ public function sortingOrdersDependenciesHigherThanPackageDataProvider()
*
* @param Package[] $packages
* @param string[] $expectedOrderedList
* @param array<string, int> $weights
*/
public function testSortingOrdersDependenciesHigherThanPackage($packages, $expectedOrderedList)
public function testSortingOrdersDependenciesHigherThanPackage($packages, $expectedOrderedList, $weights = array())
{
$sortedPackages = PackageSorter::sortPackages($packages);
$sortedPackages = PackageSorter::sortPackages($packages, $weights);
$sortedPackageNames = array_map(function ($package) {
return $package->getName();
}, $sortedPackages);
Expand Down