Skip to content

Commit 061d2c7

Browse files
committed
Use a partial buffer in SymfonyStyle
1 parent 05240f0 commit 061d2c7

File tree

3 files changed

+86
-5
lines changed

3 files changed

+86
-5
lines changed

Output/TrimmedBufferOutput.php

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Output;
13+
14+
use Symfony\Component\Console\Exception\InvalidArgumentException;
15+
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
16+
17+
/**
18+
* A BufferedOutput that keeps only the last N chars.
19+
*
20+
* @author Jérémy Derussé <jeremy@derusse.com>
21+
*/
22+
class TrimmedBufferOutput extends Output
23+
{
24+
private $maxLength;
25+
private $buffer = '';
26+
27+
public function __construct(
28+
?int $verbosity = self::VERBOSITY_NORMAL,
29+
bool $decorated = false,
30+
OutputFormatterInterface $formatter = null,
31+
int $maxLength
32+
) {
33+
if ($maxLength <= 0) {
34+
throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength));
35+
}
36+
37+
parent::__construct($verbosity, $decorated, $formatter);
38+
$this->maxLength = $maxLength;
39+
}
40+
41+
/**
42+
* Empties buffer and returns its content.
43+
*
44+
* @return string
45+
*/
46+
public function fetch()
47+
{
48+
$content = $this->buffer;
49+
$this->buffer = '';
50+
51+
return $content;
52+
}
53+
54+
/**
55+
* {@inheritdoc}
56+
*/
57+
protected function doWrite($message, $newline)
58+
{
59+
$this->buffer .= $message;
60+
61+
if ($newline) {
62+
$this->buffer .= \PHP_EOL;
63+
}
64+
65+
$this->buffer = substr($this->buffer, 0 - $this->maxLength);
66+
}
67+
}

Style/SymfonyStyle.php

+4-5
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
use Symfony\Component\Console\Helper\TableCell;
2222
use Symfony\Component\Console\Helper\TableSeparator;
2323
use Symfony\Component\Console\Input\InputInterface;
24-
use Symfony\Component\Console\Output\BufferedOutput;
2524
use Symfony\Component\Console\Output\OutputInterface;
25+
use Symfony\Component\Console\Output\TrimmedBufferOutput;
2626
use Symfony\Component\Console\Question\ChoiceQuestion;
2727
use Symfony\Component\Console\Question\ConfirmationQuestion;
2828
use Symfony\Component\Console\Question\Question;
@@ -46,7 +46,7 @@ class SymfonyStyle extends OutputStyle
4646
public function __construct(InputInterface $input, OutputInterface $output)
4747
{
4848
$this->input = $input;
49-
$this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter());
49+
$this->bufferedOutput = new TrimmedBufferOutput($output->getVerbosity(), false, clone $output->getFormatter(), \DIRECTORY_SEPARATOR === '\\' ? 4 : 2);
5050
// Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.
5151
$width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;
5252
$this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);
@@ -449,9 +449,8 @@ private function autoPrependText(): void
449449

450450
private function writeBuffer(string $message, bool $newLine, int $type): void
451451
{
452-
// We need to know if the two last chars are PHP_EOL
453-
// Preserve the last 4 chars inserted (PHP_EOL on windows is two chars) in the history buffer
454-
$this->bufferedOutput->write(substr($message, -4), $newLine, $type);
452+
// We need to know if the last chars are PHP_EOL
453+
$this->bufferedOutput->write($message, $newLine, $type);
455454
}
456455

457456
private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array

Tests/Style/SymfonyStyleTest.php

+15
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Console\Command\Command;
1616
use Symfony\Component\Console\Formatter\OutputFormatter;
17+
use Symfony\Component\Console\Input\ArrayInput;
1718
use Symfony\Component\Console\Input\InputInterface;
1819
use Symfony\Component\Console\Output\ConsoleOutputInterface;
20+
use Symfony\Component\Console\Output\NullOutput;
1921
use Symfony\Component\Console\Output\OutputInterface;
2022
use Symfony\Component\Console\Style\SymfonyStyle;
2123
use Symfony\Component\Console\Tester\CommandTester;
@@ -115,4 +117,17 @@ public function testGetErrorStyleUsesTheCurrentOutputIfNoErrorOutputIsAvailable(
115117

116118
$this->assertInstanceOf(SymfonyStyle::class, $style->getErrorStyle());
117119
}
120+
121+
public function testMemoryConsumption()
122+
{
123+
$io = new SymfonyStyle(new ArrayInput([]), new NullOutput());
124+
$str = 'teststr';
125+
$io->writeln($str, SymfonyStyle::VERBOSITY_QUIET);
126+
$start = memory_get_usage();
127+
for ($i = 0; $i < 100; ++$i) {
128+
$io->writeln($str, SymfonyStyle::VERBOSITY_QUIET);
129+
}
130+
131+
$this->assertSame(0, memory_get_usage() - $start);
132+
}
118133
}

0 commit comments

Comments
 (0)