From 8f1b3d21db998e02a8e11dd31ffcf4c65ddb1299 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 20 Dec 2021 14:23:35 +0100 Subject: [PATCH] Add --no-scripts to all commands and disable plugins/scripts when running self-update (#10371) * Add --no-scripts as global parameter available to all commands, and handle it by default when creating a Composer instance from Command::getComposer * Disable scripts/plugins for self-update command, fixes #10351 --- doc/03-cli.md | 7 +-- src/Composer/Command/BaseCommand.php | 15 +++-- src/Composer/Command/CreateProjectCommand.php | 57 +++++++++---------- src/Composer/Command/DumpAutoloadCommand.php | 2 - src/Composer/Command/InstallCommand.php | 4 +- src/Composer/Command/ReinstallCommand.php | 4 +- src/Composer/Command/RemoveCommand.php | 4 +- src/Composer/Command/RequireCommand.php | 4 +- src/Composer/Command/UpdateCommand.php | 4 +- src/Composer/Console/Application.php | 12 +++- src/Composer/Factory.php | 21 ++++--- tests/Composer/Test/ApplicationTest.php | 10 ++++ 12 files changed, 78 insertions(+), 66 deletions(-) diff --git a/doc/03-cli.md b/doc/03-cli.md index 499088b4f..1d262dfd7 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -22,6 +22,7 @@ The following options are available with every command: * **--quiet (-q):** Do not output any message. * **--no-interaction (-n):** Do not ask any interactive question. * **--no-plugins:** Disables plugins. +* **--no-scripts:** Skips execution of scripts defined in `composer.json`. * **--no-cache:** Disables the use of the cache directory. Same as setting the COMPOSER_CACHE_DIR env var to /dev/null (or NUL on Windows). * **--working-dir (-d):** If specified, use the given directory as working directory. @@ -100,7 +101,6 @@ resolution. * **--no-dev:** Skip installing packages listed in `require-dev`. The autoloader generation skips the `autoload-dev` rules. * **--no-autoloader:** Skips autoloader generation. -* **--no-scripts:** Skips execution of scripts defined in `composer.json`. * **--no-progress:** Removes the progress display that can mess with some terminals or scripts which don't handle backspace characters. * **--optimize-autoloader (-o):** Convert PSR-0/4 autoloading to classmap to get a faster @@ -186,7 +186,6 @@ php composer.phar update vendor/package:2.0.1 vendor/package2:3.0.* lock file being out of date. * **--with:** Temporary version constraint to add, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 * **--no-autoloader:** Skips autoloader generation. -* **--no-scripts:** Skips execution of scripts defined in `composer.json`. * **--no-progress:** Removes the progress display that can mess with some terminals or scripts which don't handle backspace characters. * **--with-dependencies (-w):** Update also dependencies of packages in the argument list, except those which are root requirements. @@ -254,7 +253,6 @@ If you do not specify a package, Composer will prompt you to search for a packag terminals or scripts which don't handle backspace characters. * **--no-update:** Disables the automatic update of the dependencies (implies --no-install). * **--no-install:** Does not run the install step after updating the composer.lock file. -* **--no-scripts:** Skips execution of scripts defined in `composer.json`. * **--update-no-dev:** Run the dependency update with the `--no-dev` option. * **--update-with-dependencies (-w):** Also update dependencies of the newly required packages, except those that are root requirements. * **--update-with-all-dependencies (-W):** Also update dependencies of the newly required packages, including those that are root requirements. @@ -297,7 +295,6 @@ uninstalled. terminals or scripts which don't handle backspace characters. * **--no-update:** Disables the automatic update of the dependencies (implies --no-install). * **--no-install:** Does not run the install step after updating the composer.lock file. -* **--no-scripts:** Skips execution of scripts defined in `composer.json`. * **--update-no-dev:** Run the dependency update with the --no-dev option. * **--update-with-dependencies (-w):** Also update dependencies of the removed packages. (Deprecated, is now default behavior) @@ -348,7 +345,6 @@ php composer.phar reinstall "acme/*" versions of packages, use `--prefer-install=auto`. See also [config.preferred-install](06-config.md#preferred-install). Passing this flag will override the config value. * **--no-autoloader:** Skips autoloader generation. -* **--no-scripts:** Skips execution of scripts defined in `composer.json`. * **--no-progress:** Removes the progress display that can mess with some terminals or scripts which don't handle backspace characters. * **--optimize-autoloader (-o):** Convert PSR-0/4 autoloading to classmap to get a faster @@ -877,7 +873,6 @@ using this option you can still use PSR-0/4 for convenience and classmaps for performance. ### Options -* **--no-scripts:** Skips the execution of all scripts defined in the `composer.json` file. * **--optimize (-o):** Convert PSR-0/4 autoloading to classmap to get a faster autoloader. This is recommended especially for production, but can take a bit of time to run, so it is currently not done by default. diff --git a/src/Composer/Command/BaseCommand.php b/src/Composer/Command/BaseCommand.php index 0afcc0db1..59cbbe9ab 100644 --- a/src/Composer/Command/BaseCommand.php +++ b/src/Composer/Command/BaseCommand.php @@ -52,16 +52,17 @@ abstract class BaseCommand extends Command /** * @param bool $required * @param bool|null $disablePlugins + * @param bool|null $disableScripts * @throws \RuntimeException * @return Composer|null */ - public function getComposer($required = true, $disablePlugins = null) + public function getComposer($required = true, $disablePlugins = null, $disableScripts = null) { if (null === $this->composer) { $application = $this->getApplication(); if ($application instanceof Application) { /* @var $application Application */ - $this->composer = $application->getComposer($required, $disablePlugins); + $this->composer = $application->getComposer($required, $disablePlugins, $disableScripts); /** @phpstan-ignore-next-line */ } elseif ($required) { throw new \RuntimeException( @@ -140,9 +141,15 @@ abstract class BaseCommand extends Command { // initialize a plugin-enabled Composer instance, either local or global $disablePlugins = $input->hasParameterOption('--no-plugins'); - $composer = $this->getComposer(false, $disablePlugins); + $disableScripts = $input->hasParameterOption('--no-scripts'); + if ($this instanceof SelfUpdateCommand) { + $disablePlugins = true; + $disableScripts = true; + } + + $composer = $this->getComposer(false, $disablePlugins, $disableScripts); if (null === $composer) { - $composer = Factory::createGlobal($this->getIO(), $disablePlugins); + $composer = Factory::createGlobal($this->getIO(), $disablePlugins, $disableScripts); } if ($composer) { $preCommandRunEvent = new PreCommandRunEvent(PluginEvents::PRE_COMMAND_RUN, $input, $this->getName()); diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index d2ff21e9e..a1eba060f 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -170,25 +170,25 @@ EOT } /** - * @param string|null $packageName - * @param string|null $directory - * @param string|null $packageVersion - * @param string $stability - * @param bool $preferSource - * @param bool $preferDist - * @param bool $installDevPackages + * @param string|null $packageName + * @param string|null $directory + * @param string|null $packageVersion + * @param string $stability + * @param bool $preferSource + * @param bool $preferDist + * @param bool $installDevPackages * @param string|array|null $repositories - * @param bool $disablePlugins - * @param bool $noScripts - * @param bool $noProgress - * @param bool $noInstall - * @param bool $secureHttp - * @param bool $addRepository + * @param bool $disablePlugins + * @param bool $disableScripts + * @param bool $noProgress + * @param bool $noInstall + * @param bool $secureHttp + * @param bool $addRepository * * @return int * @throws \Exception */ - public function installProject(IOInterface $io, Config $config, InputInterface $input, $packageName = null, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositories = null, $disablePlugins = false, $noScripts = false, $noProgress = false, $noInstall = false, PlatformRequirementFilterInterface $platformRequirementFilter = null, $secureHttp = true, $addRepository = false) + public function installProject(IOInterface $io, Config $config, InputInterface $input, $packageName = null, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositories = null, $disablePlugins = false, $disableScripts = false, $noProgress = false, $noInstall = false, PlatformRequirementFilterInterface $platformRequirementFilter = null, $secureHttp = true, $addRepository = false) { $oldCwd = getcwd(); @@ -204,7 +204,7 @@ EOT $this->suggestedPackagesReporter = new SuggestedPackagesReporter($io); if ($packageName !== null) { - $installedFromVcs = $this->installRootPackage($io, $config, $packageName, $platformRequirementFilter, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repositories, $disablePlugins, $noScripts, $noProgress, $secureHttp); + $installedFromVcs = $this->installRootPackage($io, $config, $packageName, $platformRequirementFilter, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repositories, $disablePlugins, $disableScripts, $noProgress, $secureHttp); } else { $installedFromVcs = false; } @@ -213,8 +213,7 @@ EOT unlink('composer.lock'); } - $composer = Factory::create($io, null, $disablePlugins); - $composer->getEventDispatcher()->setRunScripts(!$noScripts); + $composer = Factory::create($io, null, $disablePlugins, $disableScripts); // add the repository to the composer.json and use it for the install run later if ($repositories !== null && $addRepository) { @@ -336,23 +335,23 @@ EOT } /** - * @param string $packageName - * @param string|null $directory - * @param string|null $packageVersion - * @param string|null $stability - * @param bool $preferSource - * @param bool $preferDist - * @param bool $installDevPackages + * @param string $packageName + * @param string|null $directory + * @param string|null $packageVersion + * @param string|null $stability + * @param bool $preferSource + * @param bool $preferDist + * @param bool $installDevPackages * @param array|null $repositories - * @param bool $disablePlugins - * @param bool $noScripts - * @param bool $noProgress - * @param bool $secureHttp + * @param bool $disablePlugins + * @param bool $disableScripts + * @param bool $noProgress + * @param bool $secureHttp * * @return bool * @throws \Exception */ - protected function installRootPackage(IOInterface $io, Config $config, $packageName, PlatformRequirementFilterInterface $platformRequirementFilter, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, array $repositories = null, $disablePlugins = false, $noScripts = false, $noProgress = false, $secureHttp = true) + protected function installRootPackage(IOInterface $io, Config $config, $packageName, PlatformRequirementFilterInterface $platformRequirementFilter, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, array $repositories = null, $disablePlugins = false, $disableScripts = false, $noProgress = false, $secureHttp = true) { if (!$secureHttp) { $config->merge(array('config' => array('secure-http' => false)), Config::SOURCE_COMMAND); diff --git a/src/Composer/Command/DumpAutoloadCommand.php b/src/Composer/Command/DumpAutoloadCommand.php index 7640af731..2b105e81c 100644 --- a/src/Composer/Command/DumpAutoloadCommand.php +++ b/src/Composer/Command/DumpAutoloadCommand.php @@ -34,7 +34,6 @@ class DumpAutoloadCommand extends BaseCommand ->setAliases(array('dumpautoload')) ->setDescription('Dumps the autoloader.') ->setDefinition(array( - new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'), new InputOption('optimize', 'o', InputOption::VALUE_NONE, 'Optimizes PSR0 and PSR4 packages to be loaded with classmaps too, good for production.'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize`.'), new InputOption('apcu', null, InputOption::VALUE_NONE, 'Use APCu to cache found/not-found classes.'), @@ -60,7 +59,6 @@ EOT protected function execute(InputInterface $input, OutputInterface $output) { $composer = $this->getComposer(); - $composer->getEventDispatcher()->setRunScripts(!$input->getOption('no-scripts')); $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'dump-autoload', $input, $output); $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index fb3fc4aa3..5d1d01836 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -48,7 +48,6 @@ class InstallCommand extends BaseCommand new InputOption('no-suggest', null, InputOption::VALUE_NONE, 'DEPRECATED: This flag does not exist anymore.'), new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'), new InputOption('no-autoloader', null, InputOption::VALUE_NONE, 'Skips autoloader generation'), - new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'), new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'), new InputOption('no-install', null, InputOption::VALUE_NONE, 'Do not use, only defined here to catch misuse of the install command.'), new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'), @@ -97,8 +96,7 @@ EOT return 1; } - $composer = $this->getComposer(true, $input->getOption('no-plugins')); - $composer->getEventDispatcher()->setRunScripts(!$input->getOption('no-scripts')); + $composer = $this->getComposer(true, $input->getOption('no-plugins'), $input->getOption('no-scripts')); if ((!$composer->getLocker() || !$composer->getLocker()->isLocked()) && !HttpDownloader::isCurlEnabled()) { $io->writeError('Composer is operating significantly slower than normal because you do not have the PHP curl extension enabled.'); diff --git a/src/Composer/Command/ReinstallCommand.php b/src/Composer/Command/ReinstallCommand.php index 55f5a7582..3143fc50c 100644 --- a/src/Composer/Command/ReinstallCommand.php +++ b/src/Composer/Command/ReinstallCommand.php @@ -44,7 +44,6 @@ class ReinstallCommand extends BaseCommand new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist (default behavior).'), new InputOption('prefer-install', null, InputOption::VALUE_REQUIRED, 'Forces installation from package dist|source|auto (auto chooses source for dev versions, dist for the rest).'), new InputOption('no-autoloader', null, InputOption::VALUE_NONE, 'Skips autoloader generation'), - new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'), new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'), new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'), @@ -73,8 +72,7 @@ EOT { $io = $this->getIO(); - $composer = $this->getComposer(true, $input->getOption('no-plugins')); - $composer->getEventDispatcher()->setRunScripts(!$input->getOption('no-scripts')); + $composer = $this->getComposer(true, $input->getOption('no-plugins'), $input->getOption('no-scripts')); $localRepo = $composer->getRepositoryManager()->getLocalRepository(); $packagesToReinstall = array(); diff --git a/src/Composer/Command/RemoveCommand.php b/src/Composer/Command/RemoveCommand.php index 777db98a2..7705e3f0a 100644 --- a/src/Composer/Command/RemoveCommand.php +++ b/src/Composer/Command/RemoveCommand.php @@ -48,7 +48,6 @@ class RemoveCommand extends BaseCommand new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'), new InputOption('no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies (implies --no-install).'), new InputOption('no-install', null, InputOption::VALUE_NONE, 'Skip the install step after updating the composer.lock file.'), - new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'), new InputOption('update-no-dev', null, InputOption::VALUE_NONE, 'Run the dependency update with the --no-dev option.'), new InputOption('update-with-dependencies', 'w', InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated with explicit dependencies. (Deprecrated, is now default behavior)'), new InputOption('update-with-all-dependencies', 'W', InputOption::VALUE_NONE, 'Allows all inherited dependencies to be updated, including those that are root requirements.'), @@ -217,8 +216,7 @@ EOT // Update packages $this->resetComposer(); - $composer = $this->getComposer(true, $input->getOption('no-plugins')); - $composer->getEventDispatcher()->setRunScripts(!$input->getOption('no-scripts')); + $composer = $this->getComposer(true, $input->getOption('no-plugins'), $input->getOption('no-scripts')); if ($dryRun) { $rootPackage = $composer->getPackage(); diff --git a/src/Composer/Command/RequireCommand.php b/src/Composer/Command/RequireCommand.php index 751e99d21..92fc2114a 100644 --- a/src/Composer/Command/RequireCommand.php +++ b/src/Composer/Command/RequireCommand.php @@ -77,7 +77,6 @@ class RequireCommand extends InitCommand new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'), new InputOption('no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies (implies --no-install).'), new InputOption('no-install', null, InputOption::VALUE_NONE, 'Skip the install step after updating the composer.lock file.'), - new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'), new InputOption('update-no-dev', null, InputOption::VALUE_NONE, 'Run the dependency update with the --no-dev option.'), new InputOption('update-with-dependencies', 'w', InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated, except those that are root requirements.'), new InputOption('update-with-all-dependencies', 'W', InputOption::VALUE_NONE, 'Allows all inherited dependencies to be updated, including those that are root requirements.'), @@ -356,8 +355,7 @@ EOT { // Update packages $this->resetComposer(); - $composer = $this->getComposer(true, $input->getOption('no-plugins')); - $composer->getEventDispatcher()->setRunScripts(!$input->getOption('no-scripts')); + $composer = $this->getComposer(true, $input->getOption('no-plugins'), $input->getOption('no-scripts')); $this->dependencyResolutionCompleted = false; $composer->getEventDispatcher()->addListener(InstallerEvents::PRE_OPERATIONS_EXEC, array($this, 'markSolverComplete'), 10000); diff --git a/src/Composer/Command/UpdateCommand.php b/src/Composer/Command/UpdateCommand.php index 276a9198d..9b752a218 100644 --- a/src/Composer/Command/UpdateCommand.php +++ b/src/Composer/Command/UpdateCommand.php @@ -59,7 +59,6 @@ class UpdateCommand extends BaseCommand new InputOption('lock', null, InputOption::VALUE_NONE, 'Overwrites the lock file hash to suppress warning about the lock file being out of date without updating package versions. Package metadata like mirrors and URLs are updated if they changed.'), new InputOption('no-install', null, InputOption::VALUE_NONE, 'Skip the install step after updating the composer.lock file.'), new InputOption('no-autoloader', null, InputOption::VALUE_NONE, 'Skips autoloader generation'), - new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'), new InputOption('no-suggest', null, InputOption::VALUE_NONE, 'DEPRECATED: This flag does not exist anymore.'), new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'), new InputOption('with-dependencies', 'w', InputOption::VALUE_NONE, 'Update also dependencies of packages in the argument list, except those which are root requirements.'), @@ -124,8 +123,7 @@ EOT $io->writeError('You are using the deprecated option "--no-suggest". It has no effect and will break in Composer 3.'); } - $composer = $this->getComposer(true, $input->getOption('no-plugins')); - $composer->getEventDispatcher()->setRunScripts(!$input->getOption('no-scripts')); + $composer = $this->getComposer(true, $input->getOption('no-plugins'), $input->getOption('no-scripts')); if (!HttpDownloader::isCurlEnabled()) { $io->writeError('Composer is operating significantly slower than normal because you do not have the PHP curl extension enabled.'); diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index 2701e118f..532570cba 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -69,6 +69,8 @@ class Application extends BaseApplication private $hasPluginCommands = false; /** @var bool */ private $disablePluginsByDefault = false; + /** @var bool */ + private $disableScriptsByDefault = false; /** * @var string Store the initial working directory at startup time @@ -134,6 +136,7 @@ class Application extends BaseApplication public function doRun(InputInterface $input, OutputInterface $output) { $this->disablePluginsByDefault = $input->hasParameterOption('--no-plugins'); + $this->disableScriptsByDefault = $input->hasParameterOption('--no-scripts'); if (Platform::getEnv('COMPOSER_NO_INTERACTION') || !Platform::isTty(defined('STDIN') ? STDIN : fopen('php://stdin', 'r'))) { $input->setInteractive(false); @@ -422,19 +425,23 @@ class Application extends BaseApplication /** * @param bool $required * @param bool|null $disablePlugins + * @param bool|null $disableScripts * @throws JsonValidationException * @throws \InvalidArgumentException * @return ?\Composer\Composer If $required is true then the return value is guaranteed */ - public function getComposer($required = true, $disablePlugins = null) + public function getComposer($required = true, $disablePlugins = null, $disableScripts = null) { if (null === $disablePlugins) { $disablePlugins = $this->disablePluginsByDefault; } + if (null === $disableScripts) { + $disableScripts = $this->disableScriptsByDefault; + } if (null === $this->composer) { try { - $this->composer = Factory::create($this->io, null, $disablePlugins); + $this->composer = Factory::create($this->io, null, $disablePlugins, $disableScripts); } catch (\InvalidArgumentException $e) { if ($required) { $this->io->writeError($e->getMessage()); @@ -552,6 +559,7 @@ class Application extends BaseApplication $definition = parent::getDefaultInputDefinition(); $definition->addOption(new InputOption('--profile', null, InputOption::VALUE_NONE, 'Display timing and memory usage information')); $definition->addOption(new InputOption('--no-plugins', null, InputOption::VALUE_NONE, 'Whether to disable plugins.')); + $definition->addOption(new InputOption('--no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.')); $definition->addOption(new InputOption('--working-dir', '-d', InputOption::VALUE_REQUIRED, 'If specified, use the given directory as working directory.')); $definition->addOption(new InputOption('--no-cache', null, InputOption::VALUE_NONE, 'Prevent use of the cache')); diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index bc9f7ef29..ee0b07f3e 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -294,13 +294,14 @@ class Factory * @param array|string|null $localConfig either a configuration array or a filename to read from, if null it will * read from the default filename * @param bool $disablePlugins Whether plugins should not be loaded + * @param bool $disableScripts Whether scripts should not be run * @param string|null $cwd * @param bool $fullLoad Whether to initialize everything or only main project stuff (used when loading the global composer) * @throws \InvalidArgumentException * @throws \UnexpectedValueException * @return Composer */ - public function createComposer(IOInterface $io, $localConfig = null, $disablePlugins = false, $cwd = null, $fullLoad = true) + public function createComposer(IOInterface $io, $localConfig = null, $disablePlugins = false, $cwd = null, $fullLoad = true, $disableScripts = false) { $cwd = $cwd ?: (string) getcwd(); @@ -382,6 +383,7 @@ class Factory // initialize event dispatcher $dispatcher = new EventDispatcher($composer, $io, $process); + $dispatcher->setRunScripts(!$disableScripts); $composer->setEventDispatcher($dispatcher); // initialize repository manager @@ -428,7 +430,7 @@ class Factory if ($fullLoad) { $globalComposer = null; if (realpath($config->get('home')) !== $cwd) { - $globalComposer = $this->createGlobalComposer($io, $config, $disablePlugins); + $globalComposer = $this->createGlobalComposer($io, $config, $disablePlugins, $disableScripts); } $pm = $this->createPluginManager($io, $composer, $globalComposer, $disablePlugins); @@ -460,13 +462,14 @@ class Factory /** * @param IOInterface $io IO instance * @param bool $disablePlugins Whether plugins should not be loaded + * @param bool $disableScripts Whether scripts should not be executed * @return Composer|null */ - public static function createGlobal(IOInterface $io, $disablePlugins = false) + public static function createGlobal(IOInterface $io, $disablePlugins = false, $disableScripts = false) { $factory = new static(); - return $factory->createGlobalComposer($io, static::createConfig($io), $disablePlugins, true); + return $factory->createGlobalComposer($io, static::createConfig($io), $disablePlugins, $disableScripts, true); } /** @@ -487,15 +490,16 @@ class Factory /** * @param bool $disablePlugins + * @param bool $disableScripts * @param bool $fullLoad * * @return Composer|null */ - protected function createGlobalComposer(IOInterface $io, Config $config, $disablePlugins, $fullLoad = false) + protected function createGlobalComposer(IOInterface $io, Config $config, $disablePlugins, $disableScripts, $fullLoad = false) { $composer = null; try { - $composer = $this->createComposer($io, $config->get('home') . '/composer.json', $disablePlugins, $config->get('home'), $fullLoad); + $composer = $this->createComposer($io, $config->get('home') . '/composer.json', $disablePlugins, $config->get('home'), $fullLoad, $disableScripts); } catch (\Exception $e) { $io->writeError('Failed to initialize global composer: '.$e->getMessage(), true, IOInterface::DEBUG); } @@ -629,13 +633,14 @@ class Factory * @param mixed $config either a configuration array or a filename to read from, if null it will read from * the default filename * @param bool $disablePlugins Whether plugins should not be loaded + * @param bool $disableScripts Whether scripts should not be run * @return Composer */ - public static function create(IOInterface $io, $config = null, $disablePlugins = false) + public static function create(IOInterface $io, $config = null, $disablePlugins = false, $disableScripts = false) { $factory = new static(); - return $factory->createComposer($io, $config, $disablePlugins); + return $factory->createComposer($io, $config, $disablePlugins, null, true, $disableScripts); } /** diff --git a/tests/Composer/Test/ApplicationTest.php b/tests/Composer/Test/ApplicationTest.php index e55d31d99..d24024e73 100644 --- a/tests/Composer/Test/ApplicationTest.php +++ b/tests/Composer/Test/ApplicationTest.php @@ -40,6 +40,11 @@ class ApplicationTest extends TestCase ->with($this->equalTo('--no-plugins')) ->will($this->returnValue(true)); + $inputMock->expects($this->at($index++)) + ->method('hasParameterOption') + ->with($this->equalTo('--no-scripts')) + ->will($this->returnValue(false)); + $inputMock->expects($this->at($index++)) ->method('setInteractive') ->with($this->equalTo(false)); @@ -108,6 +113,11 @@ class ApplicationTest extends TestCase ->with($this->equalTo('--no-plugins')) ->will($this->returnValue(true)); + $inputMock->expects($this->at($index++)) + ->method('hasParameterOption') + ->with($this->equalTo('--no-scripts')) + ->will($this->returnValue(false)); + $inputMock->expects($this->at($index++)) ->method('setInteractive') ->with($this->equalTo(false));