-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[WIP] [Console] added a Process helper #10609
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Console\Helper; | ||
|
||
use Symfony\Component\Console\Helper\Helper; | ||
|
||
/** | ||
* Helps outputting debug information when running an external program from a command. | ||
* | ||
* An external program can be a Process, an HTTP request, or anything else. | ||
* | ||
* @author Fabien Potencier <fabien@symfony.com> | ||
*/ | ||
class DebugFormatterHelper extends Helper | ||
{ | ||
private $colors = array('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'); | ||
private $started = array(); | ||
private $count = -1; | ||
|
||
public function start($id, $message, $prefix = 'RUN') | ||
{ | ||
$this->started[$id] = array('border' => ++$this->count % count($this->colors)); | ||
|
||
return sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message); | ||
} | ||
|
||
public function progress($id, $buffer, $error = false, $prefix = 'OUT', $errorPrefix = 'ERR') | ||
{ | ||
$message = ''; | ||
|
||
if ($error) { | ||
if (!isset($this->started[$id]['err'])) { | ||
$message = sprintf("%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix); | ||
$this->started[$id]['err'] = true; | ||
} | ||
|
||
$message .= str_replace("\n", sprintf("\n%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix), $buffer); | ||
} else { | ||
if (!isset($this->started[$id]['out'])) { | ||
$message = sprintf("%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix); | ||
$this->started[$id]['out'] = true; | ||
} | ||
|
||
$message .= str_replace("\n", sprintf("\n%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix), $buffer); | ||
} | ||
|
||
return $message; | ||
} | ||
|
||
public function stop($id, $message, $successful, $prefix = 'RES') | ||
{ | ||
$trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : ''; | ||
|
||
if ($successful) { | ||
return sprintf("%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message); | ||
} | ||
|
||
return sprintf("%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message); | ||
} | ||
|
||
private function getBorder($id) | ||
{ | ||
return sprintf('<bg=%s> </>', $this->colors[$this->started[$id]['border']]); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function getName() | ||
{ | ||
return 'debug_formatter'; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Console\Helper; | ||
|
||
use Symfony\Component\Console\Helper\Helper; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
use Symfony\Component\Process\Process; | ||
|
||
/** | ||
* The Process class provides helpers to run external processes. | ||
* | ||
* @author Fabien Potencier <fabien@symfony.com> | ||
*/ | ||
class ProcessHelper extends Helper | ||
{ | ||
/** | ||
* Runs an external process. | ||
* | ||
* @param OutputInterface $output An OutputInterface instance | ||
* @param string|Process $cmd An instance of Process or a command to run | ||
* @param string|null $error An error message that must be displayed if something went wrong | ||
* @param callback|null $callback A PHP callback to run whenever there is some | ||
* output available on STDOUT or STDERR | ||
* | ||
* @return Process The process that ran | ||
*/ | ||
public function run(OutputInterface $output, $cmd, $error = null, $callback = null) | ||
{ | ||
$verbose = $output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE; | ||
$debug = $output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG; | ||
|
||
$formatter = $this->getHelperSet()->get('debug_formatter'); | ||
|
||
$process = $cmd instanceof Process ? $cmd : new Process($cmd); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is a bad idea to allow running non-sanitized commands like this. I'd rather use the following to run a sanitize command: $cmd instanceof Process ? $cmd : ProcessBuilder::create(is_array($cmd) ? $cmd : array($cmd))->getProcess(); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to run a full command you can use I've to admit people would be able to run |
||
|
||
if ($verbose) { | ||
$output->write($formatter->start(spl_object_hash($process), $process->getCommandLine())); | ||
} | ||
|
||
if ($debug) { | ||
$callback = $this->wrapCallback($output, $process, $callback); | ||
} | ||
|
||
$process->run($callback); | ||
|
||
if ($verbose) { | ||
$message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run sucessfully', $process->getExitCode()); | ||
$output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful())); | ||
} | ||
|
||
if (!$process->isSuccessful() && null !== $error) { | ||
$output->writeln(sprintf('<error>%s</error>'), $error); | ||
} | ||
|
||
return $process; | ||
} | ||
|
||
/** | ||
* Wraps a Process callback to add debugging output. | ||
* | ||
* @param OutputInterface $output An OutputInterface interface | ||
* @param callable|null $callback A PHP callable | ||
*/ | ||
public function wrapCallback(OutputInterface $output, Process $process, $callback = null) | ||
{ | ||
$formatter = $this->getHelperSet()->get('debug_formatter'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we must register this helper in the Application, it would currently fail. |
||
|
||
return function ($type, $buffer) use ($output, $process, $callback, $formatter) { | ||
$output->write($formatter->progress(spl_object_hash($process), $buffer, 'err' === $type)); | ||
|
||
if (null !== $callback) { | ||
$callback($type, $buffer); | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function getName() | ||
{ | ||
return 'process'; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about the DebugFormatterHelper ?