PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/forum/vendor/symfony/console/Symfony/Component/Console/Shell.php

https://github.com/AJenbo/ubuntudanmark.dk
PHP | 229 lines | 193 code | 8 blank | 28 comment | 2 complexity | c6d74512367ee55d845f2b195f58f3d2 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Console;
  11. use Symfony\Component\Console\Input\StringInput;
  12. use Symfony\Component\Console\Output\ConsoleOutput;
  13. use Symfony\Component\Process\ProcessBuilder;
  14. use Symfony\Component\Process\PhpExecutableFinder;
  15. /**
  16. * A Shell wraps an Application to add shell capabilities to it.
  17. *
  18. * Support for history and completion only works with a PHP compiled
  19. * with readline support (either --with-readline or --with-libedit)
  20. *
  21. * @author Fabien Potencier <fabien@symfony.com>
  22. * @author Martin HasoĊˆ <martin.hason@gmail.com>
  23. */
  24. class Shell
  25. {
  26. private $application;
  27. private $history;
  28. private $output;
  29. private $hasReadline;
  30. private $processIsolation;
  31. /**
  32. * Constructor.
  33. *
  34. * If there is no readline support for the current PHP executable
  35. * a \RuntimeException exception is thrown.
  36. *
  37. * @param Application $application An application instance
  38. */
  39. public function __construct(Application $application)
  40. {
  41. $this->hasReadline = function_exists('readline');
  42. $this->application = $application;
  43. $this->history = getenv('HOME').'/.history_'.$application->getName();
  44. $this->output = new ConsoleOutput();
  45. $this->processIsolation = false;
  46. }
  47. /**
  48. * Runs the shell.
  49. */
  50. public function run()
  51. {
  52. $this->application->setAutoExit(false);
  53. $this->application->setCatchExceptions(true);
  54. if ($this->hasReadline) {
  55. readline_read_history($this->history);
  56. readline_completion_function(array($this, 'autocompleter'));
  57. }
  58. $this->output->writeln($this->getHeader());
  59. $php = null;
  60. if ($this->processIsolation) {
  61. $finder = new PhpExecutableFinder();
  62. $php = $finder->find();
  63. $this->output->writeln(<<<'EOF'
  64. <info>Running with process isolation, you should consider this:</info>
  65. * each command is executed as separate process,
  66. * commands don't support interactivity, all params must be passed explicitly,
  67. * commands output is not colorized.
  68. EOF
  69. );
  70. }
  71. while (true) {
  72. $command = $this->readline();
  73. if (false === $command) {
  74. $this->output->writeln("\n");
  75. break;
  76. }
  77. if ($this->hasReadline) {
  78. readline_add_history($command);
  79. readline_write_history($this->history);
  80. }
  81. if ($this->processIsolation) {
  82. $pb = new ProcessBuilder();
  83. $process = $pb
  84. ->add($php)
  85. ->add($_SERVER['argv'][0])
  86. ->add($command)
  87. ->inheritEnvironmentVariables(true)
  88. ->getProcess()
  89. ;
  90. $output = $this->output;
  91. $process->run(function ($type, $data) use ($output) {
  92. $output->writeln($data);
  93. });
  94. $ret = $process->getExitCode();
  95. } else {
  96. $ret = $this->application->run(new StringInput($command), $this->output);
  97. }
  98. if (0 !== $ret) {
  99. $this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
  100. }
  101. }
  102. }
  103. /**
  104. * Returns the shell header.
  105. *
  106. * @return string The header string
  107. */
  108. protected function getHeader()
  109. {
  110. return <<<EOF
  111. Welcome to the <info>{$this->application->getName()}</info> shell (<comment>{$this->application->getVersion()}</comment>).
  112. At the prompt, type <comment>help</comment> for some help,
  113. or <comment>list</comment> to get a list of available commands.
  114. To exit the shell, type <comment>^D</comment>.
  115. EOF;
  116. }
  117. /**
  118. * Renders a prompt.
  119. *
  120. * @return string The prompt
  121. */
  122. protected function getPrompt()
  123. {
  124. // using the formatter here is required when using readline
  125. return $this->output->getFormatter()->format($this->application->getName().' > ');
  126. }
  127. protected function getOutput()
  128. {
  129. return $this->output;
  130. }
  131. protected function getApplication()
  132. {
  133. return $this->application;
  134. }
  135. /**
  136. * Tries to return autocompletion for the current entered text.
  137. *
  138. * @param string $text The last segment of the entered text
  139. *
  140. * @return bool|array A list of guessed strings or true
  141. */
  142. private function autocompleter($text)
  143. {
  144. $info = readline_info();
  145. $text = substr($info['line_buffer'], 0, $info['end']);
  146. if ($info['point'] !== $info['end']) {
  147. return true;
  148. }
  149. // task name?
  150. if (false === strpos($text, ' ') || !$text) {
  151. return array_keys($this->application->all());
  152. }
  153. // options and arguments?
  154. try {
  155. $command = $this->application->find(substr($text, 0, strpos($text, ' ')));
  156. } catch (\Exception $e) {
  157. return true;
  158. }
  159. $list = array('--help');
  160. foreach ($command->getDefinition()->getOptions() as $option) {
  161. $list[] = '--'.$option->getName();
  162. }
  163. return $list;
  164. }
  165. /**
  166. * Reads a single line from standard input.
  167. *
  168. * @return string The single line from standard input
  169. */
  170. private function readline()
  171. {
  172. if ($this->hasReadline) {
  173. $line = readline($this->getPrompt());
  174. } else {
  175. $this->output->write($this->getPrompt());
  176. $line = fgets(STDIN, 1024);
  177. $line = (false === $line || '' === $line) ? false : rtrim($line);
  178. }
  179. return $line;
  180. }
  181. public function getProcessIsolation()
  182. {
  183. return $this->processIsolation;
  184. }
  185. public function setProcessIsolation($processIsolation)
  186. {
  187. $this->processIsolation = (bool) $processIsolation;
  188. if ($this->processIsolation && !class_exists('Symfony\\Component\\Process\\Process')) {
  189. throw new \RuntimeException('Unable to isolate processes as the Symfony Process Component is not installed.');
  190. }
  191. }
  192. }