CheckPlatformReqsCommand.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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 Composer\Package\Link;
  13. use Composer\Package\PackageInterface;
  14. use Composer\Semver\Constraint\Constraint;
  15. use Symfony\Component\Console\Helper\Table;
  16. use Symfony\Component\Console\Input\InputInterface;
  17. use Symfony\Component\Console\Input\InputOption;
  18. use Symfony\Component\Console\Output\OutputInterface;
  19. use Composer\Repository\PlatformRepository;
  20. use Composer\Repository\InstalledRepository;
  21. class CheckPlatformReqsCommand extends BaseCommand
  22. {
  23. protected function configure()
  24. {
  25. $this->setName('check-platform-reqs')
  26. ->setDescription('Check that platform requirements are satisfied.')
  27. ->setDefinition(array(
  28. new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables checking of require-dev packages requirements.'),
  29. ))
  30. ->setHelp(
  31. <<<EOT
  32. Checks that your PHP and extensions versions match the platform requirements of the installed packages.
  33. Unlike update/install, this command will ignore config.platform settings and check the real platform packages so you can be certain you have the required platform dependencies.
  34. <info>php composer.phar check-platform-reqs</info>
  35. EOT
  36. );
  37. }
  38. protected function execute(InputInterface $input, OutputInterface $output)
  39. {
  40. $composer = $this->getComposer();
  41. $requires = $composer->getPackage()->getRequires();
  42. if ($input->getOption('no-dev')) {
  43. $installedRepo = $composer->getLocker()->getLockedRepository(!$input->getOption('no-dev'));
  44. $dependencies = $installedRepo->getPackages();
  45. } else {
  46. $installedRepo = $composer->getRepositoryManager()->getLocalRepository();
  47. // fallback to lockfile if installed repo is empty
  48. if (!$installedRepo->getPackages()) {
  49. $installedRepo = $composer->getLocker()->getLockedRepository(true);
  50. }
  51. $requires += $composer->getPackage()->getDevRequires();
  52. }
  53. foreach ($requires as $require => $link) {
  54. $requires[$require] = array($link);
  55. }
  56. $installedRepo = new InstalledRepository(array($installedRepo));
  57. foreach ($installedRepo->getPackages() as $package) {
  58. foreach ($package->getRequires() as $require => $link) {
  59. $requires[$require][] = $link;
  60. }
  61. }
  62. ksort($requires);
  63. $installedRepo->addRepository(new PlatformRepository(array(), array()));
  64. $results = array();
  65. $exitCode = 0;
  66. /**
  67. * @var Link[] $links
  68. */
  69. foreach ($requires as $require => $links) {
  70. if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $require)) {
  71. $candidates = $installedRepo->findPackagesWithReplacersAndProviders($require);
  72. if ($candidates) {
  73. $reqResults = array();
  74. foreach ($candidates as $candidate) {
  75. $candidateConstraint = null;
  76. if ($candidate->getName() === $require) {
  77. $candidateConstraint = new Constraint('=', $candidate->getVersion());
  78. $candidateConstraint->setPrettyString($candidate->getPrettyVersion());
  79. } else {
  80. foreach (array_merge($candidate->getProvides(), $candidate->getReplaces()) as $link) {
  81. if ($link->getTarget() === $require) {
  82. $candidateConstraint = $link->getConstraint();
  83. break;
  84. }
  85. }
  86. }
  87. // safety check for phpstan, but it should not be possible to get a candidate out of findPackagesWithReplacersAndProviders without a constraint matching $require
  88. if (!$candidateConstraint) {
  89. continue;
  90. }
  91. foreach ($links as $link) {
  92. if (!$link->getConstraint()->matches($candidateConstraint)) {
  93. $reqResults[] = array(
  94. $candidate->getName() === $require ? $candidate->getPrettyName() : $require,
  95. $candidateConstraint->getPrettyString(),
  96. $link,
  97. '<error>failed</error>'.($candidate->getName() === $require ? '' : ' <comment>provided by '.$candidate->getPrettyName().'</comment>'),
  98. );
  99. // skip to next candidate
  100. continue 2;
  101. }
  102. }
  103. $results[] = array(
  104. $candidate->getName() === $require ? $candidate->getPrettyName() : $require,
  105. $candidateConstraint->getPrettyString(),
  106. null,
  107. '<info>success</info>'.($candidate->getName() === $require ? '' : ' <comment>provided by '.$candidate->getPrettyName().'</comment>'),
  108. );
  109. // candidate matched, skip to next requirement
  110. continue 2;
  111. }
  112. // show the first error from every failed candidate
  113. $results = array_merge($results, $reqResults);
  114. $exitCode = max($exitCode, 1);
  115. continue;
  116. }
  117. $results[] = array(
  118. $require,
  119. 'n/a',
  120. $links[0],
  121. '<error>missing</error>',
  122. );
  123. $exitCode = max($exitCode, 2);
  124. }
  125. }
  126. $this->printTable($output, $results);
  127. return $exitCode;
  128. }
  129. protected function printTable(OutputInterface $output, $results)
  130. {
  131. $table = array();
  132. $rows = array();
  133. foreach ($results as $result) {
  134. /**
  135. * @var Link|null $link
  136. */
  137. list($platformPackage, $version, $link, $status) = $result;
  138. $rows[] = array(
  139. $platformPackage,
  140. $version,
  141. $link ? sprintf('%s %s %s (%s)', $link->getSource(), $link->getDescription(), $link->getTarget(), $link->getPrettyConstraint()) : '',
  142. $status,
  143. );
  144. }
  145. $table = array_merge($rows, $table);
  146. // Render table
  147. $renderer = new Table($output);
  148. $renderer->setStyle('compact');
  149. $rendererStyle = $renderer->getStyle();
  150. $rendererStyle->setVerticalBorderChar('');
  151. $rendererStyle->setCellRowContentFormat('%s ');
  152. $renderer->setRows($table)->render();
  153. }
  154. }