PageRenderTime 25ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/Phrozn/Runner/CommandLine/Callback/Base.php

https://github.com/ezimuel/phrozn
PHP | 378 lines | 193 code | 37 blank | 148 comment | 28 complexity | 32e9426a27dc4c2e41671e57967600cd MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright 2011 Victor Farazdagi
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. * @category Phrozn
  18. * @package Phrozn\Runner\CommandLine
  19. * @author Victor Farazdagi
  20. * @copyright 2011 Victor Farazdagi
  21. * @license http://www.apache.org/licenses/LICENSE-2.0
  22. */
  23. namespace Phrozn\Runner\CommandLine\Callback;
  24. use Phrozn\Runner\CommandLine,
  25. Phrozn\Outputter\Console\Color,
  26. Phrozn\Outputter\DefaultOutputter as Outputter,
  27. Phrozn\Outputter\PlainOutputter,
  28. Phrozn\Runner\CommandLine\Reader,
  29. Symfony\Component\Yaml\Yaml,
  30. Phrozn\Runner\CommandLine\Commands;
  31. /**
  32. * Base methods for phrozn command callbacks
  33. *
  34. * @category Phrozn
  35. * @package Phrozn\Runner
  36. * @author Victor Farazdagi
  37. */
  38. abstract class Base
  39. implements CommandLine\Callback
  40. {
  41. /**
  42. * Status constants
  43. */
  44. const STATUS_FAIL = ' [%rFAIL%n] ';
  45. const STATUS_ADDED = ' [%gADDED%n] ';
  46. const STATUS_DELETED = ' [%gDELETED%n] ';
  47. const STATUS_OK = ' [%gOK%n] ';
  48. /**
  49. * Whether to spice output with ANSI colors
  50. */
  51. private $useAnsiColors;
  52. /**
  53. * @var \Console_CommandLine_Outputter
  54. */
  55. private $outputter;
  56. /**
  57. * @var \Console_CommandLine_Result
  58. */
  59. private $result;
  60. /**
  61. * Contents of command-name.yml
  62. */
  63. private $config;
  64. /**
  65. * Loaded phrozn.yml
  66. *
  67. * @array
  68. */
  69. private $commandMeta;
  70. /**
  71. * Data to be used as an answer to confirmation in UTs
  72. * @var string
  73. */
  74. private $unitTestData;
  75. /**
  76. * Set CLI outputter
  77. *
  78. * @param Console_CommandLine_Outputter $outputter Where to forward output
  79. *
  80. * @return Phrozn\Runner\CommandLine\Callback
  81. */
  82. public function setOutputter($out)
  83. {
  84. $this->outputter = $out;
  85. return $this;
  86. }
  87. /**
  88. * Get CLI outputter
  89. *
  90. * @return Console_CommandLine_Outputter CLI outputter instance
  91. */
  92. public function getOutputter()
  93. {
  94. if (null === $this->outputter) {
  95. $this->outputter = new Outputter();
  96. }
  97. return $this->outputter;
  98. }
  99. /**
  100. * Result object of CLI input parsing
  101. *
  102. * @param Console_CommandLine_Result $result Parser's result
  103. *
  104. * @return Phrozn\Runner\CommandLine\Callback
  105. */
  106. public function setParseResult($result)
  107. {
  108. $this->result = $result;
  109. return $this;
  110. }
  111. /**
  112. * Get parsed result object
  113. *
  114. * @return Console_CommandLine_Result
  115. */
  116. public function getParseResult()
  117. {
  118. return $this->result;
  119. }
  120. /**
  121. * Set config data for a given callback
  122. *
  123. * @param array $config Config array
  124. *
  125. * @return Phrozn\Runner\CommandLine\Callback
  126. */
  127. public function setConfig($config)
  128. {
  129. $this->config = $config;
  130. return $this;
  131. }
  132. /**
  133. * Get command config array
  134. *
  135. * @return array
  136. */
  137. public function getConfig()
  138. {
  139. return $this->config;
  140. }
  141. /**
  142. * Output string to stdout (flushes output). Wrapper around Outputter
  143. *
  144. * @param string $str String to output
  145. *
  146. * @return \Phrozn\Runner\CommandLine\Callback
  147. */
  148. public function out($str)
  149. {
  150. $str = Color::convert($str);
  151. if ($this->useAnsiColors() === false) {
  152. $str = Color::strip($str);
  153. }
  154. $this->getOutputter()->stdout($str, '');
  155. if (count(\ob_get_status()) !== 0) {
  156. ob_flush();
  157. }
  158. }
  159. /**
  160. * Read-line either from STDIN or mock unit test data
  161. *
  162. * @return string
  163. */
  164. public function readLine()
  165. {
  166. if (null !== $this->unitTestData) {
  167. return $this->unitTestData;
  168. } else {
  169. $outputter = new PlainOutputter();
  170. $reader = new Reader();
  171. return $reader
  172. ->setOutputter($outputter)
  173. ->readLine("Type 'yes' to continue: ");
  174. }
  175. }
  176. /**
  177. * Since Unit Testing readline can be tricky, confirm answer is exposed
  178. * to unit test via this method. Simply pass the string you want to be used
  179. * in place of readline() result.
  180. *
  181. * @return \Phrozn\Runner\CommandLine\Callback
  182. */
  183. public function setUnitTestData($data)
  184. {
  185. $this->unitTestData = $data;
  186. return $this;
  187. }
  188. /**
  189. * Combine command documentation
  190. *
  191. * @param string $file Command file to combine
  192. * @param boolean $verbose Whether to provide full documentation or just summary
  193. *
  194. * @return string
  195. */
  196. protected function combine($file, $verbose = false)
  197. {
  198. $config = $this->getConfig();
  199. $file = $config['paths']['configs'] . 'commands/' . $file . '.yml';
  200. $data = Yaml::load($file);
  201. if ($data === $file) {
  202. return false;
  203. }
  204. $docs = $data['docs'];
  205. $command = $data['command'];
  206. $out = '';
  207. $out .= sprintf("%s: %s\n", $docs['name'], $docs['summary']);
  208. $out .= 'usage: ' . trim($docs['usage']) . "\n";
  209. $out .= "\n " . $this->pre($docs['description']) . "\n";
  210. $hasOptions = false;
  211. if (isset($command['options']) && count($command['options'])) {
  212. $out .= "Available options:\n";
  213. foreach ($command['options'] as $opt) {
  214. $spaces = str_repeat(' ', 30 - strlen($opt['doc_name']));
  215. $out .= " {$opt['doc_name']} {$spaces} : {$opt['description']}\n";
  216. }
  217. $hasOptions = true;
  218. }
  219. if (isset($command['arguments']) && count($command['arguments'])) {
  220. $out .= $hasOptions ? "\n": "";
  221. $out .= "Valid arguments:\n";
  222. foreach ($command['arguments'] as $arg) {
  223. $spaces = str_repeat(' ', 30 - strlen($arg['help_name']));
  224. $out .= " {$arg['help_name']} {$spaces} : {$arg['description']}\n";
  225. }
  226. }
  227. if (isset($command['commands']) && count($command['commands'])) {
  228. $out .= "Valid commands:\n";
  229. foreach ($command['commands'] as $subcommand) {
  230. $spaces = str_repeat(' ', 30 - strlen($subcommand['name']));
  231. $out .= " {$subcommand['name']} {$spaces} : {$subcommand['description']}\n";
  232. }
  233. }
  234. if ($verbose) {
  235. if (isset($docs['extradesc'])) {
  236. $out .= "\nExtended Documentation:";
  237. $out .= "\n " . $this->pre(trim($docs['extradesc'])) . "\n";
  238. }
  239. if (isset($docs['examples'])) {
  240. $out .= "\nExamples:";
  241. $out .= "\n " . $this->pre(trim($docs['examples'])) . "\n";
  242. }
  243. } else {
  244. $out .= "\nUse help with -v or --verbose option to get more information.\n";
  245. }
  246. return $out;
  247. }
  248. /**
  249. * Prepend all lines in array with intendation
  250. *
  251. * @param array $arr Array to combine
  252. *
  253. * @return string
  254. */
  255. protected function pre($arr)
  256. {
  257. return implode("\n ", explode("\n", $arr));
  258. }
  259. /**
  260. * Phrozn CLI header
  261. *
  262. * @return string
  263. */
  264. protected function getHeader()
  265. {
  266. $meta = $this->getCommandMeta();
  267. return $out = "%P{$meta['name']} {$meta['version']} by {$meta['author']}\n%n";
  268. }
  269. /**
  270. * Phrozn CLI footer
  271. *
  272. * @return string
  273. */
  274. protected function getFooter()
  275. {
  276. $meta = $this->getCommandMeta();
  277. $out = "\n{$meta['description']}\n";
  278. $out .= "For additional information, see %9http://phrozn.info%n";
  279. return $out;
  280. }
  281. protected function pad($str)
  282. {
  283. return str_repeat(' ', strlen(Color::strip(Color::convert($str))));
  284. }
  285. /**
  286. * See whether given path is absolute or relative
  287. *
  288. * @param string $path Path to check
  289. *
  290. * @return boolean
  291. */
  292. protected function isAbsolute($path)
  293. {
  294. if (PHP_OS == 'WINNT' || PHP_OS == 'WIN32') {
  295. $pattern = '/^[a-zA-z]:.*[^.lnk]$/';
  296. return preg_match($pattern, $path);
  297. } else {
  298. return $path{0} == '/';
  299. }
  300. }
  301. /**
  302. * Extract path argument or fallback to cwd
  303. *
  304. * @param string $name Name of the path argument
  305. * @param boolean $realpath Whether to apply realpath() to path
  306. * @param \Console_CommandLine_Result $command Command line result to use
  307. *
  308. * @return string
  309. */
  310. protected function getPathArgument($name, $realpath = true, $command = null)
  311. {
  312. if (null == $command) {
  313. $command = $this->getParseResult()->command;
  314. }
  315. $path = isset($command->args[$name]) ? $command->args[$name] : \getcwd();
  316. if (!$this->isAbsolute($path)) { // not an absolute path
  317. $path = \getcwd() . '/./' . $path;
  318. }
  319. if ($realpath) {
  320. $path = realpath($path);
  321. }
  322. return $path;
  323. }
  324. private function useAnsiColors()
  325. {
  326. if (null === $this->useAnsiColors) {
  327. $config = $this->getConfig();
  328. $meta = Yaml::load($config['paths']['configs'] . 'phrozn.yml');
  329. $this->useAnsiColors = (bool)$meta['use_ansi_colors'];
  330. }
  331. return $this->useAnsiColors;
  332. }
  333. private function getCommandMeta()
  334. {
  335. if (null === $this->commandMeta) {
  336. $config = $this->getConfig();
  337. $this->commandMeta = Yaml::load($config['paths']['configs'] . 'phrozn.yml');
  338. }
  339. return $this->commandMeta;
  340. }
  341. }