diff --git a/CHANGELOG-2.1.md b/CHANGELOG-2.1.md index 1d867dd8da..4b977f119b 100644 --- a/CHANGELOG-2.1.md +++ b/CHANGELOG-2.1.md @@ -128,6 +128,7 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c * added support for STDERR in the console output class (errors are now sent to STDERR) * made the defaults (helper set, commands, input definition) in Application more easily customizable * added support for the shell even if readline is not available + * added support for process isolation in Symfony shell via `--process-isolation` switch ### ClassLoader diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php index d19b4eab42..cd80330fb2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php @@ -39,6 +39,7 @@ class Application extends BaseApplication parent::__construct('Symfony', Kernel::VERSION.' - '.$kernel->getName().'/'.$kernel->getEnvironment().($kernel->isDebug() ? '/debug' : '')); $this->getDefinition()->addOption(new InputOption('--shell', '-s', InputOption::VALUE_NONE, 'Launch the shell.')); + $this->getDefinition()->addOption(new InputOption('--process-isolation', null, InputOption::VALUE_NONE, 'Launch commands from shell as a separate processes.')); $this->getDefinition()->addOption(new InputOption('--env', '-e', InputOption::VALUE_REQUIRED, 'The Environment name.', $kernel->getEnvironment())); $this->getDefinition()->addOption(new InputOption('--no-debug', null, InputOption::VALUE_NONE, 'Switches off debug mode.')); } @@ -67,6 +68,7 @@ class Application extends BaseApplication if (true === $input->hasParameterOption(array('--shell', '-s'))) { $shell = new Shell($this); + $shell->setProcessIsolation($input->hasParameterOption(array('--process-isolation'))); $shell->run(); return 0; diff --git a/src/Symfony/Component/Console/Shell.php b/src/Symfony/Component/Console/Shell.php index 1eaa958184..6b89b048ea 100644 --- a/src/Symfony/Component/Console/Shell.php +++ b/src/Symfony/Component/Console/Shell.php @@ -14,6 +14,8 @@ namespace Symfony\Component\Console; use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\Process\ProcessBuilder; +use Symfony\Component\Process\PhpExecutableFinder; /** * A Shell wraps an Application to add shell capabilities to it. @@ -31,6 +33,7 @@ class Shell private $output; private $hasReadline; private $prompt; + private $processIsolation; /** * Constructor. @@ -39,8 +42,6 @@ class Shell * a \RuntimeException exception is thrown. * * @param Application $application An application instance - * - * @throws \RuntimeException When Readline extension is not enabled */ public function __construct(Application $application) { @@ -49,6 +50,7 @@ class Shell $this->history = getenv('HOME').'/.history_'.$application->getName(); $this->output = new ConsoleOutput(); $this->prompt = $application->getName().' > '; + $this->processIsolation = false; } /** @@ -65,6 +67,20 @@ class Shell } $this->output->writeln($this->getHeader()); + $php = null; + if ($this->processIsolation) { + $finder = new PhpExecutableFinder(); + $php = $finder->find(); + $this->output->writeln(<<Running with process isolation, you should consider this: + * each command is executed as separate process, + * commands don't support interactivity, all params must be passed explicitly, + * commands output is not colorized. + +EOF + ); + } + while (true) { $command = $this->readline(); @@ -79,7 +95,28 @@ class Shell readline_write_history($this->history); } - if (0 !== $ret = $this->application->run(new StringInput($command), $this->output)) { + if ($this->processIsolation) { + $pb = new ProcessBuilder(); + + $process = $pb + ->add($php) + ->add($_SERVER['argv'][0]) + ->add($command) + ->inheritEnvironmentVariables(true) + ->getProcess() + ; + + $output = $this->output; + $process->run(function($type, $data) use ($output) { + $output->writeln($data); + }); + + $ret = $process->getExitCode(); + } else { + $ret = $this->application->run(new StringInput($command), $this->output); + } + + if (0 !== $ret) { $this->output->writeln(sprintf('The command terminated with an error status (%s)', $ret)); } } @@ -156,4 +193,14 @@ EOF; return $line; } + + public function getProcessIsolation() + { + return $this->processIsolation; + } + + public function setProcessIsolation($processIsolation) + { + $this->processIsolation = (Boolean) $processIsolation; + } }