8000 feature #52605 [Console] Support `ProgressBar::iterate()` on empty ar… · symfony/symfony@4e944be · GitHub
[go: up one dir, main page]

Skip to content

Commit 4e944be

Browse files
committed
feature #52605 [Console] Support ProgressBar::iterate() on empty array (GromNaN)
This PR was merged into the 7.1 branch. Discussion ---------- [Console] Support `ProgressBar::iterate()` on empty array | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix #47244 | License | MIT Alternative to #47259 Use `$max = null` to indicate that the value is unknown. This allows `0` to be displayed by directly setting the progress bar to 100%. Zero is only supported for `iterate()`. When passed to the constructor or `setMaxSteps`, it means "unknown max". Commits ------- 574b8a3 Fix ProgressBar::iterate on empty iterator
2 parents c9e7809 + 574b8a3 commit 4e944be

File tree

2 files changed

+58
-17
lines changed

2 files changed

+58
-17
lines changed

src/Symfony/Component/Console/Helper/ProgressBar.php

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ public function getStartTime(): int
195195

196196
public function getMaxSteps(): int
197197
{
198-
return $this->max;
198+
return $this->max ?? 0;
199199
}
200200

201201
public function getProgress(): int
@@ -215,7 +215,7 @@ public function getProgressPercent(): float
215215

216216
public function getBarOffset(): float
217217
{
218-
return floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth);
218+
return floor(null !== $this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth);
219219
}
220220

221221
public function getEstimated(): float
@@ -253,7 +253,7 @@ public function setBarCharacter(string $char): void
253253

254254
public function getBarCharacter(): string
255255
{
256-
return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar);
256+
return $this->barChar ?? (null !== $this->max ? '=' : $this->emptyBarChar);
257257
}
258258

259259
public function setEmptyBarCharacter(string $char): void
@@ -315,7 +315,21 @@ public function maxSecondsBetweenRedraws(float $seconds): void
315315
*/
316316
public function iterate(iterable $iterable, int $max = null): iterable
317317
{
318-
$this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0));
318+
if (0 === $max) {
319+
$max = null;
320+
}
321+
322+
$max ??= is_countable($iterable) ? \count($iterable) : null;
323+
324+
if (0 === $max) {
325+
$this->max = 0;
326+
$this->stepWidth = 2;
327+
$this->finish();
328+
329+
return;
330+
}
331+
332+
$this->start($max);
319333

320334
foreach ($iterable as $key => $value) {
321335
yield $key => $value;
@@ -373,11 +387,15 @@ public function setProgress(int $step): void
373387
$step = 0;
374388
}
375389

376-
$redrawFreq = $this->redrawFreq ?? (($this->max ?: 10) / 10);
377-
$prevPeriod = (int) ($this->step / $redrawFreq);
378-
$currPeriod = (int) ($step / $redrawFreq);
390+
$redrawFreq = $this->redrawFreq ?? (($this->max ?? 10) / 10);
391+
$prevPeriod = $redrawFreq ? (int) ($this->step / $redrawFreq) : 0;
392+
$currPeriod = $redrawFreq ? (int) ($step / $redrawFreq) : 0;
379393
$this->step = $step;
380-
$this->percent = $this->max ? (float) $this->step / $this->max : 0;
394+
$this->percent = match ($this->max) {
395+
null => 0,
396+
0 => 1,
397+
default => (float) $this->step / $this->max,
398+
};
381399
$timeInterval = microtime(true) - $this->lastWriteTime;
382400

383401
// Draw regardless of other limits
@@ -398,28 +416,37 @@ public function setProgress(int $step): void
398416
}
399417
}
400418

401-
public function setMaxSteps(int $max): void
419+
public function setMaxSteps(?int $max): void
402420
{
421+
if (0 === $max) {
422+
$max = null;
423+
}
424+
403425
$this->format = null;
404-
$this->max = max(0, $max);
405-
$this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4;
426+
if (null === $max) {
427+
$this->max = null;
428+
$this->stepWidth = 4;
429+
} else {
430+
$this->max = max(0, $max);
431+
$this->stepWidth = Helper::width((string) $this->max);
432+
}
406433
}
407434

408435
/**
409436
* Finishes the progress output.
410437
*/
411438
public function finish(): void
412439
{
413-
if (!$this->max) {
440+
if (null === $this->max) {
414441
$this->max = $this->step;
415442
}
416443

417-
if ($this->step === $this->max && !$this->overwrite) {
444+
if (($this->step === $this->max || null === $this->max) && !$this->overwrite) {
418445
// prevent double 100% output
419446
return;
420447
}
421448

422-
$this->setProgress($this->max);
449+
$this->setProgress($this->max ?? $this->step);
423450
}
424451

425452
/**
@@ -542,14 +569,14 @@ private static function initPlaceholderFormatters(): array
542569
},
543570
'elapsed' => fn (self $bar) => Helper::formatTime(time() - $bar->getStartTime(), 2),
544571
'remaining' => function (self $bar) {
545-
if (!$bar->getMaxSteps()) {
572+
if (null === $bar->getMaxSteps()) {
546573
throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
547574
}
548575

549576
return Helper::formatTime($bar->getRemaining(), 2);
550577
},
551578
'estimated' => function (self $bar) {
552-
if (!$bar->getMaxSteps()) {
579+
if (null === $bar->getMaxSteps()) {
553580
throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
554581
}
555582

src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,20 @@ public function testIterateUncountable()
10921092
);
10931093
}
10941094

1095+
public function testEmptyInputWithDebugFormat()
1096+
{
1097+
$bar = new ProgressBar($output = $this->getOutputStream());
1098+
$bar->setFormat('%current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%');
1099+
1100+
$this->assertEquals([], iterator_to_array($bar->iterate([])));
1101+
1102+
rewind($output->getStream());
1103+
$this->assertEquals(
1104+
' 0/0 [============================] 100% < 1 sec/< 1 sec',
1105+
stream_get_contents($output->getStream())
1106+
);
1107+
}
1108+
10951109
protected function getOutputStream($decorated = true, $verbosity = StreamOutput::VERBOSITY_NORMAL)
10961110
{
10971111
return new StreamOutput(fopen('php://memory', 'r+', false), $verbosity, $decorated);
@@ -1263,7 +1277,7 @@ public function testMultiLineFormatIsFullyCorrectlyWithManuallyCleanup()
12631277
'Foo!'.\PHP_EOL.
12641278
$this->generateOutput('[--->------------------------]').
12651279
"\nProcessing \"foobar\"...".
1266-
$this->generateOutput("[----->----------------------]\nProcessing \"foobar\"..."),
1280+
$this->generateOutput("[============================]\nProcessing \"foobar\"..."),
12671281
stream_get_contents($output->getStream())
12681282
);
12691283
}

0 commit comments

Comments
 (0)
0