PageRenderTime 1212ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 0ms

/monica/monica/vendor/zendframework/zendframework/library/Zend/ProgressBar/Adapter/Console.php

https://bitbucket.org/alexandretaz/maniac_divers
PHP | 519 lines | 237 code | 81 blank | 201 comment | 32 complexity | 21fad483d975a7eb9ad63b17bf955b30 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\ProgressBar\Adapter;
  10. use Zend\ProgressBar\Adapter\Exception;
  11. use Zend\Stdlib\ErrorHandler;
  12. use Zend\Stdlib\StringUtils;
  13. /**
  14. * Zend_ProgressBar_Adapter_Console offers a text-based progressbar for console
  15. * applications
  16. */
  17. class Console extends AbstractAdapter
  18. {
  19. /**
  20. * Percentage value of the progress
  21. */
  22. const ELEMENT_PERCENT = 'ELEMENT_PERCENT';
  23. /**
  24. * Visual value of the progress
  25. */
  26. const ELEMENT_BAR = 'ELEMENT_BAR';
  27. /**
  28. * ETA of the progress
  29. */
  30. const ELEMENT_ETA = 'ELEMENT_ETA';
  31. /**
  32. * Text part of the progress
  33. */
  34. const ELEMENT_TEXT = 'ELEMENT_TEXT';
  35. /**
  36. * Finish action: End of Line
  37. */
  38. const FINISH_ACTION_EOL = 'FINISH_ACTION_EOL';
  39. /**
  40. * Finish action: Clear Line
  41. */
  42. const FINISH_ACTION_CLEAR_LINE = 'FINISH_ACTION_CLEAR_LINE';
  43. /**
  44. * Finish action: None
  45. */
  46. const FINISH_ACTION_NONE = 'FINISH_ACTION_NONE';
  47. /**
  48. * Width of the progressbar
  49. *
  50. * @var integer
  51. */
  52. protected $width = null;
  53. /**
  54. * Elements to display
  55. *
  56. * @var array
  57. */
  58. protected $elements = array(self::ELEMENT_PERCENT,
  59. self::ELEMENT_BAR,
  60. self::ELEMENT_ETA);
  61. /**
  62. * Which action to do at finish call
  63. *
  64. * @var string
  65. */
  66. protected $finishAction = self::FINISH_ACTION_EOL;
  67. /**
  68. * Width of the bar element
  69. *
  70. * @var integer
  71. */
  72. protected $barWidth;
  73. /**
  74. * Left character(s) within the bar
  75. *
  76. * @var string
  77. */
  78. protected $barLeftChar = '#';
  79. /**
  80. * Indicator character(s) within the bar
  81. *
  82. * @var string
  83. */
  84. protected $barIndicatorChar = '';
  85. /**
  86. * Right character(s) within the bar
  87. *
  88. * @var string
  89. */
  90. protected $barRightChar = '-';
  91. /**
  92. * Output-stream, when STDOUT is not defined (e.g. in CGI) or set manually
  93. *
  94. * @var resource
  95. */
  96. protected $outputStream = null;
  97. /**
  98. * Width of the text element
  99. *
  100. * @var string
  101. */
  102. protected $textWidth = 20;
  103. /**
  104. * Whether the output started yet or not
  105. *
  106. * @var bool
  107. */
  108. protected $outputStarted = false;
  109. /**
  110. * Charset of text element
  111. *
  112. * @var string
  113. */
  114. protected $charset = 'utf-8';
  115. /**
  116. * Defined by Zend_ProgressBar_Adapter
  117. *
  118. * @param array|\Traversable $options
  119. */
  120. public function __construct($options = null)
  121. {
  122. // Call parent constructor with options
  123. parent::__construct($options);
  124. // Check if a width was set, else use auto width
  125. if ($this->width === null) {
  126. $this->setWidth();
  127. }
  128. }
  129. /**
  130. * Close local stdout, when open
  131. */
  132. public function __destruct()
  133. {
  134. if ($this->outputStream !== null) {
  135. fclose($this->outputStream);
  136. }
  137. }
  138. /**
  139. * Set a different output-stream
  140. *
  141. * @param string $resource
  142. * @throws Exception\RuntimeException
  143. * @return \Zend\ProgressBar\Adapter\Console
  144. */
  145. public function setOutputStream($resource)
  146. {
  147. ErrorHandler::start();
  148. $stream = fopen($resource, 'w');
  149. $error = ErrorHandler::stop();
  150. if ($stream === false) {
  151. throw new Exception\RuntimeException('Unable to open stream', 0, $error);
  152. }
  153. if ($this->outputStream !== null) {
  154. fclose($this->outputStream);
  155. }
  156. $this->outputStream = $stream;
  157. }
  158. /**
  159. * Get the current output stream
  160. *
  161. * @return resource
  162. */
  163. public function getOutputStream()
  164. {
  165. if ($this->outputStream === null) {
  166. if (!defined('STDOUT')) {
  167. $this->outputStream = fopen('php://stdout', 'w');
  168. } else {
  169. return STDOUT;
  170. }
  171. }
  172. return $this->outputStream;
  173. }
  174. /**
  175. * Set the width of the progressbar
  176. *
  177. * @param integer $width
  178. * @return \Zend\ProgressBar\Adapter\Console
  179. */
  180. public function setWidth($width = null)
  181. {
  182. if ($width === null || !is_integer($width)) {
  183. if (substr(PHP_OS, 0, 3) === 'WIN') {
  184. // We have to default to 79 on windows, because the windows
  185. // terminal always has a fixed width of 80 characters and the
  186. // cursor is counted to the line, else windows would line break
  187. // after every update.
  188. $this->width = 79;
  189. } else {
  190. // Set the default width of 80
  191. $this->width = 80;
  192. // Try to determine the width through stty
  193. ErrorHandler::start();
  194. if (preg_match('#\d+ (\d+)#', shell_exec('stty size'), $match) === 1) {
  195. $this->width = (int) $match[1];
  196. } elseif (preg_match('#columns = (\d+);#', shell_exec('stty'), $match) === 1) {
  197. $this->width = (int) $match[1];
  198. }
  199. ErrorHandler::stop();
  200. }
  201. } else {
  202. $this->width = (int) $width;
  203. }
  204. $this->_calculateBarWidth();
  205. return $this;
  206. }
  207. /**
  208. * Set the elements to display with the progressbar
  209. *
  210. * @param array $elements
  211. * @throws \Zend\ProgressBar\Adapter\Exception\InvalidArgumentException When an invalid element is found in the array
  212. * @return \Zend\ProgressBar\Adapter\Console
  213. */
  214. public function setElements(array $elements)
  215. {
  216. $allowedElements = array(self::ELEMENT_PERCENT,
  217. self::ELEMENT_BAR,
  218. self::ELEMENT_ETA,
  219. self::ELEMENT_TEXT);
  220. if (count(array_diff($elements, $allowedElements)) > 0) {
  221. throw new Exception\InvalidArgumentException('Invalid element found in $elements array');
  222. }
  223. $this->elements = $elements;
  224. $this->_calculateBarWidth();
  225. return $this;
  226. }
  227. /**
  228. * Set the left-hand character for the bar
  229. *
  230. * @param string $char
  231. * @throws \Zend\ProgressBar\Adapter\Exception\InvalidArgumentException When character is empty
  232. * @return \Zend\ProgressBar\Adapter\Console
  233. */
  234. public function setBarLeftChar($char)
  235. {
  236. if (empty($char)) {
  237. throw new Exception\InvalidArgumentException('Character may not be empty');
  238. }
  239. $this->barLeftChar = (string) $char;
  240. return $this;
  241. }
  242. /**
  243. * Set the right-hand character for the bar
  244. *
  245. * @param string $char
  246. * @throws \Zend\ProgressBar\Adapter\Exception\InvalidArgumentException When character is empty
  247. * @return \Zend\ProgressBar\Adapter\Console
  248. */
  249. public function setBarRightChar($char)
  250. {
  251. if (empty($char)) {
  252. throw new Exception\InvalidArgumentException('Character may not be empty');
  253. }
  254. $this->barRightChar = (string) $char;
  255. return $this;
  256. }
  257. /**
  258. * Set the indicator character for the bar
  259. *
  260. * @param string $char
  261. * @return \Zend\ProgressBar\Adapter\Console
  262. */
  263. public function setBarIndicatorChar($char)
  264. {
  265. $this->barIndicatorChar = (string) $char;
  266. return $this;
  267. }
  268. /**
  269. * Set the width of the text element
  270. *
  271. * @param integer $width
  272. * @return \Zend\ProgressBar\Adapter\Console
  273. */
  274. public function setTextWidth($width)
  275. {
  276. $this->textWidth = (int) $width;
  277. $this->_calculateBarWidth();
  278. return $this;
  279. }
  280. /**
  281. * Set the charset of the text element
  282. *
  283. * @param string $charset
  284. */
  285. public function setCharset($charset)
  286. {
  287. $this->charset = $charset;
  288. }
  289. /**
  290. * Set the finish action
  291. *
  292. * @param string $action
  293. * @throws \Zend\ProgressBar\Adapter\Exception\InvalidArgumentException When an invalid action is specified
  294. * @return \Zend\ProgressBar\Adapter\Console
  295. */
  296. public function setFinishAction($action)
  297. {
  298. $allowedActions = array(self::FINISH_ACTION_CLEAR_LINE,
  299. self::FINISH_ACTION_EOL,
  300. self::FINISH_ACTION_NONE);
  301. if (!in_array($action, $allowedActions)) {
  302. throw new Exception\InvalidArgumentException('Invalid finish action specified');
  303. }
  304. $this->finishAction = $action;
  305. return $this;
  306. }
  307. /**
  308. * Defined by Zend\ProgressBar\Adapter\AbstractAdapter
  309. *
  310. * @param float $current Current progress value
  311. * @param float $max Max progress value
  312. * @param float $percent Current percent value
  313. * @param integer $timeTaken Taken time in seconds
  314. * @param integer $timeRemaining Remaining time in seconds
  315. * @param string $text Status text
  316. * @return void
  317. */
  318. public function notify($current, $max, $percent, $timeTaken, $timeRemaining, $text)
  319. {
  320. // See if we must clear the line
  321. if ($this->outputStarted) {
  322. $data = str_repeat("\x08", $this->width);
  323. } else {
  324. $data = '';
  325. $this->outputStarted = true;
  326. }
  327. // Build all elements
  328. $renderedElements = array();
  329. foreach ($this->elements as $element) {
  330. switch ($element) {
  331. case self::ELEMENT_BAR:
  332. $visualWidth = $this->barWidth - 2;
  333. $bar = '[';
  334. $indicatorWidth = strlen($this->barIndicatorChar);
  335. $doneWidth = min($visualWidth - $indicatorWidth, round($visualWidth * $percent));
  336. if ($doneWidth > 0) {
  337. $bar .= substr(str_repeat($this->barLeftChar, ceil($doneWidth / strlen($this->barLeftChar))), 0, $doneWidth);
  338. }
  339. $bar .= $this->barIndicatorChar;
  340. $leftWidth = $visualWidth - $doneWidth - $indicatorWidth;
  341. if ($leftWidth > 0) {
  342. $bar .= substr(str_repeat($this->barRightChar, ceil($leftWidth / strlen($this->barRightChar))), 0, $leftWidth);
  343. }
  344. $bar .= ']';
  345. $renderedElements[] = $bar;
  346. break;
  347. case self::ELEMENT_PERCENT:
  348. $renderedElements[] = str_pad(round($percent * 100), 3, ' ', STR_PAD_LEFT) . '%';
  349. break;
  350. case self::ELEMENT_ETA:
  351. // In the first 5 seconds we don't get accurate results,
  352. // this skipping technique is found in many progressbar
  353. // implementations.
  354. if ($timeTaken < 5) {
  355. $renderedElements[] = str_repeat(' ', 12);
  356. break;
  357. }
  358. if ($timeRemaining === null || $timeRemaining > 86400) {
  359. $etaFormatted = '??:??:??';
  360. } else {
  361. $hours = floor($timeRemaining / 3600);
  362. $minutes = floor(($timeRemaining % 3600) / 60);
  363. $seconds = ($timeRemaining % 3600 % 60);
  364. $etaFormatted = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
  365. }
  366. $renderedElements[] = 'ETA ' . $etaFormatted;
  367. break;
  368. case self::ELEMENT_TEXT:
  369. $renderedElements[] = StringUtils::getWrapper($this->charset)->strPad(
  370. substr($text, 0, $this->textWidth),
  371. $this->textWidth,
  372. ' ',
  373. STR_PAD_RIGHT
  374. );
  375. break;
  376. }
  377. }
  378. $data .= implode(' ', $renderedElements);
  379. // Output line data
  380. $this->_outputData($data);
  381. }
  382. /**
  383. * Defined by Zend\ProgressBar\Adapter\AbstractAdapter
  384. *
  385. * @return void
  386. */
  387. public function finish()
  388. {
  389. switch ($this->finishAction) {
  390. case self::FINISH_ACTION_EOL:
  391. $this->_outputData(PHP_EOL);
  392. break;
  393. case self::FINISH_ACTION_CLEAR_LINE:
  394. if ($this->outputStarted) {
  395. $data = str_repeat("\x08", $this->width)
  396. . str_repeat(' ', $this->width)
  397. . str_repeat("\x08", $this->width);
  398. $this->_outputData($data);
  399. }
  400. break;
  401. case self::FINISH_ACTION_NONE:
  402. break;
  403. }
  404. }
  405. /**
  406. * Calculate the bar width when other elements changed
  407. *
  408. * @return void
  409. */
  410. protected function _calculateBarWidth()
  411. {
  412. if (in_array(self::ELEMENT_BAR, $this->elements)) {
  413. $barWidth = $this->width;
  414. if (in_array(self::ELEMENT_PERCENT, $this->elements)) {
  415. $barWidth -= 4;
  416. }
  417. if (in_array(self::ELEMENT_ETA, $this->elements)) {
  418. $barWidth -= 12;
  419. }
  420. if (in_array(self::ELEMENT_TEXT, $this->elements)) {
  421. $barWidth -= $this->textWidth;
  422. }
  423. $this->barWidth = $barWidth - (count($this->elements) - 1);
  424. }
  425. }
  426. /**
  427. * Outputs given data to STDOUT.
  428. *
  429. * This split-off is required for unit-testing.
  430. *
  431. * @param string $data
  432. * @return void
  433. */
  434. protected function _outputData($data)
  435. {
  436. fwrite($this->getOutputStream(), $data);
  437. }
  438. }