StatusCommand.php 4.6 KB

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