Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 229 lines (191 sloc) 6.389 kb
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
1 <?php
2
3 /*
4a83d99 blue-eyes normalized license messages in PHP files
blue-eyes authored
4 * This file is part of the Symfony package.
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
5 *
b933805 Fabien Potencier replaced symfony-project.org by symfony.com
fabpot authored
6 * (c) Fabien Potencier <fabien@symfony.com>
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
7 *
4a83d99 blue-eyes normalized license messages in PHP files
blue-eyes authored
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
10 */
11
4a83d99 blue-eyes normalized license messages in PHP files
blue-eyes authored
12 namespace Symfony\Component\Console;
13
14 use Symfony\Component\Console\Input\StringInput;
15 use Symfony\Component\Console\Output\ConsoleOutput;
75ca317 Dariusz Górecki [Console] Enable process isolantion in Shell
canni authored
16 use Symfony\Component\Process\ProcessBuilder;
17 use Symfony\Component\Process\PhpExecutableFinder;
4a83d99 blue-eyes normalized license messages in PHP files
blue-eyes authored
18
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
19 /**
20 * A Shell wraps an Application to add shell capabilities to it.
21 *
38f8df6 Fabien Potencier [Console] tweaked previous merge
fabpot authored
22 * Support for history and completion only works with a PHP compiled
23 * with readline support (either --with-readline or --with-libedit)
24 *
b933805 Fabien Potencier replaced symfony-project.org by symfony.com
fabpot authored
25 * @author Fabien Potencier <fabien@symfony.com>
a0eacbb Martin Hasoň [Console] added support for interactive shell without readline extension
hason authored
26 * @author Martin Hasoň <martin.hason@gmail.com>
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
27 */
28 class Shell
29 {
67dbf5e Fabien Potencier moved most protected to private in the Console component
fabpot authored
30 private $application;
31 private $history;
32 private $output;
419d318 Martin Hasoň [Console] fixed CS and simplified code
hason authored
33 private $hasReadline;
b975b8b Tobias Schultze unify constructor initialization style throughout symfony
Tobion authored
34 private $processIsolation = false;
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
35
36 /**
37 * Constructor.
38 *
39 * If there is no readline support for the current PHP executable
40 * a \RuntimeException exception is thrown.
41 *
42 * @param Application $application An application instance
43 */
44 public function __construct(Application $application)
45 {
38f8df6 Fabien Potencier [Console] tweaked previous merge
fabpot authored
46 $this->hasReadline = function_exists('readline');
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
47 $this->application = $application;
48 $this->history = getenv('HOME').'/.history_'.$application->getName();
49 $this->output = new ConsoleOutput();
50 }
51
52 /**
53 * Runs the shell.
54 */
55 public function run()
56 {
57 $this->application->setAutoExit(false);
58 $this->application->setCatchExceptions(true);
59
419d318 Martin Hasoň [Console] fixed CS and simplified code
hason authored
60 if ($this->hasReadline) {
a0eacbb Martin Hasoň [Console] added support for interactive shell without readline extension
hason authored
61 readline_read_history($this->history);
62 readline_completion_function(array($this, 'autocompleter'));
63 }
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
64
65 $this->output->writeln($this->getHeader());
75ca317 Dariusz Górecki [Console] Enable process isolantion in Shell
canni authored
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
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
80 while (true) {
a0eacbb Martin Hasoň [Console] added support for interactive shell without readline extension
hason authored
81 $command = $this->readline();
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
82
83 if (false === $command) {
84 $this->output->writeln("\n");
85
86 break;
87 }
88
419d318 Martin Hasoň [Console] fixed CS and simplified code
hason authored
89 if ($this->hasReadline) {
a0eacbb Martin Hasoň [Console] added support for interactive shell without readline extension
hason authored
90 readline_add_history($command);
91 readline_write_history($this->history);
92 }
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
93
75ca317 Dariusz Górecki [Console] Enable process isolantion in Shell
canni authored
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;
035e072 Fabien Potencier fixed CS for lambdas
fabpot authored
106 $process->run(function ($type, $data) use ($output) {
75ca317 Dariusz Górecki [Console] Enable process isolantion in Shell
canni authored
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) {
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
116 $this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
117 }
118 }
119 }
120
121 /**
a0eacbb Martin Hasoň [Console] added support for interactive shell without readline extension
hason authored
122 * Returns the shell header.
123 *
124 * @return string The header string
125 */
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,
11ebd03 Fabien Potencier merged 2.0
fabpot authored
133 or <comment>list</comment> to get a list of available commands.
a0eacbb Martin Hasoň [Console] added support for interactive shell without readline extension
hason authored
134
135 To exit the shell, type <comment>^D</comment>.
136
137 EOF;
138 }
139
140 /**
0022ee8 Fabien Potencier [Console] made the shel prompt easily customizable (closes #7710)
fabpot authored
141 * Renders a prompt.
142 *
143 * @return string The prompt
144 */
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
161 /**
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
162 * Tries to return autocompletion for the current entered text.
163 *
a75d3d9 Hugo Hamon [Console] removed unused $position parameter in Shell::autocompleter() m...
hhamon authored
164 * @param string $text The last segment of the entered text
b9307cb Fabien Potencier [Console] fixed some CS
fabpot authored
165 *
c1fc7ae Graham Campbell Docblock fixes
GrahamCampbell authored
166 * @return bool|array A list of guessed strings or true
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
167 */
a75d3d9 Hugo Hamon [Console] removed unused $position parameter in Shell::autocompleter() m...
hhamon authored
168 private function autocompleter($text)
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
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) {
e22b923 Fabien Potencier made some method name changes to have a better coherence throughout the ...
fabpot authored
179 return array_keys($this->application->all());
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
180 }
181
182 // options and arguments?
183 try {
cda9fe4 Katsuhiro OGAWA [Console] fixed call to undefined method.
fivestar authored
184 $command = $this->application->find(substr($text, 0, strpos($text, ' ')));
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
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
197 /**
a0eacbb Martin Hasoň [Console] added support for interactive shell without readline extension
hason authored
198 * Reads a single line from standard input.
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
199 *
a0eacbb Martin Hasoň [Console] added support for interactive shell without readline extension
hason authored
200 * @return string The single line from standard input
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
201 */
a0eacbb Martin Hasoň [Console] added support for interactive shell without readline extension
hason authored
202 private function readline()
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
203 {
419d318 Martin Hasoň [Console] fixed CS and simplified code
hason authored
204 if ($this->hasReadline) {
0022ee8 Fabien Potencier [Console] made the shel prompt easily customizable (closes #7710)
fabpot authored
205 $line = readline($this->getPrompt());
a0eacbb Martin Hasoň [Console] added support for interactive shell without readline extension
hason authored
206 } else {
0022ee8 Fabien Potencier [Console] made the shel prompt easily customizable (closes #7710)
fabpot authored
207 $this->output->write($this->getPrompt());
419d318 Martin Hasoň [Console] fixed CS and simplified code
hason authored
208 $line = fgets(STDIN, 1024);
209 $line = (!$line && strlen($line) == 0) ? false : rtrim($line);
a0eacbb Martin Hasoň [Console] added support for interactive shell without readline extension
hason authored
210 }
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
211
419d318 Martin Hasoň [Console] fixed CS and simplified code
hason authored
212 return $line;
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
213 }
75ca317 Dariusz Górecki [Console] Enable process isolantion in Shell
canni authored
214
215 public function getProcessIsolation()
216 {
217 return $this->processIsolation;
218 }
219
220 public function setProcessIsolation($processIsolation)
221 {
3f40d2c Fabien Potencier made types consistent with those defined in Hack
fabpot authored
222 $this->processIsolation = (bool) $processIsolation;
fb16385 Filipe Guerra [Console] Fix #5897 - Console component require Shell component
alias-mac authored
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 }
75ca317 Dariusz Górecki [Console] Enable process isolantion in Shell
canni authored
227 }
68c191c Fabien Potencier renamed Symfony\Components to Symfony\Component
fabpot authored
228 }
Something went wrong with that request. Please try again.