00001 #!/usr/bin/php -q
00002 <?php
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 class ShellDispatcher {
00037
00038
00039
00040
00041
00042
00043 var $stdin;
00044
00045
00046
00047
00048
00049
00050 var $stdout;
00051
00052
00053
00054
00055
00056
00057 var $stderr;
00058
00059
00060
00061
00062
00063
00064 var $params = array();
00065
00066
00067
00068
00069
00070
00071 var $args = array();
00072
00073
00074
00075
00076
00077
00078 var $shell = null;
00079
00080
00081
00082
00083
00084
00085 var $shellClass = null;
00086
00087
00088
00089
00090
00091
00092 var $shellCommand = null;
00093
00094
00095
00096
00097
00098
00099 var $shellPaths = array();
00100
00101
00102
00103
00104
00105
00106 var $shellPath = null;
00107
00108
00109
00110
00111
00112
00113 var $shellName = null;
00114
00115
00116
00117
00118
00119 function ShellDispatcher($args = array()) {
00120 $this->__construct($args);
00121 }
00122
00123
00124
00125
00126
00127 function __construct($args = array()) {
00128 set_time_limit(0);
00129 $this->__initConstants();
00130 $this->parseParams($args);
00131 $this->__initEnvironment();
00132 $this->dispatch();
00133 die("\n");
00134 }
00135
00136
00137
00138
00139
00140 function __initConstants() {
00141 if (function_exists('ini_set')) {
00142 ini_set('display_errors', '1');
00143 ini_set('error_reporting', E_ALL);
00144 ini_set('html_errors', false);
00145 ini_set('implicit_flush', true);
00146 ini_set('max_execution_time', 0);
00147 }
00148
00149 if (!defined('CAKE_CORE_INCLUDE_PATH')) {
00150 define('PHP5', (phpversion() >= 5));
00151 define('DS', DIRECTORY_SEPARATOR);
00152 define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));
00153 define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
00154 define('DISABLE_DEFAULT_ERROR_HANDLING', false);
00155 define('CAKEPHP_SHELL', true);
00156 }
00157 require_once(CORE_PATH . 'cake' . DS . 'basics.php');
00158 }
00159
00160
00161
00162
00163
00164 function __initEnvironment() {
00165 $this->stdin = fopen('php:
00166 $this->stdout = fopen('php:
00167 $this->stderr = fopen('php:
00168
00169 if (!$this->__bootstrap()) {
00170 $this->stderr("\nCakePHP Console: ");
00171 $this->stderr("\nUnable to load Cake core:");
00172 $this->stderr("\tMake sure " . DS . 'cake' . DS . 'libs exists in ' . CAKE_CORE_INCLUDE_PATH);
00173 exit();
00174 }
00175
00176 if (!isset($this->args[0]) || !isset($this->params['working'])) {
00177 $this->stderr("\nCakePHP Console: ");
00178 $this->stderr('This file has been loaded incorrectly and cannot continue.');
00179 $this->stderr('Please make sure that ' . DIRECTORY_SEPARATOR . 'cake' . DIRECTORY_SEPARATOR . 'console is in your system path,');
00180 $this->stderr('and check the manual for the correct usage of this command.');
00181 $this->stderr('(http:
00182 exit();
00183 }
00184
00185 if (basename(__FILE__) != basename($this->args[0])) {
00186 $this->stderr("\nCakePHP Console: ");
00187 $this->stderr('Warning: the dispatcher may have been loaded incorrectly, which could lead to unexpected results...');
00188 if ($this->getInput('Continue anyway?', array('y', 'n'), 'y') == 'n') {
00189 exit();
00190 }
00191 }
00192
00193 $this->shiftArgs();
00194
00195 $this->shellPaths = array(
00196 APP . 'vendors' . DS . 'shells' . DS,
00197 VENDORS . 'shells' . DS,
00198 CONSOLE_LIBS
00199 );
00200 }
00201
00202
00203
00204
00205
00206
00207 function __bootstrap() {
00208
00209 define('ROOT', $this->params['root']);
00210 define('APP_DIR', $this->params['app']);
00211 define('APP_PATH', $this->params['working'] . DS);
00212 define('WWW_ROOT', APP_PATH . $this->params['webroot'] . DS);
00213
00214 $includes = array(
00215 CORE_PATH . 'cake' . DS . 'config' . DS . 'paths.php',
00216 CORE_PATH . 'cake' . DS . 'libs' . DS . 'object.php',
00217 CORE_PATH . 'cake' . DS . 'libs' . DS . 'inflector.php',
00218 CORE_PATH . 'cake' . DS . 'libs' . DS . 'configure.php',
00219 CORE_PATH . 'cake' . DS . 'libs' . DS . 'file.php',
00220 CORE_PATH . 'cake' . DS . 'libs' . DS . 'cache.php',
00221 CORE_PATH . 'cake' . DS . 'libs' . DS . 'string.php',
00222 CORE_PATH . 'cake' . DS . 'libs' . DS . 'class_registry.php',
00223 CORE_PATH . 'cake' . DS . 'console' . DS . 'error.php'
00224 );
00225
00226 foreach ($includes as $inc) {
00227 if (!require($inc)) {
00228 $this->stderr("Failed to load Cake core file {$inc}");
00229 return false;
00230 }
00231 }
00232
00233 Configure::getInstance(file_exists(CONFIGS . 'bootstrap.php'));
00234
00235 if (!file_exists(APP_PATH . 'config' . DS . 'core.php')) {
00236 include_once CORE_PATH . 'cake' . DS . 'console' . DS . 'libs' . DS . 'templates' . DS . 'skel' . DS . 'config' . DS . 'core.php';
00237 Configure::buildPaths(array());
00238 }
00239
00240 Configure::write('debug', 1);
00241 return true;
00242 }
00243
00244
00245
00246
00247
00248
00249 function dispatch() {
00250 if (isset($this->args[0])) {
00251 $plugin = null;
00252 $shell = $this->args[0];
00253 if (strpos($shell, '.') !== false) {
00254 list($plugin, $shell) = explode('.', $this->args[0]);
00255 }
00256
00257 $this->shell = $shell;
00258 $this->shiftArgs();
00259 $this->shellName = Inflector::camelize($this->shell);
00260 $this->shellClass = $this->shellName . 'Shell';
00261
00262 if ($this->shell == 'help') {
00263 $this->help();
00264 } else {
00265 $loaded = false;
00266 $paths = array();
00267
00268 if ($plugin !== null) {
00269 $pluginPaths = Configure::read('pluginPaths');
00270 $count = count($pluginPaths);
00271 for ($i = 0; $i < $count; $i++) {
00272 $paths[] = $pluginPaths[$i] . $plugin . DS . 'vendors' . DS . 'shells' . DS;
00273 }
00274 }
00275
00276 $vendorPaths = array_values(Configure::read('vendorPaths'));
00277 $count = count($vendorPaths);
00278
00279 for ($i = 0; $i < $count; $i++) {
00280 $paths[] = rtrim($vendorPaths[$i], DS) . DS . 'shells' . DS;
00281 }
00282
00283 $this->shellPaths = array_merge($paths, array(CONSOLE_LIBS));
00284 foreach ($this->shellPaths as $path) {
00285 $this->shellPath = $path . $this->shell . ".php";
00286 if (file_exists($this->shellPath)) {
00287 $loaded = true;
00288 break;
00289 }
00290 }
00291
00292 if ($loaded) {
00293 if (!class_exists('Shell')) {
00294 require CONSOLE_LIBS . 'shell.php';
00295 }
00296 require $this->shellPath;
00297 if (class_exists($this->shellClass)) {
00298 $command = null;
00299 if (isset($this->args[0])) {
00300 $command = $this->args[0];
00301 }
00302 $this->shellCommand = Inflector::variable($command);
00303 $shell = new $this->shellClass($this);
00304
00305 if (strtolower(get_parent_class($shell)) == 'shell') {
00306 $shell->initialize();
00307 $shell->loadTasks();
00308
00309 foreach ($shell->taskNames as $task) {
00310 if (strtolower(get_parent_class($shell)) == 'shell') {
00311 $shell->{$task}->initialize();
00312 $shell->{$task}->loadTasks();
00313 }
00314 }
00315
00316 $task = Inflector::camelize($command);
00317 if (in_array($task, $shell->taskNames)) {
00318 $this->shiftArgs();
00319 $shell->{$task}->startup();
00320 if (isset($this->args[0]) && $this->args[0] == 'help') {
00321 if (method_exists($shell->{$task}, 'help')) {
00322 $shell->{$task}->help();
00323 exit();
00324 } else {
00325 $this->help();
00326 }
00327 }
00328 $shell->{$task}->execute();
00329 return;
00330 }
00331 }
00332
00333 $classMethods = get_class_methods($shell);
00334
00335 $privateMethod = $missingCommand = false;
00336 if ((in_array($command, $classMethods) || in_array(strtolower($command), $classMethods)) && strpos($command, '_', 0) === 0) {
00337 $privateMethod = true;
00338 }
00339
00340 if (!in_array($command, $classMethods) && !in_array(strtolower($command), $classMethods)) {
00341 $missingCommand = true;
00342 }
00343
00344 $protectedCommands = array(
00345 'initialize','in','out','err','hr',
00346 'createfile', 'isdir','copydir','object','tostring',
00347 'requestaction','log','cakeerror', 'shelldispatcher',
00348 '__initconstants','__initenvironment','__construct',
00349 'dispatch','__bootstrap','getinput','stdout','stderr','parseparams','shiftargs'
00350 );
00351
00352 if (in_array(strtolower($command), $protectedCommands)) {
00353 $missingCommand = true;
00354 }
00355
00356 if ($missingCommand && method_exists($shell, 'main')) {
00357 $shell->startup();
00358 $shell->main();
00359 } elseif (!$privateMethod && method_exists($shell, $command)) {
00360 $this->shiftArgs();
00361 $shell->startup();
00362 $shell->{$command}();
00363 } else {
00364 $this->stderr("Unknown {$this->shellName} command '$command'.\nFor usage, try 'cake {$this->shell} help'.\n\n");
00365 }
00366 } else {
00367 $this->stderr('Class '.$this->shellClass.' could not be loaded');
00368 }
00369 } else {
00370 $this->help();
00371 }
00372 }
00373 } else {
00374 $this->help();
00375 }
00376 }
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 function getInput($prompt, $options = null, $default = null) {
00387 if (!is_array($options)) {
00388 $print_options = '';
00389 } else {
00390 $print_options = '(' . implode('/', $options) . ')';
00391 }
00392
00393 if ($default == null) {
00394 $this->stdout($prompt . " $print_options \n" . '> ', false);
00395 } else {
00396 $this->stdout($prompt . " $print_options \n" . "[$default] > ", false);
00397 }
00398 $result = fgets($this->stdin);
00399
00400 if ($result === false){
00401 exit;
00402 }
00403 $result = trim($result);
00404
00405 if ($default != null && empty($result)) {
00406 return $default;
00407 } else {
00408 return $result;
00409 }
00410 }
00411
00412
00413
00414
00415
00416
00417
00418 function stdout($string, $newline = true) {
00419 if ($newline) {
00420 fwrite($this->stdout, $string . "\n");
00421 } else {
00422 fwrite($this->stdout, $string);
00423 }
00424 }
00425
00426
00427
00428
00429
00430
00431 function stderr($string) {
00432 fwrite($this->stderr, 'Error: '. $string);
00433 }
00434
00435
00436
00437
00438
00439
00440 function parseParams($params) {
00441 $this->__parseParams($params);
00442
00443 $defaults = array('app' => 'app', 'root' => dirname(dirname(dirname(__FILE__))), 'working' => null, 'webroot' => 'webroot');
00444
00445 $params = array_merge($defaults, array_intersect_key($this->params, $defaults));
00446
00447 $isWin = array_filter(array_map('strpos', $params, array('\\')));
00448
00449 $params = str_replace('\\', '/', $params);
00450
00451 if (!empty($params['working']) && (!isset($this->args[0]) || isset($this->args[0]) && $this->args[0]{0} !== '.')) {
00452 if (empty($this->params['app']) && $params['working'] != $params['root']) {
00453 $params['root'] = dirname($params['working']);
00454 $params['app'] = basename($params['working']);
00455 } else {
00456 $params['root'] = $params['working'];
00457 }
00458 }
00459
00460 if($params['app'][0] == '/' || preg_match('/([a-z])(:)/i', $params['app'], $matches)) {
00461 $params['root'] = dirname($params['app']);
00462 } elseif (strpos($params['app'], '/')) {
00463 $params['root'] .= '/' . dirname($params['app']);
00464 }
00465
00466 $params['app'] = basename($params['app']);
00467 $params['working'] = $params['root'] . '/' . $params['app'];
00468
00469 if (!empty($matches[0]) || !empty($isWin)) {
00470 $params = str_replace('/', '\\', $params);
00471 }
00472
00473 $this->params = array_merge($this->params, $params);
00474 }
00475
00476
00477
00478
00479
00480
00481 function __parseParams($params) {
00482 $count = count($params);
00483 for ($i = 0; $i < $count; $i++) {
00484 if (isset($params[$i])) {
00485 if ($params[$i]{0} === '-') {
00486 $key = substr($params[$i], 1);
00487 $this->params[$key] = true;
00488 unset($params[$i]);
00489 if (isset($params[++$i])) {
00490 if ($params[$i]{0} !== '-') {
00491 $this->params[$key] = str_replace('"', '', $params[$i]);
00492 unset($params[$i]);
00493 } else {
00494 $i--;
00495 $this->__parseParams($params);
00496 }
00497 }
00498 } else {
00499 $this->args[] = $params[$i];
00500 unset($params[$i]);
00501 }
00502
00503 }
00504 }
00505 }
00506
00507
00508
00509
00510
00511
00512 function shiftArgs() {
00513 if (empty($this->args)) {
00514 return false;
00515 }
00516 unset($this->args[0]);
00517 $this->args = array_values($this->args);
00518 return true;
00519 }
00520
00521
00522
00523
00524
00525 function help() {
00526 $this->stdout("\nWelcome to CakePHP v" . Configure::version() . " Console");
00527 $this->stdout("---------------------------------------------------------------");
00528 $this->stdout("Current Paths:");
00529 $this->stdout(" -app: ". $this->params['app']);
00530 $this->stdout(" -working: " . $this->params['working']);
00531 $this->stdout(" -root: " . $this->params['root']);
00532 $this->stdout(" -core: " . CORE_PATH);
00533 $this->stdout("");
00534 $this->stdout("Changing Paths:");
00535 $this->stdout("your working path should be the same as your application path");
00536 $this->stdout("to change your path use the '-app' param.");
00537 $this->stdout("Example: -app relative/path/to/myapp or -app /absolute/path/to/myapp");
00538
00539 $this->stdout("\nAvailable Shells:");
00540 foreach ($this->shellPaths as $path) {
00541 if (is_dir($path)) {
00542 $shells = Configure::listObjects('file', $path);
00543 $path = r(CORE_PATH, '', $path);
00544 $this->stdout("\n " . $path . ":");
00545 if (empty($shells)) {
00546 $this->stdout("\t - none");
00547 } else {
00548 foreach ($shells as $shell) {
00549 if ($shell != 'shell.php') {
00550 $this->stdout("\t " . r('.php', '', $shell));
00551 }
00552 }
00553 }
00554 }
00555 }
00556 $this->stdout("\nTo run a command, type 'cake shell_name [args]'");
00557 $this->stdout("To get help on a specific command, type 'cake shell_name help'");
00558 exit();
00559 }
00560 }
00561 if (!defined('DISABLE_AUTO_DISPATCH')) {
00562 $dispatcher = new ShellDispatcher($argv);
00563 }
00564 ?>