diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php
index 774370b51..0679bb46f 100644
--- a/src/Composer/Console/Application.php
+++ b/src/Composer/Console/Application.php
@@ -220,7 +220,7 @@ class Application extends BaseApplication
// Clobber sudo credentials if COMPOSER_ALLOW_SUPERUSER is not set before loading plugins
if ($needsSudoCheck) {
- $isNonAllowedRoot = function_exists('posix_getuid') && posix_getuid() === 0;
+ $isNonAllowedRoot = $this->isRunningAsRoot();
if ($isNonAllowedRoot) {
if ($uid = (int) Platform::getEnv('SUDO_UID')) {
@@ -476,6 +476,12 @@ class Application extends BaseApplication
$io->writeError('Check https://getcomposer.org/doc/06-config.md#process-timeout for details', true, IOInterface::QUIET);
}
+ if ($this->getDisablePluginsByDefault() && $this->isRunningAsRoot() && !$this->io->isInteractive()) {
+ $io->writeError('Plugins have been disabled automatically as you are running as root, this may be the cause of the following exception. See also https://getcomposer.org/root', true, IOInterface::QUIET);
+ } elseif ($exception instanceof CommandNotFoundException && $this->getDisablePluginsByDefault()) {
+ $io->writeError('Plugins have been disabled, which may be why some commands are missing, unless you made a typo', true, IOInterface::QUIET);
+ }
+
$hints = HttpDownloader::getExceptionHints($exception);
if (null !== $hints && count($hints) > 0) {
foreach ($hints as $hint) {
@@ -678,4 +684,9 @@ class Application extends BaseApplication
return $config->get('use-parent-dir');
}
+
+ private function isRunningAsRoot(): bool
+ {
+ return function_exists('posix_getuid') && posix_getuid() === 0;
+ }
}
diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php
index 74f356826..27afa7c3a 100644
--- a/src/Composer/Installer/InstallationManager.php
+++ b/src/Composer/Installer/InstallationManager.php
@@ -94,8 +94,8 @@ class InstallationManager
/**
* Disables plugins.
*
- * We prevent any plugins from being instantiated by simply
- * deactivating the installer for them. This ensure that no third-party
+ * We prevent any plugins from being instantiated by
+ * disabling the PluginManager. This ensures that no third-party
* code is ever executed.
*/
public function disablePlugins(): void
@@ -105,7 +105,7 @@ class InstallationManager
continue;
}
- unset($this->installers[$i]);
+ $installer->disablePlugins();
}
}
diff --git a/src/Composer/Installer/PluginInstaller.php b/src/Composer/Installer/PluginInstaller.php
index 3a982f13b..58ba0d7d7 100644
--- a/src/Composer/Installer/PluginInstaller.php
+++ b/src/Composer/Installer/PluginInstaller.php
@@ -43,6 +43,11 @@ class PluginInstaller extends LibraryInstaller
return $packageType === 'composer-plugin' || $packageType === 'composer-installer';
}
+ public function disablePlugins(): void
+ {
+ $this->getPluginManager()->disablePlugins();
+ }
+
/**
* @inheritDoc
*/
diff --git a/src/Composer/Plugin/PluginManager.php b/src/Composer/Plugin/PluginManager.php
index 731a5aba0..f594478a6 100644
--- a/src/Composer/Plugin/PluginManager.php
+++ b/src/Composer/Plugin/PluginManager.php
@@ -153,6 +153,7 @@ class PluginManager
public function registerPackage(PackageInterface $package, bool $failOnMissingClasses = false, bool $isGlobalPlugin = false): void
{
if ($this->arePluginsDisabled($isGlobalPlugin ? 'global' : 'local')) {
+ $this->io->writeError('The "'.$package->getName().'" plugin was not loaded as plugins are disabled.');
return;
}
@@ -656,6 +657,14 @@ class PluginManager
return $this->disablePlugins === true || $this->disablePlugins === $type;
}
+ /**
+ * @internal
+ */
+ public function disablePlugins(): void
+ {
+ $this->disablePlugins = true;
+ }
+
/**
* @internal
*/