cake.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. #!/usr/bin/php -q
  2. <?php
  3. /* SVN FILE: $Id$ */
  4. /**
  5. * Command-line code generation utility to automate programmer chores.
  6. *
  7. * CLI dispatcher class
  8. *
  9. * PHP versions 4 and 5
  10. *
  11. * CakePHP(tm) : Rapid Development Framework <http://www.cakephp.org/>
  12. * Copyright 2005-2007, Cake Software Foundation, Inc.
  13. * 1785 E. Sahara Avenue, Suite 490-204
  14. * Las Vegas, Nevada 89104
  15. *
  16. * Licensed under The MIT License
  17. * Redistributions of files must retain the above copyright notice.
  18. *
  19. * @filesource
  20. * @copyright Copyright 2005-2007, Cake Software Foundation, Inc.
  21. * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
  22. * @package cake
  23. * @subpackage cake.cake.scripts.bake
  24. * @since CakePHP(tm) v 1.2
  25. * @version $Revision$
  26. * @modifiedby $LastChangedBy$
  27. * @lastmodified $Date$
  28. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  29. */
  30. class ConsoleDispatcher {
  31. /**
  32. * Standard input stream.
  33. *
  34. * @var filehandle
  35. */
  36. var $stdin;
  37. /**
  38. * Standard output stream.
  39. *
  40. * @var filehandle
  41. */
  42. var $stdout;
  43. /**
  44. * Standard error stream.
  45. *
  46. * @var filehandle
  47. */
  48. var $stderr;
  49. /**
  50. * Contains command switches parsed from the command line.
  51. *
  52. * @var array
  53. */
  54. var $params = array();
  55. /**
  56. * Contains arguments parsed from the command line.
  57. *
  58. * @var array
  59. */
  60. var $args = array();
  61. /**
  62. * The file name of the script that was invoked.
  63. *
  64. * @var string
  65. */
  66. var $script = null;
  67. /**
  68. * The class name of the script that was invoked.
  69. *
  70. * @var string
  71. */
  72. var $scriptClass = null;
  73. /**
  74. * The command called if public methods are available.
  75. *
  76. * @var string
  77. */
  78. var $scriptCommand = null;
  79. /**
  80. * The path location of scripts.
  81. *
  82. * @var array
  83. */
  84. var $scriptPaths = array();
  85. /**
  86. * The path to the current script location.
  87. *
  88. * @var string
  89. */
  90. var $scriptPath = null;
  91. /**
  92. * The name of the script in lowercase underscore.
  93. *
  94. * @var string
  95. */
  96. var $scriptName = null;
  97. /**
  98. * Constructs this ConsoleDispatcher instance.
  99. *
  100. * @param array $args the argv.
  101. * @return void
  102. */
  103. function ConsoleDispatcher($args = array()) {
  104. $this->__construct($args);
  105. }
  106. function __construct($args = array()) {
  107. $this->__initConstants();
  108. $this->parseParams($args);
  109. $this->__initEnvironment();
  110. $this->dispatch();
  111. die("\n");
  112. }
  113. /**
  114. * Defines core configuration.
  115. *
  116. * @return void
  117. */
  118. function __initConstants() {
  119. if (function_exists('ini_set')) {
  120. ini_set('display_errors', '1');
  121. ini_set('error_reporting', E_ALL);
  122. ini_set('html_errors', false);
  123. ini_set('implicit_flush', true);
  124. ini_set('max_execution_time', 60 * 5);
  125. }
  126. define('PHP5', (phpversion() >= 5));
  127. define('DS', DIRECTORY_SEPARATOR);
  128. define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));
  129. define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
  130. define('DISABLE_DEFAULT_ERROR_HANDLING', false);
  131. }
  132. /**
  133. * Defines current working environment.
  134. *
  135. * @return void
  136. */
  137. function __initEnvironment() {
  138. $this->stdin = fopen('php://stdin', 'r');
  139. $this->stdout = fopen('php://stdout', 'w');
  140. $this->stderr = fopen('php://stderr', 'w');
  141. if (!isset($this->args[0]) || !isset($this->params['working'])) {
  142. $this->stdout("\nCakePHP Console: ");
  143. $this->stdout('This file has been loaded incorrectly and cannot continue.');
  144. $this->stdout('Please make sure that ' . DIRECTORY_SEPARATOR . 'cake' . DIRECTORY_SEPARATOR . 'console is in your system path,');
  145. $this->stdout('and check the manual for the correct usage of this command.');
  146. $this->stdout('(http://manual.cakephp.org/)');
  147. exit();
  148. }
  149. if (basename(__FILE__) != basename($this->args[0])) {
  150. $this->stdout("\nCakePHP Console: ");
  151. $this->stdout('Warning: the dispatcher may have been loaded incorrectly, which could lead to unexpected results...');
  152. if ($this->getInput('Continue anyway?', array('y', 'n'), 'y') == 'n') {
  153. exit();
  154. }
  155. }
  156. if (!$this->__bootstrap()) {
  157. $this->stdout("\nCakePHP Console: ");
  158. $this->stdout("\nUnable to load Cake core:");
  159. $this->stdout("\tMake sure " . DS . 'cake' . DS . 'libs exists in ' . CAKE_CORE_INCLUDE_PATH);
  160. exit();
  161. }
  162. $this->shiftArgs();
  163. $this->scriptPaths = array(
  164. VENDORS . 'scripts' . DS,
  165. APP . 'vendors' . DS . 'scripts' . DS,
  166. CONSOLE_LIBS
  167. );
  168. }
  169. /**
  170. * Initializes the environment and loads the Cake core.
  171. *
  172. * @return boolean Returns false if loading failed.
  173. */
  174. function __bootstrap() {
  175. define('ROOT', dirname($this->params['working']));
  176. define('APP_DIR', basename($this->params['working']));
  177. define('APP_PATH', ROOT . DS . APP_DIR . DS);
  178. $includes = array(
  179. CORE_PATH . 'cake' . DS . 'basics.php',
  180. CORE_PATH . 'cake' . DS . 'config' . DS . 'paths.php',
  181. );
  182. if(!file_exists(APP_PATH . 'config' . DS . 'core.php')) {
  183. $includes[] = CORE_PATH . 'cake' . DS . 'console' . DS . 'libs' . DS . 'templates' . DS . 'skel' . DS . 'config' . DS . 'core.php';
  184. } else {
  185. $includes[] = APP_PATH . 'config' . DS . 'core.php';
  186. }
  187. foreach ($includes as $inc) {
  188. if (!@include_once($inc)) {
  189. $this->stdout("Failed to load Cake core file {$inc}");
  190. return false;
  191. }
  192. }
  193. $libraries = array('object', 'session', 'configure', 'inflector', 'model'.DS.'connection_manager',
  194. 'debugger', 'security', 'controller' . DS . 'controller');
  195. foreach ($libraries as $inc) {
  196. if (!file_exists(LIBS . $inc . '.php')) {
  197. $this->stdout("Failed to load Cake core class " . ucwords($inc));
  198. $this->stdout("(" . LIBS.$inc.".php)");
  199. return false;
  200. }
  201. uses($inc);
  202. }
  203. Configure::getInstance(file_exists(CONFIGS . 'bootstrap.php'));
  204. Configure::write('debug', 1);
  205. return true;
  206. }
  207. /**
  208. * Dispatches a CLI request
  209. *
  210. * @return void
  211. */
  212. function dispatch() {
  213. $this->stdout("\nWelcome to CakePHP v" . Configure::version() . " Console");
  214. if (!isset($this->args[0]) || (isset($this->args[0]) && $this->args[0] != 'help')) {
  215. $this->stdout("Type 'cake help' for help\n");
  216. }
  217. $protectedCommands = array('initialize', 'main','in','out','err','hr',
  218. 'createFile', 'isDir','copyDir','Object','toString',
  219. 'requestAction','log','cakeError', 'ConsoleDispatcher',
  220. '__initConstants','__initEnvironment','__construct',
  221. 'dispatch','__bootstrap','getInput','stdout','stderr','parseParams','shiftArgs'
  222. );
  223. if (isset($this->args[0])) {
  224. // Load requested script
  225. $this->script = $this->args[0];
  226. $this->shiftArgs();
  227. $this->scriptName = Inflector::camelize($this->script);
  228. $this->scriptClass = $this->scriptName . 'Script';
  229. if (method_exists($this, $this->script) && !in_array($this->script, $protectedCommands)) {
  230. $this->{$this->script}();
  231. } else {
  232. $loaded = false;
  233. foreach($this->scriptPaths as $path) {
  234. $this->scriptPath = $path . $this->script . ".php";
  235. if (file_exists($this->scriptPath)) {
  236. $loaded = true;
  237. break;
  238. }
  239. }
  240. if (!$loaded) {
  241. $this->stdout('Unable to dispatch requested script: ', false);
  242. $this->stdout("'".$this->script.".php' does not exist in: \n" . implode("\nor ", $this->scriptPaths));
  243. exit();
  244. } else {
  245. require CONSOLE_LIBS . 'cake_script.php';
  246. require $this->scriptPath;
  247. if(class_exists($this->scriptClass)) {
  248. $script = new $this->scriptClass($this);
  249. $command = null;
  250. if(isset($this->args[0])) {
  251. $command = $this->args[0];
  252. }
  253. $classMethods = get_class_methods($script);
  254. $privateMethod = $missingCommand = false;
  255. if((in_array($command, $classMethods) || in_array(strtolower($command), $classMethods)) && strpos($command, '_', 0) === 0) {
  256. $privateMethod = true;
  257. }
  258. if(!in_array($command, $classMethods) && !in_array(strtolower($command), $classMethods)) {
  259. $missingCommand = true;
  260. }
  261. if (in_array(strtolower($command), $protectedCommands)) {
  262. $missingCommand = true;
  263. }
  264. if($command == 'help') {
  265. if(method_exists($script, 'help')) {
  266. $script->initialize();
  267. $script->help();
  268. } else {
  269. $this->help();
  270. }
  271. } else if($missingCommand && method_exists($script, 'main')) {
  272. $script->initialize();
  273. $script->main();
  274. } else if(!$privateMethod && method_exists($script, $command)) {
  275. $script->command = $command;
  276. $this->shiftArgs();
  277. $script->initialize();
  278. $script->{$command}();
  279. } else {
  280. $this->stderr("Unknown {$this->scriptName} command '$command'.\nFor usage, try 'cake {$this->script} help'.\n\n");
  281. }
  282. } else {
  283. $this->stderr('Class '.$this->scriptClass.' could not be loaded');
  284. }
  285. }
  286. }
  287. } else {
  288. $this->help();
  289. }
  290. }
  291. /**
  292. * Prompts the user for input, and returns it.
  293. *
  294. * @param string $prompt Prompt text.
  295. * @param mixed $options Array or string of options.
  296. * @param string $default Default input value.
  297. * @return Either the default value, or the user-provided input.
  298. */
  299. function getInput($prompt, $options = null, $default = null) {
  300. if (!is_array($options)) {
  301. $print_options = '';
  302. } else {
  303. $print_options = '(' . implode('/', $options) . ')';
  304. }
  305. if($default == null) {
  306. $this->stdout($prompt . " $print_options \n" . '> ', false);
  307. } else {
  308. $this->stdout($prompt . " $print_options \n" . "[$default] > ", false);
  309. }
  310. $result = trim(fgets($this->stdin));
  311. if($default != null && empty($result)) {
  312. return $default;
  313. } else {
  314. return $result;
  315. }
  316. }
  317. /**
  318. * Outputs to the stdout filehandle.
  319. *
  320. * @param string $string String to output.
  321. * @param boolean $newline If true, the outputs gets an added newline.
  322. */
  323. function stdout($string, $newline = true) {
  324. if ($newline) {
  325. fwrite($this->stdout, $string . "\n");
  326. } else {
  327. fwrite($this->stdout, $string);
  328. }
  329. }
  330. /**
  331. * Outputs to the stderr filehandle.
  332. *
  333. * @param string $string Error text to output.
  334. */
  335. function stderr($string) {
  336. fwrite($this->stderr, 'Error: '. $string);
  337. }
  338. /**
  339. * Parses command line options
  340. *
  341. * @param array $params
  342. * @return void
  343. */
  344. function parseParams($params) {
  345. $out = array();
  346. for ($i = 0; $i < count($params); $i++) {
  347. if (strpos($params[$i], '-') === 0) {
  348. $this->params[substr($params[$i], 1)] = str_replace('"', '', $params[++$i]);
  349. } else {
  350. $this->args[] = $params[$i];
  351. }
  352. }
  353. $app = 'app';
  354. if(isset($this->params['app'])) {
  355. if($this->params['app']{0} == '/') {
  356. $this->params['working'] = $this->params['app'];
  357. } else {
  358. $app = $this->params['app'];
  359. }
  360. }
  361. if(empty($this->params['working'])) {
  362. $this->params['working'] = dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . $app;
  363. }
  364. }
  365. /**
  366. * Removes first argument and shifts other arguments up
  367. *
  368. * @return boolean False if there are no arguments
  369. */
  370. function shiftArgs() {
  371. if (empty($this->args)) {
  372. return false;
  373. }
  374. unset($this->args[0]);
  375. $this->args = array_values($this->args);
  376. return true;
  377. }
  378. /**
  379. * Shows console help
  380. *
  381. * @return void
  382. */
  383. function help() {
  384. print_r($this->args);
  385. $this->stdout("\nPaths:");
  386. $this->stdout(" -working: " . $this->params['working']);
  387. $this->stdout(" -app: ". APP_DIR);
  388. $this->stdout(" -cake: " . CORE_PATH);
  389. $this->stdout("\nAvailable Scripts:");
  390. foreach($this->scriptPaths as $path) {
  391. $this->stdout("\n " . $path . ":");
  392. foreach (listClasses($path) as $script) {
  393. if ($script != 'cake_script.php') {
  394. $this->stdout("\t - " . r('.php', '', $script));
  395. }
  396. }
  397. }
  398. $this->stdout("\nTo run a command, type 'cake script_name [args]'");
  399. $this->stdout("To get help on a specific command, type 'cake script_name help'");
  400. }
  401. }
  402. if (!defined('DISABLE_AUTO_DISPATCH')) {
  403. $dispatcher = new ConsoleDispatcher($argv);
  404. }
  405. ?>