2007-03-09 23:15:03 +00:00
< ? php
2007-03-27 05:10:42 +00:00
/* SVN FILE: $Id$ */
/**
2007-05-13 20:17:27 +00:00
* Base class for Shells
2007-03-27 05:10:42 +00:00
*
* Long description for file
*
* PHP versions 4 and 5
*
* CakePHP ( tm ) : Rapid Development Framework < http :// www . cakephp . org />
* Copyright 2005 - 2007 , Cake Software Foundation , Inc .
* 1785 E . Sahara Avenue , Suite 490 - 204
* Las Vegas , Nevada 89104
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice .
*
* @ filesource
* @ copyright Copyright 2005 - 2007 , Cake Software Foundation , Inc .
* @ link http :// www . cakefoundation . org / projects / info / cakephp CakePHP ( tm ) Project
* @ package cake
* @ subpackage cake . cake . scripts
* @ since CakePHP ( tm ) v 1.2 . 0.4604
* @ version $Revision $
* @ modifiedby $LastChangedBy $
* @ lastmodified $Date $
* @ license http :// www . opensource . org / licenses / mit - license . php The MIT License
*/
2007-03-09 23:15:03 +00:00
/**
* Base class for command - line utilities for automating programmer chores .
*
* @ package cake
2007-05-13 20:17:27 +00:00
* @ subpackage cake . cake . console . libs
2007-03-09 23:15:03 +00:00
*/
2007-05-13 20:17:27 +00:00
require_once CAKE . 'console' . DS . 'error.php' ;
2007-05-12 21:18:07 +00:00
class Shell extends Object {
2007-03-09 23:15:03 +00:00
/**
2007-05-12 21:18:07 +00:00
* ShellDispatcher object
2007-03-09 23:15:03 +00:00
*
2007-05-12 21:18:07 +00:00
* @ var object An instance of the ShellDispatcher object that loaded this script
2007-03-09 23:15:03 +00:00
*/
2007-05-04 19:32:05 +00:00
var $Dispatch = null ;
2007-03-09 23:15:03 +00:00
/**
* If true , the script will ask for permission to perform actions .
*
* @ var boolean
*/
var $interactive = true ;
/**
* Holds the DATABASE_CONFIG object for the app . Null if database . php could not be found ,
* or the app does not exist .
*
* @ var object
*/
var $dbConfig = null ;
/**
* Contains command switches parsed from the command line .
*
* @ var array
*/
var $params = array ();
/**
* Contains arguments parsed from the command line .
*
* @ var array
*/
var $args = array ();
2007-05-13 20:17:27 +00:00
/**
* The file name of the shell that was invoked .
*
* @ var string
*/
var $shell = null ;
/**
* The class name of the shell that was invoked .
*
* @ var string
*/
var $className = null ;
/**
* The command called if public methods are available .
*
* @ var string
*/
var $command = null ;
/**
* The name of the shell in camelized .
*
* @ var string
*/
var $name = null ;
/**
* Contains tasks to load and instantiate
*
* @ var array
*/
var $tasks = array ();
/**
* Contains models to load and instantiate
*
* @ var array
*/
var $uses = array ();
2007-03-09 23:15:03 +00:00
/**
2007-05-12 21:18:07 +00:00
* Constructs this Shell instance .
2007-03-09 23:15:03 +00:00
*
*/
function __construct ( & $dispatch ) {
2007-05-04 03:49:53 +00:00
$this -> Dispatch = & $dispatch ;
2007-05-13 20:17:27 +00:00
$vars = array ( 'params' , 'args' , 'shell' , 'shellName' => 'name' , 'shellClass' => 'className' , 'shellCommand' => 'command' );
foreach ( $vars as $key => $var ) {
if ( is_string ( $key )){
$this -> { $var } = & $this -> Dispatch -> { $key };
} else {
$this -> { $var } = & $this -> Dispatch -> { $var };
}
2007-05-12 23:40:37 +00:00
}
2007-05-13 20:17:27 +00:00
$this -> _loadTasks ();
2007-05-04 00:25:04 +00:00
}
/**
2007-05-12 21:18:07 +00:00
* Initializes the Shell
2007-05-04 00:25:04 +00:00
* can be overriden in subclasses
*
2007-05-13 20:49:37 +00:00
* @ return void
2007-05-04 03:49:53 +00:00
*/
2007-05-04 00:25:04 +00:00
function initialize () {
2007-05-13 20:17:27 +00:00
$this -> _loadModels ();
2007-05-13 20:49:37 +00:00
$this -> _welcome ();
}
/**
* Displays a header for the shell
*
* @ return void
*/
function _welcome () {
2007-05-12 19:47:14 +00:00
$this -> hr ();
2007-05-13 20:17:27 +00:00
$this -> out ( 'App : ' . APP_DIR );
2007-05-12 19:47:14 +00:00
$this -> out ( 'Path: ' . ROOT . DS . APP_DIR );
$this -> hr ();
2007-03-09 23:15:03 +00:00
}
2007-05-04 00:25:04 +00:00
/**
* Loads database file and constructs DATABASE_CONFIG class
* makes $this -> dbConfig available to subclasses
*
* @ return bool
*/
2007-05-03 21:14:46 +00:00
function _loadDbConfig () {
if ( config ( 'database' )) {
if ( class_exists ( 'DATABASE_CONFIG' )) {
$this -> dbConfig = new DATABASE_CONFIG ();
return true ;
}
}
2007-05-04 00:25:04 +00:00
$this -> err ( 'Database config could not be loaded' );
2007-05-13 01:36:56 +00:00
$this -> out ( 'Run \'bake\' to create the database configuration' );
2007-05-03 21:14:46 +00:00
return false ;
}
2007-05-04 00:25:04 +00:00
/**
2007-05-13 20:17:27 +00:00
* if var $uses = true
2007-05-04 00:25:04 +00:00
* Loads AppModel file and constructs AppModel class
* makes $this -> AppModel available to subclasses
2007-05-13 20:17:27 +00:00
* if var $uses is an array of models
2007-05-04 00:25:04 +00:00
*
* @ return bool
*/
2007-05-13 20:17:27 +00:00
function _loadModels () {
if ( $this -> uses === null || $this -> uses === false ) {
return ;
}
2007-05-03 21:14:46 +00:00
uses ( 'model' . DS . 'connection_manager' ,
'model' . DS . 'datasources' . DS . 'dbo_source' , 'model' . DS . 'model'
);
2007-05-13 20:17:27 +00:00
if ( $this -> uses === true && loadModel ()) {
2007-05-13 01:36:56 +00:00
$this -> AppModel = & new AppModel ( false , false , false );
2007-05-03 21:14:46 +00:00
return true ;
}
2007-05-13 20:17:27 +00:00
if ( $this -> uses !== true && ! empty ( $this -> uses )) {
$uses = is_array ( $this -> uses ) ? $this -> uses : array ( $this -> uses );
$this -> modelClass = $uses [ 0 ];
foreach ( $uses as $modelClass ) {
$modelKey = Inflector :: underscore ( $modelClass );
if ( ! class_exists ( $modelClass )){
loadModel ( $modelClass );
}
if ( class_exists ( $modelClass )) {
$model =& new $modelClass ();
$this -> modelNames [] = $modelClass ;
$this -> { $modelClass } =& $model ;
ClassRegistry :: addObject ( $modelKey , $model );
} else {
return $this -> cakeError ( 'missingModel' , array ( array ( 'className' => $modelClass )));
}
}
return true ;
}
2007-05-03 21:14:46 +00:00
return false ;
}
2007-05-13 20:17:27 +00:00
/**
* Loads tasks defined in var $tasks
*
* @ return bool
*/
function _loadTasks () {
if ( $this -> tasks === null || $this -> tasks === false ) {
return ;
}
2007-05-03 21:14:46 +00:00
2007-05-13 20:17:27 +00:00
if ( $this -> tasks !== true && ! empty ( $this -> tasks )) {
$tasks = $this -> tasks ;
if ( ! is_array ( $tasks )) {
$tasks = array ( $tasks );
}
$this -> taskClass = $tasks [ 0 ];
foreach ( $tasks as $taskName ) {
$taskKey = Inflector :: underscore ( $taskName );
$loaded = false ;
foreach ( $this -> Dispatch -> shellPaths as $path ) {
$taskPath = $path . 'tasks' . DS . Inflector :: underscore ( $taskName ) . '.php' ;
if ( file_exists ( $taskPath )) {
$loaded = true ;
break ;
}
}
if ( $loaded ) {
require $taskPath ;
$taskClass = Inflector :: camelize ( $taskName . 'Task' );
if ( class_exists ( $taskClass )) {
$task =& new $taskClass ( $this -> Dispatch );
$this -> taskNames [] = $taskName ;
$this -> { $taskName } =& $task ;
ClassRegistry :: addObject ( $taskKey , $task );
} else {
$this -> err ( " Task ' " . $taskName . " ' could not be loaded " );
exit ();
}
} else {
$this -> err ( " Task ' " . $taskName . " ' could not be found " );
exit ();
}
}
}
return false ;
}
2007-03-09 23:15:03 +00:00
/**
* Prompts the user for input , and returns it .
*
* @ param string $prompt Prompt text .
* @ param mixed $options Array or string of options .
* @ param string $default Default input value .
* @ return Either the default value , or the user - provided input .
*/
function in ( $prompt , $options = null , $default = null ) {
2007-05-04 03:49:53 +00:00
return $this -> Dispatch -> getInput ( $prompt , $options , $default );
2007-03-09 23:15:03 +00:00
}
/**
* Outputs to the stdout filehandle .
*
* @ param string $string String to output .
* @ param boolean $newline If true , the outputs gets an added newline .
*/
function out ( $string , $newline = true ) {
2007-05-04 03:49:53 +00:00
return $this -> Dispatch -> stdout ( $string , $newline );
2007-03-09 23:15:03 +00:00
}
/**
* Outputs to the stderr filehandle .
*
* @ param string $string Error text to output .
*/
function err ( $string ) {
2007-05-04 04:37:25 +00:00
return $this -> Dispatch -> stderr ( $string . " \n " );
2007-03-09 23:15:03 +00:00
}
/**
* Outputs a series of minus characters to the standard output , acts as a visual separator .
*
*/
2007-05-02 18:41:55 +00:00
function hr ( $newline = false ) {
if ( $newline ) {
$this -> out ( " \n " );
}
2007-03-09 23:15:03 +00:00
$this -> out ( '---------------------------------------------------------------' );
2007-05-02 18:41:55 +00:00
if ( $newline ) {
$this -> out ( " \n " );
}
2007-03-09 23:15:03 +00:00
}
2007-05-04 03:49:53 +00:00
/**
* Displays a formatted error message
*
* @ param unknown_type $title
* @ param unknown_type $msg
*/
function displayError ( $title , $msg ) {
$out = " \n " ;
$out .= " Error: $title\n " ;
$out .= " $msg\n " ;
$out .= " \n " ;
$this -> out ( $out );
exit ();
}
/**
* Will check the number args matches otherwise throw an error
*
* @ param unknown_type $expectedNum
* @ param unknown_type $command
*/
2007-05-04 19:32:05 +00:00
function _checkArgs ( $expectedNum , $command = null ) {
2007-05-04 03:49:53 +00:00
if ( ! $command ) {
$command = $this -> command ;
}
if ( count ( $this -> args ) < $expectedNum ) {
2007-05-12 21:18:07 +00:00
$this -> displayError ( 'Wrong number of parameters: ' . count ( $this -> args ), 'Please type \'cake ' . $this -> Dispatch -> shell . ' help\' for help on usage of the ' . $command . ' command.' );
2007-05-04 03:49:53 +00:00
}
}
2007-03-09 23:15:03 +00:00
/**
* Creates a file at given path .
*
* @ param string $path Where to put the file .
* @ param string $contents Content to put in the file .
* @ return Success
*/
function createFile ( $path , $contents ) {
$path = str_replace ( DS . DS , DS , $path );
echo " \n Creating file $path\n " ;
if ( is_file ( $path ) && $this -> interactive === true ) {
2007-05-03 21:14:46 +00:00
$this -> out ( __ ( " File exists, overwrite? " , true ) . " { $path } (y/n/q): " );
2007-03-09 23:15:03 +00:00
$key = trim ( fgets ( $this -> stdin ));
if ( $key == 'q' ) {
2007-05-03 21:14:46 +00:00
$this -> out ( __ ( " Quitting. " , true ) . " \n " );
2007-03-09 23:15:03 +00:00
exit ;
} elseif ( $key == 'a' ) {
$this -> dont_ask = true ;
} elseif ( $key == 'y' ) {
} else {
2007-05-03 21:14:46 +00:00
$this -> out ( __ ( " Skip " , true ) . " { $path } \n " );
2007-03-09 23:15:03 +00:00
return false ;
}
}
2007-05-04 03:49:53 +00:00
2007-05-03 23:22:02 +00:00
uses ( 'file' );
if ( $File = new File ( $path , true )) {
$File -> write ( $contents );
2007-05-03 21:14:46 +00:00
$this -> out ( __ ( " Wrote " , true ) . " { $path } \n " );
2007-03-09 23:15:03 +00:00
return true ;
} else {
2007-05-03 21:14:46 +00:00
$this -> err ( __ ( " Error! Could not write to " , true ) . " { $path } . \n " );
2007-03-09 23:15:03 +00:00
return false ;
}
}
/**
2007-05-07 15:30:06 +00:00
* Outputs usage text on the standard output . Implement it in subclasses .
2007-03-09 23:15:03 +00:00
*
*/
function help () {
2007-05-13 20:17:27 +00:00
if ( $this -> command != null ) {
$this -> err ( " Unknown { $this -> name } command ' $this->command '. \n For usage, try 'cake { $this -> shell } help'. \n \n " );
} else {
$this -> Dispatch -> help ();
}
2007-03-09 23:15:03 +00:00
}
/**
* Returns true if given path is a directory .
*
* @ param string $path
* @ return True if given path is a directory .
*/
function isDir ( $path ) {
if ( is_dir ( $path )) {
return true ;
} else {
return false ;
}
}
/**
* Recursive directory copy .
*
* @ param string $fromDir
* @ param string $toDir
* @ param octal $chmod
* @ param boolean $verbose
* @ return Success .
*/
function copyDir ( $fromDir , $toDir , $chmod = 0755 , $verbose = false ) {
$errors = array ();
$messages = array ();
if ( ! is_dir ( $toDir )) {
uses ( 'folder' );
$folder = new Folder ();
$folder -> mkdirr ( $toDir , 0755 );
}
if ( ! is_writable ( $toDir )) {
$errors [] = 'target ' . $toDir . ' is not writable' ;
}
if ( ! is_dir ( $fromDir )) {
$errors [] = 'source ' . $fromDir . ' is not a directory' ;
}
if ( ! empty ( $errors )) {
if ( $verbose ) {
foreach ( $errors as $err ) {
$this -> stdout ( 'Error: ' . $err );
}
}
return false ;
}
$exceptions = array ( '.' , '..' , '.svn' );
$handle = opendir ( $fromDir );
while ( false !== ( $item = readdir ( $handle ))) {
if ( ! in_array ( $item , $exceptions )) {
$from = str_replace ( '//' , '/' , $fromDir . '/' . $item );
$to = str_replace ( '//' , '/' , $toDir . '/' . $item );
if ( is_file ( $from )) {
if ( @ copy ( $from , $to )) {
chmod ( $to , $chmod );
touch ( $to , filemtime ( $from ));
$messages [] = 'File copied from ' . $from . ' to ' . $to ;
} else {
$errors [] = 'cannot copy file from ' . $from . ' to ' . $to ;
}
}
if ( is_dir ( $from )) {
if ( @ mkdir ( $to )) {
chmod ( $to , $chmod );
$messages [] = 'Directory created: ' . $to ;
} else {
$errors [] = 'cannot create directory ' . $to ;
}
$this -> copyDir ( $from , $to , $chmod , $verbose );
}
}
}
closedir ( $handle );
if ( $verbose ) {
foreach ( $errors as $err ) {
$this -> stdout ( 'Error: ' . $err );
}
foreach ( $messages as $msg ) {
$this -> stdout ( $msg );
}
}
return true ;
}
}
?>