PageRenderTime 40ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

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

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