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