merged branch canni/command_in_process (PR #2894)

Commits
-------

e9b4c58 [Console] Enable process isolantion in Shell

Discussion
----------

[Console] Enable process isolantion in Shell

Bug fix: no
BC break: no
Feature addition: yes
Symfony2 test pass: yes
Fixes the following tickets: #2848 #2847
Todo: Write unit tests

See tickets for reference, need help with unit testing, because I don't know how to test this :)

---------------------------------------------------------------------------

by canni at 2011-12-16T09:36:32Z

I've tested this with different scenarios like "inception" (invoking shell from shell - will not work) ;) and others, everything seems to work great.

As I have no idea on how to pack this with unit testing some help needed, also as I don't have any windows in home ;) need someone to test it on MS os.
And we should decide, do we want process isolation by default? (This will not break the BC, break only the "expected behavior" - colorful output and "interactivity")

---------------------------------------------------------------------------

by canni at 2011-12-18T15:14:26Z

I've rebased this branch to match current `HEAD` and I've added usage of new process builder, for better portability an shell arg escaping.

---------------------------------------------------------------------------

by fabpot at 2012-02-02T08:28:32Z

@canni: Can you squash your commits before I merge this PR? Thanks.

---------------------------------------------------------------------------

by canni at 2012-02-02T09:07:16Z

@fabpot @stof done.
This commit is contained in:
Fabien Potencier 2012-02-02 10:13:02 +01:00
commit 687703db94
3 changed files with 53 additions and 3 deletions

View File

@ -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

View File

@ -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;

View File

@ -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(<<<EOF
<info>Running with process isolation, you should consider this:</info>
* 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('<error>The command terminated with an error status (%s)</error>', $ret));
}
}
@ -156,4 +193,14 @@ EOF;
return $line;
}
public function getProcessIsolation()
{
return $this->processIsolation;
}
public function setProcessIsolation($processIsolation)
{
$this->processIsolation = (Boolean) $processIsolation;
}
}