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