CommandListShell.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  10. * @link http://cakephp.org CakePHP Project
  11. * @package Cake.Console.Command
  12. * @since CakePHP v 2.0
  13. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  14. */
  15. App::uses('AppShell', 'Console/Command');
  16. App::uses('Inflector', 'Utility');
  17. /**
  18. * Shows a list of commands available from the console.
  19. *
  20. * @package Cake.Console.Command
  21. */
  22. class CommandListShell extends AppShell {
  23. /**
  24. * startup
  25. *
  26. * @return void
  27. */
  28. public function startup() {
  29. if (empty($this->params['xml'])) {
  30. parent::startup();
  31. }
  32. }
  33. /**
  34. * Main function Prints out the list of shells.
  35. *
  36. * @return void
  37. */
  38. public function main() {
  39. if (empty($this->params['xml'])) {
  40. $this->out(__d('cake_console', "<info>Current Paths:</info>"), 2);
  41. $this->out(" -app: " . APP_DIR);
  42. $this->out(" -working: " . rtrim(APP, DS));
  43. $this->out(" -root: " . rtrim(ROOT, DS));
  44. $this->out(" -core: " . rtrim(CORE_PATH, DS));
  45. $this->out("");
  46. $this->out(__d('cake_console', "<info>Changing Paths:</info>"), 2);
  47. $this->out(__d('cake_console', "Your working path should be the same as your application path to change your path use the '-app' param."));
  48. $this->out(__d('cake_console', "Example: -app relative/path/to/myapp or -app /absolute/path/to/myapp"), 2);
  49. $this->out(__d('cake_console', "<info>Available Shells:</info>"), 2);
  50. }
  51. $shellList = $this->_getShellList();
  52. if ($shellList) {
  53. ksort($shellList);
  54. if (empty($this->params['xml'])) {
  55. if (!empty($this->params['sort'])) {
  56. $this->_asSorted($shellList);
  57. } else {
  58. $this->_asText($shellList);
  59. }
  60. } else {
  61. $this->_asXml($shellList);
  62. }
  63. }
  64. }
  65. /**
  66. * Gets the shell command listing.
  67. *
  68. * @return array
  69. */
  70. protected function _getShellList() {
  71. $shellList = array();
  72. $skipFiles = array('AppShell');
  73. $corePath = App::core('Console/Command');
  74. $shells = App::objects('file', $corePath[0]);
  75. $shells = array_diff($shells, $skipFiles);
  76. $shellList = $this->_appendShells('CORE', $shells, $shellList);
  77. $appShells = App::objects('Console/Command', null, false);
  78. $appShells = array_diff($appShells, $shells, $skipFiles);
  79. $shellList = $this->_appendShells('app', $appShells, $shellList);
  80. $plugins = CakePlugin::loaded();
  81. foreach ($plugins as $plugin) {
  82. $pluginShells = App::objects($plugin . '.Console/Command');
  83. $shellList = $this->_appendShells($plugin, $pluginShells, $shellList);
  84. }
  85. return $shellList;
  86. }
  87. /**
  88. * Scan the provided paths for shells, and append them into $shellList
  89. *
  90. * @param string $type
  91. * @param array $shells
  92. * @param array $shellList
  93. * @return array
  94. */
  95. protected function _appendShells($type, $shells, $shellList) {
  96. foreach ($shells as $shell) {
  97. $shell = Inflector::underscore(str_replace('Shell', '', $shell));
  98. $shellList[$shell][$type] = $type;
  99. }
  100. return $shellList;
  101. }
  102. /**
  103. * Output text.
  104. *
  105. * @param array $shellList
  106. * @return void
  107. */
  108. protected function _asText($shellList) {
  109. if (DS === '/') {
  110. $width = exec('tput cols') - 2;
  111. }
  112. if (empty($width)) {
  113. $width = 80;
  114. }
  115. $columns = max(1, floor($width / 30));
  116. $rows = ceil(count($shellList) / $columns);
  117. foreach ($shellList as $shell => $types) {
  118. sort($types);
  119. $shellList[$shell] = str_pad($shell . ' [' . implode ($types, ', ') . ']', $width / $columns);
  120. }
  121. $out = array_chunk($shellList, $rows);
  122. for ($i = 0; $i < $rows; $i++) {
  123. $row = '';
  124. for ($j = 0; $j < $columns; $j++) {
  125. if (!isset($out[$j][$i])) {
  126. continue;
  127. }
  128. $row .= $out[$j][$i];
  129. }
  130. $this->out(" " . $row);
  131. }
  132. $this->out();
  133. $this->out(__d('cake_console', "To run an app or core command, type <info>cake shell_name [args]</info>"));
  134. $this->out(__d('cake_console', "To run a plugin command, type <info>cake Plugin.shell_name [args]</info>"));
  135. $this->out(__d('cake_console', "To get help on a specific command, type <info>cake shell_name --help</info>"), 2);
  136. }
  137. /**
  138. * Generates the shell list sorted by where the shells are found.
  139. *
  140. * @param array $shellList
  141. * @return void
  142. */
  143. protected function _asSorted($shellList) {
  144. $grouped = array();
  145. foreach ($shellList as $shell => $types) {
  146. foreach ($types as $type) {
  147. $type = Inflector::camelize($type);
  148. if (empty($grouped[$type])) {
  149. $grouped[$type] = array();
  150. }
  151. $grouped[$type][] = $shell;
  152. }
  153. }
  154. if (!empty($grouped['App'])) {
  155. sort($grouped['App'], SORT_STRING);
  156. $this->out('[ App ]');
  157. $this->out(' ' . implode(', ', $grouped['App']), 2);
  158. unset($grouped['App']);
  159. }
  160. foreach ($grouped as $section => $shells) {
  161. if ($section == 'CORE') {
  162. continue;
  163. }
  164. sort($shells, SORT_STRING);
  165. $this->out('[ ' . $section . ' ]');
  166. $this->out(' ' . implode(', ', $shells), 2);
  167. }
  168. if (!empty($grouped['CORE'])) {
  169. sort($grouped['CORE'], SORT_STRING);
  170. $this->out('[ Core ]');
  171. $this->out(' ' . implode(', ', $grouped['CORE']), 2);
  172. }
  173. $this->out();
  174. }
  175. /**
  176. * Output as XML
  177. *
  178. * @param array $shellList
  179. * @return void
  180. */
  181. protected function _asXml($shellList) {
  182. $plugins = CakePlugin::loaded();
  183. $shells = new SimpleXmlElement('<shells></shells>');
  184. foreach ($shellList as $name => $location) {
  185. $source = current($location);
  186. $callable = $name;
  187. if (in_array($source, $plugins)) {
  188. $callable = Inflector::camelize($source) . '.' . $name;
  189. }
  190. $shell = $shells->addChild('shell');
  191. $shell->addAttribute('name', $name);
  192. $shell->addAttribute('call_as', $callable);
  193. $shell->addAttribute('provider', $source);
  194. $shell->addAttribute('help', $callable . ' -h');
  195. }
  196. $this->stdout->outputAs(ConsoleOutput::RAW);
  197. $this->out($shells->saveXml());
  198. }
  199. /**
  200. * get the option parser
  201. *
  202. * @return void
  203. */
  204. public function getOptionParser() {
  205. $parser = parent::getOptionParser();
  206. return $parser->description(__d('cake_console', 'Get the list of available shells for this CakePHP application.'))
  207. ->addOption('xml', array(
  208. 'help' => __d('cake_console', 'Get the listing as XML.'),
  209. 'boolean' => true
  210. ))->addOption('sort', array(
  211. 'help' => __d('cake_console', 'Sorts the commands by where they are located.'),
  212. 'boolean' => true
  213. ));
  214. }
  215. }