1
0
Fork 0

Add --dry-run to require and remove commands, fixes #7793

pull/8566/head
Jordi Boggiano 2020-01-31 14:34:10 +01:00
parent fdfdee03c1
commit d14d411fa4
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
3 changed files with 64 additions and 7 deletions

View File

@ -198,6 +198,7 @@ If you do not specify a package, composer will prompt you to search for a packag
### Options
* **--dev:** Add packages to `require-dev`.
* **--dry-run:** Simulate the command without actually doing anything.
* **--prefer-source:** Install packages from `source` when available.
* **--prefer-dist:** Install packages from `dist` when available.
* **--no-progress:** Removes the progress display that can mess with some
@ -236,6 +237,7 @@ uninstalled.
### Options
* **--dev:** Remove packages from `require-dev`.
* **--dry-run:** Simulate the command without actually doing anything.
* **--no-progress:** Removes the progress display that can mess with some
terminals or scripts which don't handle backspace characters.
* **--no-update:** Disables the automatic update of the dependencies.

View File

@ -38,6 +38,7 @@ class RemoveCommand extends BaseCommand
->setDefinition(array(
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'Packages that should be removed.'),
new InputOption('dev', null, InputOption::VALUE_NONE, 'Removes a package from the require-dev section.'),
new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
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.'),
new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'),
@ -92,26 +93,44 @@ EOT
}
}
$dryRun = $input->getOption('dry-run');
$toRemove = array();
foreach ($packages as $package) {
if (isset($composer[$type][$package])) {
$json->removeLink($type, $composer[$type][$package]);
if ($dryRun) {
$toRemove[$type][] = $composer[$type][$package];
} else {
$json->removeLink($type, $composer[$type][$package]);
}
} elseif (isset($composer[$altType][$package])) {
$io->writeError('<warning>' . $composer[$altType][$package] . ' could not be found in ' . $type . ' but it is present in ' . $altType . '</warning>');
if ($io->isInteractive()) {
if ($io->askConfirmation('Do you want to remove it from ' . $altType . ' [<comment>yes</comment>]? ', true)) {
$json->removeLink($altType, $composer[$altType][$package]);
if ($dryRun) {
$toRemove[$altType][] = $composer[$altType][$package];
} else {
$json->removeLink($altType, $composer[$altType][$package]);
}
}
}
} elseif (isset($composer[$type]) && $matches = preg_grep(BasePackage::packageNameToRegexp($package), array_keys($composer[$type]))) {
foreach ($matches as $matchedPackage) {
$json->removeLink($type, $matchedPackage);
if ($dryRun) {
$toRemove[$type][] = $matchedPackage;
} else {
$json->removeLink($type, $matchedPackage);
}
}
} elseif (isset($composer[$altType]) && $matches = preg_grep(BasePackage::packageNameToRegexp($package), array_keys($composer[$altType]))) {
foreach ($matches as $matchedPackage) {
$io->writeError('<warning>' . $matchedPackage . ' could not be found in ' . $type . ' but it is present in ' . $altType . '</warning>');
if ($io->isInteractive()) {
if ($io->askConfirmation('Do you want to remove it from ' . $altType . ' [<comment>yes</comment>]? ', true)) {
$json->removeLink($altType, $matchedPackage);
if ($dryRun) {
$toRemove[$altType][] = $matchedPackage;
} else {
$json->removeLink($altType, $matchedPackage);
}
}
}
}
@ -128,6 +147,21 @@ EOT
$this->resetComposer();
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
if ($dryRun) {
$rootPackage = $composer->getPackage();
$links = array(
'require' => $rootPackage->getRequires(),
'require-dev' => $rootPackage->getDevRequires(),
);
foreach ($toRemove as $type => $packages) {
foreach ($packages as $package) {
unset($links[$type][$package]);
}
}
$rootPackage->setRequires($links['require']);
$rootPackage->setDevRequires($links['require-dev']);
}
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'remove', $input, $output);
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
@ -149,6 +183,7 @@ EOT
->setWhitelistTransitiveDependencies(!$input->getOption('no-update-with-dependencies'))
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
->setRunScripts(!$input->getOption('no-scripts'))
->setDryRun($dryRun)
;
$status = $install->run();

View File

@ -21,6 +21,8 @@ use Composer\Installer;
use Composer\Json\JsonFile;
use Composer\Json\JsonManipulator;
use Composer\Package\Version\VersionParser;
use Composer\Package\Loader\ArrayLoader;
use Composer\Package\BasePackage;
use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Composer\Repository\CompositeRepository;
@ -48,6 +50,7 @@ class RequireCommand extends InitCommand
->setDefinition(array(
new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Optional package name can also include a version constraint, e.g. foo/bar or foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"'),
new InputOption('dev', null, InputOption::VALUE_NONE, 'Add requirement to require-dev.'),
new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'),
new InputOption('fixed', null, InputOption::VALUE_NONE, 'Write fixed version to the composer.json.'),
@ -195,7 +198,7 @@ EOT
}
}
if (!$this->updateFileCleanly($this->json, $requirements, $requireKey, $removeKey, $sortPackages)) {
if (!$input->getOption('dry-run') && !$this->updateFileCleanly($this->json, $requirements, $requireKey, $removeKey, $sortPackages)) {
$composerDefinition = $this->json->read();
foreach ($requirements as $package => $version) {
$composerDefinition[$requireKey][$package] = $version;
@ -211,19 +214,35 @@ EOT
}
try {
return $this->doUpdate($input, $output, $io, $requirements);
return $this->doUpdate($input, $output, $io, $requirements, $requireKey, $removeKey);
} catch (\Exception $e) {
$this->revertComposerFile(false);
throw $e;
}
}
private function doUpdate(InputInterface $input, OutputInterface $output, IOInterface $io, array $requirements)
private function doUpdate(InputInterface $input, OutputInterface $output, IOInterface $io, array $requirements, $requireKey, $removeKey)
{
// Update packages
$this->resetComposer();
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
if ($input->getOption('dry-run')) {
$rootPackage = $composer->getPackage();
$links = array(
'require' => $rootPackage->getRequires(),
'require-dev' => $rootPackage->getDevRequires(),
);
$loader = new ArrayLoader();
$newLinks = $loader->parseLinks($rootPackage->getName(), $rootPackage->getPrettyVersion(), BasePackage::$supportedLinkTypes[$requireKey]['description'], $requirements);
$links[$requireKey] = array_merge($links[$requireKey], $newLinks);
foreach ($requirements as $package => $constraint) {
unset($links[$removeKey][$package]);
}
$rootPackage->setRequires($links['require']);
$rootPackage->setDevRequires($links['require-dev']);
}
$updateDevMode = !$input->getOption('update-no-dev');
$optimize = $input->getOption('optimize-autoloader') || $composer->getConfig()->get('optimize-autoloader');
$authoritative = $input->getOption('classmap-authoritative') || $composer->getConfig()->get('classmap-authoritative');
@ -250,6 +269,7 @@ EOT
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
->setPreferStable($input->getOption('prefer-stable'))
->setPreferLowest($input->getOption('prefer-lowest'))
->setDryRun($input->getOption('dry-run'))
;
// if no lock is present, or the file is brand new, we do not do a