PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/cake/console/cake.php

https://github.com/MrRio/wildflower
PHP | 581 lines | 380 code | 38 blank | 163 comment | 73 complexity | 9e9a5378fa1c0bfea31bd8ba39e43205 MD5 | raw file
Possible License(s): LGPL-2.1
  1. #!/usr/bin/php -q
  2. <?php
  3. /* SVN FILE: $Id: cake.php 7945 2008-12-19 02:16:01Z gwoo $ */
  4. /**
  5. * Command-line code generation utility to automate programmer chores.
  6. *
  7. * Shell dispatcher class
  8. *
  9. * PHP versions 4 and 5
  10. *
  11. * CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
  12. * Copyright 2005-2008, Cake Software Foundation, Inc.
  13. *
  14. * Licensed under The MIT License
  15. * Redistributions of files must retain the above copyright notice.
  16. *
  17. * @filesource
  18. * @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
  19. * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
  20. * @package cake
  21. * @subpackage cake.cake.console
  22. * @since CakePHP(tm) v 1.2.0.5012
  23. * @version $Revision: 7945 $
  24. * @modifiedby $LastChangedBy: gwoo $
  25. * @lastmodified $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
  26. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  27. */
  28. /**
  29. * Shell dispatcher
  30. *
  31. * @package cake
  32. * @subpackage cake.cake.console
  33. */
  34. class ShellDispatcher {
  35. /**
  36. * Standard input stream.
  37. *
  38. * @var filehandle
  39. * @access public
  40. */
  41. var $stdin;
  42. /**
  43. * Standard output stream.
  44. *
  45. * @var filehandle
  46. * @access public
  47. */
  48. var $stdout;
  49. /**
  50. * Standard error stream.
  51. *
  52. * @var filehandle
  53. * @access public
  54. */
  55. var $stderr;
  56. /**
  57. * Contains command switches parsed from the command line.
  58. *
  59. * @var array
  60. * @access public
  61. */
  62. var $params = array();
  63. /**
  64. * Contains arguments parsed from the command line.
  65. *
  66. * @var array
  67. * @access public
  68. */
  69. var $args = array();
  70. /**
  71. * The file name of the shell that was invoked.
  72. *
  73. * @var string
  74. * @access public
  75. */
  76. var $shell = null;
  77. /**
  78. * The class name of the shell that was invoked.
  79. *
  80. * @var string
  81. * @access public
  82. */
  83. var $shellClass = null;
  84. /**
  85. * The command called if public methods are available.
  86. *
  87. * @var string
  88. * @access public
  89. */
  90. var $shellCommand = null;
  91. /**
  92. * The path locations of shells.
  93. *
  94. * @var array
  95. * @access public
  96. */
  97. var $shellPaths = array();
  98. /**
  99. * The path to the current shell location.
  100. *
  101. * @var string
  102. * @access public
  103. */
  104. var $shellPath = null;
  105. /**
  106. * The name of the shell in camelized.
  107. *
  108. * @var string
  109. * @access public
  110. */
  111. var $shellName = null;
  112. /**
  113. * Constructs this ShellDispatcher instance.
  114. *
  115. * @param array $args the argv.
  116. */
  117. function ShellDispatcher($args = array()) {
  118. $this->__construct($args);
  119. }
  120. /**
  121. * Constructor
  122. *
  123. * @param array $args the argv.
  124. */
  125. function __construct($args = array()) {
  126. set_time_limit(0);
  127. $this->__initConstants();
  128. $this->parseParams($args);
  129. $this->_initEnvironment();
  130. $this->__buildPaths();
  131. $this->_stop($this->dispatch());
  132. }
  133. /**
  134. * Defines core configuration.
  135. *
  136. * @access private
  137. */
  138. function __initConstants() {
  139. if (function_exists('ini_set')) {
  140. ini_set('display_errors', '1');
  141. ini_set('error_reporting', E_ALL);
  142. ini_set('html_errors', false);
  143. ini_set('implicit_flush', true);
  144. ini_set('max_execution_time', 0);
  145. }
  146. if (!defined('CAKE_CORE_INCLUDE_PATH')) {
  147. define('PHP5', (PHP_VERSION >= 5));
  148. define('DS', DIRECTORY_SEPARATOR);
  149. define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));
  150. define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
  151. define('DISABLE_DEFAULT_ERROR_HANDLING', false);
  152. define('CAKEPHP_SHELL', true);
  153. }
  154. require_once(CORE_PATH . 'cake' . DS . 'basics.php');
  155. }
  156. /**
  157. * Defines current working environment.
  158. *
  159. * @access protected
  160. */
  161. function _initEnvironment() {
  162. $this->stdin = fopen('php://stdin', 'r');
  163. $this->stdout = fopen('php://stdout', 'w');
  164. $this->stderr = fopen('php://stderr', 'w');
  165. if (!$this->__bootstrap()) {
  166. $this->stderr("\nCakePHP Console: ");
  167. $this->stderr("\nUnable to load Cake core:");
  168. $this->stderr("\tMake sure " . DS . 'cake' . DS . 'libs exists in ' . CAKE_CORE_INCLUDE_PATH);
  169. $this->_stop();
  170. }
  171. if (!isset($this->args[0]) || !isset($this->params['working'])) {
  172. $this->stderr("\nCakePHP Console: ");
  173. $this->stderr('This file has been loaded incorrectly and cannot continue.');
  174. $this->stderr('Please make sure that ' . DIRECTORY_SEPARATOR . 'cake' . DIRECTORY_SEPARATOR . 'console is in your system path,');
  175. $this->stderr('and check the manual for the correct usage of this command.');
  176. $this->stderr('(http://manual.cakephp.org/)');
  177. $this->_stop();
  178. }
  179. if (basename(__FILE__) != basename($this->args[0])) {
  180. $this->stderr("\nCakePHP Console: ");
  181. $this->stderr('Warning: the dispatcher may have been loaded incorrectly, which could lead to unexpected results...');
  182. if ($this->getInput('Continue anyway?', array('y', 'n'), 'y') == 'n') {
  183. $this->_stop();
  184. }
  185. }
  186. $this->shiftArgs();
  187. }
  188. /**
  189. * Builds the shell paths.
  190. *
  191. * @access private
  192. * @return void
  193. */
  194. function __buildPaths() {
  195. $paths = array();
  196. $pluginPaths = Configure::read('pluginPaths');
  197. foreach ($pluginPaths as $pluginPath) {
  198. $plugins = Configure::listObjects('plugin', $pluginPath);
  199. foreach ((array)$plugins as $plugin) {
  200. $path = $pluginPath . Inflector::underscore($plugin) . DS . 'vendors' . DS . 'shells' . DS;
  201. if (file_exists($path)) {
  202. $paths[] = $path;
  203. }
  204. }
  205. }
  206. $vendorPaths = array_values(Configure::read('vendorPaths'));
  207. foreach ($vendorPaths as $vendorPath) {
  208. $path = rtrim($vendorPath, DS) . DS . 'shells' . DS;
  209. if (file_exists($path)) {
  210. $paths[] = $path;
  211. }
  212. }
  213. $this->shellPaths = array_values(array_unique(array_merge($paths, Configure::read('shellPaths'))));
  214. }
  215. /**
  216. * Initializes the environment and loads the Cake core.
  217. *
  218. * @return boolean Success.
  219. * @access private
  220. */
  221. function __bootstrap() {
  222. define('ROOT', $this->params['root']);
  223. define('APP_DIR', $this->params['app']);
  224. define('APP_PATH', $this->params['working'] . DS);
  225. define('WWW_ROOT', APP_PATH . $this->params['webroot'] . DS);
  226. $includes = array(
  227. CORE_PATH . 'cake' . DS . 'config' . DS . 'paths.php',
  228. CORE_PATH . 'cake' . DS . 'libs' . DS . 'object.php',
  229. CORE_PATH . 'cake' . DS . 'libs' . DS . 'inflector.php',
  230. CORE_PATH . 'cake' . DS . 'libs' . DS . 'configure.php',
  231. CORE_PATH . 'cake' . DS . 'libs' . DS . 'file.php',
  232. CORE_PATH . 'cake' . DS . 'libs' . DS . 'cache.php',
  233. CORE_PATH . 'cake' . DS . 'libs' . DS . 'string.php',
  234. CORE_PATH . 'cake' . DS . 'libs' . DS . 'class_registry.php',
  235. CORE_PATH . 'cake' . DS . 'console' . DS . 'error.php'
  236. );
  237. foreach ($includes as $inc) {
  238. if (!require($inc)) {
  239. $this->stderr("Failed to load Cake core file {$inc}");
  240. return false;
  241. }
  242. }
  243. Configure::getInstance(file_exists(CONFIGS . 'bootstrap.php'));
  244. if (!file_exists(APP_PATH . 'config' . DS . 'core.php')) {
  245. include_once CORE_PATH . 'cake' . DS . 'console' . DS . 'libs' . DS . 'templates' . DS . 'skel' . DS . 'config' . DS . 'core.php';
  246. Configure::buildPaths(array());
  247. }
  248. Configure::write('debug', 1);
  249. return true;
  250. }
  251. /**
  252. * Dispatches a CLI request
  253. *
  254. * @access public
  255. */
  256. function dispatch() {
  257. if (isset($this->args[0])) {
  258. $plugin = null;
  259. $shell = $this->args[0];
  260. if (strpos($shell, '.') !== false) {
  261. list($plugin, $shell) = explode('.', $this->args[0]);
  262. }
  263. $this->shell = $shell;
  264. $this->shiftArgs();
  265. $this->shellName = Inflector::camelize($this->shell);
  266. $this->shellClass = $this->shellName . 'Shell';
  267. if ($this->shell === 'help') {
  268. $this->help();
  269. } else {
  270. $loaded = false;
  271. foreach ($this->shellPaths as $path) {
  272. $this->shellPath = $path . $this->shell . '.php';
  273. $isPlugin = ($plugin && strpos($path, DS . $plugin . DS . 'vendors' . DS . 'shells' . DS) !== false);
  274. if (($isPlugin && file_exists($this->shellPath)) || (!$plugin && file_exists($this->shellPath))) {
  275. $loaded = true;
  276. break;
  277. }
  278. }
  279. if ($loaded) {
  280. if (!class_exists('Shell')) {
  281. require CONSOLE_LIBS . 'shell.php';
  282. }
  283. require $this->shellPath;
  284. if (class_exists($this->shellClass)) {
  285. $command = null;
  286. if (isset($this->args[0])) {
  287. $command = $this->args[0];
  288. }
  289. $this->shellCommand = Inflector::variable($command);
  290. $shell = new $this->shellClass($this);
  291. if (strtolower(get_parent_class($shell)) == 'shell') {
  292. $shell->initialize();
  293. $shell->loadTasks();
  294. foreach ($shell->taskNames as $task) {
  295. if (strtolower(get_parent_class($shell)) == 'shell') {
  296. $shell->{$task}->initialize();
  297. $shell->{$task}->loadTasks();
  298. }
  299. }
  300. $task = Inflector::camelize($command);
  301. if (in_array($task, $shell->taskNames)) {
  302. $this->shiftArgs();
  303. $shell->{$task}->startup();
  304. if (isset($this->args[0]) && $this->args[0] == 'help') {
  305. if (method_exists($shell->{$task}, 'help')) {
  306. $shell->{$task}->help();
  307. $this->_stop();
  308. } else {
  309. $this->help();
  310. }
  311. }
  312. return $shell->{$task}->execute();
  313. }
  314. }
  315. $classMethods = get_class_methods($shell);
  316. $privateMethod = $missingCommand = false;
  317. if ((in_array($command, $classMethods) || in_array(strtolower($command), $classMethods)) && strpos($command, '_', 0) === 0) {
  318. $privateMethod = true;
  319. }
  320. if (!in_array($command, $classMethods) && !in_array(strtolower($command), $classMethods)) {
  321. $missingCommand = true;
  322. }
  323. $protectedCommands = array(
  324. 'initialize','in','out','err','hr',
  325. 'createfile', 'isdir','copydir','object','tostring',
  326. 'requestaction','log','cakeerror', 'shelldispatcher',
  327. '__initconstants','__initenvironment','__construct',
  328. 'dispatch','__bootstrap','getinput','stdout','stderr','parseparams','shiftargs'
  329. );
  330. if (in_array(strtolower($command), $protectedCommands)) {
  331. $missingCommand = true;
  332. }
  333. if ($missingCommand && method_exists($shell, 'main')) {
  334. $shell->startup();
  335. return $shell->main();
  336. } elseif (!$privateMethod && method_exists($shell, $command)) {
  337. $this->shiftArgs();
  338. $shell->startup();
  339. return $shell->{$command}();
  340. } else {
  341. $this->stderr("Unknown {$this->shellName} command '$command'.\nFor usage, try 'cake {$this->shell} help'.\n\n");
  342. }
  343. } else {
  344. $this->stderr('Class '.$this->shellClass.' could not be loaded');
  345. }
  346. } else {
  347. $this->help();
  348. }
  349. }
  350. } else {
  351. $this->help();
  352. }
  353. }
  354. /**
  355. * Prompts the user for input, and returns it.
  356. *
  357. * @param string $prompt Prompt text.
  358. * @param mixed $options Array or string of options.
  359. * @param string $default Default input value.
  360. * @return Either the default value, or the user-provided input.
  361. * @access public
  362. */
  363. function getInput($prompt, $options = null, $default = null) {
  364. if (!is_array($options)) {
  365. $printOptions = '';
  366. } else {
  367. $printOptions = '(' . implode('/', $options) . ')';
  368. }
  369. if ($default == null) {
  370. $this->stdout($prompt . " $printOptions \n" . '> ', false);
  371. } else {
  372. $this->stdout($prompt . " $printOptions \n" . "[$default] > ", false);
  373. }
  374. $result = fgets($this->stdin);
  375. if ($result === false) {
  376. exit;
  377. }
  378. $result = trim($result);
  379. if ($default != null && empty($result)) {
  380. return $default;
  381. }
  382. return $result;
  383. }
  384. /**
  385. * Outputs to the stdout filehandle.
  386. *
  387. * @param string $string String to output.
  388. * @param boolean $newline If true, the outputs gets an added newline.
  389. * @access public
  390. */
  391. function stdout($string, $newline = true) {
  392. if ($newline) {
  393. fwrite($this->stdout, $string . "\n");
  394. } else {
  395. fwrite($this->stdout, $string);
  396. }
  397. }
  398. /**
  399. * Outputs to the stderr filehandle.
  400. *
  401. * @param string $string Error text to output.
  402. * @access public
  403. */
  404. function stderr($string) {
  405. fwrite($this->stderr, 'Error: '. $string);
  406. }
  407. /**
  408. * Parses command line options
  409. *
  410. * @param array $params Parameters to parse
  411. * @access public
  412. */
  413. function parseParams($params) {
  414. $this->__parseParams($params);
  415. $defaults = array('app' => 'app', 'root' => dirname(dirname(dirname(__FILE__))), 'working' => null, 'webroot' => 'webroot');
  416. $params = array_merge($defaults, array_intersect_key($this->params, $defaults));
  417. $isWin = array_filter(array_map('strpos', $params, array('\\')));
  418. $params = str_replace('\\', '/', $params);
  419. if (!empty($params['working']) && (!isset($this->args[0]) || isset($this->args[0]) && $this->args[0]{0} !== '.')) {
  420. if (empty($this->params['app']) && $params['working'] != $params['root']) {
  421. $params['root'] = dirname($params['working']);
  422. $params['app'] = basename($params['working']);
  423. } else {
  424. $params['root'] = $params['working'];
  425. }
  426. }
  427. if ($params['app'][0] == '/' || preg_match('/([a-zA-Z])(:)/i', $params['app'], $matches)) {
  428. $params['root'] = dirname($params['app']);
  429. } elseif (strpos($params['app'], '/')) {
  430. $params['root'] .= '/' . dirname($params['app']);
  431. }
  432. $params['app'] = basename($params['app']);
  433. $params['working'] = rtrim($params['root'], '/') . '/' . $params['app'];
  434. if (!empty($matches[0]) || !empty($isWin)) {
  435. $params = str_replace('/', '\\', $params);
  436. }
  437. $this->params = array_merge($this->params, $params);
  438. }
  439. /**
  440. * Helper for recursively paraing params
  441. *
  442. * @return array params
  443. * @access private
  444. */
  445. function __parseParams($params) {
  446. $count = count($params);
  447. for ($i = 0; $i < $count; $i++) {
  448. if (isset($params[$i])) {
  449. if ($params[$i]{0} === '-') {
  450. $key = substr($params[$i], 1);
  451. $this->params[$key] = true;
  452. unset($params[$i]);
  453. if (isset($params[++$i])) {
  454. if ($params[$i]{0} !== '-') {
  455. $this->params[$key] = str_replace('"', '', $params[$i]);
  456. unset($params[$i]);
  457. } else {
  458. $i--;
  459. $this->__parseParams($params);
  460. }
  461. }
  462. } else {
  463. $this->args[] = $params[$i];
  464. unset($params[$i]);
  465. }
  466. }
  467. }
  468. }
  469. /**
  470. * Removes first argument and shifts other arguments up
  471. *
  472. * @return boolean False if there are no arguments
  473. * @access public
  474. */
  475. function shiftArgs() {
  476. if (empty($this->args)) {
  477. return false;
  478. }
  479. unset($this->args[0]);
  480. $this->args = array_values($this->args);
  481. return true;
  482. }
  483. /**
  484. * Shows console help
  485. *
  486. * @access public
  487. */
  488. function help() {
  489. $this->stdout("\nWelcome to CakePHP v" . Configure::version() . " Console");
  490. $this->stdout("---------------------------------------------------------------");
  491. $this->stdout("Current Paths:");
  492. $this->stdout(" -app: ". $this->params['app']);
  493. $this->stdout(" -working: " . rtrim($this->params['working'], DS));
  494. $this->stdout(" -root: " . rtrim($this->params['root'], DS));
  495. $this->stdout(" -core: " . rtrim(CORE_PATH, DS));
  496. $this->stdout("");
  497. $this->stdout("Changing Paths:");
  498. $this->stdout("your working path should be the same as your application path");
  499. $this->stdout("to change your path use the '-app' param.");
  500. $this->stdout("Example: -app relative/path/to/myapp or -app /absolute/path/to/myapp");
  501. $this->stdout("\nAvailable Shells:");
  502. $_shells = array();
  503. foreach ($this->shellPaths as $path) {
  504. if (is_dir($path)) {
  505. $shells = Configure::listObjects('file', $path);
  506. $path = str_replace(CORE_PATH, 'CORE/', $path);
  507. $path = str_replace(ROOT, 'ROOT', $path);
  508. $path = rtrim($path, DS);
  509. $this->stdout("\n " . $path . ":");
  510. if (empty($shells)) {
  511. $this->stdout("\t - none");
  512. } else {
  513. foreach ($shells as $shell) {
  514. if ($shell !== 'shell.php') {
  515. $this->stdout("\t " . str_replace('.php', '', $shell));
  516. }
  517. }
  518. }
  519. }
  520. }
  521. $this->stdout("\nTo run a command, type 'cake shell_name [args]'");
  522. $this->stdout("To get help on a specific command, type 'cake shell_name help'");
  523. $this->_stop();
  524. }
  525. /**
  526. * Stop execution of the current script
  527. *
  528. * @param $status see http://php.net/exit for values
  529. * @return void
  530. * @access protected
  531. */
  532. function _stop($status = 0) {
  533. exit($status);
  534. }
  535. }
  536. if (!defined('DISABLE_AUTO_DISPATCH')) {
  537. $dispatcher = new ShellDispatcher($argv);
  538. }
  539. ?>