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

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

https://bitbucket.org/gencer/symfony
PHP | 457 lines | 248 code | 56 blank | 153 comment | 35 complexity | 8d15d53d8300707db32bd9c300cf0a25 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\NullOutput;
  12. use Symfony\Component\Console\Output\OutputInterface;
  13. /**
  14. * The Progress class provides helpers to display progress output.
  15. *
  16. * @author Chris Jones <leeked@gmail.com>
  17. * @author Fabien Potencier <fabien@symfony.com>
  18. *
  19. * @deprecated Deprecated since 2.5, to be removed in 3.0; use ProgressBar instead.
  20. */
  21. class ProgressHelper extends Helper
  22. {
  23. const FORMAT_QUIET = ' %percent%%';
  24. const FORMAT_NORMAL = ' %current%/%max% [%bar%] %percent%%';
  25. const FORMAT_VERBOSE = ' %current%/%max% [%bar%] %percent%% Elapsed: %elapsed%';
  26. const FORMAT_QUIET_NOMAX = ' %current%';
  27. const FORMAT_NORMAL_NOMAX = ' %current% [%bar%]';
  28. const FORMAT_VERBOSE_NOMAX = ' %current% [%bar%] Elapsed: %elapsed%';
  29. // options
  30. private $barWidth = 28;
  31. private $barChar = '=';
  32. private $emptyBarChar = '-';
  33. private $progressChar = '>';
  34. private $format = null;
  35. private $redrawFreq = 1;
  36. private $lastMessagesLength;
  37. private $barCharOriginal;
  38. /**
  39. * @var OutputInterface
  40. */
  41. private $output;
  42. /**
  43. * Current step
  44. *
  45. * @var int
  46. */
  47. private $current;
  48. /**
  49. * Maximum number of steps
  50. *
  51. * @var int
  52. */
  53. private $max;
  54. /**
  55. * Start time of the progress bar
  56. *
  57. * @var int
  58. */
  59. private $startTime;
  60. /**
  61. * List of formatting variables
  62. *
  63. * @var array
  64. */
  65. private $defaultFormatVars = array(
  66. 'current',
  67. 'max',
  68. 'bar',
  69. 'percent',
  70. 'elapsed',
  71. );
  72. /**
  73. * Available formatting variables
  74. *
  75. * @var array
  76. */
  77. private $formatVars;
  78. /**
  79. * Stored format part widths (used for padding)
  80. *
  81. * @var array
  82. */
  83. private $widths = array(
  84. 'current' => 4,
  85. 'max' => 4,
  86. 'percent' => 3,
  87. 'elapsed' => 6,
  88. );
  89. /**
  90. * Various time formats
  91. *
  92. * @var array
  93. */
  94. private $timeFormats = array(
  95. array(0, '???'),
  96. array(2, '1 sec'),
  97. array(59, 'secs', 1),
  98. array(60, '1 min'),
  99. array(3600, 'mins', 60),
  100. array(5400, '1 hr'),
  101. array(86400, 'hrs', 3600),
  102. array(129600, '1 day'),
  103. array(604800, 'days', 86400),
  104. );
  105. /**
  106. * Sets the progress bar width.
  107. *
  108. * @param int $size The progress bar size
  109. */
  110. public function setBarWidth($size)
  111. {
  112. $this->barWidth = (int) $size;
  113. }
  114. /**
  115. * Sets the bar character.
  116. *
  117. * @param string $char A character
  118. */
  119. public function setBarCharacter($char)
  120. {
  121. $this->barChar = $char;
  122. }
  123. /**
  124. * Sets the empty bar character.
  125. *
  126. * @param string $char A character
  127. */
  128. public function setEmptyBarCharacter($char)
  129. {
  130. $this->emptyBarChar = $char;
  131. }
  132. /**
  133. * Sets the progress bar character.
  134. *
  135. * @param string $char A character
  136. */
  137. public function setProgressCharacter($char)
  138. {
  139. $this->progressChar = $char;
  140. }
  141. /**
  142. * Sets the progress bar format.
  143. *
  144. * @param string $format The format
  145. */
  146. public function setFormat($format)
  147. {
  148. $this->format = $format;
  149. }
  150. /**
  151. * Sets the redraw frequency.
  152. *
  153. * @param int $freq The frequency in steps
  154. */
  155. public function setRedrawFrequency($freq)
  156. {
  157. $this->redrawFreq = (int) $freq;
  158. }
  159. /**
  160. * Starts the progress output.
  161. *
  162. * @param OutputInterface $output An Output instance
  163. * @param int|null $max Maximum steps
  164. */
  165. public function start(OutputInterface $output, $max = null)
  166. {
  167. $this->startTime = time();
  168. $this->current = 0;
  169. $this->max = (int) $max;
  170. // Disabling output when it does not support ANSI codes as it would result in a broken display anyway.
  171. $this->output = $output->isDecorated() ? $output : new NullOutput();
  172. $this->lastMessagesLength = 0;
  173. $this->barCharOriginal = '';
  174. if (null === $this->format) {
  175. switch ($output->getVerbosity()) {
  176. case OutputInterface::VERBOSITY_QUIET:
  177. $this->format = self::FORMAT_QUIET_NOMAX;
  178. if ($this->max > 0) {
  179. $this->format = self::FORMAT_QUIET;
  180. }
  181. break;
  182. case OutputInterface::VERBOSITY_VERBOSE:
  183. case OutputInterface::VERBOSITY_VERY_VERBOSE:
  184. case OutputInterface::VERBOSITY_DEBUG:
  185. $this->format = self::FORMAT_VERBOSE_NOMAX;
  186. if ($this->max > 0) {
  187. $this->format = self::FORMAT_VERBOSE;
  188. }
  189. break;
  190. default:
  191. $this->format = self::FORMAT_NORMAL_NOMAX;
  192. if ($this->max > 0) {
  193. $this->format = self::FORMAT_NORMAL;
  194. }
  195. break;
  196. }
  197. }
  198. $this->initialize();
  199. }
  200. /**
  201. * Advances the progress output X steps.
  202. *
  203. * @param int $step Number of steps to advance
  204. * @param bool $redraw Whether to redraw or not
  205. *
  206. * @throws \LogicException
  207. */
  208. public function advance($step = 1, $redraw = false)
  209. {
  210. $this->setCurrent($this->current + $step, $redraw);
  211. }
  212. /**
  213. * Sets the current progress.
  214. *
  215. * @param int $current The current progress
  216. * @param bool $redraw Whether to redraw or not
  217. *
  218. * @throws \LogicException
  219. */
  220. public function setCurrent($current, $redraw = false)
  221. {
  222. if (null === $this->startTime) {
  223. throw new \LogicException('You must start the progress bar before calling setCurrent().');
  224. }
  225. $current = (int) $current;
  226. if ($current < $this->current) {
  227. throw new \LogicException('You can\'t regress the progress bar');
  228. }
  229. if (0 === $this->current) {
  230. $redraw = true;
  231. }
  232. $prevPeriod = intval($this->current / $this->redrawFreq);
  233. $this->current = $current;
  234. $currPeriod = intval($this->current / $this->redrawFreq);
  235. if ($redraw || $prevPeriod !== $currPeriod || $this->max === $this->current) {
  236. $this->display();
  237. }
  238. }
  239. /**
  240. * Outputs the current progress string.
  241. *
  242. * @param bool $finish Forces the end result
  243. *
  244. * @throws \LogicException
  245. */
  246. public function display($finish = false)
  247. {
  248. if (null === $this->startTime) {
  249. throw new \LogicException('You must start the progress bar before calling display().');
  250. }
  251. $message = $this->format;
  252. foreach ($this->generate($finish) as $name => $value) {
  253. $message = str_replace("%{$name}%", $value, $message);
  254. }
  255. $this->overwrite($this->output, $message);
  256. }
  257. /**
  258. * Removes the progress bar from the current line.
  259. *
  260. * This is useful if you wish to write some output
  261. * while a progress bar is running.
  262. * Call display() to show the progress bar again.
  263. */
  264. public function clear()
  265. {
  266. $this->overwrite($this->output, '');
  267. }
  268. /**
  269. * Finishes the progress output.
  270. */
  271. public function finish()
  272. {
  273. if (null === $this->startTime) {
  274. throw new \LogicException('You must start the progress bar before calling finish().');
  275. }
  276. if (null !== $this->startTime) {
  277. if (!$this->max) {
  278. $this->barChar = $this->barCharOriginal;
  279. $this->display(true);
  280. }
  281. $this->startTime = null;
  282. $this->output->writeln('');
  283. $this->output = null;
  284. }
  285. }
  286. /**
  287. * Initializes the progress helper.
  288. */
  289. private function initialize()
  290. {
  291. $this->formatVars = array();
  292. foreach ($this->defaultFormatVars as $var) {
  293. if (false !== strpos($this->format, "%{$var}%")) {
  294. $this->formatVars[$var] = true;
  295. }
  296. }
  297. if ($this->max > 0) {
  298. $this->widths['max'] = $this->strlen($this->max);
  299. $this->widths['current'] = $this->widths['max'];
  300. } else {
  301. $this->barCharOriginal = $this->barChar;
  302. $this->barChar = $this->emptyBarChar;
  303. }
  304. }
  305. /**
  306. * Generates the array map of format variables to values.
  307. *
  308. * @param bool $finish Forces the end result
  309. *
  310. * @return array Array of format vars and values
  311. */
  312. private function generate($finish = false)
  313. {
  314. $vars = array();
  315. $percent = 0;
  316. if ($this->max > 0) {
  317. $percent = (float) $this->current / $this->max;
  318. }
  319. if (isset($this->formatVars['bar'])) {
  320. $completeBars = 0;
  321. if ($this->max > 0) {
  322. $completeBars = floor($percent * $this->barWidth);
  323. } else {
  324. if (!$finish) {
  325. $completeBars = floor($this->current % $this->barWidth);
  326. } else {
  327. $completeBars = $this->barWidth;
  328. }
  329. }
  330. $emptyBars = $this->barWidth - $completeBars - $this->strlen($this->progressChar);
  331. $bar = str_repeat($this->barChar, $completeBars);
  332. if ($completeBars < $this->barWidth) {
  333. $bar .= $this->progressChar;
  334. $bar .= str_repeat($this->emptyBarChar, $emptyBars);
  335. }
  336. $vars['bar'] = $bar;
  337. }
  338. if (isset($this->formatVars['elapsed'])) {
  339. $elapsed = time() - $this->startTime;
  340. $vars['elapsed'] = str_pad($this->humaneTime($elapsed), $this->widths['elapsed'], ' ', STR_PAD_LEFT);
  341. }
  342. if (isset($this->formatVars['current'])) {
  343. $vars['current'] = str_pad($this->current, $this->widths['current'], ' ', STR_PAD_LEFT);
  344. }
  345. if (isset($this->formatVars['max'])) {
  346. $vars['max'] = $this->max;
  347. }
  348. if (isset($this->formatVars['percent'])) {
  349. $vars['percent'] = str_pad(floor($percent * 100), $this->widths['percent'], ' ', STR_PAD_LEFT);
  350. }
  351. return $vars;
  352. }
  353. /**
  354. * Converts seconds into human-readable format.
  355. *
  356. * @param int $secs Number of seconds
  357. *
  358. * @return string Time in readable format
  359. */
  360. private function humaneTime($secs)
  361. {
  362. $text = '';
  363. foreach ($this->timeFormats as $format) {
  364. if ($secs < $format[0]) {
  365. if (count($format) == 2) {
  366. $text = $format[1];
  367. break;
  368. } else {
  369. $text = ceil($secs / $format[2]).' '.$format[1];
  370. break;
  371. }
  372. }
  373. }
  374. return $text;
  375. }
  376. /**
  377. * Overwrites a previous message to the output.
  378. *
  379. * @param OutputInterface $output An Output instance
  380. * @param string $message The message
  381. */
  382. private function overwrite(OutputInterface $output, $message)
  383. {
  384. $length = $this->strlen($message);
  385. // append whitespace to match the last line's length
  386. if (null !== $this->lastMessagesLength && $this->lastMessagesLength > $length) {
  387. $message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
  388. }
  389. // carriage return
  390. $output->write("\x0D");
  391. $output->write($message);
  392. $this->lastMessagesLength = $this->strlen($message);
  393. }
  394. /**
  395. * {@inheritdoc}
  396. */
  397. public function getName()
  398. {
  399. return 'progress';
  400. }
  401. }