ソースを参照

Finalize and bring up to speed the remove command, refs #2479

Jordi Boggiano 11 年 前
コミット
e3f32a79f3
2 ファイル変更46 行追加31 行削除
  1. 10 7
      doc/03-cli.md
  2. 36 24
      src/Composer/Command/RemoveCommand.php

+ 10 - 7
doc/03-cli.md

@@ -163,6 +163,7 @@ php composer.phar require vendor/package:2.* vendor/package2:dev-master
 * **--no-update:** Disables the automatic update of the dependencies.
 * **--no-progress:** Removes the progress display that can mess with some
   terminals or scripts which don't handle backspace characters.
+* **--update-no-dev** Run the dependency update with the --no-dev option.
 * **--update-with-dependencies** Also update dependencies of the newly
   required packages.
 
@@ -171,18 +172,20 @@ php composer.phar require vendor/package:2.* vendor/package2:dev-master
 The `remove` command removes packages from the `composer.json` file from
 the current directory.
 
-    $ php composer.phar remove <vendor/package>
+```sh
+php composer.phar remove vendor/package vendor/package2
+```
 
 After removing the requirements, the modified requirements will be
 uninstalled.
 
 ### Options
-* **--dry-run:** If you want to run through an uninstallation without actually
-  uninstalling a package, you can use `--dry-run`. This will simulate the
-  uninstallation and show you what would happen.
-* **--dev:** Add packages to `require-dev`.
-* **--no-update:** Only remove the package from the composer.json file, but
-  won't remove the files or update the composer.lock
+* **--dev:** Remove packages from `require-dev`.
+* **--no-update:** Disables the automatic update of the dependencies.
+* **--no-progress:** Removes the progress display that can mess with some
+  terminals or scripts which don't handle backspace characters.
+* **--update-no-dev** Run the dependency update with the --no-dev option.
+* **--update-with-dependencies** Also update dependencies of the removed packages.
 
 ## global
 

+ 36 - 24
src/Composer/Command/RemoveCommand.php

@@ -25,6 +25,7 @@ use Symfony\Component\Console\Output\OutputInterface;
 
 /**
  * @author Pierre du Plessis <pdples@gmail.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
  */
 class RemoveCommand extends Command
 {
@@ -34,11 +35,12 @@ class RemoveCommand extends Command
             ->setName('remove')
             ->setDescription('Removes a package from the require or require-dev')
             ->setDefinition(array(
-                new InputArgument('packages', InputArgument::IS_ARRAY, 'Packages that should be removed, if not provided all packages are.'),
-                new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
-                new InputOption('dev', null, InputOption::VALUE_NONE, 'Removes a package from the require-dev section'),
-                new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'),
-                new InputOption('no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies.')
+                new InputArgument('packages', InputArgument::IS_ARRAY, 'Packages that should be removed.'),
+                new InputOption('dev', null, InputOption::VALUE_NONE, 'Removes a package from the require-dev section.'),
+                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('update-no-dev', null, InputOption::VALUE_NONE, 'Run the dependency update with the --no-dev option.'),
+                new InputOption('update-with-dependencies', null, InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated with explicit dependencies.'),
             ))
             ->setHelp(<<<EOT
 The <info>remove</info> command removes a package from the current
@@ -53,54 +55,64 @@ EOT
 
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        $composer = $this->getComposer();
         $packages = $input->getArgument('packages');
 
-        $io = $this->getIO();
-
-        $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'remove', $input, $output);
-        $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
-
         $file = Factory::getComposerFile();
 
         $json = new JsonFile($file);
+        $composer = $json->read();
         $composerBackup = file_get_contents($json->getPath());
 
         $json = new JsonConfigSource($json);
 
         $type = $input->getOption('dev') ? 'require-dev' : 'require';
+        $altType = !$input->getOption('dev') ? 'require-dev' : 'require';
 
         foreach ($packages as $package) {
-            $json->removeLink($type, $package);
+            if (isset($composer[$type][$package])) {
+                $json->removeLink($type, $package);
+            } elseif (isset($composer[$altType][$package])) {
+                $output->writeln('<warning>'.$package.' could not be found in '.$type.' but it is present in '.$altType.'</warning>');
+                $dialog = $this->getHelperSet()->get('dialog');
+                if ($this->getIO()->isInteractive()) {
+                    if ($dialog->askConfirmation($output, $dialog->getQuestion('Do you want to remove it from '.$altType, 'yes', '?'), true)) {
+                        $json->removeLink($altType, $package);
+                    }
+                }
+            } else {
+                $output->writeln('<warning>'.$package.' is not required in your composer.json and has not been removed</warning>');
+            }
         }
 
         if ($input->getOption('no-update')) {
-            if ($input->getOption('dry-run')) {
-                file_put_contents($json->getPath(), $composerBackup);
-            }
-
             return 0;
         }
 
-        $composer = Factory::create($io);
+        // Update packages
+        $composer = $this->getComposer();
+        $composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
+        $io = $this->getIO();
+
+        $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'remove', $input, $output);
+        $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
 
         $install = Installer::create($io, $composer);
 
+        $updateDevMode = !$input->getOption('update-no-dev');
         $install
-            ->setDryRun($input->getOption('dry-run'))
             ->setVerbose($input->getOption('verbose'))
-            ->setDevMode($input->getOption('dev'))
+            ->setDevMode($updateDevMode)
             ->setUpdate(true)
             ->setUpdateWhitelist($packages)
+            ->setWhitelistDependencies($input->getOption('update-with-dependencies'));
         ;
 
-        if (!$install->run()) {
-            $output->writeln("\n".'<error>Remove failed, reverting '.$file.' to its original content.</error>');
+        $status = $install->run();
+        if ($status !== 0) {
+            $output->writeln("\n".'<error>Removal failed, reverting '.$file.' to its original content.</error>');
             file_put_contents($json->getPath(), $composerBackup);
-
-            return 1;
         }
 
-        return 0;
+        return $status;
     }
 }