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