[Console] Add ProgressBar::preventRedrawFasterThan() and forceRedrawSlowerThan() methods
This commit is contained in:
parent
dca9325e61
commit
83edac321e
@ -1,6 +1,11 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
4.4.0
|
||||
-----
|
||||
|
||||
* added method `preventRedrawFasterThan()` and `forceRedrawSlowerThan()` on `ProgressBar`
|
||||
|
||||
4.3.0
|
||||
-----
|
||||
|
||||
|
@ -32,6 +32,10 @@ final class ProgressBar
|
||||
private $format;
|
||||
private $internalFormat;
|
||||
private $redrawFreq = 1;
|
||||
private $writeCount;
|
||||
private $lastWriteTime;
|
||||
private $minSecondsBetweenRedraws = 0;
|
||||
private $maxSecondsBetweenRedraws = 1;
|
||||
private $output;
|
||||
private $step = 0;
|
||||
private $max;
|
||||
@ -51,7 +55,7 @@ final class ProgressBar
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
* @param int $max Maximum steps (0 if unknown)
|
||||
*/
|
||||
public function __construct(OutputInterface $output, int $max = 0)
|
||||
public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 0)
|
||||
{
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
@ -61,12 +65,17 @@ final class ProgressBar
|
||||
$this->setMaxSteps($max);
|
||||
$this->terminal = new Terminal();
|
||||
|
||||
if (0 < $minSecondsBetweenRedraws) {
|
||||
$this->redrawFreq = null;
|
||||
$this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws;
|
||||
}
|
||||
|
||||
if (!$this->output->isDecorated()) {
|
||||
// disable overwrite when output does not support ANSI codes.
|
||||
$this->overwrite = false;
|
||||
|
||||
// set a reasonable redraw frequency so output isn't flooded
|
||||
$this->setRedrawFrequency($max / 10);
|
||||
$this->redrawFreq = null;
|
||||
}
|
||||
|
||||
$this->startTime = time();
|
||||
@ -183,6 +192,11 @@ final class ProgressBar
|
||||
return $this->percent;
|
||||
}
|
||||
|
||||
public function getBarOffset(): int
|
||||
{
|
||||
return floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? min(5, $this->barWidth / 15) * $this->writeCount : $this->step) % $this->barWidth);
|
||||
}
|
||||
|
||||
public function setBarWidth(int $size)
|
||||
{
|
||||
$this->barWidth = max(1, $size);
|
||||
@ -238,9 +252,19 @@ final class ProgressBar
|
||||
*
|
||||
* @param int|float $freq The frequency in steps
|
||||
*/
|
||||
public function setRedrawFrequency(int $freq)
|
||||
public function setRedrawFrequency(?int $freq)
|
||||
{
|
||||
$this->redrawFreq = max($freq, 1);
|
||||
$this->redrawFreq = null !== $freq ? max(1, $freq) : null;
|
||||
}
|
||||
|
||||
public function preventRedrawFasterThan(float $intervalInSeconds): void
|
||||
{
|
||||
$this->minSecondsBetweenRedraws = $intervalInSeconds;
|
||||
}
|
||||
|
||||
public function forceRedrawSlowerThan(float $intervalInSeconds): void
|
||||
{
|
||||
$this->maxSecondsBetweenRedraws = $intervalInSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -305,11 +329,27 @@ final class ProgressBar
|
||||
$step = 0;
|
||||
}
|
||||
|
||||
$prevPeriod = (int) ($this->step / $this->redrawFreq);
|
||||
$currPeriod = (int) ($step / $this->redrawFreq);
|
||||
$redrawFreq = $this->redrawFreq ?? (($this->max ?: 10) / 10);
|
||||
$prevPeriod = (int) ($this->step / $redrawFreq);
|
||||
$currPeriod = (int) ($step / $redrawFreq);
|
||||
$this->step = $step;
|
||||
$this->percent = $this->max ? (float) $this->step / $this->max : 0;
|
||||
if ($prevPeriod !== $currPeriod || $this->max === $step) {
|
||||
$timeInterval = microtime(true) - $this->lastWriteTime;
|
||||
|
||||
// Draw regardless of other limits
|
||||
if ($this->max === $step) {
|
||||
$this->display();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Throttling
|
||||
if ($timeInterval < $this->minSecondsBetweenRedraws) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw each step period, but not too late
|
||||
if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) {
|
||||
$this->display();
|
||||
}
|
||||
}
|
||||
@ -413,8 +453,10 @@ final class ProgressBar
|
||||
}
|
||||
|
||||
$this->firstRun = false;
|
||||
$this->lastWriteTime = microtime(true);
|
||||
|
||||
$this->output->write($message);
|
||||
++$this->writeCount;
|
||||
}
|
||||
|
||||
private function determineBestFormat(): string
|
||||
@ -436,7 +478,7 @@ final class ProgressBar
|
||||
{
|
||||
return [
|
||||
'bar' => function (self $bar, OutputInterface $output) {
|
||||
$completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth());
|
||||
$completeBars = $bar->getBarOffset();
|
||||
$display = str_repeat($bar->getBarCharacter(), $completeBars);
|
||||
if ($completeBars < $bar->getBarWidth()) {
|
||||
$emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
|
||||
|
@ -944,4 +944,58 @@ class ProgressBarTest extends TestCase
|
||||
$this->assertEquals(5, $bar->getBarWidth(), stream_get_contents($output->getStream()));
|
||||
putenv('COLUMNS=120');
|
||||
}
|
||||
|
||||
public function testForceRedrawSlowerThan(): void
|
||||
{
|
||||
$bar = new ProgressBar($output = $this->getOutputStream());
|
||||
$bar->setRedrawFrequency(4); // disable step based redraws
|
||||
$bar->start();
|
||||
$bar->setProgress(1); // No treshold hit, no redraw
|
||||
$bar->forceRedrawSlowerThan(2);
|
||||
sleep(1);
|
||||
$bar->setProgress(2); // Still no redraw because redraw is forced after 2 seconds only
|
||||
sleep(1);
|
||||
$bar->setProgress(3); // 1+1 = 2 -> redraw finally
|
||||
$bar->setProgress(4); // step based redraw freq hit, redraw even without sleep
|
||||
$bar->setProgress(5); // No treshold hit, no redraw
|
||||
$bar->preventRedrawFasterThan(3);
|
||||
sleep(2);
|
||||
$bar->setProgress(6); // No redraw even though 2 seconds passed. Throttling has priority
|
||||
$bar->preventRedrawFasterThan(2);
|
||||
$bar->setProgress(7); // Throttling relaxed, draw
|
||||
|
||||
rewind($output->getStream());
|
||||
$this->assertEquals(
|
||||
' 0 [>---------------------------]'.
|
||||
$this->generateOutput(' 3 [--->------------------------]').
|
||||
$this->generateOutput(' 4 [---->-----------------------]').
|
||||
$this->generateOutput(' 7 [------->--------------------]'),
|
||||
stream_get_contents($output->getStream())
|
||||
);
|
||||
}
|
||||
|
||||
public function testPreventRedrawFasterThan()
|
||||
{
|
||||
$bar = new ProgressBar($output = $this->getOutputStream());
|
||||
$bar->setRedrawFrequency(1);
|
||||
$bar->preventRedrawFasterThan(1);
|
||||
$bar->start();
|
||||
$bar->setProgress(1); // Too fast, should not draw
|
||||
sleep(1);
|
||||
$bar->setProgress(2); // 1 second passed, draw
|
||||
$bar->preventRedrawFasterThan(2);
|
||||
sleep(1);
|
||||
$bar->setProgress(3); // 1 second passed but we changed threshold, should not draw
|
||||
sleep(1);
|
||||
$bar->setProgress(4); // 1+1 seconds = 2 seconds passed which conforms threshold, draw
|
||||
$bar->setProgress(5); // No treshold hit, no redraw
|
||||
|
||||
rewind($output->getStream());
|
||||
$this->assertEquals(
|
||||
' 0 [>---------------------------]'.
|
||||
$this->generateOutput(' 2 [-->-------------------------]').
|
||||
$this->generateOutput(' 4 [---->-----------------------]'),
|
||||
stream_get_contents($output->getStream())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user