TYPO3  7.6
console/Shell.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11 
12 namespace Symfony\Component\Console;
13 
16 use Symfony\Component\Process\ProcessBuilder;
17 use Symfony\Component\Process\PhpExecutableFinder;
18 
28 class Shell
29 {
30  private $application;
31  private $history;
32  private $output;
33  private $hasReadline;
34  private $processIsolation = false;
35 
45  {
46  $this->hasReadline = function_exists('readline');
47  $this->application = $application;
48  $this->history = getenv('HOME').'/.history_'.$application->getName();
49  $this->output = new ConsoleOutput();
50  }
51 
55  public function run()
56  {
57  $this->application->setAutoExit(false);
58  $this->application->setCatchExceptions(true);
59 
60  if ($this->hasReadline) {
61  readline_read_history($this->history);
62  readline_completion_function(array($this, 'autocompleter'));
63  }
64 
65  $this->output->writeln($this->getHeader());
66  $php = null;
67  if ($this->processIsolation) {
68  $finder = new PhpExecutableFinder();
69  $php = $finder->find();
70  $this->output->writeln(<<<EOF
71 <info>Running with process isolation, you should consider this:</info>
72  * each command is executed as separate process,
73  * commands don't support interactivity, all params must be passed explicitly,
74  * commands output is not colorized.
75 
76 EOF
77  );
78  }
79 
80  while (true) {
81  $command = $this->readline();
82 
83  if (false === $command) {
84  $this->output->writeln("\n");
85 
86  break;
87  }
88 
89  if ($this->hasReadline) {
90  readline_add_history($command);
91  readline_write_history($this->history);
92  }
93 
94  if ($this->processIsolation) {
95  $pb = new ProcessBuilder();
96 
97  $process = $pb
98  ->add($php)
99  ->add($_SERVER['argv'][0])
100  ->add($command)
101  ->inheritEnvironmentVariables(true)
102  ->getProcess()
103  ;
104 
105  $output = $this->output;
106  $process->run(function ($type, $data) use ($output) {
107  $output->writeln($data);
108  });
109 
110  $ret = $process->getExitCode();
111  } else {
112  $ret = $this->application->run(new StringInput($command), $this->output);
113  }
114 
115  if (0 !== $ret) {
116  $this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
117  }
118  }
119  }
120 
126  protected function getHeader()
127  {
128  return <<<EOF
129 
130 Welcome to the <info>{$this->application->getName()}</info> shell (<comment>{$this->application->getVersion()}</comment>).
131 
132 At the prompt, type <comment>help</comment> for some help,
133 or <comment>list</comment> to get a list of available commands.
134 
135 To exit the shell, type <comment>^D</comment>.
136 
137 EOF;
138  }
139 
145  protected function getPrompt()
146  {
147  // using the formatter here is required when using readline
148  return $this->output->getFormatter()->format($this->application->getName().' > ');
149  }
150 
151  protected function getOutput()
152  {
153  return $this->output;
154  }
155 
156  protected function getApplication()
157  {
158  return $this->application;
159  }
160 
168  private function autocompleter($text)
169  {
170  $info = readline_info();
171  $text = substr($info['line_buffer'], 0, $info['end']);
172 
173  if ($info['point'] !== $info['end']) {
174  return true;
175  }
176 
177  // task name?
178  if (false === strpos($text, ' ') || !$text) {
179  return array_keys($this->application->all());
180  }
181 
182  // options and arguments?
183  try {
184  $command = $this->application->find(substr($text, 0, strpos($text, ' ')));
185  } catch (\Exception $e) {
186  return true;
187  }
188 
189  $list = array('--help');
190  foreach ($command->getDefinition()->getOptions() as $option) {
191  $list[] = '--'.$option->getName();
192  }
193 
194  return $list;
195  }
196 
202  private function readline()
203  {
204  if ($this->hasReadline) {
205  $line = readline($this->getPrompt());
206  } else {
207  $this->output->write($this->getPrompt());
208  $line = fgets(STDIN, 1024);
209  $line = (false === $line || '' === $line) ? false : rtrim($line);
210  }
211 
212  return $line;
213  }
214 
215  public function getProcessIsolation()
216  {
217  return $this->processIsolation;
218  }
219 
220  public function setProcessIsolation($processIsolation)
221  {
222  $this->processIsolation = (bool) $processIsolation;
223 
224  if ($this->processIsolation && !class_exists('Symfony\\Component\\Process\\Process')) {
225  throw new \RuntimeException('Unable to isolate processes as the Symfony Process Component is not installed.');
226  }
227  }
228 }