PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Zend/ProgressBar/Adapter/Console.php

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