Skip to content

Commit c670801

Browse files
fabpotromainneutron
authored andcommitted
[Console] added a Process helper
1 parent fe26753 commit c670801

File tree

4 files changed

+178
-0
lines changed

4 files changed

+178
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ CHANGELOG
55
-----
66

77
* deprecated the dialog helper (use the question helper instead)
8+
* added a Process helper
89
* deprecated TableHelper in favor of Table
910
* deprecated ProgressHelper in favor of ProgressBar
1011
* added a question helper
1112
* added a way to set the process name of a command
1213
* added a way to set a default command instead of `ListCommand`
14+
* added a way to set the process title of a command
1315

1416
2.4.0
1517
-----

Helper/DebugFormatterHelper.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Helper;
13+
14+
use Symfony\Component\Console\Helper\Helper;
15+
16+
/**
17+
* Helps outputting debug information when running an external program from a command.
18+
*
19+
* An external program can be a Process, an HTTP request, or anything else.
20+
*
21+
* @author Fabien Potencier <[email protected]>
22+
*/
23+
class DebugFormatterHelper extends Helper
24+
{
25+
private $colors = array('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white');
26+
private $started = array();
27+
private $count = -1;
28+
29+
public function start($id, $message, $prefix = 'RUN')
30+
{
31+
$this->started[$id] = array('border' => ++$this->count % count($this->colors));
32+
33+
return sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message);
34+
}
35+
36+
public function progress($id, $buffer, $error = false, $prefix = 'OUT', $errorPrefix = 'ERR')
37+
{
38+
$message = '';
39+
40+
if ($error) {
41+
if (!isset($this->started[$id]['err'])) {
42+
$message = sprintf("%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix);
43+
$this->started[$id]['err'] = true;
44+
}
45+
46+
$message .= str_replace("\n", sprintf("\n%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix), $buffer);
47+
} else {
48+
if (!isset($this->started[$id]['out'])) {
49+
$message = sprintf("%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix);
50+
$this->started[$id]['out'] = true;
51+
}
52+
53+
$message .= str_replace("\n", sprintf("\n%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix), $buffer);
54+
}
55+
56+
return $message;
57+
}
58+
59+
public function stop($id, $message, $successful, $prefix = 'RES')
60+
{
61+
$trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';
62+
63+
if ($successful) {
64+
return sprintf("%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
65+
}
66+
67+
return sprintf("%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
68+
}
69+
70+
private function getBorder($id)
71+
{
72+
return sprintf('<bg=%s> </>', $this->colors[$this->started[$id]['border']]);
73+
}
74+
75+
/**
76+
* {@inheritDoc}
77+
*/
78+
public function getName()
79+
{
80+
return 'debug_formatter';
81+
}
82+
}

Helper/ProcessHelper.php

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Helper;
13+
14+
use Symfony\Component\Console\Helper\Helper;
15+
use Symfony\Component\Console\Output\OutputInterface;
16+
use Symfony\Component\Process\Process;
17+
18+
/**
19+
* The Process class provides helpers to run external processes.
20+
*
21+
* @author Fabien Potencier <[email protected]>
22+
*/
23+
class ProcessHelper extends Helper
24+
{
25+
/**
26+
* Runs an external process.
27+
*
28+
* @param OutputInterface $output An OutputInterface instance
29+
* @param string|Process $cmd An instance of Process or a command to run
30+
* @param string|null $error An error message that must be displayed if something went wrong
31+
* @param callback|null $callback A PHP callback to run whenever there is some
32+
* output available on STDOUT or STDERR
33+
*
34+
* @return Process The process that ran
35+
*/
36+
public function run(OutputInterface $output, $cmd, $error = null, $callback = null)
37+
{
38+
$verbose = $output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE;
39+
$debug = $output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG;
40+
41+
$formatter = $this->getHelperSet()->get('debug_formatter');
42+
43+
$process = $cmd instanceof Process ? $cmd : new Process($cmd);
44+
45+
if ($verbose) {
46+
$output->write($formatter->start(spl_object_hash($process), $process->getCommandLine()));
47+
}
48+
49+
if ($debug) {
50+
$callback = $this->wrapCallback($output, $process, $callback);
51+
}
52+
53+
$process->run($callback);
54+
55+
if ($verbose) {
56+
$message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run sucessfully', $process->getExitCode());
57+
$output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));
58+
}
59+
60+
if (!$process->isSuccessful() && null !== $error) {
61+
$output->writeln(sprintf('<error>%s</error>'), $error);
62+
}
63+
64+
return $process;
65+
}
66+
67+
/**
68+
* Wraps a Process callback to add debugging output.
69+
*
70+
* @param OutputInterface $output An OutputInterface interface
71+
* @param callable|null $callback A PHP callable
72+
*/
73+
public function wrapCallback(OutputInterface $output, Process $process, $callback = null)
74+
{
75+
$formatter = $this->getHelperSet()->get('debug_formatter');
76+
77+
return function ($type, $buffer) use ($output, $process, $callback, $formatter) {
78+
$output->write($formatter->progress(spl_object_hash($process), $buffer, 'err' === $type));
79+
80+
if (null !== $callback) {
81+
$callback($type, $buffer);
82+
}
83+
};
84+
}
85+
86+
/**
87+
* {@inheritDoc}
88+
*/
89+
public function getName()
90+
{
91+
return 'process';
92+
}
93+
}

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
},
2525
"suggest": {
2626
"symfony/event-dispatcher": "",
27+
"symfony/process": "",
2728
"psr/log": "For using the console logger"
2829
},
2930
"autoload": {

0 commit comments

Comments
 (0)