StatusCommand.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\Command;
  12. use Symfony\Component\Console\Input\InputInterface;
  13. use Symfony\Component\Console\Input\InputOption;
  14. use Symfony\Component\Console\Output\OutputInterface;
  15. use Composer\Downloader\ChangeReportInterface;
  16. use Composer\Plugin\CommandEvent;
  17. use Composer\Plugin\PluginEvents;
  18. use Composer\Script\ScriptEvents;
  19. use Composer\Downloader\DvcsDownloaderInterface;
  20. /**
  21. * @author Tiago Ribeiro <tiago.ribeiro@seegno.com>
  22. * @author Rui Marinho <rui.marinho@seegno.com>
  23. */
  24. class StatusCommand extends BaseCommand
  25. {
  26. protected function configure()
  27. {
  28. $this
  29. ->setName('status')
  30. ->setDescription('Show a list of locally modified packages')
  31. ->setDefinition(array(
  32. new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Show modified files for each directory that contains changes.'),
  33. ))
  34. ->setHelp(<<<EOT
  35. The status command displays a list of dependencies that have
  36. been modified locally.
  37. EOT
  38. )
  39. ;
  40. }
  41. protected function execute(InputInterface $input, OutputInterface $output)
  42. {
  43. // init repos
  44. $composer = $this->getComposer();
  45. $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'status', $input, $output);
  46. $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
  47. $installedRepo = $composer->getRepositoryManager()->getLocalRepository();
  48. $dm = $composer->getDownloadManager();
  49. $im = $composer->getInstallationManager();
  50. // Dispatch pre-status-command
  51. $composer->getEventDispatcher()->dispatchScript(ScriptEvents::PRE_STATUS_CMD, true);
  52. $errors = array();
  53. $io = $this->getIO();
  54. $unpushedChanges = array();
  55. // list packages
  56. foreach ($installedRepo->getCanonicalPackages() as $package) {
  57. $downloader = $dm->getDownloaderForInstalledPackage($package);
  58. if ($downloader instanceof ChangeReportInterface) {
  59. $targetDir = $im->getInstallPath($package);
  60. if (is_link($targetDir)) {
  61. $errors[$targetDir] = $targetDir . ' is a symbolic link.';
  62. }
  63. if ($changes = $downloader->getLocalChanges($package, $targetDir, true)) {
  64. $errors[$targetDir] = $changes;
  65. }
  66. if ($downloader instanceof DvcsDownloaderInterface) {
  67. if ($unpushed = $downloader->getUnpushedChanges($package, $targetDir)) {
  68. $unpushedChanges[$targetDir] = $unpushed;
  69. }
  70. }
  71. }
  72. }
  73. // output errors/warnings
  74. if (!$errors && !$unpushedChanges) {
  75. $io->writeError('<info>No local changes</info>');
  76. } elseif ($errors) {
  77. $io->writeError('<error>You have changes in the following dependencies:</error>');
  78. }
  79. foreach ($errors as $path => $changes) {
  80. if ($input->getOption('verbose')) {
  81. $indentedChanges = implode("\n", array_map(function ($line) {
  82. return ' ' . ltrim($line);
  83. }, explode("\n", $changes)));
  84. $io->write('<info>'.$path.'</info>:');
  85. $io->write($indentedChanges);
  86. } else {
  87. $io->write($path);
  88. }
  89. }
  90. if ($unpushedChanges) {
  91. $io->writeError('<warning>You have unpushed changes on the current branch in the following dependencies:</warning>');
  92. foreach ($unpushedChanges as $path => $changes) {
  93. if ($input->getOption('verbose')) {
  94. $indentedChanges = implode("\n", array_map(function ($line) {
  95. return ' ' . ltrim($line);
  96. }, explode("\n", $changes)));
  97. $io->write('<info>'.$path.'</info>:');
  98. $io->write($indentedChanges);
  99. } else {
  100. $io->write($path);
  101. }
  102. }
  103. }
  104. if (($errors || $unpushedChanges) && !$input->getOption('verbose')) {
  105. $io->writeError('Use --verbose (-v) to see a list of files');
  106. }
  107. // Dispatch post-status-command
  108. $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_STATUS_CMD, true);
  109. return ($errors ? 1 : 0) + ($unpushedChanges ? 2 : 0);
  110. }
  111. }