PageRenderTime 28ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/symfony/console/Helper/ProgressBar.php

https://gitlab.com/Pasantias/pasantiasASLG
PHP | 620 lines | 334 code | 78 blank | 208 comment | 36 complexity | 428ff60914ac46b1c29372fb7ea2919a MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Console\Helper;
  11. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  12. use Symfony\Component\Console\Output\OutputInterface;
  13. /**
  14. * The ProgressBar provides helpers to display progress output.
  15. *
  16. * @author Fabien Potencier <fabien@symfony.com>
  17. * @author Chris Jones <leeked@gmail.com>
  18. */
  19. class ProgressBar
  20. {
  21. // options
  22. private $barWidth = 28;
  23. private $barChar;
  24. private $emptyBarChar = '-';
  25. private $progressChar = '>';
  26. private $format;
  27. private $internalFormat;
  28. private $redrawFreq = 1;
  29. /**
  30. * @var OutputInterface
  31. */
  32. private $output;
  33. private $step = 0;
  34. private $max;
  35. private $startTime;
  36. private $stepWidth;
  37. private $percent = 0.0;
  38. private $formatLineCount;
  39. private $messages;
  40. private $overwrite = true;
  41. private static $formatters;
  42. private static $formats;
  43. /**
  44. * Constructor.
  45. *
  46. * @param OutputInterface $output An OutputInterface instance
  47. * @param int $max Maximum steps (0 if unknown)
  48. */
  49. public function __construct(OutputInterface $output, $max = 0)
  50. {
  51. if ($output instanceof ConsoleOutputInterface) {
  52. $output = $output->getErrorOutput();
  53. }
  54. $this->output = $output;
  55. $this->setMaxSteps($max);
  56. if (!$this->output->isDecorated()) {
  57. // disable overwrite when output does not support ANSI codes.
  58. $this->overwrite = false;
  59. // set a reasonable redraw frequency so output isn't flooded
  60. $this->setRedrawFrequency($max / 10);
  61. }
  62. $this->startTime = time();
  63. }
  64. /**
  65. * Sets a placeholder formatter for a given name.
  66. *
  67. * This method also allow you to override an existing placeholder.
  68. *
  69. * @param string $name The placeholder name (including the delimiter char like %)
  70. * @param callable $callable A PHP callable
  71. */
  72. public static function setPlaceholderFormatterDefinition($name, $callable)
  73. {
  74. if (!self::$formatters) {
  75. self::$formatters = self::initPlaceholderFormatters();
  76. }
  77. self::$formatters[$name] = $callable;
  78. }
  79. /**
  80. * Gets the placeholder formatter for a given name.
  81. *
  82. * @param string $name The placeholder name (including the delimiter char like %)
  83. *
  84. * @return callable|null A PHP callable
  85. */
  86. public static function getPlaceholderFormatterDefinition($name)
  87. {
  88. if (!self::$formatters) {
  89. self::$formatters = self::initPlaceholderFormatters();
  90. }
  91. return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
  92. }
  93. /**
  94. * Sets a format for a given name.
  95. *
  96. * This method also allow you to override an existing format.
  97. *
  98. * @param string $name The format name
  99. * @param string $format A format string
  100. */
  101. public static function setFormatDefinition($name, $format)
  102. {
  103. if (!self::$formats) {
  104. self::$formats = self::initFormats();
  105. }
  106. self::$formats[$name] = $format;
  107. }
  108. /**
  109. * Gets the format for a given name.
  110. *
  111. * @param string $name The format name
  112. *
  113. * @return string|null A format string
  114. */
  115. public static function getFormatDefinition($name)
  116. {
  117. if (!self::$formats) {
  118. self::$formats = self::initFormats();
  119. }
  120. return isset(self::$formats[$name]) ? self::$formats[$name] : null;
  121. }
  122. public function setMessage($message, $name = 'message')
  123. {
  124. $this->messages[$name] = $message;
  125. }
  126. public function getMessage($name = 'message')
  127. {
  128. return $this->messages[$name];
  129. }
  130. /**
  131. * Gets the progress bar start time.
  132. *
  133. * @return int The progress bar start time
  134. */
  135. public function getStartTime()
  136. {
  137. return $this->startTime;
  138. }
  139. /**
  140. * Gets the progress bar maximal steps.
  141. *
  142. * @return int The progress bar max steps
  143. */
  144. public function getMaxSteps()
  145. {
  146. return $this->max;
  147. }
  148. /**
  149. * Gets the progress bar step.
  150. *
  151. * @deprecated since version 2.6, to be removed in 3.0. Use {@link getProgress()} instead.
  152. *
  153. * @return int The progress bar step
  154. */
  155. public function getStep()
  156. {
  157. @trigger_error('The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the getProgress() method instead.', E_USER_DEPRECATED);
  158. return $this->getProgress();
  159. }
  160. /**
  161. * Gets the current step position.
  162. *
  163. * @return int The progress bar step
  164. */
  165. public function getProgress()
  166. {
  167. return $this->step;
  168. }
  169. /**
  170. * Gets the progress bar step width.
  171. *
  172. * @internal This method is public for PHP 5.3 compatibility, it should not be used.
  173. *
  174. * @return int The progress bar step width
  175. */
  176. public function getStepWidth()
  177. {
  178. return $this->stepWidth;
  179. }
  180. /**
  181. * Gets the current progress bar percent.
  182. *
  183. * @return float The current progress bar percent
  184. */
  185. public function getProgressPercent()
  186. {
  187. return $this->percent;
  188. }
  189. /**
  190. * Sets the progress bar width.
  191. *
  192. * @param int $size The progress bar size
  193. */
  194. public function setBarWidth($size)
  195. {
  196. $this->barWidth = (int) $size;
  197. }
  198. /**
  199. * Gets the progress bar width.
  200. *
  201. * @return int The progress bar size
  202. */
  203. public function getBarWidth()
  204. {
  205. return $this->barWidth;
  206. }
  207. /**
  208. * Sets the bar character.
  209. *
  210. * @param string $char A character
  211. */
  212. public function setBarCharacter($char)
  213. {
  214. $this->barChar = $char;
  215. }
  216. /**
  217. * Gets the bar character.
  218. *
  219. * @return string A character
  220. */
  221. public function getBarCharacter()
  222. {
  223. if (null === $this->barChar) {
  224. return $this->max ? '=' : $this->emptyBarChar;
  225. }
  226. return $this->barChar;
  227. }
  228. /**
  229. * Sets the empty bar character.
  230. *
  231. * @param string $char A character
  232. */
  233. public function setEmptyBarCharacter($char)
  234. {
  235. $this->emptyBarChar = $char;
  236. }
  237. /**
  238. * Gets the empty bar character.
  239. *
  240. * @return string A character
  241. */
  242. public function getEmptyBarCharacter()
  243. {
  244. return $this->emptyBarChar;
  245. }
  246. /**
  247. * Sets the progress bar character.
  248. *
  249. * @param string $char A character
  250. */
  251. public function setProgressCharacter($char)
  252. {
  253. $this->progressChar = $char;
  254. }
  255. /**
  256. * Gets the progress bar character.
  257. *
  258. * @return string A character
  259. */
  260. public function getProgressCharacter()
  261. {
  262. return $this->progressChar;
  263. }
  264. /**
  265. * Sets the progress bar format.
  266. *
  267. * @param string $format The format
  268. */
  269. public function setFormat($format)
  270. {
  271. $this->format = null;
  272. $this->internalFormat = $format;
  273. }
  274. /**
  275. * Sets the redraw frequency.
  276. *
  277. * @param int|float $freq The frequency in steps
  278. */
  279. public function setRedrawFrequency($freq)
  280. {
  281. $this->redrawFreq = max((int) $freq, 1);
  282. }
  283. /**
  284. * Starts the progress output.
  285. *
  286. * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged
  287. */
  288. public function start($max = null)
  289. {
  290. $this->startTime = time();
  291. $this->step = 0;
  292. $this->percent = 0.0;
  293. if (null !== $max) {
  294. $this->setMaxSteps($max);
  295. }
  296. $this->display();
  297. }
  298. /**
  299. * Advances the progress output X steps.
  300. *
  301. * @param int $step Number of steps to advance
  302. *
  303. * @throws \LogicException
  304. */
  305. public function advance($step = 1)
  306. {
  307. $this->setProgress($this->step + $step);
  308. }
  309. /**
  310. * Sets the current progress.
  311. *
  312. * @deprecated since version 2.6, to be removed in 3.0. Use {@link setProgress()} instead.
  313. *
  314. * @param int $step The current progress
  315. *
  316. * @throws \LogicException
  317. */
  318. public function setCurrent($step)
  319. {
  320. @trigger_error('The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the setProgress() method instead.', E_USER_DEPRECATED);
  321. $this->setProgress($step);
  322. }
  323. /**
  324. * Sets whether to overwrite the progressbar, false for new line.
  325. *
  326. * @param bool $overwrite
  327. */
  328. public function setOverwrite($overwrite)
  329. {
  330. $this->overwrite = (bool) $overwrite;
  331. }
  332. /**
  333. * Sets the current progress.
  334. *
  335. * @param int $step The current progress
  336. *
  337. * @throws \LogicException
  338. */
  339. public function setProgress($step)
  340. {
  341. $step = (int) $step;
  342. if ($step < $this->step) {
  343. throw new \LogicException('You can\'t regress the progress bar.');
  344. }
  345. if ($this->max && $step > $this->max) {
  346. $this->max = $step;
  347. }
  348. $prevPeriod = (int) ($this->step / $this->redrawFreq);
  349. $currPeriod = (int) ($step / $this->redrawFreq);
  350. $this->step = $step;
  351. $this->percent = $this->max ? (float) $this->step / $this->max : 0;
  352. if ($prevPeriod !== $currPeriod || $this->max === $step) {
  353. $this->display();
  354. }
  355. }
  356. /**
  357. * Finishes the progress output.
  358. */
  359. public function finish()
  360. {
  361. if (!$this->max) {
  362. $this->max = $this->step;
  363. }
  364. if ($this->step === $this->max && !$this->overwrite) {
  365. // prevent double 100% output
  366. return;
  367. }
  368. $this->setProgress($this->max);
  369. }
  370. /**
  371. * Outputs the current progress string.
  372. */
  373. public function display()
  374. {
  375. if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
  376. return;
  377. }
  378. if (null === $this->format) {
  379. $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
  380. }
  381. // these 3 variables can be removed in favor of using $this in the closure when support for PHP 5.3 will be dropped.
  382. $self = $this;
  383. $output = $this->output;
  384. $messages = $this->messages;
  385. $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self, $output, $messages) {
  386. if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
  387. $text = call_user_func($formatter, $self, $output);
  388. } elseif (isset($messages[$matches[1]])) {
  389. $text = $messages[$matches[1]];
  390. } else {
  391. return $matches[0];
  392. }
  393. if (isset($matches[2])) {
  394. $text = sprintf('%'.$matches[2], $text);
  395. }
  396. return $text;
  397. }, $this->format));
  398. }
  399. /**
  400. * Removes the progress bar from the current line.
  401. *
  402. * This is useful if you wish to write some output
  403. * while a progress bar is running.
  404. * Call display() to show the progress bar again.
  405. */
  406. public function clear()
  407. {
  408. if (!$this->overwrite) {
  409. return;
  410. }
  411. if (null === $this->format) {
  412. $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
  413. }
  414. $this->overwrite('');
  415. }
  416. /**
  417. * Sets the progress bar format.
  418. *
  419. * @param string $format The format
  420. */
  421. private function setRealFormat($format)
  422. {
  423. // try to use the _nomax variant if available
  424. if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {
  425. $this->format = self::getFormatDefinition($format.'_nomax');
  426. } elseif (null !== self::getFormatDefinition($format)) {
  427. $this->format = self::getFormatDefinition($format);
  428. } else {
  429. $this->format = $format;
  430. }
  431. $this->formatLineCount = substr_count($this->format, "\n");
  432. }
  433. /**
  434. * Sets the progress bar maximal steps.
  435. *
  436. * @param int $max The progress bar max steps
  437. */
  438. private function setMaxSteps($max)
  439. {
  440. $this->max = max(0, (int) $max);
  441. $this->stepWidth = $this->max ? Helper::strlen($this->max) : 4;
  442. }
  443. /**
  444. * Overwrites a previous message to the output.
  445. *
  446. * @param string $message The message
  447. */
  448. private function overwrite($message)
  449. {
  450. if ($this->overwrite) {
  451. // Move the cursor to the beginning of the line
  452. $this->output->write("\x0D");
  453. // Erase the line
  454. $this->output->write("\x1B[2K");
  455. // Erase previous lines
  456. if ($this->formatLineCount > 0) {
  457. $this->output->write(str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount));
  458. }
  459. } elseif ($this->step > 0) {
  460. $this->output->writeln('');
  461. }
  462. $this->output->write($message);
  463. }
  464. private function determineBestFormat()
  465. {
  466. switch ($this->output->getVerbosity()) {
  467. // OutputInterface::VERBOSITY_QUIET: display is disabled anyway
  468. case OutputInterface::VERBOSITY_VERBOSE:
  469. return $this->max ? 'verbose' : 'verbose_nomax';
  470. case OutputInterface::VERBOSITY_VERY_VERBOSE:
  471. return $this->max ? 'very_verbose' : 'very_verbose_nomax';
  472. case OutputInterface::VERBOSITY_DEBUG:
  473. return $this->max ? 'debug' : 'debug_nomax';
  474. default:
  475. return $this->max ? 'normal' : 'normal_nomax';
  476. }
  477. }
  478. private static function initPlaceholderFormatters()
  479. {
  480. return array(
  481. 'bar' => function (ProgressBar $bar, OutputInterface $output) {
  482. $completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth());
  483. $display = str_repeat($bar->getBarCharacter(), $completeBars);
  484. if ($completeBars < $bar->getBarWidth()) {
  485. $emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
  486. $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
  487. }
  488. return $display;
  489. },
  490. 'elapsed' => function (ProgressBar $bar) {
  491. return Helper::formatTime(time() - $bar->getStartTime());
  492. },
  493. 'remaining' => function (ProgressBar $bar) {
  494. if (!$bar->getMaxSteps()) {
  495. throw new \LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
  496. }
  497. if (!$bar->getProgress()) {
  498. $remaining = 0;
  499. } else {
  500. $remaining = round((time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress()));
  501. }
  502. return Helper::formatTime($remaining);
  503. },
  504. 'estimated' => function (ProgressBar $bar) {
  505. if (!$bar->getMaxSteps()) {
  506. throw new \LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
  507. }
  508. if (!$bar->getProgress()) {
  509. $estimated = 0;
  510. } else {
  511. $estimated = round((time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps());
  512. }
  513. return Helper::formatTime($estimated);
  514. },
  515. 'memory' => function (ProgressBar $bar) {
  516. return Helper::formatMemory(memory_get_usage(true));
  517. },
  518. 'current' => function (ProgressBar $bar) {
  519. return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', STR_PAD_LEFT);
  520. },
  521. 'max' => function (ProgressBar $bar) {
  522. return $bar->getMaxSteps();
  523. },
  524. 'percent' => function (ProgressBar $bar) {
  525. return floor($bar->getProgressPercent() * 100);
  526. },
  527. );
  528. }
  529. private static function initFormats()
  530. {
  531. return array(
  532. 'normal' => ' %current%/%max% [%bar%] %percent:3s%%',
  533. 'normal_nomax' => ' %current% [%bar%]',
  534. 'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
  535. 'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
  536. 'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
  537. 'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
  538. 'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
  539. 'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
  540. );
  541. }
  542. }