ConsoleIO.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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\IO;
  12. use Symfony\Component\Console\Input\InputInterface;
  13. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  14. use Symfony\Component\Console\Output\OutputInterface;
  15. use Symfony\Component\Console\Helper\HelperSet;
  16. use Symfony\Component\Console\Question\ConfirmationQuestion;
  17. use Symfony\Component\Console\Question\Question;
  18. use Symfony\Component\Process\ExecutableFinder;
  19. /**
  20. * The Input/Output helper.
  21. *
  22. * @author François Pluchino <francois.pluchino@opendisplay.com>
  23. * @author Jordi Boggiano <j.boggiano@seld.be>
  24. */
  25. class ConsoleIO extends BaseIO
  26. {
  27. protected $input;
  28. protected $output;
  29. protected $helperSet;
  30. protected $lastMessage;
  31. protected $lastMessageErr;
  32. private $startTime;
  33. /**
  34. * Constructor.
  35. *
  36. * @param InputInterface $input The input instance
  37. * @param OutputInterface $output The output instance
  38. * @param HelperSet $helperSet The helperSet instance
  39. */
  40. public function __construct(InputInterface $input, OutputInterface $output, HelperSet $helperSet)
  41. {
  42. $this->input = $input;
  43. $this->output = $output;
  44. $this->helperSet = $helperSet;
  45. }
  46. public function enableDebugging($startTime)
  47. {
  48. $this->startTime = $startTime;
  49. }
  50. /**
  51. * {@inheritDoc}
  52. */
  53. public function isInteractive()
  54. {
  55. return $this->input->isInteractive();
  56. }
  57. /**
  58. * {@inheritDoc}
  59. */
  60. public function isDecorated()
  61. {
  62. return $this->output->isDecorated();
  63. }
  64. /**
  65. * {@inheritDoc}
  66. */
  67. public function isVerbose()
  68. {
  69. return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE;
  70. }
  71. /**
  72. * {@inheritDoc}
  73. */
  74. public function isVeryVerbose()
  75. {
  76. return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE;
  77. }
  78. /**
  79. * {@inheritDoc}
  80. */
  81. public function isDebug()
  82. {
  83. return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG;
  84. }
  85. /**
  86. * {@inheritDoc}
  87. */
  88. public function write($messages, $newline = true)
  89. {
  90. $this->doWrite($messages, $newline, false);
  91. }
  92. /**
  93. * {@inheritDoc}
  94. */
  95. public function writeError($messages, $newline = true)
  96. {
  97. $this->doWrite($messages, $newline, true);
  98. }
  99. /**
  100. * @param array $messages
  101. * @param boolean $newline
  102. * @param boolean $stderr
  103. */
  104. private function doWrite($messages, $newline, $stderr)
  105. {
  106. if (null !== $this->startTime) {
  107. $memoryUsage = memory_get_usage() / 1024 / 1024;
  108. $timeSpent = microtime(true) - $this->startTime;
  109. $messages = array_map(function ($message) use ($memoryUsage, $timeSpent) {
  110. return sprintf('[%.1fMB/%.2fs] %s', $memoryUsage, $timeSpent, $message);
  111. }, (array) $messages);
  112. }
  113. if (true === $stderr && $this->output instanceof ConsoleOutputInterface) {
  114. $this->output->getErrorOutput()->write($messages, $newline);
  115. $this->lastMessageErr = join($newline ? "\n" : '', (array) $messages);
  116. return;
  117. }
  118. $this->output->write($messages, $newline);
  119. $this->lastMessage = join($newline ? "\n" : '', (array) $messages);
  120. }
  121. /**
  122. * {@inheritDoc}
  123. */
  124. public function overwrite($messages, $newline = true, $size = null)
  125. {
  126. $this->doOverwrite($messages, $newline, $size, false);
  127. }
  128. /**
  129. * {@inheritDoc}
  130. */
  131. public function overwriteError($messages, $newline = true, $size = null)
  132. {
  133. $this->doOverwrite($messages, $newline, $size, true);
  134. }
  135. /**
  136. * @param array $messages
  137. * @param boolean $newline
  138. * @param integer $size
  139. * @param boolean $stderr
  140. */
  141. private function doOverwrite($messages, $newline, $size, $stderr)
  142. {
  143. // messages can be an array, let's convert it to string anyway
  144. $messages = join($newline ? "\n" : '', (array) $messages);
  145. // since overwrite is supposed to overwrite last message...
  146. if (!isset($size)) {
  147. // removing possible formatting of lastMessage with strip_tags
  148. $size = strlen(strip_tags($stderr ? $this->lastMessageErr : $this->lastMessage));
  149. }
  150. // ...let's fill its length with backspaces
  151. $this->doWrite(str_repeat("\x08", $size), false, $stderr);
  152. // write the new message
  153. $this->doWrite($messages, false, $stderr);
  154. $fill = $size - strlen(strip_tags($messages));
  155. if ($fill > 0) {
  156. // whitespace whatever has left
  157. $this->doWrite(str_repeat(' ', $fill), false, $stderr);
  158. // move the cursor back
  159. $this->doWrite(str_repeat("\x08", $fill), false, $stderr);
  160. }
  161. if ($newline) {
  162. $this->doWrite('', true, $stderr);
  163. }
  164. if ($stderr) {
  165. $this->lastMessageErr = $messages;
  166. } else {
  167. $this->lastMessage = $messages;
  168. }
  169. }
  170. /**
  171. * {@inheritDoc}
  172. */
  173. public function ask($question, $default = null)
  174. {
  175. $output = $this->output;
  176. if ($output instanceof ConsoleOutputInterface) {
  177. $output = $output->getErrorOutput();
  178. }
  179. /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
  180. $helper = $this->helperSet->get('question');
  181. $question = new Question($question, $default);
  182. return $helper->ask($this->input, $output, $question);
  183. }
  184. /**
  185. * {@inheritDoc}
  186. */
  187. public function askConfirmation($question, $default = true)
  188. {
  189. $output = $this->output;
  190. if ($output instanceof ConsoleOutputInterface) {
  191. $output = $output->getErrorOutput();
  192. }
  193. /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
  194. $helper = $this->helperSet->get('question');
  195. $question = new ConfirmationQuestion($question, $default);
  196. return $helper->ask($this->input, $output, $question);
  197. }
  198. /**
  199. * {@inheritDoc}
  200. */
  201. public function askAndValidate($question, $validator, $attempts = null, $default = null)
  202. {
  203. $output = $this->output;
  204. if ($output instanceof ConsoleOutputInterface) {
  205. $output = $output->getErrorOutput();
  206. }
  207. /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
  208. $helper = $this->helperSet->get('question');
  209. $question = new Question($question, $default);
  210. $question->setValidator($validator);
  211. $question->setMaxAttempts($attempts);
  212. return $helper->ask($this->input, $output, $question);
  213. }
  214. /**
  215. * {@inheritDoc}
  216. */
  217. public function askAndHideAnswer($question)
  218. {
  219. $this->writeError($question, false);
  220. return \Seld\CliPrompt\CliPrompt::hiddenPrompt(true);
  221. }
  222. }