1
0
Fork 0
mirror of https://github.com/composer/composer synced 2025-05-09 16:42:57 +00:00

Fix UX when a non-required plugin is still present in vendor dir (#12000)

Composer now skips it and does not prompt if it is not allowed to run, fixes #11944
This commit is contained in:
Jordi Boggiano 2024-05-31 10:29:56 +02:00 committed by GitHub
parent 37d722e73c
commit c1be804a0c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 40 additions and 9 deletions

View file

@ -20,11 +20,13 @@ use Composer\Package\BasePackage;
use Composer\Package\CompletePackage;
use Composer\Package\Locker;
use Composer\Package\Package;
use Composer\Package\RootPackageInterface;
use Composer\Package\Version\VersionParser;
use Composer\PartialComposer;
use Composer\Pcre\Preg;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\InstalledRepository;
use Composer\Repository\RepositoryUtils;
use Composer\Repository\RootPackageRepository;
use Composer\Package\PackageInterface;
use Composer\Package\Link;
@ -98,7 +100,7 @@ class PluginManager
{
if (!$this->arePluginsDisabled('local')) {
$repo = $this->composer->getRepositoryManager()->getLocalRepository();
$this->loadRepository($repo, false);
$this->loadRepository($repo, false, $this->composer->getPackage());
}
if ($this->globalComposer !== null && !$this->arePluginsDisabled('global')) {
@ -445,9 +447,11 @@ class PluginManager
*
* @param RepositoryInterface $repo Repository to scan for plugins to install
*
* @phpstan-param ($isGlobalRepo is true ? null : RootPackageInterface) $rootPackage
*
* @throws \RuntimeException
*/
private function loadRepository(RepositoryInterface $repo, bool $isGlobalRepo): void
private function loadRepository(RepositoryInterface $repo, bool $isGlobalRepo, ?RootPackageInterface $rootPackage = null): void
{
$packages = $repo->getPackages();
@ -462,10 +466,28 @@ class PluginManager
}
$sortedPackages = PackageSorter::sortPackages($packages, $weights);
if (!$isGlobalRepo) {
$requiredPackages = RepositoryUtils::filterRequiredPackages($packages, $rootPackage, true);
}
foreach ($sortedPackages as $package) {
if (!($package instanceof CompletePackage)) {
continue;
}
if (!in_array($package->getType(), ['composer-plugin', 'composer-installer'], true)) {
continue;
}
if (
!$isGlobalRepo
&& !in_array($package, $requiredPackages, true)
&& !$this->isPluginAllowed($package->getName(), false, true, false)
) {
$this->io->writeError('<warning>The "'.$package->getName().'" plugin was not loaded as it is not listed in allow-plugins and is not required by the root package anymore.</warning>');
continue;
}
if ('composer-plugin' === $package->getType()) {
$this->registerPackage($package, false, $isGlobalRepo);
// Backward compatibility
@ -668,7 +690,7 @@ class PluginManager
/**
* @internal
*/
public function isPluginAllowed(string $package, bool $isGlobalPlugin, bool $optional = false): bool
public function isPluginAllowed(string $package, bool $isGlobalPlugin, bool $optional = false, bool $prompt = true): bool
{
if ($isGlobalPlugin) {
$rules = &$this->allowGlobalPluginRules;
@ -703,7 +725,7 @@ class PluginManager
return false;
}
if ($this->io->isInteractive()) {
if ($this->io->isInteractive() && $prompt) {
$composer = $isGlobalPlugin && $this->globalComposer !== null ? $this->globalComposer : $this->composer;
$this->io->writeError('<warning>'.$package.($isGlobalPlugin || $this->runningInGlobalDir ? ' (installed globally)' : '').' contains a Composer plugin which is currently not in your allow-plugins config. See https://getcomposer.org/allow-plugins</warning>');

View file

@ -24,23 +24,28 @@ class RepositoryUtils
/**
* Find all of $packages which are required by $requirer, either directly or transitively
*
* Require-dev is ignored
* Require-dev is ignored by default, you can enable the require-dev of the initial $requirer
* packages by passing $includeRequireDev=true, but require-dev of transitive dependencies
* are always ignored.
*
* @template T of PackageInterface
* @param array<T> $packages
* @param list<T> $bucket Do not pass this in, only used to avoid recursion with circular deps
* @return list<T>
*/
public static function filterRequiredPackages(array $packages, PackageInterface $requirer, array $bucket = []): array
public static function filterRequiredPackages(array $packages, PackageInterface $requirer, bool $includeRequireDev = false, array $bucket = []): array
{
$requires = $requirer->getRequires();
if ($includeRequireDev) {
$requires = array_merge($requires, $requirer->getDevRequires());
}
foreach ($packages as $candidate) {
foreach ($candidate->getNames() as $name) {
if (isset($requires[$name])) {
if (!in_array($candidate, $bucket, true)) {
$bucket[] = $candidate;
$bucket = self::filterRequiredPackages($packages, $candidate, $bucket);
$bucket = self::filterRequiredPackages($packages, $candidate, false, $bucket);
}
break;
}