Upgrade framework

This commit is contained in:
2023-11-14 16:54:35 +01:00
parent 1648a5cd42
commit 4fcf6fffcc
10548 changed files with 693138 additions and 466698 deletions

View File

@@ -11,9 +11,11 @@
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Cursor;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Terminal;
/**
@@ -24,38 +26,46 @@ use Symfony\Component\Console\Terminal;
*/
final class ProgressBar
{
// options
private $barWidth = 28;
private $barChar;
private $emptyBarChar = '-';
private $progressChar = '>';
private $format;
private $internalFormat;
private $redrawFreq = 1;
public const FORMAT_VERBOSE = 'verbose';
public const FORMAT_VERY_VERBOSE = 'very_verbose';
public const FORMAT_DEBUG = 'debug';
public const FORMAT_NORMAL = 'normal';
/**
* @var OutputInterface
*/
private const FORMAT_VERBOSE_NOMAX = 'verbose_nomax';
private const FORMAT_VERY_VERBOSE_NOMAX = 'very_verbose_nomax';
private const FORMAT_DEBUG_NOMAX = 'debug_nomax';
private const FORMAT_NORMAL_NOMAX = 'normal_nomax';
private int $barWidth = 28;
private string $barChar;
private string $emptyBarChar = '-';
private string $progressChar = '>';
private ?string $format = null;
private ?string $internalFormat = null;
private ?int $redrawFreq = 1;
private int $writeCount = 0;
private float $lastWriteTime = 0;
private float $minSecondsBetweenRedraws = 0;
private float $maxSecondsBetweenRedraws = 1;
private $output;
private $step = 0;
private $max;
private $startTime;
private $stepWidth;
private $percent = 0.0;
private $formatLineCount;
private $messages = array();
private $overwrite = true;
private int $step = 0;
private ?int $max = null;
private int $startTime;
private int $stepWidth;
private float $percent = 0.0;
private array $messages = [];
private bool $overwrite = true;
private $terminal;
private $firstRun = true;
private ?string $previousMessage = null;
private $cursor;
private static $formatters;
private static $formats;
private static array $formatters;
private static array $formats;
/**
* @param OutputInterface $output An OutputInterface instance
* @param int $max Maximum steps (0 if unknown)
* @param int $max Maximum steps (0 if unknown)
*/
public function __construct(OutputInterface $output, $max = 0)
public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 1 / 25)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
@@ -65,15 +75,21 @@ 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();
$this->cursor = new Cursor($output);
}
/**
@@ -84,11 +100,9 @@ final class ProgressBar
* @param string $name The placeholder name (including the delimiter char like %)
* @param callable $callable A PHP callable
*/
public static function setPlaceholderFormatterDefinition($name, callable $callable)
public static function setPlaceholderFormatterDefinition(string $name, callable $callable): void
{
if (!self::$formatters) {
self::$formatters = self::initPlaceholderFormatters();
}
self::$formatters ??= self::initPlaceholderFormatters();
self::$formatters[$name] = $callable;
}
@@ -97,16 +111,12 @@ final class ProgressBar
* Gets the placeholder formatter for a given name.
*
* @param string $name The placeholder name (including the delimiter char like %)
*
* @return callable|null A PHP callable
*/
public static function getPlaceholderFormatterDefinition($name)
public static function getPlaceholderFormatterDefinition(string $name): ?callable
{
if (!self::$formatters) {
self::$formatters = self::initPlaceholderFormatters();
}
self::$formatters ??= self::initPlaceholderFormatters();
return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
return self::$formatters[$name] ?? null;
}
/**
@@ -117,11 +127,9 @@ final class ProgressBar
* @param string $name The format name
* @param string $format A format string
*/
public static function setFormatDefinition($name, $format)
public static function setFormatDefinition(string $name, string $format): void
{
if (!self::$formats) {
self::$formats = self::initFormats();
}
self::$formats ??= self::initFormats();
self::$formats[$name] = $format;
}
@@ -130,16 +138,12 @@ final class ProgressBar
* Gets the format for a given name.
*
* @param string $name The format name
*
* @return string|null A format string
*/
public static function getFormatDefinition($name)
public static function getFormatDefinition(string $name): ?string
{
if (!self::$formats) {
self::$formats = self::initFormats();
}
self::$formats ??= self::initFormats();
return isset(self::$formats[$name]) ? self::$formats[$name] : null;
return self::$formats[$name] ?? null;
}
/**
@@ -152,156 +156,105 @@ final class ProgressBar
* @param string $message The text to associate with the placeholder
* @param string $name The name of the placeholder
*/
public function setMessage($message, $name = 'message')
public function setMessage(string $message, string $name = 'message')
{
$this->messages[$name] = $message;
}
public function getMessage($name = 'message')
public function getMessage(string $name = 'message')
{
return $this->messages[$name];
}
/**
* Gets the progress bar start time.
*
* @return int The progress bar start time
*/
public function getStartTime()
public function getStartTime(): int
{
return $this->startTime;
}
/**
* Gets the progress bar maximal steps.
*
* @return int The progress bar max steps
*/
public function getMaxSteps()
public function getMaxSteps(): int
{
return $this->max;
}
/**
* Gets the current step position.
*
* @return int The progress bar step
*/
public function getProgress()
public function getProgress(): int
{
return $this->step;
}
/**
* Gets the progress bar step width.
*
* @return int The progress bar step width
*/
private function getStepWidth()
private function getStepWidth(): int
{
return $this->stepWidth;
}
/**
* Gets the current progress bar percent.
*
* @return float The current progress bar percent
*/
public function getProgressPercent()
public function getProgressPercent(): float
{
return $this->percent;
}
/**
* Sets the progress bar width.
*
* @param int $size The progress bar size
*/
public function setBarWidth($size)
public function getBarOffset(): float
{
$this->barWidth = max(1, (int) $size);
return floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth);
}
/**
* Gets the progress bar width.
*
* @return int The progress bar size
*/
public function getBarWidth()
public function getEstimated(): float
{
if (!$this->step) {
return 0;
}
return round((time() - $this->startTime) / $this->step * $this->max);
}
public function getRemaining(): float
{
if (!$this->step) {
return 0;
}
return round((time() - $this->startTime) / $this->step * ($this->max - $this->step));
}
public function setBarWidth(int $size)
{
$this->barWidth = max(1, $size);
}
public function getBarWidth(): int
{
return $this->barWidth;
}
/**
* Sets the bar character.
*
* @param string $char A character
*/
public function setBarCharacter($char)
public function setBarCharacter(string $char)
{
$this->barChar = $char;
}
/**
* Gets the bar character.
*
* @return string A character
*/
public function getBarCharacter()
public function getBarCharacter(): string
{
if (null === $this->barChar) {
return $this->max ? '=' : $this->emptyBarChar;
}
return $this->barChar;
return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar);
}
/**
* Sets the empty bar character.
*
* @param string $char A character
*/
public function setEmptyBarCharacter($char)
public function setEmptyBarCharacter(string $char)
{
$this->emptyBarChar = $char;
}
/**
* Gets the empty bar character.
*
* @return string A character
*/
public function getEmptyBarCharacter()
public function getEmptyBarCharacter(): string
{
return $this->emptyBarChar;
}
/**
* Sets the progress bar character.
*
* @param string $char A character
*/
public function setProgressCharacter($char)
public function setProgressCharacter(string $char)
{
$this->progressChar = $char;
}
/**
* Gets the progress bar character.
*
* @return string A character
*/
public function getProgressCharacter()
public function getProgressCharacter(): string
{
return $this->progressChar;
}
/**
* Sets the progress bar format.
*
* @param string $format The format
*/
public function setFormat($format)
public function setFormat(string $format)
{
$this->format = null;
$this->internalFormat = $format;
@@ -310,11 +263,39 @@ final class ProgressBar
/**
* Sets the redraw frequency.
*
* @param int|float $freq The frequency in steps
* @param int|null $freq The frequency in steps
*/
public function setRedrawFrequency($freq)
public function setRedrawFrequency(?int $freq)
{
$this->redrawFreq = max((int) $freq, 1);
$this->redrawFreq = null !== $freq ? max(1, $freq) : null;
}
public function minSecondsBetweenRedraws(float $seconds): void
{
$this->minSecondsBetweenRedraws = $seconds;
}
public function maxSecondsBetweenRedraws(float $seconds): void
{
$this->maxSecondsBetweenRedraws = $seconds;
}
/**
* Returns an iterator that will automatically update the progress bar when iterated.
*
* @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable
*/
public function iterate(iterable $iterable, int $max = null): iterable
{
$this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0));
foreach ($iterable as $key => $value) {
yield $key => $value;
$this->advance();
}
$this->finish();
}
/**
@@ -322,7 +303,7 @@ final class ProgressBar
*
* @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged
*/
public function start($max = null)
public function start(int $max = null)
{
$this->startTime = time();
$this->step = 0;
@@ -340,49 +321,63 @@ final class ProgressBar
*
* @param int $step Number of steps to advance
*/
public function advance($step = 1)
public function advance(int $step = 1)
{
$this->setProgress($this->step + $step);
}
/**
* Sets whether to overwrite the progressbar, false for new line.
*
* @param bool $overwrite
*/
public function setOverwrite($overwrite)
public function setOverwrite(bool $overwrite)
{
$this->overwrite = (bool) $overwrite;
$this->overwrite = $overwrite;
}
/**
* Sets the current progress.
*
* @param int $step The current progress
*/
public function setProgress($step)
public function setProgress(int $step)
{
$step = (int) $step;
if ($this->max && $step > $this->max) {
$this->max = $step;
} elseif ($step < 0) {
$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();
}
}
public function setMaxSteps(int $max)
{
$this->format = null;
$this->max = max(0, $max);
$this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4;
}
/**
* Finishes the progress output.
*/
public function finish()
public function finish(): void
{
if (!$this->max) {
$this->max = $this->step;
@@ -399,7 +394,7 @@ final class ProgressBar
/**
* Outputs the current progress string.
*/
public function display()
public function display(): void
{
if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
return;
@@ -419,7 +414,7 @@ final class ProgressBar
* while a progress bar is running.
* Call display() to show the progress bar again.
*/
public function clear()
public function clear(): void
{
if (!$this->overwrite) {
return;
@@ -432,12 +427,7 @@ final class ProgressBar
$this->overwrite('');
}
/**
* Sets the progress bar format.
*
* @param string $format The format
*/
private function setRealFormat($format)
private function setRealFormat(string $format)
{
// try to use the _nomax variant if available
if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {
@@ -447,148 +437,139 @@ final class ProgressBar
} else {
$this->format = $format;
}
$this->formatLineCount = substr_count($this->format, "\n");
}
/**
* Sets the progress bar maximal steps.
*
* @param int $max The progress bar max steps
*/
private function setMaxSteps($max)
{
$this->max = max(0, (int) $max);
$this->stepWidth = $this->max ? Helper::strlen($this->max) : 4;
}
/**
* Overwrites a previous message to the output.
*
* @param string $message The message
*/
private function overwrite($message)
private function overwrite(string $message): void
{
if ($this->previousMessage === $message) {
return;
}
$originalMessage = $message;
if ($this->overwrite) {
if (!$this->firstRun) {
// Move the cursor to the beginning of the line
$this->output->write("\x0D");
if (null !== $this->previousMessage) {
if ($this->output instanceof ConsoleSectionOutput) {
$messageLines = explode("\n", $this->previousMessage);
$lineCount = \count($messageLines);
foreach ($messageLines as $messageLine) {
$messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine));
if ($messageLineLength > $this->terminal->getWidth()) {
$lineCount += floor($messageLineLength / $this->terminal->getWidth());
}
}
$this->output->clear($lineCount);
} else {
$lineCount = substr_count($this->previousMessage, "\n");
for ($i = 0; $i < $lineCount; ++$i) {
$this->cursor->moveToColumn(1);
$this->cursor->clearLine();
$this->cursor->moveUp();
}
// Erase the line
$this->output->write("\x1B[2K");
// Erase previous lines
if ($this->formatLineCount > 0) {
$this->output->write(str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount));
$this->cursor->moveToColumn(1);
$this->cursor->clearLine();
}
}
} elseif ($this->step > 0) {
$this->output->writeln('');
$message = \PHP_EOL.$message;
}
$this->firstRun = false;
$this->previousMessage = $originalMessage;
$this->lastWriteTime = microtime(true);
$this->output->write($message);
++$this->writeCount;
}
private function determineBestFormat()
private function determineBestFormat(): string
{
switch ($this->output->getVerbosity()) {
// OutputInterface::VERBOSITY_QUIET: display is disabled anyway
case OutputInterface::VERBOSITY_VERBOSE:
return $this->max ? 'verbose' : 'verbose_nomax';
return $this->max ? self::FORMAT_VERBOSE : self::FORMAT_VERBOSE_NOMAX;
case OutputInterface::VERBOSITY_VERY_VERBOSE:
return $this->max ? 'very_verbose' : 'very_verbose_nomax';
return $this->max ? self::FORMAT_VERY_VERBOSE : self::FORMAT_VERY_VERBOSE_NOMAX;
case OutputInterface::VERBOSITY_DEBUG:
return $this->max ? 'debug' : 'debug_nomax';
return $this->max ? self::FORMAT_DEBUG : self::FORMAT_DEBUG_NOMAX;
default:
return $this->max ? 'normal' : 'normal_nomax';
return $this->max ? self::FORMAT_NORMAL : self::FORMAT_NORMAL_NOMAX;
}
}
private static function initPlaceholderFormatters()
private static function initPlaceholderFormatters(): array
{
return array(
'bar' => function (ProgressBar $bar, OutputInterface $output) {
$completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth());
return [
'bar' => function (self $bar, OutputInterface $output) {
$completeBars = $bar->getBarOffset();
$display = str_repeat($bar->getBarCharacter(), $completeBars);
if ($completeBars < $bar->getBarWidth()) {
$emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
$emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter()));
$display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
}
return $display;
},
'elapsed' => function (ProgressBar $bar) {
'elapsed' => function (self $bar) {
return Helper::formatTime(time() - $bar->getStartTime());
},
'remaining' => function (ProgressBar $bar) {
'remaining' => function (self $bar) {
if (!$bar->getMaxSteps()) {
throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
}
if (!$bar->getProgress()) {
$remaining = 0;
} else {
$remaining = round((time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress()));
}
return Helper::formatTime($remaining);
return Helper::formatTime($bar->getRemaining());
},
'estimated' => function (ProgressBar $bar) {
'estimated' => function (self $bar) {
if (!$bar->getMaxSteps()) {
throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
}
if (!$bar->getProgress()) {
$estimated = 0;
} else {
$estimated = round((time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps());
}
return Helper::formatTime($estimated);
return Helper::formatTime($bar->getEstimated());
},
'memory' => function (ProgressBar $bar) {
'memory' => function (self $bar) {
return Helper::formatMemory(memory_get_usage(true));
},
'current' => function (ProgressBar $bar) {
return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', STR_PAD_LEFT);
'current' => function (self $bar) {
return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT);
},
'max' => function (ProgressBar $bar) {
'max' => function (self $bar) {
return $bar->getMaxSteps();
},
'percent' => function (ProgressBar $bar) {
'percent' => function (self $bar) {
return floor($bar->getProgressPercent() * 100);
},
);
];
}
private static function initFormats()
private static function initFormats(): array
{
return array(
'normal' => ' %current%/%max% [%bar%] %percent:3s%%',
'normal_nomax' => ' %current% [%bar%]',
return [
self::FORMAT_NORMAL => ' %current%/%max% [%bar%] %percent:3s%%',
self::FORMAT_NORMAL_NOMAX => ' %current% [%bar%]',
'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
self::FORMAT_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
self::FORMAT_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%',
'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
self::FORMAT_VERY_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
self::FORMAT_VERY_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%',
'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
);
self::FORMAT_DEBUG => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
self::FORMAT_DEBUG_NOMAX => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
];
}
/**
* @return string
*/
private function buildLine()
private function buildLine(): string
{
\assert(null !== $this->format);
$regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i";
$callback = function ($matches) {
if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) {
$text = call_user_func($formatter, $this, $this->output);
$text = $formatter($this, $this->output);
} elseif (isset($this->messages[$matches[1]])) {
$text = $this->messages[$matches[1]];
} else {
@@ -605,7 +586,7 @@ final class ProgressBar
// gets string length for each sub line with multiline format
$linesLength = array_map(function ($subLine) {
return Helper::strlenWithoutDecoration($this->output->getFormatter(), rtrim($subLine, "\r"));
return Helper::width(Helper::removeDecoration($this->output->getFormatter(), rtrim($subLine, "\r")));
}, explode("\n", $line));
$linesWidth = max($linesLength);