Merge branch '2.0-console' into 2.0

Conflicts:
	cake/console/shells/acl.php
	cake/tests/cases/console/libs/tasks/plugin.test.php
This commit is contained in:
mark_story 2010-11-02 23:49:19 -04:00
commit bff711e2dc
94 changed files with 6264 additions and 3124 deletions

26
app/console/cake Executable file
View file

@ -0,0 +1,26 @@
#!/bin/bash
################################################################################
#
# Bake is a shell script for running CakePHP bake script
# PHP 5
#
# CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
# Copyright 2005-2010, Cake Software Foundation, Inc.
#
# Licensed under The MIT License
# Redistributions of files must retain the above copyright notice.
#
# @copyright Copyright 2005-2010, Cake Software Foundation, Inc.
# @link http://cakephp.org CakePHP(tm) Project
# @package cake
# @subpackage cake.app.console
# @since CakePHP(tm) v 2.0
# @license MIT License (http://www.opensource.org/licenses/mit-license.php)
#
################################################################################
LIB=${0/%cake/}
APP=`pwd`
exec php -q ${LIB}cake.php -working "${APP}" "$@"
exit;

33
app/console/cake.bat Normal file
View file

@ -0,0 +1,33 @@
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Bake is a shell script for running CakePHP bake script
:: PHP 5
::
:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
:: Copyright 2005-2010, Cake Software Foundation, Inc.
::
:: Licensed under The MIT License
:: Redistributions of files must retain the above copyright notice.
::
:: @copyright Copyright 2005-2010, Cake Software Foundation, Inc.
:: @link http://cakephp.org CakePHP(tm) Project
:: @package cake
:: @subpackage cake.app.console
:: @since CakePHP(tm) v 2.0
:: @license MIT License (http://www.opensource.org/licenses/mit-license.php)
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: In order for this script to work as intended, the cake\console\ folder must be in your PATH
@echo.
@echo off
SET app=%0
SET lib=%~dp0
php -q "%lib%cake.php" -working "%CD%" %*
echo.
exit /B %ERRORLEVEL%

25
app/console/cake.php Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/php -q
<?php
/**
* Command-line code generation utility to automate programmer chores.
*
* Shell dispatcher class
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc.
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.console
* @since CakePHP(tm) v 1.2.0.5012
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
require_once(dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'cake' . DIRECTORY_SEPARATOR . 'console' . DIRECTORY_SEPARATOR . 'shell_dispatcher.php');
return ShellDispatcher::run($argv);

View file

@ -92,20 +92,39 @@
*/
function debug($var = false, $showHtml = false, $showFrom = true) {
if (Configure::read('debug') > 0) {
$file = '';
$line = '';
if ($showFrom) {
$calledFrom = debug_backtrace();
echo '<strong>' . substr(str_replace(ROOT, '', $calledFrom[0]['file']), 1) . '</strong>';
echo ' (line <strong>' . $calledFrom[0]['line'] . '</strong>)';
$file = substr(str_replace(ROOT, '', $calledFrom[0]['file']), 1);
$line = $calledFrom[0]['line'];
}
echo "\n<pre class=\"cake-debug\">\n";
$html = <<<HTML
<strong>%s</strong> (line <strong>%s</strong>)
<pre class="cake-debug">
%s
</pre>
HTML;
$text = <<<TEXT
%s (line %s)
########## DEBUG ##########
%s
###########################
TEXT;
$template = $html;
if (php_sapi_name() == 'cli') {
$template = $text;
}
$var = print_r($var, true);
if ($showHtml) {
$var = str_replace('<', '&lt;', str_replace('>', '&gt;', $var));
}
echo $var . "\n</pre>\n";
printf($template, $file, $line, $var);
}
}
if (!function_exists('sortByKey')) {
/**

View file

@ -20,638 +20,6 @@
* @since CakePHP(tm) v 1.2.0.5012
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR. 'shell_dispatcher.php');
/**
* Shell dispatcher
*
* @package cake
* @subpackage cake.cake.console
*/
class ShellDispatcher {
/**
* Standard input stream.
*
* @var filehandle
* @access public
*/
public $stdin;
/**
* Standard output stream.
*
* @var filehandle
* @access public
*/
public $stdout;
/**
* Standard error stream.
*
* @var filehandle
* @access public
*/
public $stderr;
/**
* Contains command switches parsed from the command line.
*
* @var array
* @access public
*/
public $params = array();
/**
* Contains arguments parsed from the command line.
*
* @var array
* @access public
*/
public $args = array();
/**
* The file name of the shell that was invoked.
*
* @var string
* @access public
*/
public $shell = null;
/**
* The class name of the shell that was invoked.
*
* @var string
* @access public
*/
public $shellClass = null;
/**
* The command called if public methods are available.
*
* @var string
* @access public
*/
public $shellCommand = null;
/**
* The path locations of shells.
*
* @var array
* @access public
*/
public $shellPaths = array();
/**
* The path to the current shell location.
*
* @var string
* @access public
*/
public $shellPath = null;
/**
* The name of the shell in camelized.
*
* @var string
* @access public
*/
public $shellName = null;
/**
* TaskCollection object for the command
*
* @var TaskCollection
*/
protected $_Tasks;
/**
* Constructor
*
* The execution of the script is stopped after dispatching the request with
* a status code of either 0 or 1 according to the result of the dispatch.
*
* @param array $args the argv
* @return void
*/
public function __construct($args = array()) {
set_time_limit(0);
$this->__initConstants();
$this->parseParams($args);
$this->_initEnvironment();
$this->__buildPaths();
$this->_stop($this->dispatch() === false ? 1 : 0);
}
/**
* Defines core configuration.
*
* @access private
*/
function __initConstants() {
if (function_exists('ini_set')) {
ini_set('display_errors', '1');
ini_set('error_reporting', E_ALL & ~E_DEPRECATED);
ini_set('html_errors', false);
ini_set('implicit_flush', true);
ini_set('max_execution_time', 0);
}
if (!defined('CAKE_CORE_INCLUDE_PATH')) {
define('DS', DIRECTORY_SEPARATOR);
define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));
define('DISABLE_DEFAULT_ERROR_HANDLING', false);
define('CAKEPHP_SHELL', true);
if (!defined('CORE_PATH')) {
if (function_exists('ini_set') && ini_set('include_path', CAKE_CORE_INCLUDE_PATH . PATH_SEPARATOR . ini_get('include_path'))) {
define('CORE_PATH', null);
} else {
define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
}
}
}
}
/**
* Defines current working environment.
*
*/
protected function _initEnvironment() {
$this->stdin = fopen('php://stdin', 'r');
$this->stdout = fopen('php://stdout', 'w');
$this->stderr = fopen('php://stderr', 'w');
if (!$this->__bootstrap()) {
$this->stderr("\nCakePHP Console: ");
$this->stderr("\nUnable to load Cake core:");
$this->stderr("\tMake sure " . DS . 'cake' . DS . 'libs exists in ' . CAKE_CORE_INCLUDE_PATH);
$this->_stop();
}
if (!isset($this->args[0]) || !isset($this->params['working'])) {
$this->stderr("\nCakePHP Console: ");
$this->stderr('This file has been loaded incorrectly and cannot continue.');
$this->stderr('Please make sure that ' . DIRECTORY_SEPARATOR . 'cake' . DIRECTORY_SEPARATOR . 'console is in your system path,');
$this->stderr('and check the manual for the correct usage of this command.');
$this->stderr('(http://manual.cakephp.org/)');
$this->_stop();
}
if (basename(__FILE__) != basename($this->args[0])) {
$this->stderr("\nCakePHP Console: ");
$this->stderr('Warning: the dispatcher may have been loaded incorrectly, which could lead to unexpected results...');
if ($this->getInput('Continue anyway?', array('y', 'n'), 'y') == 'n') {
$this->_stop();
}
}
$this->shiftArgs();
}
/**
* Builds the shell paths.
*
* @access private
* @return void
*/
function __buildPaths() {
$paths = array();
if (!class_exists('Folder')) {
require LIBS . 'folder.php';
}
$plugins = App::objects('plugin', null, false);
foreach ((array)$plugins as $plugin) {
$pluginPath = App::pluginPath($plugin);
$path = $pluginPath . 'vendors' . DS . 'shells' . DS;
if (file_exists($path)) {
$paths[] = $path;
}
}
$vendorPaths = array_values(App::path('vendors'));
foreach ($vendorPaths as $vendorPath) {
$path = rtrim($vendorPath, DS) . DS . 'shells' . DS;
if (file_exists($path)) {
$paths[] = $path;
}
}
$this->shellPaths = array_values(array_unique(array_merge($paths, App::path('shells'))));
}
/**
* Initializes the environment and loads the Cake core.
*
* @return boolean Success.
* @access private
*/
function __bootstrap() {
define('ROOT', $this->params['root']);
define('APP_DIR', $this->params['app']);
define('APP_PATH', $this->params['working'] . DS);
define('WWW_ROOT', APP_PATH . $this->params['webroot'] . DS);
if (!is_dir(ROOT . DS . APP_DIR . DS . 'tmp')) {
define('TMP', CORE_PATH . 'cake' . DS . 'console' . DS . 'templates' . DS . 'skel' . DS . 'tmp' . DS);
}
$boot = file_exists(ROOT . DS . APP_DIR . DS . 'config' . DS . 'bootstrap.php');
require CORE_PATH . 'cake' . DS . 'bootstrap.php';
require_once CORE_PATH . 'cake' . DS . 'console' . DS . 'console_error_handler.php';
set_exception_handler(array('ConsoleErrorHandler', 'handleException'));
if (!file_exists(APP_PATH . 'config' . DS . 'core.php')) {
include_once CORE_PATH . 'cake' . DS . 'console' . DS . 'templates' . DS . 'skel' . DS . 'config' . DS . 'core.php';
App::build();
}
if (!defined('FULL_BASE_URL')) {
define('FULL_BASE_URL', '/');
}
return true;
}
/**
* Clear the console
*
* @return void
*/
public function clear() {
if (empty($this->params['noclear'])) {
if ( DS === '/') {
passthru('clear');
} else {
passthru('cls');
}
}
}
/**
* Dispatches a CLI request
*
* @return boolean
*/
public function dispatch() {
$arg = $this->shiftArgs();
if (!$arg) {
$this->help();
return false;
}
if ($arg == 'help') {
$this->help();
return true;
}
list($plugin, $shell) = pluginSplit($arg);
$this->shell = $shell;
$this->shellName = Inflector::camelize($shell);
$this->shellClass = $this->shellName . 'Shell';
$arg = null;
if (isset($this->args[0])) {
$arg = $this->args[0];
$this->shellCommand = Inflector::variable($arg);
}
$Shell = $this->_getShell($plugin);
if (!$Shell) {
$title = sprintf(__('Error: Class %s could not be loaded.'), $this->shellClass);
$this->stderr($title . "\n");
return false;
}
$methods = array();
if (is_a($Shell, 'Shell')) {
$Shell->initialize();
$Shell->loadTasks();
foreach ($Shell->taskNames as $task) {
if (is_a($Shell->{$task}, 'Shell')) {
$Shell->{$task}->initialize();
$Shell->{$task}->loadTasks();
}
}
$task = Inflector::camelize($arg);
if (in_array($task, $Shell->taskNames)) {
$this->shiftArgs();
$Shell->{$task}->startup();
if (isset($this->args[0]) && $this->args[0] == 'help') {
if (method_exists($Shell->{$task}, 'help')) {
$Shell->{$task}->help();
} else {
$this->help();
}
return true;
}
return $Shell->{$task}->execute();
}
$methods = array_diff(get_class_methods('Shell'), array('help'));
}
$methods = array_diff(get_class_methods($Shell), $methods);
$added = in_array(strtolower($arg), array_map('strtolower', $methods));
$private = $arg[0] == '_' && method_exists($Shell, $arg);
if (!$private) {
if ($added) {
$this->shiftArgs();
$Shell->startup();
return $Shell->{$arg}();
}
if (method_exists($Shell, 'main')) {
$Shell->startup();
return $Shell->main();
}
}
$title = sprintf(__('Error: Unknown %1$s command %2$s.'), $this->shellName, $arg);
$message = sprintf(__('For usage try `cake %s help`'), $this->shell);
$this->stderr($title . "\n" . $message . "\n");
return false;
}
/**
* Get shell to use, either plugin shell or application shell
*
* All paths in the shellPaths property are searched.
* shell, shellPath and shellClass properties are taken into account.
*
* @param string $plugin Optionally the name of a plugin
* @return mixed False if no shell could be found or an object on success
*/
protected function _getShell($plugin = null) {
foreach ($this->shellPaths as $path) {
$this->shellPath = $path . $this->shell . '.php';
$pluginShellPath = DS . $plugin . DS . 'vendors' . DS . 'shells' . DS;
if ((strpos($path, $pluginShellPath) !== false || !$plugin) && file_exists($this->shellPath)) {
$loaded = true;
break;
}
}
if (!isset($loaded)) {
return false;
}
if (!class_exists('Shell')) {
require CONSOLE_LIBS . 'shell.php';
}
if (!class_exists($this->shellClass)) {
require $this->shellPath;
}
if (!class_exists($this->shellClass)) {
return false;
}
$Shell = new $this->shellClass($this);
return $Shell;
}
/**
* Returns a TaskCollection object for Shells to use when loading their tasks.
*
* @return TaskCollection object.
*/
public function getTaskCollection() {
if (empty($this->_Tasks)) {
$this->_Tasks = new TaskCollection($this);
}
return $this->_Tasks;
}
/**
* 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.
*/
public function getInput($prompt, $options = null, $default = null) {
if (!is_array($options)) {
$printOptions = '';
} else {
$printOptions = '(' . implode('/', $options) . ')';
}
if ($default === null) {
$this->stdout($prompt . " $printOptions \n" . '> ', false);
} else {
$this->stdout($prompt . " $printOptions \n" . "[$default] > ", false);
}
$result = fgets($this->stdin);
if ($result === false) {
exit;
}
$result = trim($result);
if ($default != null && empty($result)) {
return $default;
}
return $result;
}
/**
* Outputs to the stdout filehandle.
*
* @param string $string String to output.
* @param boolean $newline If true, the outputs gets an added newline.
* @return integer Returns the number of bytes output to stdout.
*/
public function stdout($string, $newline = true) {
if ($newline) {
return fwrite($this->stdout, $string . "\n");
} else {
return fwrite($this->stdout, $string);
}
}
/**
* Outputs to the stderr filehandle.
*
* @param string $string Error text to output.
*/
public function stderr($string) {
fwrite($this->stderr, $string);
}
/**
* Parses command line options
*
* @param array $params Parameters to parse
*/
public function parseParams($params) {
$this->__parseParams($params);
$defaults = array('app' => 'app', 'root' => dirname(dirname(dirname(__FILE__))), 'working' => null, 'webroot' => 'webroot');
$params = array_merge($defaults, array_intersect_key($this->params, $defaults));
$isWin = false;
foreach ($defaults as $default => $value) {
if (strpos($params[$default], '\\') !== false) {
$isWin = true;
break;
}
}
$params = str_replace('\\', '/', $params);
if (!empty($params['working']) && (!isset($this->args[0]) || isset($this->args[0]) && $this->args[0]{0} !== '.')) {
if (empty($this->params['app']) && $params['working'] != $params['root']) {
$params['root'] = dirname($params['working']);
$params['app'] = basename($params['working']);
} else {
$params['root'] = $params['working'];
}
}
if ($params['app'][0] == '/' || preg_match('/([a-z])(:)/i', $params['app'], $matches)) {
$params['root'] = dirname($params['app']);
} elseif (strpos($params['app'], '/')) {
$params['root'] .= '/' . dirname($params['app']);
}
$params['app'] = basename($params['app']);
$params['working'] = rtrim($params['root'], '/') . '/' . $params['app'];
if (!empty($matches[0]) || !empty($isWin)) {
$params = str_replace('/', '\\', $params);
}
$this->params = array_merge($this->params, $params);
}
/**
* Helper for recursively parsing params
*
* @return array params
* @access private
*/
function __parseParams($params) {
$count = count($params);
for ($i = 0; $i < $count; $i++) {
if (isset($params[$i])) {
if ($params[$i]{0} === '-') {
$key = substr($params[$i], 1);
$this->params[$key] = true;
unset($params[$i]);
if (isset($params[++$i])) {
if ($params[$i]{0} !== '-') {
$this->params[$key] = str_replace('"', '', $params[$i]);
unset($params[$i]);
} else {
$i--;
$this->__parseParams($params);
}
}
} else {
$this->args[] = $params[$i];
unset($params[$i]);
}
}
}
}
/**
* Removes first argument and shifts other arguments up
*
* @return mixed Null if there are no arguments otherwise the shifted argument
*/
public function shiftArgs() {
return array_shift($this->args);
}
/**
* Shows console help
*
*/
public function help() {
$this->clear();
$this->stdout("\nWelcome to CakePHP v" . Configure::version() . " Console");
$this->stdout("---------------------------------------------------------------");
$this->stdout("Current Paths:");
$this->stdout(" -app: ". $this->params['app']);
$this->stdout(" -working: " . rtrim($this->params['working'], DS));
$this->stdout(" -root: " . rtrim($this->params['root'], DS));
$this->stdout(" -core: " . rtrim(CORE_PATH, DS));
$this->stdout("");
$this->stdout("Changing Paths:");
$this->stdout("your working path should be the same as your application path");
$this->stdout("to change your path use the '-app' param.");
$this->stdout("Example: -app relative/path/to/myapp or -app /absolute/path/to/myapp");
$this->stdout("\nAvailable Shells:");
$shellList = array();
foreach ($this->shellPaths as $path) {
if (!is_dir($path)) {
continue;
}
$shells = App::objects('file', $path);
if (empty($shells)) {
continue;
}
if (preg_match('@plugins[\\\/]([^\\\/]*)@', $path, $matches)) {
$type = Inflector::camelize($matches[1]);
} elseif (preg_match('@([^\\\/]*)[\\\/]vendors[\\\/]@', $path, $matches)) {
$type = $matches[1];
} elseif (strpos($path, CAKE_CORE_INCLUDE_PATH . DS . 'cake') === 0) {
$type = 'CORE';
} else {
$type = 'app';
}
foreach ($shells as $shell) {
if ($shell !== 'shell.php') {
$shell = str_replace('.php', '', $shell);
$shellList[$shell][$type] = $type;
}
}
}
if ($shellList) {
ksort($shellList);
if (DS === '/') {
$width = exec('tput cols') - 2;
}
if (empty($width)) {
$width = 80;
}
$columns = max(1, floor($width / 30));
$rows = ceil(count($shellList) / $columns);
foreach ($shellList as $shell => $types) {
sort($types);
$shellList[$shell] = str_pad($shell . ' [' . implode ($types, ', ') . ']', $width / $columns);
}
$out = array_chunk($shellList, $rows);
for ($i = 0; $i < $rows; $i++) {
$row = '';
for ($j = 0; $j < $columns; $j++) {
if (!isset($out[$j][$i])) {
continue;
}
$row .= $out[$j][$i];
}
$this->stdout(" " . $row);
}
}
$this->stdout("\nTo run a command, type 'cake shell_name [args]'");
$this->stdout("To get help on a specific command, type 'cake shell_name help'");
}
/**
* Stop execution of the current script
*
* @param $status see http://php.net/exit for values
* @return void
*/
protected function _stop($status = 0) {
exit($status);
}
}
if (!defined('DISABLE_AUTO_DISPATCH')) {
$dispatcher = new ShellDispatcher($argv);
}
return ShellDispatcher::run($argv);

View file

@ -14,11 +14,11 @@
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.console
* @since CakePHP(tm) v 1.2.0.5074
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Core', 'ErrorHandler');
require_once 'console_output.php';
/**
* Error Handler for Cake console. Does simple printing of the
@ -44,7 +44,7 @@ class ConsoleErrorHandler extends ErrorHandler {
* @param array $messages Error messages
*/
function __construct($error) {
$this->stderr = fopen('php://stderr', 'w');
$this->stderr = new ConsoleOutput('php://stderr');
parent::__construct($error);
}
@ -105,15 +105,11 @@ class ConsoleErrorHandler extends ErrorHandler {
* @return void
*/
public function _outputMessage($template = null) {
$this->stderr($this->error->getMessage() . "\n" . $this->error->getTraceAsString());
$this->stderr->write(sprintf(
__("<error>Error:</error> %s\n%s"),
$this->error->getMessage(),
$this->error->getTraceAsString()
));
}
/**
* Outputs to the stderr filehandle.
*
* @param string $string Error text to output.
*/
public function stderr($string) {
fwrite($this->stderr, "Error: ". $string . "\n");
}
}

View file

@ -0,0 +1,50 @@
<?php
/**
* ConsoleInput file.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.console
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Object wrapper for interacting with stdin
*
* @package cake.console
*/
class ConsoleInput {
/**
* Input value.
*
* @var resource
*/
protected $_input;
/**
* Constructor
*
* @return void
*/
public function __construct($handle = 'php://stdin') {
$this->_input = fopen($handle, 'r');
}
/**
* Read a value from the stream
*
* @return mixed The value of the stream
*/
public function read() {
return fgets($this->_input);
}
}

View file

@ -0,0 +1,144 @@
<?php
/**
* ConsoleArgumentOption file
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.console
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* An object to represent a single argument used in the command line.
* ConsoleOptionParser creates these when you use addArgument()
*
* @see ConsoleOptionParser::addArgument()
* @package cake.console
*/
class ConsoleInputArgument {
protected $_name, $_help, $_required, $_choices;
/**
* Make a new Input Argument
*
* @param mixed $name The long name of the option, or an array with all the properites.
* @param string $help The help text for this option
* @param boolean $required Whether this argument is required. Missing required args will trigger exceptions
* @param arraty $choices Valid choices for this option.
* @return void
*/
public function __construct($name, $help = '', $required = false, $choices = array()) {
if (is_array($name) && isset($name['name'])) {
foreach ($name as $key => $value) {
$this->{'_' . $key} = $value;
}
} else {
$this->_name = $name;
$this->_help = $help;
$this->_required = $required;
$this->_choices = $choices;
}
}
/**
* Get the name of the argument
*
* @return string
*/
public function name() {
return $this->_name;
}
/**
* Generate the help for this this argument.
*
* @param int $width The width to make the name of the option.
* @return string
*/
public function help($width = 0) {
$name = $this->_name;
if (strlen($name) < $width) {
$name = str_pad($name, $width, ' ');
}
$optional = '';
if (!$this->isRequired()) {
$optional = __(' <comment>(optional)</comment>');
}
if (!empty($this->_choices)) {
$optional .= sprintf(__(' <comment>(choices: %s)</comment>'), implode('|', $this->_choices));
}
return sprintf('%s%s%s', $name, $this->_help, $optional);
}
/**
* Get the usage value for this argument
*
* @return string
*/
public function usage() {
$name = $this->_name;
if (!empty($this->_choices)) {
$name = implode('|', $this->_choices);
}
$name = '<' . $name . '>';
if (!$this->isRequired()) {
$name = '[' . $name . ']';
}
return $name;
}
/**
* Check if this argument is a required argument
*
* @return boolean
*/
public function isRequired() {
return (bool) $this->_required;
}
/**
* Check that $value is a valid choice for this argument.
*
* @return boolean
*/
public function validChoice($value) {
if (empty($this->_choices)) {
return true;
}
if (!in_array($value, $this->_choices)) {
throw new InvalidArgumentException(sprintf(
__('"%s" is not a valid value for %s. Please use one of "%s"'),
$value, $this->_name, implode(', ', $this->_choices)
));
}
return true;
}
/**
* Append this argument to the passed in SimpleXml object.
*
* @param SimpleXmlElement The parent element.
* @return SimpleXmlElement The parent with this argument appended.
*/
public function xml(SimpleXmlElement $parent) {
$option = $parent->addChild('argument');
$option->addAttribute('name', $this->_name);
$option->addAttribute('help', $this->_help);
$option->addAttribute('required', $this->isRequired());
$choices = $option->addChild('choices');
foreach ($this->_choices as $valid) {
$choices->addChild('choice', $valid);
}
return $parent;
}
}

View file

@ -0,0 +1,166 @@
<?php
/**
* ConsoleInputOption file
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.console
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* An object to represent a single option used in the command line.
* ConsoleOptionParser creates these when you use addOption()
*
* @see ConsoleOptionParser::addOption()
* @package cake.console
*/
class ConsoleInputOption {
protected $_name, $_short, $_help, $_boolean, $_default, $_choices;
/**
* Make a new Input Option
*
* @param mixed $name The long name of the option, or an array with all the properites.
* @param string $short The short alias for this option
* @param string $help The help text for this option
* @param boolean $boolean Whether this option is a boolean option. Boolean options don't consume extra tokens
* @param string $default The default value for this option.
* @param arraty $choices Valid choices for this option.
* @return void
*/
public function __construct($name, $short = null, $help = '', $boolean = false, $default = '', $choices = array()) {
if (is_array($name) && isset($name['name'])) {
foreach ($name as $key => $value) {
$this->{'_' . $key} = $value;
}
} else {
$this->_name = $name;
$this->_short = $short;
$this->_help = $help;
$this->_boolean = $boolean;
$this->_default = $default;
$this->_choices = $choices;
}
}
/**
* Get the name of the argument
*
* @return string
*/
public function name() {
return $this->_name;
}
/**
* Generate the help for this this option.
*
* @param int $width The width to make the name of the option.
* @return string
*/
public function help($width = 0) {
$default = $short = '';
if (!empty($this->_default) && $this->_default !== true) {
$default = sprintf(__(' <comment>(default: %s)</comment>'), $this->_default);
}
if (!empty($this->_choices)) {
$default .= sprintf(__(' <comment>(choices: %s)</comment>'), implode('|', $this->_choices));
}
if (!empty($this->_short)) {
$short = ', -' . $this->_short;
}
$name = sprintf('--%s%s', $this->_name, $short);
if (strlen($name) < $width) {
$name = str_pad($name, $width, ' ');
}
return sprintf('%s%s%s', $name, $this->_help, $default);
}
/**
* Get the usage value for this option
*
* @return string
*/
public function usage() {
$name = empty($this->_short) ? '--' . $this->_name : '-' . $this->_short;
$default = '';
if (!empty($this->_default) && $this->_default !== true) {
$default = ' ' . $this->_default;
}
if (!empty($this->_choices)) {
$default = ' ' . implode('|', $this->_choices);
}
return sprintf('[%s%s]', $name, $default);
}
/**
* Get the default value for this option
*
* @return void
*/
public function defaultValue() {
return $this->_default;
}
/**
* Check if this option is a boolean option
*
* @return boolean
*/
public function isBoolean() {
return (bool) $this->_boolean;
}
/**
* Check that a value is a valid choice for this option.
*
* @return boolean
*/
public function validChoice($value) {
if (empty($this->_choices)) {
return true;
}
if (!in_array($value, $this->_choices)) {
throw new InvalidArgumentException(sprintf(
__('"%s" is not a valid value for --%s. Please use one of "%s"'),
$value, $this->_name, implode(', ', $this->_choices)
));
}
return true;
}
/**
* Append the option's xml into the parent.
*
* @param SimpleXmlElement The parent element.
* @return SimpleXmlElement The parent with this option appended.
*/
public function xml(SimpleXmlElement $parent) {
$option = $parent->addChild('option');
$option->addAttribute('name', '--' . $this->_name);
$short = '';
if (strlen($this->_short)) {
$short = $this->_short;
}
$option->addAttribute('short', '-' . $short);
$option->addAttribute('boolean', $this->_boolean);
$option->addChild('default', $this->_default);
$choices = $option->addChild('choices');
foreach ($this->_choices as $valid) {
$choices->addChild('choice', $valid);
}
return $parent;
}
}

View file

@ -0,0 +1,105 @@
<?php
/**
* ConsoleInputSubcommand file
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.console
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* An object to represent a single subcommand used in the command line.
* ConsoleOptionParser creates these when you use addSubcommand()
*
* @see ConsoleOptionParser::addSubcommand()
* @package cake.console
*/
class ConsoleInputSubcommand {
protected $_name;
protected $_help;
protected $_parser;
/**
* Make a new Subcommand
*
* @param mixed $name The long name of the subcommand, or an array with all the properites.
* @param string $help The help text for this option
* @param ConsoleOptionParser $parser A parser for this subcommand.
* @return void
*/
public function __construct($name, $help = '', $parser = null) {
if (is_array($name) && isset($name['name'])) {
foreach ($name as $key => $value) {
$this->{'_' . $key} = $value;
}
} else {
$this->_name = $name;
$this->_help = $help;
$this->_parser = $parser;
}
if (is_array($this->_parser)) {
$this->_parser['command'] = $this->_name;
$this->_parser = ConsoleOptionParser::buildFromArray($this->_parser);
}
}
/**
* Get the name of the subcommand
*
* @return string
*/
public function name() {
return $this->_name;
}
/**
* Generate the help for this this subcommand.
*
* @param int $width The width to make the name of the subcommand.
* @return string
*/
public function help($width = 0) {
$name = $this->_name;
if (strlen($name) < $width) {
$name = str_pad($name, $width, ' ');
}
return $name . $this->_help;
}
/**
* Get the usage value for this option
*
* @return mixed Either false or a ConsoleOptionParser
*/
public function parser() {
if ($this->_parser instanceof ConsoleOptionParser) {
return $this->_parser;
}
return false;
}
/**
* Append this subcommand to the Parent element
*
* @param SimpleXmlElement The parent element.
* @return SimpleXmlElement The parent with this subcommand appended.
*/
public function xml(SimpleXmlElement $parent) {
$command = $parent->addChild('command');
$command->addAttribute('name', $this->_name);
$command->addAttribute('help', $this->_help);
return $parent;
}
}

View file

@ -0,0 +1,591 @@
<?php
/**
* ConsoleOptionParser file
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.console
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
require_once CONSOLE_LIBS . 'console_input_option.php';
require_once CONSOLE_LIBS . 'console_input_argument.php';
require_once CONSOLE_LIBS . 'console_input_subcommand.php';
require_once CONSOLE_LIBS . 'help_formatter.php';
/**
* Handles parsing the ARGV in the command line and provides support
* for GetOpt compatible option definition. Provides a builder pattern implementation
* for creating shell option parsers.
*
* @package cake
* @subpackage cake.cake.console
*/
class ConsoleOptionParser {
/**
* Description text - displays before options when help is generated
*
* @see ConsoleOptionParser::description()
* @var string
*/
protected $_description = null;
/**
* Epilog text - displays after options when help is generated
*
* @see ConsoleOptionParser::epilog()
* @var string
*/
protected $_epilog = null;
/**
* Option definitions.
*
* @see ConsoleOptionParser::addOption()
* @var array
*/
protected $_options = array();
/**
* Map of short -> long options, generated when using addOption()
*
* @var string
*/
protected $_shortOptions = array();
/**
* Positional argument definitions.
*
* @see ConsoleOptionParser::addArgument()
* @var array
*/
protected $_args = array();
/**
* Subcommands for this Shell.
*
* @var array
*/
protected $_subcommands = array();
/**
* Construct an OptionParser so you can define its behavior
*
* ### Options
*
* Named arguments come in two forms, long and short. Long arguments are preceeded
* by two - and give a more verbose option name. i.e. `--version`. Short arguments are
* preceeded by one - and are only one character long. They usually match with a long option,
* and provide a more terse alternative.
*
* #### Using Options
*
* Options can be defined with both long and short forms. By using `$parser->addOption()`
* you can define new options. The name of the option is used as its long form, and you
* can supply an additional short form, with the `short` option.
*
* Calling options can be done using syntax similar to most *nix command line tools. Long options
* cane either include an `=` or leave it out.
*
* `cake myshell command --connection default --name=something`
*
* Short options can be defined singally or in groups.
*
* `cake myshell command -cn`
*
* ### Positional arguments
*
* If no positional arguments are defined, all of them will be parsed. If you define positional
* arguments any arguments greater than those defined will cause exceptions. Additionally you can
* declare arguments as optional, by setting the required param to false.
*
* `$parser->addArgument('model', array('required' => false));`
*
* ### Providing Help text
*
* By providing help text for your positional arguments and named arguments, the ConsoleOptionParser
* can generate a help display for you. You can view the help for shells by using the `--help` or `-h` switch.
*
* @param string $command The command name this parser is for. The command name is used for generating help.
* @param boolean $defaultOptions Whether you want the verbose and quiet options set.
*/
public function __construct($command = null, $defaultOptions = true) {
$this->_command = $command;
$this->addOption('help', array(
'short' => 'h',
'help' => 'Display this help.',
'boolean' => true
));
if ($defaultOptions) {
$this->addOption('verbose', array(
'short' => 'v',
'help' => __('Enable verbose output.'),
'boolean' => true
))->addOption('quiet', array(
'short' => 'q',
'help' => __('Enable quiet output.'),
'boolean' => true
));
}
}
/**
* Static factory method for creating new OptionParsers so you can chain methods off of them.
*
* @param string $command The command name this parser is for. The command name is used for generating help.
* @param boolean $defaultOptions Whether you want the verbose and quiet options set.
* @return ConsoleOptionParser
*/
public static function create($command, $defaultOptions = true) {
return new ConsoleOptionParser($command, $defaultOptions);
}
/**
* Build a parser from an array. Uses an array like
*
* {{{
* $spec = array(
* 'description' => 'text',
* 'epilog' => 'text',
* 'arguments' => array(
* // list of arguments compatible with addArguments.
* ),
* 'options' => array(
* // list of options compatible with addOptions
* ),
* 'subcommands' => array(
* // list of subcommands to add.
* )
* );
* }}}
*
* @param array $spec The spec to build the OptionParser with.
* @return ConsoleOptionParser
*/
public static function buildFromArray($spec) {
$parser = new ConsoleOptionParser($spec['command']);
if (!empty($spec['arguments'])) {
$parser->addArguments($spec['arguments']);
}
if (!empty($spec['options'])) {
$parser->addOptions($spec['options']);
}
if (!empty($spec['subcommands'])) {
$parser->addSubcommands($spec['subcommands']);
}
if (!empty($spec['description'])) {
$parser->description($spec['description']);
}
if (!empty($spec['epilog'])) {
$parser->epilog($spec['epilog']);
}
return $parser;
}
/**
* Get or set the command name for shell/task
*
* @param string $text The text to set, or null if you want to read
* @return mixed If reading, the value of the command. If setting $this will be returned
*/
public function command($text = null) {
if ($text !== null) {
$this->_command = $text;
return $this;
}
return $this->_command;
}
/**
* Get or set the description text for shell/task
*
* @param mixed $text The text to set, or null if you want to read. . If an array the text will be imploded with "\n"
* @return mixed If reading, the value of the description. If setting $this will be returned
*/
public function description($text = null) {
if ($text !== null) {
if (is_array($text)) {
$text = implode("\n", $text);
}
$this->_description = $text;
return $this;
}
return $this->_description;
}
/**
* Get or set an epilog to the parser. The epilog is added to the end of
* the options and arguments listing when help is generated.
*
* @param mixed $text Text when setting or null when reading. If an array the text will be imploded with "\n"
* @return mixed If reading, the value of the epilog. If setting $this will be returned.
*/
public function epilog($text = null) {
if ($text !== null) {
if (is_array($text)) {
$text = implode("\n", $text);
}
$this->_epilog = $text;
return $this;
}
return $this->_epilog;
}
/**
* Add an option to the option parser. Options allow you to define optional or required
* parameters for your console application. Options are defined by the parameters they use.
*
* ### Params
*
* - `short` - The single letter variant for this option, leave undefined for none.
* - `help` - Help text for this option. Used when generating help for the option.
* - `default` - The default value for this option. Defaults are added into the parsed params when the
* attached option is not provided or has no value. Using default and boolean together will not work.
* are added into the parsed parameters when the option is undefined. Defaults to null.
* - `boolean` - The option uses no value, its just a boolean switch. Defaults to false.
* If an option is defined as boolean, it will always be added to the parsed params. If no present
* it will be false, if present it will be true.
* - `choices` A list of valid choices for this option. If left empty all values are valid..
* An exception will be raised when parse() encounters an invalid value.
*
* @param string $name The long name you want to the value to be parsed out as when options are parsed.
* @param array $params An array of parameters that define the behavior of the option
* @return returns $this.
*/
public function addOption($name, $params = array()) {
$defaults = array(
'name' => $name,
'short' => null,
'help' => '',
'default' => null,
'boolean' => false,
'choices' => array()
);
$options = array_merge($defaults, $params);
$this->_options[$name] = new ConsoleInputOption($options);
if (!empty($options['short'])) {
$this->_shortOptions[$options['short']] = $name;
}
return $this;
}
/**
* Add a positional argument to the option parser.
*
* ### Params
*
* - `help` The help text to display for this argument.
* - `required` Whether this parameter is required.
* - `index` The index for the arg, if left undefined the argument will be put
* onto the end of the arguments. If you define the same index twice the first
* option will be overwritten.
* - `choices` A list of valid choices for this argument. If left empty all values are valid..
* An exception will be raised when parse() encounters an invalid value.
*
* @param string $name The name of the argument.
* @param array $params Parameters for the argument, see above.
* @return $this.
*/
public function addArgument($name, $params = array()) {
$defaults = array(
'name' => $name,
'help' => '',
'index' => count($this->_args),
'required' => false,
'choices' => array()
);
$options = array_merge($defaults, $params);
$index = $options['index'];
unset($options['index']);
$this->_args[$index] = new ConsoleInputArgument($options);
return $this;
}
/**
* Add multiple arugments at once. Take an array of arugment defintions.
* The keys are used as the argument names, and the values as params for the argument.
*
* @param array $args Array of arguments to add.
* @see ConsoleOptionParser::addArgument()
* @return $this
*/
public function addArguments(array $args) {
foreach ($args as $name => $params) {
$this->addArgument($name, $params);
}
return $this;
}
/**
* Add multiple options at once. Takes an array of option definitions.
* The keys are used as option names, and the values as params for the option.
*
* @param array $options Array of options to add.
* @see ConsoleOptionParser::addOption()
* @return $this
*/
public function addOptions(array $options) {
foreach ($options as $name => $params) {
$this->addOption($name, $params);
}
return $this;
}
/**
* Append a subcommand to the subcommand list.
* Subcommands are usually methods on your Shell, but can also be used to document
* Tasks
*
* ### Params
*
* - `help` - Help text for the subcommand.
* - `parser` - A ConsoleOptionParser for the subcommand. This allows you to create method
* specific option parsers. When help is generated for a subcommand, if a parser is present
* it will be used.
*
* @param string $name Name of the subcommand
* @param array $params Array of params, see above.
* @return $this.
*/
public function addSubcommand($name, $params = array()) {
$defaults = array(
'name' => $name,
'help' => '',
'parser' => null
);
$options = array_merge($defaults, $params);
$this->_subcommands[$name] = new ConsoleInputSubcommand($options);
return $this;
}
/**
* Add multiple subcommands at once.
*
* @param array $commands Array of subcommands.
* @return $this
*/
public function addSubcommands(array $commands) {
foreach ($commands as $name => $params) {
$this->addSubcommand($name, $params);
}
return $this;
}
/**
* Gets the arguments defined in the parser.
*
* @return array Array of argument descriptions
*/
public function arguments() {
return $this->_args;
}
/**
* Get the defined options in the parser.
*
* @return array
*/
public function options() {
return $this->_options;
}
/**
* Get the array of defined subcommands
*
* @return array
*/
public function subcommands() {
return $this->_subcommands;
}
/**
* Parse the argv array into a set of params and args. If $command is not null
* and $command is equal to a subcommand that has a parser, that parser will be used
* to parse the $argv
*
* @param array $argv Array of args (argv) to parse.
* @param string $command The subcommand to use. If this parameter is a subcommand, that has a parser,
* That parser will be used to parse $argv instead.
* @return Array array($params, $args)
* @throws InvalidArgumentException When an invalid parameter is encountered.
* RuntimeException when required arguments are not supplied.
*/
public function parse($argv, $command = null) {
if (isset($this->_subcommands[$command]) && $this->_subcommands[$command]->parser()) {
return $this->_subcommands[$command]->parser()->parse($argv);
}
$params = $args = array();
$this->_tokens = $argv;
while ($token = array_shift($this->_tokens)) {
if (substr($token, 0, 2) == '--') {
$params = $this->_parseLongOption($token, $params);
} elseif (substr($token, 0, 1) == '-') {
$params = $this->_parseShortOption($token, $params);
} else {
$args = $this->_parseArg($token, $args);
}
}
foreach ($this->_args as $i => $arg) {
if ($arg->isRequired() && !isset($args[$i]) && empty($params['help'])) {
throw new RuntimeException(
sprintf(__('Missing required arguments. %s is required.'), $arg->name())
);
}
}
foreach ($this->_options as $option) {
$name = $option->name();
$isBoolean = $option->isBoolean();
$default = $option->defaultValue();
if ($default !== null && !isset($params[$name]) && !$isBoolean) {
$params[$name] = $default;
}
if ($isBoolean && !isset($params[$name])) {
$params[$name] = false;
}
}
return array($params, $args);
}
/**
* Gets formatted help for this parser object.
* Generates help text based on the description, options, arguments, subcommands and epilog
* in the parser.
*
* @param string $subcommand If present and a valid subcommand that has a linked parser.
* That subcommands help will be shown instead.
* @param int $width The width to format user content to. Defaults to 72
* @return string Generated help.
*/
public function help($subcommand = null, $format = 'text', $width = 72) {
if (
isset($this->_subcommands[$subcommand]) &&
$this->_subcommands[$subcommand]->parser() instanceof self
) {
$subparser = $this->_subcommands[$subcommand]->parser();
$subparser->command($this->command() . ' ' . $subparser->command());
return $subparser->help(null, $format, $width);
}
$formatter = new HelpFormatter($this);
if ($format == 'text' || $format === true) {
return $formatter->text($width);
} elseif ($format == 'xml') {
return $formatter->xml();
}
}
/**
* Parse the value for a long option out of $this->_tokens. Will handle
* options with an `=` in them.
*
* @param string $option The option to parse.
* @param array $params The params to append the parsed value into
* @return array Params with $option added in.
*/
protected function _parseLongOption($option, $params) {
$name = substr($option, 2);
if (strpos($name, '=') !== false) {
list($name, $value) = explode('=', $name, 2);
array_unshift($this->_tokens, $value);
}
return $this->_parseOption($name, $params);
}
/**
* Parse the value for a short option out of $this->_tokens
* If the $option is a combination of multiple shortcuts like -otf
* they will be shifted onto the token stack and parsed individually.
*
* @param string $option The option to parse.
* @param array $params The params to append the parsed value into
* @return array Params with $option added in.
*/
protected function _parseShortOption($option, $params) {
$key = substr($option, 1);
if (strlen($key) > 1) {
$flags = str_split($key);
$key = $flags[0];
for ($i = 1, $len = count($flags); $i < $len; $i++) {
array_unshift($this->_tokens, '-' . $flags[$i]);
}
}
$name = $this->_shortOptions[$key];
return $this->_parseOption($name, $params);
}
/**
* Parse an option by its name index.
*
* @param string $option The option to parse.
* @param array $params The params to append the parsed value into
* @return array Params with $option added in.
*/
protected function _parseOption($name, $params) {
if (!isset($this->_options[$name])) {
throw new InvalidArgumentException(sprintf(__('Unknown option `%s`'), $name));
}
$option = $this->_options[$name];
$isBoolean = $option->isBoolean();
$nextValue = $this->_nextToken();
if (!$isBoolean && !empty($nextValue) && $nextValue{0} != '-') {
array_shift($this->_tokens);
$value = $nextValue;
} elseif ($isBoolean) {
$value = true;
} else {
$value = $option->defaultValue();
}
if ($option->validChoice($value)) {
$params[$name] = $value;
return $params;
}
}
/**
* Parse an argument, and ensure that the argument doesn't exceed the number of arguments
* and that the argument is a valid choice.
*
* @param string $argument The argument to append
* @param array $args The array of parsed args to append to.
* @return array Args
*/
protected function _parseArg($argument, $args) {
if (empty($this->_args)) {
array_push($args, $argument);
return $args;
}
$next = count($args);
if (!isset($this->_args[$next])) {
throw new InvalidArgumentException(__('Too many arguments.'));
}
if ($this->_args[$next]->validChoice($argument)) {
array_push($args, $argument);
return $args;
}
}
/**
* Find the next token in the argv set.
*
* @param string
* @return next token or ''
*/
protected function _nextToken() {
return isset($this->_tokens[0]) ? $this->_tokens[0] : '';
}
}

View file

@ -0,0 +1,289 @@
<?php
/**
* ConsoleOutput file.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.console
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Object wrapper for outputing information from a shell application.
* Can be connected to any stream resource that can be used with fopen()
*
* Can generate colourzied output on consoles that support it. There are a few
* built in styles
*
* - `error` Error messages.
* - `warning` Warning messages.
* - `info` Informational messages.
* - `comment` Additional text.
* - `question` Magenta text used for user prompts
*
* By defining styles with addStyle() you can create custom console styles.
*
* ### Using styles in output
*
* You can format console output using tags with the name of the style to apply. From inside a shell object
*
* `$this->out('<warning>Overwrite:</warning> foo.php was overwritten.');`
*
* This would create orange 'Overwrite:' text, while the rest of the text would remain the normal colour.
* See ConsoleOutput::styles() to learn more about defining your own styles. Nested styles are not supported
* at this time.
*
* @package cake.console
*/
class ConsoleOutput {
/**
* Raw output constant - no modification of output text.
*/
const RAW = 0;
/**
* Plain output - tags will be stripped.
*/
const PLAIN = 1;
/**
* Colour output - Convert known tags in to ANSI color escape codes.
*/
const COLOR = 2;
/**
* Constant for a newline.
*/
const LF = PHP_EOL;
/**
* File handle for output.
*
* @var resource
*/
protected $_output;
/**
* The current output type. Manipulated with ConsoleOutput::outputAs();
*
* @var integer.
*/
protected $_outputAs = self::COLOR;
/**
* text colors used in coloured output.
*
* @var array
*/
protected static $_foregroundColors = array(
'black' => 30,
'red' => 31,
'green' => 32,
'yellow' => 33,
'blue' => 34,
'magenta' => 35,
'cyan' => 36,
'white' => 37
);
/**
* background colours used in coloured output.
*
* @var array
*/
protected static $_backgroundColors = array(
'black' => 40,
'red' => 41,
'green' => 42,
'yellow' => 43,
'blue' => 44,
'magenta' => 45,
'cyan' => 46,
'white' => 47
);
/**
* formatting options for coloured output
*
* @var string
*/
protected static $_options = array(
'bold' => 1,
'underline' => 4,
'blink' => 5,
'reverse' => 7,
);
/**
* Styles that are available as tags in console output.
* You can modify these styles with ConsoleOutput::styles()
*
* @var array
*/
protected static $_styles = array(
'error' => array('text' => 'red', 'underline' => true),
'warning' => array('text' => 'yellow'),
'info' => array('text' => 'cyan'),
'success' => array('text' => 'green'),
'comment' => array('text' => 'blue'),
'question' => array('text' => "magenta"),
);
/**
* Construct the output object.
*
* Checks for a pretty console enviornment. Ansicon allows pretty consoles
* on windows, and is supported.
*
* @return void
*/
public function __construct($stream = 'php://stdout') {
$this->_output = fopen($stream, 'w');
if (DS == '\\' && !(bool)env('ANSICON')) {
$this->_outputAs = self::PLAIN;
}
}
/**
* Outputs a single or multiple messages to stdout. If no parameters
* are passed outputs just a newline.
*
* @param mixed $message A string or a an array of strings to output
* @param integer $newlines Number of newlines to append
* @return integer Returns the number of bytes returned from writing to stdout.
*/
public function write($message, $newlines = 1) {
if (is_array($message)) {
$message = implode(self::LF, $message);
}
return $this->_write($this->styleText($message . str_repeat(self::LF, $newlines)));
}
/**
* Apply styling to text.
*
* @param string $text Text with styling tags.
* @return string String with color codes added.
*/
public function styleText($text) {
if ($this->_outputAs == self::RAW) {
return $text;
}
if ($this->_outputAs == self::PLAIN) {
return strip_tags($text);
}
return preg_replace_callback(
'/<(?<tag>[a-z0-9-_]+)>(?<text>.*?)<\/(\1)>/ims', array($this, '_replaceTags'), $text
);
}
/**
* Replace tags with color codes.
*
* @param array $matches.
* @return string
*/
protected function _replaceTags($matches) {
$style = $this->styles($matches['tag']);
if (empty($style)) {
return '<' . $matches['tag'] . '>' . $matches['text'] . '</' . $matches['tag'] . '>';
}
$styleInfo = array();
if (!empty($style['text']) && isset(self::$_foregroundColors[$style['text']])) {
$styleInfo[] = self::$_foregroundColors[$style['text']];
}
if (!empty($style['background']) && isset(self::$_backgroundColors[$style['background']])) {
$styleInfo[] = self::$_backgroundColors[$style['background']];
}
unset($style['text'], $style['background']);
foreach ($style as $option => $value) {
if ($value) {
$styleInfo[] = self::$_options[$option];
}
}
return "\033[" . implode($styleInfo, ';') . 'm' . $matches['text'] . "\033[0m";
}
/**
* Writes a message to the output stream
*
* @param string $message Message to write.
* @return boolean success
*/
protected function _write($message) {
return fwrite($this->_output, $message);
}
/**
* Get the current styles offered, or append new ones in.
*
* ### Get a style definition
*
* `$this->output->styles('error');`
*
* ### Get all the style definitions
*
* `$this->output->styles();`
*
* ### Create or modify an existing style
*
* `$this->output->styles('annoy', array('text' => 'purple', 'background' => 'yellow', 'blink' => true));`
*
* ### Remove a style
*
* `$this->output->styles('annoy', false);`
*
* @param string $style The style to get or create.
* @param mixed $definition The array definition of the style to change or create a style
* or false to remove a style.
* @return mixed If you are getting styles, the style or null will be returned. If you are creating/modifying
* styles true will be returned.
*/
function styles($style = null, $definition = null) {
if ($style === null && $definition === null) {
return self::$_styles;
}
if (is_string($style) && $definition === null) {
return isset(self::$_styles[$style]) ? self::$_styles[$style] : null;
}
if ($definition === false) {
unset(self::$_styles[$style]);
return true;
}
self::$_styles[$style] = $definition;
return true;
}
/**
* Get/Set the output type to use. The output type how formatting tags are treated.
*
* @param int $type The output type to use. Should be one of the class contstants.
* @return mixed Either null or the value if getting.
*/
public function outputAs($type = null) {
if ($type === null) {
return $this->_outputAs;
}
$this->_outputAs = $type;
}
/**
* clean up and close handles
*
* @return void
*/
public function __destruct() {
fclose($this->_output);
}
}

View file

@ -0,0 +1,176 @@
<?php
/**
* HelpFormatter
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.console
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* HelpFormatter formats help for console shells. Can format to either
* text or XML formats. Uses ConsoleOptionParser methods to generate help.
*
* Generally not directly used. Using $parser->help($command, 'xml'); is usually
* how you would access help. Or via the `--help=xml` option on the command line.
*
* Xml output is useful for intergration with other tools like IDE's or other build tools.
*
*/
class HelpFormatter {
/**
* Build the help formatter for a an OptionParser
*
* @return void
*/
public function __construct(ConsoleOptionParser $parser) {
$this->_parser = $parser;
}
/**
* Get the help as formatted text suitable for output on the command line.
*
* @param integer $width The width of the help output.
* @return string
*/
public function text($width = 72) {
$parser = $this->_parser;
$out = array();
$description = $parser->description();
if (!empty($description)) {
$out[] = String::wrap($description, $width);
$out[] = '';
}
$out[] = '<info>Usage:</info>';
$out[] = $this->_generateUsage();
$out[] = '';
$subcommands = $parser->subcommands();
if (!empty($subcommands)) {
$out[] = '<info>Subcommands:</info>';
$out[] = '';
$max = $this->_getMaxLength($subcommands) + 2;
foreach ($subcommands as $command) {
$out[] = String::wrap($command->help($max), array(
'width' => $width,
'indent' => str_repeat(' ', $max),
'indentAt' => 1
));
}
$out[] = '';
$out[] = sprintf(
__('To see help on a subcommand use <info>`cake %s [subcommand] --help`</info>'),
$parser->command()
);
$out[] = '';
}
$options = $parser->options();
if (!empty($options)) {
$max = $this->_getMaxLength($options) + 8;
$out[] = '<info>Options:</info>';
$out[] = '';
foreach ($options as $option) {
$out[] = String::wrap($option->help($max), array(
'width' => $width,
'indent' => str_repeat(' ', $max),
'indentAt' => 1
));
}
$out[] = '';
}
$arguments = $parser->arguments();
if (!empty($arguments)) {
$max = $this->_getMaxLength($arguments) + 2;
$out[] = '<info>Arguments:</info>';
$out[] = '';
foreach ($arguments as $argument) {
$out[] = String::wrap($argument->help($max), array(
'width' => $width,
'indent' => str_repeat(' ', $max),
'indentAt' => 1
));
}
$out[] = '';
}
$epilog = $parser->epilog();
if (!empty($epilog)) {
$out[] = String::wrap($epilog, $width);
$out[] = '';
}
return implode("\n", $out);
}
/**
* Generate the usage for a shell based on its arguments and options.
* Usage strings favour short options over the long ones. and optional args will
* be indicated with []
*
* @return string
*/
protected function _generateUsage() {
$usage = array('cake ' . $this->_parser->command());
$subcommands = $this->_parser->subcommands();
if (!empty($subcommands)) {
$usage[] = '[subcommand]';
}
foreach ($this->_parser->options() as $option) {
$usage[] = $option->usage();
}
foreach ($this->_parser->arguments() as $argument) {
$usage[] = $argument->usage();
}
return implode(' ', $usage);
}
/**
* Iterate over a collection and find the longest named thing.
*
* @return integer
*/
protected function _getMaxLength($collection) {
$max = 0;
foreach ($collection as $item) {
$max = (strlen($item->name()) > $max) ? strlen($item->name()) : $max;
}
return $max;
}
/**
* Get the help as an xml string.
*
* @param boolean $string Return the SimpleXml object or a string. Defaults to true.
* @return mixed. See $string
*/
public function xml($string = true) {
$parser = $this->_parser;
$xml = new SimpleXmlElement('<shell></shell>');
$xml->addChild('commmand', $parser->command());
$xml->addChild('description', $parser->description());
$xml->addChild('epilog', $parser->epilog());
$subcommands = $xml->addChild('subcommands');
foreach ($parser->subcommands() as $command) {
$command->xml($subcommands);
}
$options = $xml->addChild('options');
foreach ($parser->options() as $option) {
$option->xml($options);
}
$arguments = $xml->addChild('arguments');
foreach ($parser->arguments() as $argument) {
$argument->xml($arguments);
}
return $string ? $xml->asXml() : $xml;
}
}

View file

@ -20,11 +20,18 @@ App::import('Core', 'ObjectCollection');
class TaskCollection extends ObjectCollection {
/**
* Shell Dispatcher to give to tasks. and use to find tasks.
* Shell to use to set params to tasks.
*
* @var array
*/
protected $_Dispatch;
protected $_Shell;
/**
* The directory inside each shell path that contains tasks.
*
* @var string
*/
public $taskPathPrefix = 'tasks/';
/**
* Constructor
@ -32,11 +39,13 @@ class TaskCollection extends ObjectCollection {
* @param array $paths Array of paths to search for tasks on .
* @return void
*/
public function __construct(ShellDispatcher $Dispatcher) {
$this->_Dispatch = $Dispatcher;
public function __construct(Shell $Shell) {
$this->_Shell = $Shell;
}
/**
* Loads/constructs a task. Will return the instance in the registry if it already exists.
* Loads/constructs a task. Will return the instance in the collection
* if it already exists.
*
* @param string $task Task name to load
* @param array $settings Settings for the task.
@ -53,35 +62,21 @@ class TaskCollection extends ObjectCollection {
$taskFile = Inflector::underscore($name);
$taskClass = $name . 'Task';
if (!class_exists($taskClass)) {
$taskFile = $this->_getPath($taskFile);
require_once $taskFile;
if (!App::import('Shell', $plugin . $this->taskPathPrefix . $name)) {
throw new MissingTaskFileException($taskFile . '.php');
}
if (!class_exists($taskClass)) {
throw new MissingTaskClassException($taskClass);
}
}
$this->_loaded[$name] = new $taskClass($this->_Dispatch);
$this->_loaded[$name] = new $taskClass(
$this->_Shell->stdout, $this->_Shell->stderr, $this->_Shell->stdin
);
if ($enable === true) {
$this->_enabled[] = $name;
}
return $this->_loaded[$name];
}
/**
* Find a task file on one of the paths.
*
* @param string $file Underscored name of the file to find missing .php
* @return string Filename to the task
* @throws MissingTaskFileException
*/
protected function _getPath($file) {
foreach ($this->_Dispatch->shellPaths as $path) {
$taskPath = $path . 'tasks' . DS . $file . '.php';
if (file_exists($taskPath)) {
return $taskPath;
}
}
throw new MissingTaskFileException($file . '.php');
}
}

View file

@ -0,0 +1,327 @@
<?php
/**
* ShellDispatcher file
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.console
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Shell dispatcher handles dispatching cli commands.
*
* @package cake
* @subpackage cake.cake.console
*/
class ShellDispatcher {
/**
* Contains command switches parsed from the command line.
*
* @var array
* @access public
*/
public $params = array();
/**
* Contains arguments parsed from the command line.
*
* @var array
* @access public
*/
public $args = array();
/**
* Constructor
*
* The execution of the script is stopped after dispatching the request with
* a status code of either 0 or 1 according to the result of the dispatch.
*
* @param array $args the argv
* @return void
*/
public function __construct($args = array(), $bootstrap = true) {
set_time_limit(0);
if ($bootstrap) {
$this->__initConstants();
}
$this->parseParams($args);
if ($bootstrap) {
$this->_initEnvironment();
}
}
/**
* Run the dispatcher
*
* @return void
*/
public static function run($argv) {
$dispatcher = new ShellDispatcher($argv);
$dispatcher->_stop($dispatcher->dispatch() === false ? 1 : 0);
}
/**
* Defines core configuration.
*
* @access private
*/
function __initConstants() {
if (function_exists('ini_set')) {
ini_set('display_errors', '1');
ini_set('error_reporting', E_ALL & ~E_DEPRECATED);
ini_set('html_errors', false);
ini_set('implicit_flush', true);
ini_set('max_execution_time', 0);
}
if (!defined('CAKE_CORE_INCLUDE_PATH')) {
define('DS', DIRECTORY_SEPARATOR);
define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));
define('DISABLE_DEFAULT_ERROR_HANDLING', false);
define('CAKEPHP_SHELL', true);
if (!defined('CORE_PATH')) {
if (function_exists('ini_set') && ini_set('include_path', CAKE_CORE_INCLUDE_PATH . PATH_SEPARATOR . ini_get('include_path'))) {
define('CORE_PATH', null);
} else {
define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);
}
}
}
}
/**
* Defines current working environment.
*
*/
protected function _initEnvironment() {
if (!$this->__bootstrap()) {
$message = "Unable to load CakePHP core.\nMake sure " . DS . 'cake' . DS . 'libs exists in ' . CAKE_CORE_INCLUDE_PATH;
throw new RuntimeException($message);
}
if (!isset($this->args[0]) || !isset($this->params['working'])) {
$message = "This file has been loaded incorrectly and cannot continue.\n" .
"Please make sure that " . DIRECTORY_SEPARATOR . "cake" . DIRECTORY_SEPARATOR . "console is in your system path,\n" .
"and check the cookbook for the correct usage of this command.\n" .
"(http://book.cakephp.org/)";
throw new RuntimeException($message);
}
$this->shiftArgs();
}
/**
* Initializes the environment and loads the Cake core.
*
* @return boolean Success.
* @access private
*/
function __bootstrap() {
define('ROOT', $this->params['root']);
define('APP_DIR', $this->params['app']);
define('APP_PATH', $this->params['working'] . DS);
define('WWW_ROOT', APP_PATH . $this->params['webroot'] . DS);
if (!is_dir(ROOT . DS . APP_DIR . DS . 'tmp')) {
define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'cake' . DS . 'console' . DS . 'templates' . DS . 'skel' . DS . 'tmp' . DS);
}
$boot = file_exists(ROOT . DS . APP_DIR . DS . 'config' . DS . 'bootstrap.php');
require CORE_PATH . 'cake' . DS . 'bootstrap.php';
require_once CONSOLE_LIBS . 'console_error_handler.php';
set_exception_handler(array('ConsoleErrorHandler', 'handleException'));
if (!file_exists(APP_PATH . 'config' . DS . 'core.php')) {
include_once CAKE_CORE_INCLUDE_PATH . DS . 'cake' . DS . 'console' . DS . 'templates' . DS . 'skel' . DS . 'config' . DS . 'core.php';
App::build();
}
if (!defined('FULL_BASE_URL')) {
define('FULL_BASE_URL', '/');
}
return true;
}
/**
* Dispatches a CLI request
*
* @return boolean
*/
public function dispatch() {
$shell = $this->shiftArgs();
if (!$shell) {
$this->help();
return false;
}
if (in_array($shell, array('help', '--help', '-h'))) {
$this->help();
return true;
}
$Shell = $this->_getShell($shell);
$command = null;
if (isset($this->args[0])) {
$command = $this->args[0];
}
if ($Shell instanceof Shell) {
$Shell->initialize();
$Shell->loadTasks();
return $Shell->runCommand($command, $this->args);
}
$methods = array_diff(get_class_methods($Shell), get_class_methods('Shell'));
$added = in_array($command, $methods);
$private = $command[0] == '_' && method_exists($Shell, $command);
if (!$private) {
if ($added) {
$this->shiftArgs();
$Shell->startup();
return $Shell->{$command}();
}
if (method_exists($Shell, 'main')) {
$Shell->startup();
return $Shell->main();
}
}
throw new MissingShellMethodException(array('shell' => $shell, 'method' => $arg));
}
/**
* Get shell to use, either plugin shell or application shell
*
* All paths in the loaded shell paths are searched.
*
* @param string $shell Optionally the name of a plugin
* @return mixed False if no shell could be found or an object on success
* @throws MissingShellFileException, MissingShellClassException when errors are encountered.
*/
protected function _getShell($shell) {
list($plugin, $shell) = pluginSplit($shell, true);
$loaded = App::import('Shell', $plugin . $shell);
$class = Inflector::camelize($shell) . 'Shell';
if (!$loaded) {
throw new MissingShellFileException(array('shell' => $shell));
}
if (!class_exists($class)) {
throw new MissingShellClassException(array('shell' => $class));
}
$Shell = new $class();
return $Shell;
}
/**
* Parses command line options and extracts the directory paths from $params
*
* @param array $params Parameters to parse
*/
public function parseParams($args) {
$this->_parsePaths($args);
$defaults = array(
'app' => 'app',
'root' => dirname(dirname(dirname(__FILE__))),
'working' => null,
'webroot' => 'webroot'
);
$params = array_merge($defaults, array_intersect_key($this->params, $defaults));
$isWin = false;
foreach ($defaults as $default => $value) {
if (strpos($params[$default], '\\') !== false) {
$isWin = true;
break;
}
}
$params = str_replace('\\', '/', $params);
if (!empty($params['working']) && (!isset($this->args[0]) || isset($this->args[0]) && $this->args[0]{0} !== '.')) {
if (empty($this->params['app']) && $params['working'] != $params['root']) {
$params['root'] = dirname($params['working']);
$params['app'] = basename($params['working']);
} else {
$params['root'] = $params['working'];
}
}
if ($params['app'][0] == '/' || preg_match('/([a-z])(:)/i', $params['app'], $matches)) {
$params['root'] = dirname($params['app']);
} elseif (strpos($params['app'], '/')) {
$params['root'] .= '/' . dirname($params['app']);
}
$params['app'] = basename($params['app']);
$params['working'] = rtrim($params['root'], '/') . '/' . $params['app'];
if (!empty($matches[0]) || !empty($isWin)) {
$params = str_replace('/', '\\', $params);
}
$this->params = array_merge($this->params, $params);
}
/**
* Parses out the paths from from the argv
*
* @return void
*/
protected function _parsePaths($args) {
$parsed = array();
$keys = array('-working', '--working', '-app', '--app', '-root', '--root');
foreach ($keys as $key) {
$index = array_search($key, $args);
if ($index !== false) {
$keyname = str_replace('-', '', $key);
$valueIndex = $index + 1;
$parsed[$keyname] = $args[$valueIndex];
array_splice($args, $index, 2);
}
}
$this->args = $args;
$this->params = $parsed;
}
/**
* Removes first argument and shifts other arguments up
*
* @return mixed Null if there are no arguments otherwise the shifted argument
*/
public function shiftArgs() {
return array_shift($this->args);
}
/**
* Shows console help. Performs an internal dispatch to the CommandList Shell
*
*/
public function help() {
$this->args = array_merge(array('command_list'), $this->args);
$this->dispatch();
}
/**
* Stop execution of the current script
*
* @param $status see http://php.net/exit for values
* @return void
*/
protected function _stop($status = 0) {
exit($status);
}
}

View file

@ -66,6 +66,7 @@ class AclShell extends Shell {
*
*/
public function startup() {
parent::startup();
if (isset($this->params['connection'])) {
$this->connection = $this->params['connection'];
}
@ -83,7 +84,7 @@ class AclShell extends Shell {
$this->_stop();
}
if ($this->command && !in_array($this->command, array('help'))) {
if ($this->command) {
if (!config('database')) {
$this->out(__('Your database configuration was not found. Take a moment to create one.'), true);
$this->args = null;
@ -105,20 +106,7 @@ class AclShell extends Shell {
*
*/
public function main() {
$out = __('Available ACL commands:') . "\n";
$out .= "\t - create\n";
$out .= "\t - delete\n";
$out .= "\t - setParent\n";
$out .= "\t - getPath\n";
$out .= "\t - check\n";
$out .= "\t - grant\n";
$out .= "\t - deny\n";
$out .= "\t - inherit\n";
$out .= "\t - view\n";
$out .= "\t - initdb\n";
$out .= "\t - help\n\n";
$out .= __("For help, run the 'help' command. For help on a specific command, run 'help <command>'");
$this->out($out);
$this->out($this->OptionParser->help());
}
/**
@ -126,8 +114,6 @@ class AclShell extends Shell {
*
*/
public function create() {
$this->_checkArgs(3, 'create');
$this->checkNodeType();
extract($this->__dataVars());
$class = ucfirst($this->args[0]);
@ -143,13 +129,13 @@ class AclShell extends Shell {
if (is_string($data) && $data != '/') {
$data = array('alias' => $data);
} elseif (is_string($data)) {
$this->error(__('/ can not be used as an alias!'), __("\t/ is the root, please supply a sub alias"));
$this->error(__('/ can not be used as an alias!') . __(" / is the root, please supply a sub alias"));
}
$data['parent_id'] = $parent;
$this->Acl->{$class}->create();
if ($this->Acl->{$class}->save($data)) {
$this->out(sprintf(__("New %s '%s' created.\n"), $class, $this->args[2]), true);
$this->out(sprintf(__("<success>New %s</success> '%s' created."), $class, $this->args[2]), 2);
} else {
$this->err(sprintf(__("There was a problem creating a new %s '%s'."), $class, $this->args[2]));
}
@ -160,17 +146,15 @@ class AclShell extends Shell {
*
*/
public function delete() {
$this->_checkArgs(2, 'delete');
$this->checkNodeType();
extract($this->__dataVars());
$identifier = $this->parseIdentifier($this->args[1]);
$nodeId = $this->_getNodeId($class, $identifier);
if (!$this->Acl->{$class}->delete($nodeId)) {
$this->error(__('Node Not Deleted'), sprintf(__('There was an error deleting the %s. Check that the node exists'), $class) . ".\n");
$this->error(__('Node Not Deleted') . sprintf(__('There was an error deleting the %s. Check that the node exists'), $class) . ".\n");
}
$this->out(sprintf(__('%s deleted'), $class) . ".\n", true);
$this->out(sprintf(__('<success>%s deleted.</success>'), $class), 2);
}
/**
@ -178,8 +162,6 @@ class AclShell extends Shell {
*
*/
public function setParent() {
$this->_checkArgs(3, 'setParent');
$this->checkNodeType();
extract($this->__dataVars());
$target = $this->parseIdentifier($this->args[1]);
$parent = $this->parseIdentifier($this->args[2]);
@ -203,8 +185,6 @@ class AclShell extends Shell {
*
*/
public function getPath() {
$this->_checkArgs(2, 'getPath');
$this->checkNodeType();
extract($this->__dataVars());
$identifier = $this->parseIdentifier($this->args[1]);
@ -247,13 +227,12 @@ class AclShell extends Shell {
*
*/
public function check() {
$this->_checkArgs(3, 'check');
extract($this->__getParams());
if ($this->Acl->check($aro, $aco, $action)) {
$this->out(sprintf(__('%s is allowed.'), $aroName), true);
$this->out(sprintf(__('%s is <success>allowed</success>.'), $aroName), true);
} else {
$this->out(sprintf(__('%s is not allowed.'), $aroName), true);
$this->out(sprintf(__('%s is <error>not allowed</error>.'), $aroName), true);
}
}
@ -262,13 +241,12 @@ class AclShell extends Shell {
*
*/
public function grant() {
$this->_checkArgs(3, 'grant');
extract($this->__getParams());
if ($this->Acl->allow($aro, $aco, $action)) {
$this->out(__('Permission granted.'), true);
$this->out(__('Permission <success>granted</success>.'), true);
} else {
$this->out(__('Permission was not granted.'), true);
$this->out(__('Permission was <error>not granted</error>.'), true);
}
}
@ -277,7 +255,6 @@ class AclShell extends Shell {
*
*/
public function deny() {
$this->_checkArgs(3, 'deny');
extract($this->__getParams());
if ($this->Acl->deny($aro, $aco, $action)) {
@ -292,7 +269,6 @@ class AclShell extends Shell {
*
*/
public function inherit() {
$this->_checkArgs(3, 'inherit');
extract($this->__getParams());
if ($this->Acl->inherit($aro, $aco, $action)) {
@ -307,8 +283,6 @@ class AclShell extends Shell {
*
*/
public function view() {
$this->_checkArgs(1, 'view');
$this->checkNodeType();
extract($this->__dataVars());
if (isset($this->args[1])) {
@ -368,116 +342,168 @@ class AclShell extends Shell {
*
*/
public function initdb() {
$this->Dispatch->args = array('schema', 'create', 'DbAcl');
$this->Dispatch->dispatch();
return $this->dispatchShell('schema create DbAcl');
}
/**
* Show help screen.
* Get the option parser.
*
* @return void
*/
public function help() {
$head = "-----------------------------------------------\n";
$head .= __('Usage: cake acl <command> <arg1> <arg2>...') . "\n";
$head .= "-----------------------------------------------\n";
$head .= __('Commands:') . "\n";
$commands = array(
'create' => "create aro|aco <parent> <node>\n" .
"\t" . __("Creates a new ACL object <node> under the parent") . "\n" .
"\t" . __("specified by <parent>, an id/alias.") . "\n" .
"\t" . __("The <parent> and <node> references can be") . "\n" .
"\t" . __("in one of the following formats:") . "\n\n" .
"\t\t- " . __("<model>.<id> - The node will be bound to a") . "\n" .
"\t\t" . __("specific record of the given model.") . "\n\n" .
"\t\t- " . __("<alias> - The node will be given a string alias,") . "\n" .
"\t\t" . __(" (or path, in the case of <parent>)") . "\n" .
"\t\t " . __("i.e. 'John'. When used with <parent>,") . "\n" .
"\t\t" . __("this takes the form of an alias path,") . "\n" .
"\t\t " . __("i.e. <group>/<subgroup>/<parent>.") . "\n\n" .
"\t" . __("To add a node at the root level,") . "\n" .
"\t" . __("enter 'root' or '/' as the <parent> parameter.") . "\n",
'delete' => "delete aro|aco <node>\n" .
"\t" . __("Deletes the ACL object with the given <node> reference") . "\n" .
"\t" . __("For more detailed parameter usage info,") . "\n" .
"\t" . __("see help for the 'create' command."),
'setparent' => "setParent aro|aco <node> <parent node>\n" .
"\t" . __("Moves the ACL object specified by <node> beneath") . "\n" .
"\t" . __("the parent ACL object specified by <parent>.") . "\n" .
"\t" . __("For more detailed parameter usage info,") . "\n" .
"\t" . __("see help for the 'create' command."),
'getpath' => "getPath aro|aco <node>\n" .
"\t" . __("Returns the path to the ACL object specified by <node>. This command", true) . "\n" .
"\t" . __("is useful in determining the inhertiance of permissions for a certain", true) . "\n" .
"\t" . __("object in the tree.", true) . "\n" .
"\t" . __("For more detailed parameter usage info,", true) . "\n" .
"\t" . __("see help for the 'create' command.", true),
'check' => "check <node> <node> [<aco_action>] " . __("or", true) . " all\n" .
"\t" . __("Use this command to check ACL permissions.", true) . "\n" .
"\t" . __("For more detailed parameter usage info,", true) . "\n" .
"\t" . __("see help for the 'create' command.", true),
'grant' => "grant <aronode> <aconode> [<aco_action>] " . __("or", true) . " all\n" .
"\t" . __("Use this command to grant ACL permissions. Once executed, the ARO", true) . "\n" .
"\t" . __("specified (and its children, if any) will have ALLOW access to the", true) . "\n" .
"\t" . __("specified ACO action (and the ACO's children, if any).", true) . "\n" .
"\t" . __("For more detailed parameter usage info,", true) . "\n" .
"\t" . __("see help for the 'create' command.", true),
'deny' => "deny <aronode> <aconode> [<aco_action>]" . __("or", true) . " all\n" .
"\t" . __("Use this command to deny ACL permissions. Once executed, the ARO", true) . "\n" .
"\t" . __("specified (and its children, if any) will have DENY access to the", true) . "\n" .
"\t" . __("specified ACO action (and the ACO's children, if any).", true) . "\n" .
"\t" . __("For more detailed parameter usage info,", true) . "\n" .
"\t" . __("see help for the 'create' command.", true),
'inherit' => "inherit <aronode> <aconode> [<aco_action>]" . __("or", true) . " all\n" .
"\t" . __("Use this command to force a child ARO object to inherit its", true) . "\n" .
"\t" . __("permissions settings from its parent.", true) . "\n" .
"\t" . __("For more detailed parameter usage info,", true) . "\n" .
"\t" . __("see help for the 'create' command.", true),
'view' => "view aro|aco [<node>]\n" .
"\t" . __("The view command will return the ARO or ACO tree.") . "\n" .
"\t" . __("The optional node parameter allows you to return") . "\n" .
"\t" . __("only a portion of the requested tree.") . "\n" .
"\t" . __("For more detailed parameter usage info,") . "\n" .
"\t" . __("see help for the 'create' command."),
'initdb' => "initdb\n".
"\t" . __("Uses this command : cake schema run create DbAcl"),
'help' => "help [<command>]\n" .
"\t" . __("Displays this help message, or a message on a specific command.")
public function getOptionParser() {
$parser = parent::getOptionParser();
$type = array(
'choices' => array('aro', 'aco'),
'required' => true,
'help' => __('Type of node to create.')
);
$this->out($head);
if (!isset($this->args[0])) {
foreach ($commands as $cmd) {
$this->out("{$cmd}\n\n");
}
} elseif (isset($commands[strtolower($this->args[0])])) {
$this->out($commands[strtolower($this->args[0])] . "\n\n");
} else {
$this->out(sprintf(__("Command '%s' not found"), $this->args[0]));
}
}
/**
* Check that first argument specifies a valid Node type (ARO/ACO)
*
*/
public function checkNodeType() {
if (!isset($this->args[0])) {
return false;
}
if ($this->args[0] != 'aco' && $this->args[0] != 'aro') {
$this->error(sprintf(__("Missing/Unknown node type: '%s'"), $this->args[0]), __('Please specify which ACL object type you wish to create. Either "aro" or "aco"'));
}
$parser->description('A console tool for managing the DbAcl')
->addSubcommand('create', array(
'help' => __('Create a new ACL node'),
'parser' => array(
'description' => __('Creates a new ACL object <node> under the parent'),
'arguments' => array(
'type' => $type,
'parent' => array(
'help' => __('The node selector for the parent.'),
'required' => true
),
'alias' => array(
'help' => __('The alias to use for the newly created node.'),
'required' => true
)
)
)
))->addSubcommand('delete', array(
'help' => __('Deletes the ACL object with the given <node> reference'),
'parser' => array(
'description' => __('Delete an ACL node.'),
'arguments' => array(
'type' => $type,
'node' => array(
'help' => __('The node identifier to delete.'),
'required' => true,
)
)
)
))->addSubcommand('setparent', array(
'help' => __('Moves the ACL node under a new parent.'),
'parser' => array(
'description' => __('Moves the ACL object specified by <node> beneath <parent>'),
'arguments' => array(
'type' => $type,
'node' => array(
'help' => __('The node to move'),
'required' => true,
),
'parent' => array(
'help' => __('The new parent for <node>.'),
'required' => true
)
)
)
))->addSubcommand('getpath', array(
'help' => __('Print out the path to an ACL node.'),
'parser' => array(
'description' => array(
__("Returns the path to the ACL object specified by <node>."),
__("This command is useful in determining the inhertiance of permissions"),
__("for a certain object in the tree.")
),
'arguments' => array(
'type' => $type,
'node' => array(
'help' => __('The node to get the path of'),
'required' => true,
)
)
)
))->addSubcommand('check', array(
'help' => __('Check the permissions between an ACO and ARO.'),
'parser' => array(
'description' => array(
__("Use this command to grant ACL permissions. Once executed, the ARO "),
__("specified (and its children, if any) will have ALLOW access to the"),
__("specified ACO action (and the ACO's children, if any).")
),
'arguments' => array(
'aro' => array('help' => __('ARO to check.'), 'required' => true),
'aco' => array('help' => __('ACO to check.'), 'required' => true),
'action' => array('help' => __('Action to check'), 'default' => 'all')
)
)
))->addSubcommand('grant', array(
'help' => __('Grant an ARO permissions to an ACO.'),
'parser' => array(
'description' => array(
__("Use this command to grant ACL permissions. Once executed, the ARO"),
__("specified (and its children, if any) will have ALLOW access to the"),
__("specified ACO action (and the ACO's children, if any).")
),
'arguments' => array(
'aro' => array('help' => __('ARO to grant permission to.'), 'required' => true),
'aco' => array('help' => __('ACO to grant access to.'), 'required' => true),
'action' => array('help' => __('Action to grant'), 'default' => 'all')
)
)
))->addSubcommand('deny', array(
'help' => __('Deny an ARO permissions to an ACO.'),
'parser' => array(
'description' => array(
__("Use this command to deny ACL permissions. Once executed, the ARO"),
__("specified (and its children, if any) will have DENY access to the"),
__("specified ACO action (and the ACO's children, if any).")
),
'arguments' => array(
'aro' => array('help' => __('ARO to deny.'), 'required' => true),
'aco' => array('help' => __('ACO to deny.'), 'required' => true),
'action' => array('help' => __('Action to deny'), 'default' => 'all')
)
)
))->addSubcommand('inherit', array(
'help' => __('Inherit an ARO\'s parent permissions.'),
'parser' => array(
'description' => array(
__("Use this command to force a child ARO object to inherit its"),
__("permissions settings from its parent.")
),
'arguments' => array(
'aro' => array('help' => __('ARO to have permisssions inherit.'), 'required' => true),
'aco' => array('help' => __('ACO to inherit permissions on.'), 'required' => true),
'action' => array('help' => __('Action to inherit'), 'default' => 'all')
)
)
))->addSubcommand('view', array(
'help' => __('View a tree or a single node\'s subtree.'),
'parser' => array(
'description' => array(
__("The view command will return the ARO or ACO tree."),
__("The optional node parameter allows you to return"),
__("only a portion of the requested tree.")
),
'arguments' => array(
'type' => $type,
'node' => array('help' => __('The optional node to view the subtree of.'))
)
)
))->addSubcommand('initdb', array(
'help' => __('Initialize the DbAcl tables. Uses this command : cake schema run create DbAcl')
))->epilog(
array(
'Node and parent arguments can be in one of the following formats:',
'',
' - <model>.<id> - The node will be bound to a specific record of the given model.',
'',
' - <alias> - The node will be given a string alias (or path, in the case of <parent>)',
" i.e. 'John'. When used with <parent>, this takes the form of an alias path,",
" i.e. <group>/<subgroup>/<parent>.",
'',
"To add a node at the root level, enter 'root' or '/' as the <parent> parameter."
)
);
return $parser;
}
/**
@ -488,7 +514,7 @@ class AclShell extends Shell {
* @return boolean Success
*/
public function nodeExists() {
if (!$this->checkNodeType() && !isset($this->args[1])) {
if (!isset($this->args[0]) || !isset($this->args[1])) {
return false;
}
extract($this->__dataVars($this->args[0]));

View file

@ -60,7 +60,7 @@ class ApiShell extends Shell {
*/
public function main() {
if (empty($this->args)) {
return $this->help();
return $this->out($this->OptionParser->help());
}
$type = strtolower($this->args[0]);
@ -78,7 +78,6 @@ class ApiShell extends Shell {
$file = Inflector::underscore($this->args[1]);
$class = Inflector::camelize($file);
}
$objects = App::objects('class', $path);
if (in_array($class, $objects)) {
if (in_array($type, array('behavior', 'component', 'helper')) && $type !== $file) {
@ -88,19 +87,18 @@ class ApiShell extends Shell {
}
} else {
$this->err(sprintf(__('%s not found'), $class));
$this->_stop();
$this->error(sprintf(__('%s not found'), $class));
}
$parsed = $this->__parseClass($path . $file .'.php', $class);
if (!empty($parsed)) {
if (isset($this->params['m'])) {
if (!isset($parsed[$this->params['m']])) {
$this->err(sprintf(__('%s::%s() could not be found'), $class, $this->params['m']));
if (isset($this->params['method'])) {
if (!isset($parsed[$this->params['method']])) {
$this->err(sprintf(__('%s::%s() could not be found'), $class, $this->params['method']));
$this->_stop();
}
$method = $parsed[$this->params['m']];
$method = $parsed[$this->params['method']];
$this->out($class .'::'.$method['method'] . $method['parameters']);
$this->hr();
$this->out($method['comment'], true);
@ -136,6 +134,23 @@ class ApiShell extends Shell {
}
}
/**
* Get and configure the optionparser.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
$parser->addArgument('type', array(
'help' => 'Either a full path or type of class (model, behavior, controller, component, view, helper)'
))->addArgument('className', array(
'help' => 'A CakePHP core class name (e.g: Component, HtmlHelper).'
))->addOption('method', array(
'short' => 'm',
'help' => __('The specific method you want help on.')
))->description(__('Lookup doc block comments for classes in CakePHP.'));
return $parser;
}
/**
* Show help for this shell.
*

View file

@ -43,22 +43,13 @@ class BakeShell extends Shell {
* Override loadTasks() to handle paths
*
*/
public function loadTasks() {
parent::loadTasks();
public function startup() {
parent::startup();
$task = Inflector::classify($this->command);
if (isset($this->{$task}) && !in_array($task, array('Project', 'DbConfig'))) {
if (isset($this->params['connection'])) {
$this->{$task}->connection = $this->params['connection'];
}
foreach($this->args as $i => $arg) {
if (strpos($arg, '.')) {
list($this->params['plugin'], $this->args[$i]) = pluginSplit($arg);
break;
}
}
if (isset($this->params['plugin'])) {
$this->{$task}->plugin = $this->params['plugin'];
}
}
}
@ -68,8 +59,9 @@ class BakeShell extends Shell {
*/
public function main() {
if (!is_dir($this->DbConfig->path)) {
if ($this->Project->execute()) {
$this->DbConfig->path = $this->params['working'] . DS . 'config' . DS;
$path = $this->Project->execute();
if (!empty($path)) {
$this->DbConfig->path = $path . 'config' . DS;
} else {
return false;
}
@ -188,38 +180,54 @@ class BakeShell extends Shell {
$this->out(__('Bake All complete'));
array_shift($this->args);
} else {
$this->err(__('Bake All could not continue without a valid model'));
$this->error(__('Bake All could not continue without a valid model'));
}
$this->_stop();
}
/**
* Displays help contents
* get the option parser.
*
* @return void
*/
public function help() {
$this->out('CakePHP Bake:');
$this->hr();
$this->out('The Bake script generates controllers, views and models for your application.');
$this->out('If run with no command line arguments, Bake guides the user through the class');
$this->out('creation process. You can customize the generation process by telling Bake');
$this->out('where different parts of your application are using command line arguments.');
$this->hr();
$this->out("Usage: cake bake <command> <arg1> <arg2>...");
$this->hr();
$this->out('Params:');
$this->out("\t-app <path> Absolute/Relative path to your app folder.\n");
$this->out('Commands:');
$this->out("\n\tbake help\n\t\tshows this help message.");
$this->out("\n\tbake all <name>\n\t\tbakes complete MVC. optional <name> of a Model");
$this->out("\n\tbake project <path>\n\t\tbakes a new app folder in the path supplied\n\t\tor in current directory if no path is specified");
$this->out("\n\tbake plugin <name>\n\t\tbakes a new plugin folder in the path supplied\n\t\tor in current directory if no path is specified.");
$this->out("\n\tbake db_config\n\t\tbakes a database.php file in config directory.");
$this->out("\n\tbake model\n\t\tbakes a model. run 'bake model help' for more info");
$this->out("\n\tbake view\n\t\tbakes views. run 'bake view help' for more info");
$this->out("\n\tbake controller\n\t\tbakes a controller. run 'bake controller help' for more info");
$this->out("\n\tbake fixture\n\t\tbakes fixtures. run 'bake fixture help' for more info.");
$this->out("\n\tbake test\n\t\tbakes unit tests. run 'bake test help' for more info.");
$this->out();
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
'The Bake script generates controllers, views and models for your application.' .
'If run with no command line arguments, Bake guides the user through the class' .
'creation process. You can customize the generation process by telling Bake' .
'where different parts of your application are using command line arguments.'
)->addSubcommand('all', array(
'help' => __('Bake a complete MVC. optional <name> of a Model'),
))->addSubcommand('project', array(
'help' => __('Bake a new app folder in the path supplied or in current directory if no path is specified'),
'parser' => $this->Project->getOptionParser()
))->addSubcommand('plugin', array(
'help' => __('Bake a new plugin folder in the path supplied or in current directory if no path is specified.'),
'parser' => $this->Plugin->getOptionParser()
))->addSubcommand('db_config', array(
'help' => __('Bake a database.php file in config directory.'),
'parser' => $this->DbConfig->getOptionParser()
))->addSubcommand('model', array(
'help' => __('Bake a model.'),
'parser' => $this->Model->getOptionParser()
))->addSubcommand('view', array(
'help' => __('Bake views for controllers.'),
'parser' => $this->View->getOptionParser()
))->addSubcommand('controller', array(
'help' => __('Bake a controller.'),
'parser' => $this->Controller->getOptionParser()
))->addSubcommand('fixture', array(
'help' => __('Bake a fixture.'),
'parser' => $this->Fixture->getOptionParser()
))->addSubcommand('test', array(
'help' => __('Bake a unit test.'),
'parser' => $this->Test->getOptionParser()
))->addOption('connection', array(
'help' => __('Database connection to use in conjunction with `bake all`.'),
'short' => 'c',
'default' => 'default'
));
}
}

View file

@ -0,0 +1,235 @@
<?php
/**
* CommandListTest file
*
* PHP 5
*
* CakePHP : Rapid Development Framework (http://cakephp.org)
* Copyright 2006-2010, Cake Software Foundation, Inc.
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2006-2010, Cake Software Foundation, Inc.
* @link http://cakephp.org CakePHP Project
* @package cake
* @subpackage cake.tests.cases.console.libs
* @since CakePHP v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Shows a list of commands available from the console.
*
* @package cake.console.libs
*/
class CommandListShell extends Shell {
/**
* startup
*
* @return void
*/
public function startup() {
if (empty($this->params['xml'])) {
parent::startup();
}
}
/**
* Main function Prints out the list of shells.
*
* @return void
*/
public function main() {
if (empty($this->params['xml'])) {
$this->out("<info>Current Paths:</info>", 2);
$this->out(" -app: ". APP_DIR);
$this->out(" -working: " . rtrim(APP_PATH, DS));
$this->out(" -root: " . rtrim(ROOT, DS));
$this->out(" -core: " . rtrim(CORE_PATH, DS));
$this->out("");
$this->out("<info>Changing Paths:</info>", 2);
$this->out("Your working path should be the same as your application path");
$this->out("to change your path use the '-app' param.");
$this->out("Example: -app relative/path/to/myapp or -app /absolute/path/to/myapp", 2);
$this->out("<info>Available Shells:</info>", 2);
}
$shellList = $this->_getShellList();
if ($shellList) {
ksort($shellList);
if (empty($this->params['xml'])) {
if (!empty($this->params['sort'])) {
$this->_asSorted($shellList);
} else {
$this->_asText($shellList);
}
} else {
$this->_asXml($shellList);
}
}
}
/**
* Gets the shell command listing.
*
* @return array
*/
protected function _getShellList() {
$shellList = array();
$corePaths = App::core('shells');
$shellList = $this->_appendShells('CORE', $corePaths, $shellList);
$appPaths = array_diff(App::path('shells'), $corePaths);
$shellList = $this->_appendShells('app', $appPaths, $shellList);
$plugins = App::objects('plugin');
foreach ($plugins as $plugin) {
$pluginPath = App::pluginPath($plugin) . 'console' . DS . 'shells' . DS;
$shellList = $this->_appendShells($plugin, array($pluginPath), $shellList);
}
return $shellList;
}
/**
* Scan the provided paths for shells, and append them into $shellList
*
* @return array
*/
protected function _appendShells($type, $paths, $shellList) {
foreach ($paths as $path) {
if (!is_dir($path)) {
continue;
}
$shells = App::objects('file', $path);
if (empty($shells)) {
continue;
}
foreach ($shells as $shell) {
if ($shell !== 'shell.php') {
$shell = str_replace('.php', '', $shell);
$shellList[$shell][$type] = $type;
}
}
}
return $shellList;
}
/**
* Output text.
*
* @return void
*/
protected function _asText($shellList) {
if (DS === '/') {
$width = exec('tput cols') - 2;
}
if (empty($width)) {
$width = 80;
}
$columns = max(1, floor($width / 30));
$rows = ceil(count($shellList) / $columns);
foreach ($shellList as $shell => $types) {
sort($types);
$shellList[$shell] = str_pad($shell . ' [' . implode ($types, ', ') . ']', $width / $columns);
}
$out = array_chunk($shellList, $rows);
for ($i = 0; $i < $rows; $i++) {
$row = '';
for ($j = 0; $j < $columns; $j++) {
if (!isset($out[$j][$i])) {
continue;
}
$row .= $out[$j][$i];
}
$this->out(" " . $row);
}
$this->out();
$this->out("To run a command, type <info>cake shell_name [args]</info>");
$this->out("To get help on a specific command, type <info>cake shell_name --help</info>", 2);
}
/**
* Generates the shell list sorted by where the shells are found.
*
* @return void
*/
protected function _asSorted($shellList) {
$grouped = array();
foreach ($shellList as $shell => $types) {
foreach ($types as $type) {
$type = Inflector::camelize($type);
if (empty($grouped[$type])) {
$grouped[$type] = array();
}
$grouped[$type][] = $shell;
}
}
if (!empty($grouped['App'])) {
sort($grouped['App'], SORT_STRING);
$this->out('[ App ]');
$this->out(' ' . implode(', ', $grouped['App']), 2);
unset($grouped['App']);
}
foreach ($grouped as $section => $shells) {
if ($section == 'CORE') {
continue;
}
sort($shells, SORT_STRING);
$this->out('[ ' . $section . ' ]');
$this->out(' ' . implode(', ', $shells), 2);
}
if (!empty($grouped['CORE'])) {
sort($grouped['CORE'], SORT_STRING);
$this->out('[ Core ]');
$this->out(' ' . implode(', ', $grouped['CORE']), 2);
}
$this->out();
}
/**
* Output as XML
*
* @return void
*/
protected function _asXml($shellList) {
$plugins = App::objects('plugin');
$shells = new SimpleXmlElement('<shells></shells>');
foreach ($shellList as $name => $location) {
$source = current($location);
$callable = $name;
if (in_array($source, $plugins)) {
$callable = Inflector::underscore($source) . '.' . $name;
}
$shell = $shells->addChild('shell');
$shell->addAttribute('name', $name);
$shell->addAttribute('call_as', $callable);
$shell->addAttribute('provider', $source);
$shell->addAttribute('help', $callable . ' -h');
}
$this->out($shells->saveXml());
}
/**
* get the option parser
*
* @return void
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description('Get the list of available shells for this CakePHP application.')
->addOption('xml', array(
'help' => __('Get the listing as XML.'),
'boolean' => true
))->addOption('sort', array(
'help' => __('Sorts the commands by where they are located.'),
'boolean' => true
));
}
}

View file

@ -65,7 +65,7 @@ class I18nShell extends Shell {
*
*/
public function main() {
$this->out(__('I18n Shell'));
$this->out(__('<info>I18n Shell</info>'));
$this->hr();
$this->out(__('[E]xtract POT file from sources'));
$this->out(__('[I]nitialize i18n database table'));
@ -81,7 +81,7 @@ class I18nShell extends Shell {
$this->initdb();
break;
case 'h':
$this->help();
$this->out($this->OptionParser->help());
break;
case 'q':
exit(0);
@ -98,27 +98,23 @@ class I18nShell extends Shell {
*
*/
public function initdb() {
$this->Dispatch->args = array('schema', 'create', 'i18n');
$this->Dispatch->dispatch();
$this->dispatchShell('schema create i18n');
}
/**
* Show help screen.
* Get and configure the Option parser
*
* @return ConsoleOptionParser
*/
public function help() {
$this->hr();
$this->out(__('I18n Shell:'));
$this->hr();
$this->out(__('I18n Shell initializes i18n database table for your application'));
$this->out(__('and generates .pot file(s) with translations.'));
$this->hr();
$this->out(__('usage:'));
$this->out(' cake i18n help');
$this->out(' cake i18n initdb [-datasource custom]');
$this->out();
$this->hr();
$this->Extract->help();
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__('I18n Shell initializes i18n database table for your application and generates .pot files(s) with translations.')
)->addSubcommand('initdb', array(
'help' => __('Initialize the i18n table.')
))->addSubcommand('extract', array(
'help' => __('Extract the po translations from your application'),
'parser' => $this->Extract->getOptionParser()
));
}
}

View file

@ -40,6 +40,13 @@ class SchemaShell extends Shell {
*/
private $__dry = null;
/**
* Schema class being used.
*
* @var CakeSchema
*/
public $Schema;
/**
* Override initialize
*
@ -95,14 +102,6 @@ class SchemaShell extends Shell {
$this->Schema =& new CakeSchema(compact('name', 'path', 'file', 'connection', 'plugin'));
}
/**
* Override main
*
*/
public function main() {
$this->help();
}
/**
* Read and output contents of schema object
* path to read as second arg
@ -128,7 +127,7 @@ class SchemaShell extends Shell {
public function generate() {
$this->out(__('Generating Schema...'));
$options = array();
if (isset($this->params['f'])) {
if (isset($this->params['force'])) {
$options = array('models' => false);
}
@ -156,8 +155,8 @@ class SchemaShell extends Shell {
$result = $Folder->read();
$numToUse = false;
if (isset($this->params['s'])) {
$numToUse = $this->params['s'];
if (isset($this->params['snapshot'])) {
$numToUse = $this->params['snapshot'];
}
$count = 0;
@ -203,7 +202,7 @@ class SchemaShell extends Shell {
$this->err(__('Schema could not be loaded'));
$this->_stop();
}
if (isset($this->params['write'])) {
if (!empty($this->params['write'])) {
if ($this->params['write'] == 1) {
$write = Inflector::underscore($this->Schema->name);
} else {
@ -263,22 +262,22 @@ class SchemaShell extends Shell {
*/
function _loadSchema() {
$name = $plugin = null;
if (isset($this->params['name'])) {
if (!empty($this->params['name'])) {
$name = $this->params['name'];
}
if (isset($this->params['plugin'])) {
if (!empty($this->params['plugin'])) {
$plugin = $this->params['plugin'];
}
if (isset($this->params['dry'])) {
if (!empty($this->params['dry'])) {
$this->__dry = true;
$this->out(__('Performing a dry run.'));
}
$options = array('name' => $name, 'plugin' => $plugin);
if (isset($this->params['s'])) {
if (!empty($this->params['snapshot'])) {
$fileName = rtrim($this->Schema->file, '.php');
$options['file'] = $fileName . '_' . $this->params['s'] . '.php';
$options['file'] = $fileName . '_' . $this->params['snapshot'] . '.php';
}
$Schema =& $this->Schema->load($options);
@ -348,7 +347,7 @@ class SchemaShell extends Shell {
$this->out(__('Comparing Database to Schema...'));
$options = array();
if (isset($this->params['f'])) {
if (isset($this->params['force'])) {
$options['models'] = false;
}
$Old = $this->Schema->read($options);
@ -422,78 +421,97 @@ class SchemaShell extends Shell {
}
/**
* Displays help contents
* get the option parser
*
* @return void
*/
public function help() {
$help = <<<TEXT
The Schema Shell generates a schema object from
the database and updates the database from the schema.
---------------------------------------------------------------
Usage: cake schema <command> <arg1> <arg2>...
---------------------------------------------------------------
Params:
-connection <config>
set db config <config>. uses 'default' if none is specified
-path <dir>
path <dir> to read and write schema.php.
default path: {$this->Schema->path}
-name <name>
Classname to use. If <name> is Plugin.className, it will
set the plugin and name params.
-file <name>
file <name> to read and write.
default file: {$this->Schema->file}
-s <number>
snapshot <number> to use for run.
-dry
Perform a dry run on create + update commands.
Queries will be output to window instead of executed.
-f
force 'generate' to create a new schema.
-plugin
Indicate the plugin to use.
Commands:
schema help
shows this help message.
schema view <name>
read and output contents of schema file.
schema generate
reads from 'connection' writes to 'path'
To force generation of all tables into the schema, use the -f param.
Use 'schema generate snapshot <number>' to generate snapshots
which you can use with the -s parameter in the other operations.
schema dump <name>
Dump database sql based on schema file to stdout.
If you use the `-write` param is used a .sql will be generated.
If `-write` is a filename, then that file name will be generate.
If `-write` is a full path, the schema will be written there.
schema create <name> <table>
Drop and create tables based on schema file
optional <table> argument can be used to create only a single
table in the schema. Pass the -s param with a number to use a snapshot.
Use the `-dry` param to preview the changes.
schema update <name> <table>
Alter the tables based on schema file. Optional <table>
parameter will only update one table.
To use a snapshot pass the `-s` param with the snapshot number.
To preview the changes that will be done use `-dry`.
TEXT;
$this->out($help);
$this->_stop();
public function getOptionParser() {
$plugin = array(
'help' => __('The plugin to use.'),
);
$connection = array(
'help' => __('Set the db config to use.'),
'default' => 'default'
);
$path = array(
'help' => __('Path to read and write schema.php'),
'default' => CONFIGS . 'schema'
);
$file = array(
'help' => __('File name to read and write.'),
'default' => 'schema.php'
);
$name = array(
'help' => __('Classname to use. If its Plugin.class, both name and plugin options will be set.')
);
$snapshot = array(
'short' => 's',
'help' => __('Snapshot number to use/make.')
);
$dry = array(
'help' => 'Perform a dry run on create and update commands. Queries will be output instead of run.',
'boolean' => true
);
$force = array(
'short' => 'f',
'help' => __('Force "generate" to create a new schema'),
'boolean' => true
);
$write = array(
'help' => __('Write the dumped SQL to a file.')
);
$parser = parent::getOptionParser();
$parser->description(
'The Schema Shell generates a schema object from' .
'the database and updates the database from the schema.'
)->addSubcommand('view', array(
'help' => 'read and output the contents of a schema file',
'parser' => array(
'options' => compact('plugin', 'path', 'file', 'name', 'connection'),
'arguments' => compact('name')
)
))->addSubcommand('generate', array(
'help' => __('Reads from --connection and writes to --path. Generate snapshots with -s'),
'parser' => array(
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'snapshot', 'force'),
'arguments' => array(
'snapshot' => array('help' => __('Generate a snapshot.'))
)
)
))->addSubcommand('dump', array(
'help' => __('Dump database SQL based on a schema file to stdout.'),
'parser' => array(
'options' => compact('plugin', 'path', 'file', 'name', 'connection'),
'arguments' => compact('name')
)
))->addSubcommand('create', array(
'help' => __('Drop and create tables based on the schema file.'),
'parser' => array(
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot'),
'args' => array(
'name' => array(
'help' => __('Name of schema to use.')
),
'table' => array(
'help' => __('Only create the specified table.')
)
)
)
))->addSubcommand('update', array(
'help' => __('Alter the tables based on the schema file.'),
'parser' => array(
'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot'),
'args' => array(
'name' => array(
'help' => __('Name of schema to use.')
),
'table' => array(
'help' => __('Only create the specified table.')
)
)
)
));
return $parser;
}
}

View file

@ -17,7 +17,10 @@
* @since CakePHP(tm) v 1.2.0.5012
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'TaskCollection');
require_once CONSOLE_LIBS . 'task_collection.php';
require_once CONSOLE_LIBS . 'console_output.php';
require_once CONSOLE_LIBS . 'console_input.php';
require_once CONSOLE_LIBS . 'console_option_parser.php';
/**
* Base class for command-line utilities for automating programmer chores.
@ -28,12 +31,18 @@ App::import('Shell', 'TaskCollection');
class Shell extends Object {
/**
* An instance of the ShellDispatcher object that loaded this script
*
* @var ShellDispatcher
* @access public
* Output constants for making verbose and quiet shells.
*/
public $Dispatch = null;
const VERBOSE = 2;
const NORMAL = 1;
const QUIET = 0;
/**
* An instance of ConsoleOptionParser that has been configured for this class.
*
* @var ConsoleOptionParser
*/
public $OptionParser;
/**
* If true, the script will ask for permission to perform actions.
@ -43,15 +52,6 @@ class Shell extends Object {
*/
public $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 DATABASE_CONFIG
* @access public
*/
public $DbConfig = null;
/**
* Contains command switches parsed from the command line.
*
@ -60,6 +60,13 @@ class Shell extends Object {
*/
public $params = array();
/**
* The command (method/task) that is being run.
*
* @var string
*/
public $command;
/**
* Contains arguments parsed from the command line.
*
@ -68,30 +75,6 @@ class Shell extends Object {
*/
public $args = array();
/**
* The file name of the shell that was invoked.
*
* @var string
* @access public
*/
public $shell = null;
/**
* The class name of the shell that was invoked.
*
* @var string
* @access public
*/
public $className = null;
/**
* The command called if public methods are available.
*
* @var string
* @access public
*/
public $command = null;
/**
* The name of the shell in camelized.
*
@ -100,14 +83,6 @@ class Shell extends Object {
*/
public $name = null;
/**
* An alias for the shell
*
* @var string
* @access public
*/
public $alias = null;
/**
* Contains tasks to load and instantiate
*
@ -139,30 +114,56 @@ class Shell extends Object {
*/
public $Tasks;
/**
* Normalized map of tasks.
*
* @var string
*/
protected $_taskMap = array();
/**
* stdout object.
*
* @var ConsoleOutput
*/
public $stdout;
/**
* stderr object.
*
* @var ConsoleOutput
*/
public $stderr;
/**
* stdin object
*
* @var ConsoleInput
*/
public $stdin;
/**
* Constructs this Shell instance.
*
*/
function __construct(&$dispatch) {
$vars = array('params', 'args', 'shell', 'shellCommand' => 'command');
foreach ($vars as $key => $var) {
if (is_string($key)) {
$this->{$var} =& $dispatch->{$key};
} else {
$this->{$var} =& $dispatch->{$var};
}
}
function __construct($stdout = null, $stderr = null, $stdin = null) {
if ($this->name == null) {
$this->name = get_class($this);
$this->name = Inflector::underscore(str_replace(array('Shell', 'Task'), '', get_class($this)));
}
$this->Tasks = new TaskCollection($this);
if ($this->alias == null) {
$this->alias = $this->name;
$this->stdout = $stdout;
$this->stderr = $stderr;
$this->stdin = $stdin;
if ($this->stdout == null) {
$this->stdout = new ConsoleOutput('php://stdout');
}
if ($this->stderr == null) {
$this->stderr = new ConsoleOutput('php://stderr');
}
if ($this->stdin == null) {
$this->stdin = new ConsoleInput('php://stdin');
}
$this->Dispatch =& $dispatch;
$this->Tasks = $dispatch->getTaskCollection();
}
/**
@ -190,31 +191,15 @@ class Shell extends Object {
*
*/
protected function _welcome() {
$this->Dispatch->clear();
$this->clear();
$this->out();
$this->out('Welcome to CakePHP v' . Configure::version() . ' Console');
$this->out('<info>Welcome to CakePHP v' . Configure::version() . ' Console</info>');
$this->hr();
$this->out('App : '. $this->params['app']);
$this->out('Path: '. $this->params['working']);
$this->out('App : '. APP_DIR);
$this->out('Path: '. APP_PATH);
$this->hr();
}
/**
* Loads database file and constructs DATABASE_CONFIG class
* makes $this->DbConfig available to subclasses
*
* @return bool
*/
protected function _loadDbConfig() {
if (config('database') && class_exists('DATABASE_CONFIG')) {
$this->DbConfig =& new DATABASE_CONFIG();
return true;
}
$this->err('Database config could not be loaded.');
$this->out('Run `bake` to create the database configuration.');
return false;
}
/**
* if public $uses = true
* Loads AppModel file and constructs AppModel class
@ -228,11 +213,6 @@ class Shell extends Object {
return;
}
if ($this->uses === true && App::import('Model', 'AppModel')) {
$this->AppModel =& new AppModel(false, false, false);
return true;
}
if ($this->uses !== true && !empty($this->uses)) {
$uses = is_array($this->uses) ? $this->uses : array($this->uses);
@ -260,14 +240,159 @@ class Shell extends Object {
if ($this->tasks === true || empty($this->tasks) || empty($this->Tasks)) {
return true;
}
$tasks = TaskCollection::normalizeObjectArray((array)$this->tasks);
foreach ($tasks as $task => $properties) {
$this->{$task} = $this->Tasks->load($properties['class'], $properties['settings']);
$this->_taskMap = TaskCollection::normalizeObjectArray((array)$this->tasks);
foreach ($this->_taskMap as $task => $properties) {
$this->taskNames[] = $task;
}
return true;
}
/**
* Check to see if this shell has a task with the provided name.
*
* @param string $task The task name to check.
* @return boolean Success
*/
public function hasTask($task) {
return isset($this->_taskMap[Inflector::camelize($task)]);
}
/**
* Check to see if this shell has a callable method by the given name.
*
* @param string $name The method name to check.
* @return boolean
*/
public function hasMethod($name) {
if (empty($this->_reflection)) {
$this->_reflection = new ReflectionClass($this);
}
try {
$method = $this->_reflection->getMethod($name);
if (!$method->isPublic() || substr($name, 0, 1) === '_') {
return false;
}
if ($method->getDeclaringClass() != $this->_reflection) {
return false;
}
return true;
} catch (ReflectionException $e) {
return false;
}
}
/**
* Dispatch a command to another Shell. Similar to Object::requestAction()
* but intended for running shells from other shells.
*
* ### Usage:
*
* With a string commmand:
*
* `return $this->dispatchShell('schema create DbAcl');`
*
* With an array command:
*
* `return $this->dispatchShell('schema', 'create', 'i18n', '--dry');`
*
* @param mixed $command Either an array of args similar to $argv. Or a string command, that can be
* exploded on space to simulate argv.
* @return mixed. The return of the other shell.
*/
public function dispatchShell() {
$args = func_get_args();
if (is_string($args[0]) && count($args) == 1) {
$args = explode(' ', $args[0]);
}
$Dispatcher = new ShellDispatcher($args, false);
return $Dispatcher->dispatch();
}
/**
* Runs the Shell with the provided argv
*
* @param array $argv Array of arguments to run the shell with. This array should be missing the shell name.
* @return void
*/
public function runCommand($command, $argv) {
$isTask = $this->hasTask($command);
$isMethod = $this->hasMethod($command);
$isMain = $this->hasMethod('main');
if ($isTask || $isMethod && $command !== 'execute') {
array_shift($argv);
}
$this->OptionParser = $this->getOptionParser();
list($this->params, $this->args) = $this->OptionParser->parse($argv, $command);
$this->command = $command;
if (!empty($this->params['help'])) {
return $this->_displayHelp($command);
}
if (($isTask || $isMethod || $isMain) && $command !== 'execute' ) {
$this->startup();
}
if ($isTask) {
$command = Inflector::camelize($command);
return $this->{$command}->runCommand('execute', $argv);
}
if ($isMethod) {
return $this->{$command}();
}
if ($isMain) {
return $this->main();
}
return $this->out($this->OptionParser->help($command));
}
/**
* Display the help in the correct format
*
* @return void
*/
protected function _displayHelp($command) {
$format = 'text';
if (!empty($this->args[0]) && $this->args[0] == 'xml') {
$format = 'xml';
$this->output->outputAs(ConsoleOutput::RAW);
} else {
$this->_welcome();
}
return $this->out($this->OptionParser->help($command, $format));
}
/**
* Gets the option parser instance and configures it.
* By overriding this method you can configure the ConsoleOptionParser before returning it.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = new ConsoleOptionParser($this->name);
return $parser;
}
/**
* Overload get for lazy building of tasks
*
* @return void
*/
public function __get($name) {
if (empty($this->{$name}) && in_array($name, $this->taskNames)) {
$properties = $this->_taskMap[$name];
$this->{$name} = $this->Tasks->load($properties['class'], $properties['settings']);
$this->{$name}->args =& $this->args;
$this->{$name}->params =& $this->params;
$this->{$name}->initialize();
$this->{$name}->loadTasks();
}
return $this->{$name};
}
/**
* Prompts the user for input, and returns it.
*
@ -280,7 +405,7 @@ class Shell extends Object {
if (!$this->interactive) {
return $default;
}
$in = $this->Dispatch->getInput($prompt, $options, $default);
$in = $this->_getInput($prompt, $options, $default);
if ($options && is_string($options)) {
if (strpos($options, ',')) {
@ -293,7 +418,7 @@ class Shell extends Object {
}
if (is_array($options)) {
while ($in == '' || ($in && (!in_array(strtolower($in), $options) && !in_array(strtoupper($in), $options)) && !in_array($in, $options))) {
$in = $this->Dispatch->getInput($prompt, $options, $default);
$in = $this->_getInput($prompt, $options, $default);
}
}
if ($in) {
@ -301,19 +426,86 @@ class Shell extends Object {
}
}
/**
* 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.
*/
protected function _getInput($prompt, $options, $default) {
if (!is_array($options)) {
$printOptions = '';
} else {
$printOptions = '(' . implode('/', $options) . ')';
}
if ($default === null) {
$this->stdout->write('<question>' . $prompt . '</question>' . " $printOptions \n" . '> ', 0);
} else {
$this->stdout->write('<question>' . $prompt . '</question>' . " $printOptions \n" . "[$default] > ", 0);
}
$result = $this->stdin->read();
if ($result === false) {
$this->_stop(1);
}
$result = trim($result);
if ($default != null && empty($result)) {
return $default;
}
return $result;
}
/**
* Wrap a block of text.
* Allows you to set the width, and indenting on a block of text.
*
* ### Options
*
* - `width` The width to wrap to. Defaults to 72
* - `wordWrap` Only wrap on words breaks (spaces) Defaults to true.
* - `indent` Indent the text with the string provided. Defaults to null.
*
* @param string $text Text the text to format.
* @param mixed $options Array of options to use, or an integer to wrap the text to.
* @return string Wrapped / indented text
* @see String::wrap()
*/
public function wrapText($text, $options = array()) {
return String::wrap($text, $options);
}
/**
* Outputs a single or multiple messages to stdout. If no parameters
* are passed outputs just a newline.
*
* ### Output levels
*
* There are 3 built-in output level. Shell::QUIET, Shell::NORMAL, Shell::VERBOSE.
* The verbose and quiet output levels, map to the `verbose` and `quiet` output switches
* present in most shells. Using Shell::QUIET for a message means it will always display.
* While using Shell::VERBOSE means it will only display when verbose output is toggled.
*
* @param mixed $message A string or a an array of strings to output
* @param integer $newlines Number of newlines to append
* @param integer $level The message's output level, see above.
* @return integer Returns the number of bytes returned from writing to stdout.
*/
public function out($message = null, $newlines = 1) {
if (is_array($message)) {
$message = implode($this->nl(), $message);
public function out($message = null, $newlines = 1, $level = Shell::NORMAL) {
$currentLevel = Shell::NORMAL;
if (!empty($this->params['verbose'])) {
$currentLevel = Shell::VERBOSE;
}
return $this->Dispatch->stdout($message . $this->nl($newlines), false);
if (!empty($this->params['quiet'])) {
$currentLevel = Shell::QUIET;
}
if ($level <= $currentLevel) {
return $this->stdout->write($message, $newlines);
}
return true;
}
/**
@ -324,10 +516,7 @@ class Shell extends Object {
* @param integer $newlines Number of newlines to append
*/
public function err($message = null, $newlines = 1) {
if (is_array($message)) {
$message = implode($this->nl(), $message);
}
$this->Dispatch->stderr($message . $this->nl($newlines));
$this->stderr->write($message, $newlines);
}
/**
@ -338,17 +527,18 @@ class Shell extends Object {
* @return string
*/
function nl($multiplier = 1) {
return str_repeat("\n", $multiplier);
return str_repeat(ConsoleOutput::LF, $multiplier);
}
/**
* Outputs a series of minus characters to the standard output, acts as a visual separator.
*
* @param integer $newlines Number of newlines to pre- and append
* @param integer $width Width of the line, defaults to 63
*/
public function hr($newlines = 0) {
public function hr($newlines = 0, $width = 63) {
$this->out(null, $newlines);
$this->out('---------------------------------------------------------------');
$this->out(str_repeat('-', $width));
$this->out(null, $newlines);
}
@ -360,7 +550,7 @@ class Shell extends Object {
* @param string $message An optional error message
*/
public function error($title, $message = null) {
$this->err(sprintf(__('Error: %s'), $title));
$this->err(sprintf(__('<error>Error:</error> %s'), $title));
if (!empty($message)) {
$this->err($message);
@ -369,21 +559,17 @@ class Shell extends Object {
}
/**
* Will check the number args matches otherwise throw an error
* Clear the console
*
* @param integer $expectedNum Expected number of paramters
* @param string $command Command
* @return void
*/
protected function _checkArgs($expectedNum, $command = null) {
if (!$command) {
$command = $this->command;
}
if (count($this->args) < $expectedNum) {
$message[] = "Got: " . count($this->args);
$message[] = "Expected: {$expectedNum}";
$message[] = "Please type `cake {$this->shell} help` for help";
$message[] = "on usage of the {$this->name} {$command}.";
$this->error('Wrong number of parameters', $message);
public function clear() {
if (empty($this->params['noclear'])) {
if ( DS === '/') {
passthru('clear');
} else {
passthru('cls');
}
}
}
@ -398,20 +584,22 @@ class Shell extends Object {
$path = str_replace(DS . DS, DS, $path);
$this->out();
$this->out(sprintf(__('Creating file %s'), $path));
if (is_file($path) && $this->interactive === true) {
$prompt = sprintf(__('File `%s` exists, overwrite?'), $path);
$key = $this->in($prompt, array('y', 'n', 'q'), 'n');
$this->out(sprintf(__('<warning>File `%s` exists</warning>'), $path));
$key = $this->in(__('Do you want to overwrite?'), array('y', 'n', 'q'), 'n');
if (strtolower($key) == 'q') {
$this->out(__('Quitting.'), 2);
$this->out(__('<error>Quitting</error>.'), 2);
$this->_stop();
} elseif (strtolower($key) != 'y') {
$this->out(sprintf(__('Skip `%s`'), $path), 2);
return false;
}
} else {
$this->out(sprintf(__('Creating file %s'), $path));
}
if (!class_exists('File')) {
require LIBS . 'file.php';
}
@ -419,27 +607,14 @@ class Shell extends Object {
if ($File = new File($path, true)) {
$data = $File->prepare($contents);
$File->write($data);
$this->out(sprintf(__('Wrote `%s`'), $path));
$this->out(sprintf(__('<success>Wrote</success> `%s`'), $path));
return true;
} else {
$this->err(sprintf(__('Could not write to `%s`.'), $path), 2);
$this->err(sprintf(__('<error>Could not write to `%s`</error>.'), $path), 2);
return false;
}
}
/**
* Outputs usage text on the standard output. Implement it in subclasses.
*
*/
public function help() {
if ($this->command != null) {
$this->err("Unknown {$this->name} command `{$this->command}`.");
$this->err("For usage, try `cake {$this->shell} help`.", 2);
} else {
$this->Dispatch->help();
}
}
/**
* Action to create a Unit Test
*
@ -449,13 +624,13 @@ class Shell extends Object {
if (App::import('vendor', 'simpletest' . DS . 'simpletest')) {
return true;
}
$prompt = 'SimpleTest is not installed. Do you want to bake unit test files anyway?';
$prompt = 'PHPUnit is not installed. Do you want to bake unit test files anyway?';
$unitTest = $this->in($prompt, array('y','n'), 'y');
$result = strtolower($unitTest) == 'y' || strtolower($unitTest) == 'yes';
if ($result) {
$this->out();
$this->out('You can download SimpleTest from http://simpletest.org');
$this->out('You can download PHPUnit from http://phpunit.de');
}
return $result;
}

View file

@ -51,9 +51,27 @@ class BakeTask extends Shell {
public function getPath() {
$path = $this->path;
if (isset($this->plugin)) {
$name = substr($this->name, 0, strlen($this->name) - 4);
$path = $this->_pluginPath($this->plugin) . Inflector::pluralize(Inflector::underscore($name)) . DS;
$path = $this->_pluginPath($this->plugin) . Inflector::pluralize(Inflector::underscore($this->name)) . DS;
}
return $path;
}
/**
* Base execute method parses some parameters and sets some properties on the bake tasks.
* call when overriding execute()
*
* @return void
*/
public function execute() {
foreach($this->args as $i => $arg) {
if (strpos($arg, '.')) {
list($this->params['plugin'], $this->args[$i]) = pluginSplit($arg);
break;
}
}
if (isset($this->params['plugin'])) {
$this->plugin = $this->params['plugin'];
}
}
}

View file

@ -56,6 +56,7 @@ class ControllerTask extends BakeTask {
*
*/
public function execute() {
parent::execute();
if (empty($this->args)) {
return $this->_interactive();
}
@ -69,26 +70,22 @@ class ControllerTask extends BakeTask {
}
$controller = $this->_controllerName($this->args[0]);
$actions = 'scaffold';
$actions = '';
if (!empty($this->args[1]) && ($this->args[1] == 'public' || $this->args[1] == 'scaffold')) {
if (!empty($this->params['public'])) {
$this->out(__('Baking basic crud methods for ') . $controller);
$actions = $this->bakeActions($controller);
} elseif (!empty($this->args[1]) && $this->args[1] == 'admin') {
$admin = $this->Project->getPrefix();
if ($admin) {
$this->out(sprintf(__('Adding %s methods'), $admin));
$actions = $this->bakeActions($controller, $admin);
}
$actions .= $this->bakeActions($controller);
}
if (!empty($this->args[2]) && $this->args[2] == 'admin') {
if (!empty($this->params['admin'])) {
$admin = $this->Project->getPrefix();
if ($admin) {
$this->out(sprintf(__('Adding %s methods'), $admin));
$actions .= "\n" . $this->bakeActions($controller, $admin);
}
}
if (empty($actions)) {
$actions = 'scaffold';
}
if ($this->bake($controller, $actions)) {
if ($this->_checkUnitTest()) {
@ -431,6 +428,34 @@ class ControllerTask extends BakeTask {
return $controllerName;
}
/**
* get the option parser.
*
* @return void
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__('Bake a controller for a model. Using options you can bake public, admin or both.')
)->addArgument('name', array(
'help' => __('Name of the controller to bake. Can use Plugin.name to bake controllers into plugins.')
))->addOption('public', array(
'help' => __('Bake a controller with basic crud actions (index, view, add, edit, delete).'),
'boolean' => true
))->addOption('admin', array(
'help' => __('Bake a controller with crud actions for one of the Routing.prefixes.'),
'boolean' => true
))->addOption('plugin', array(
'short' => 'p',
'help' => __('Plugin to bake the controller into.')
))->addOption('connection', array(
'short' => 'c',
'help' => __('The connection the controller\'s model is on.')
))->addSubcommand('all', array(
'help' => __('Bake all controllers with CRUD methods.')
))->epilog(__('Omitting all arguments and options will enter into an interactive mode.'));
}
/**
* Displays help contents
*

View file

@ -30,7 +30,6 @@ class DbConfigTask extends Shell {
* path to CONFIG directory
*
* @var string
* @access public
*/
public $path = null;
@ -38,12 +37,19 @@ class DbConfigTask extends Shell {
* Default configuration settings to use
*
* @var array
* @access private
*/
protected $_defaultConfig = array(
'name' => 'default', 'driver'=> 'mysql', 'persistent'=> 'false', 'host'=> 'localhost',
'login'=> 'root', 'password'=> 'password', 'database'=> 'project_name',
'schema'=> null, 'prefix'=> null, 'encoding' => null, 'port' => null
'name' => 'default',
'driver'=> 'mysql',
'persistent'=> 'false',
'host'=> 'localhost',
'login'=> 'root',
'password'=> 'password',
'database'=> 'project_name',
'schema'=> null,
'prefix'=> null,
'encoding' => null,
'port' => null
);
/**
@ -60,7 +66,7 @@ class DbConfigTask extends Shell {
* @var string
*/
public function initialize() {
$this->path = $this->params['working'] . DS . 'config' . DS;
$this->path = APP . 'config' . DS;
}
/**
@ -305,10 +311,10 @@ class DbConfigTask extends Shell {
$out .= "class DATABASE_CONFIG {\n\n";
foreach ($configs as $config) {
$config = array_merge($this->__defaultConfig, $config);
$config = array_merge($this->_defaultConfig, $config);
extract($config);
$out .= "\tvar \${$name} = array(\n";
$out .= "\tpublic \${$name} = array(\n";
$out .= "\t\t'driver' => '{$driver}',\n";
$out .= "\t\t'persistent' => {$persistent},\n";
$out .= "\t\t'host' => '{$host}',\n";
@ -337,7 +343,6 @@ class DbConfigTask extends Shell {
}
$out .= "}\n";
$out .= "?>";
$filename = $this->path . 'database.php';
return $this->createFile($filename, $out);
}
@ -362,4 +367,16 @@ class DbConfigTask extends Shell {
}
return $useDbConfig;
}
/**
* get the option parser
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__('Bake new database configuration settings.')
);
}
}

View file

@ -90,6 +90,13 @@ class ExtractTask extends Shell {
*/
private $__output = null;
/**
* An array of directories to exclude.
*
* @var array
*/
protected $_exclude = array();
/**
* Execution method always used for tasks
*
@ -97,14 +104,17 @@ class ExtractTask extends Shell {
* @access private
*/
function execute() {
if (!empty($this->params['exclude'])) {
$this->_exclude = explode(',', $this->params['exclude']);
}
if (isset($this->params['files']) && !is_array($this->params['files'])) {
$this->__files = explode(',', $this->params['files']);
}
if (isset($this->params['paths'])) {
$this->__paths = explode(',', $this->params['paths']);
} else {
$defaultPath = $this->params['working'];
$message = sprintf(__("What is the full path you would like to extract?\nExample: %s\n[Q]uit [D]one"), $this->params['root'] . DS . 'myapp');
$defaultPath = APP_PATH;
$message = sprintf(__("What is the full path you would like to extract?\nExample: %s\n[Q]uit [D]one"), $this->Dispatch->params['root'] . DS . 'myapp');
while (true) {
$response = $this->in($message, null, $defaultPath);
if (strtoupper($response) === 'Q') {
@ -182,6 +192,27 @@ class ExtractTask extends Shell {
$this->out(__('Done.'));
}
/**
* Get & configure the option parser
*
* @return void
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(__('CakePHP Language String Extraction:'))
->addOption('app', array('help' => __('Directory where your application is located.')))
->addOption('paths', array('help' => __('Comma separted list of paths, full paths are needed.')))
->addOption('merge', array(
'help' => __('Merge all domain strings into the default.po file.'),
'choices' => array('yes', 'no')
))
->addOption('output', array('help' => __('Full path to output directory.')))
->addOption('files', array('help' => __('Comma separated list of files, full paths are needed.')))
->addOption('exclude', array(
'help' => __('Comma separated list of directories to exclude. Any path containing a path segment with the provided values will be skipped. E.g. test,vendors')
));
}
/**
* Show help options
*
@ -484,9 +515,21 @@ class ExtractTask extends Shell {
* @access private
*/
function __searchFiles() {
$pattern = false;
if (!empty($this->_exclude)) {
$pattern = '/[\/\\\\]' . implode('|', $this->_exclude) . '[\/\\\\]/';
}
foreach ($this->__paths as $path) {
$Folder = new Folder($path);
$files = $Folder->findRecursive('.*\.(php|ctp|thtml|inc|tpl)', true);
if (!empty($pattern)) {
foreach ($files as $i => $file) {
if (preg_match($pattern, $file)) {
unset($files[$i]);
}
}
$files = array_values($files);
}
$this->__files = array_merge($this->__files, $files);
}
}

View file

@ -54,9 +54,38 @@ class FixtureTask extends BakeTask {
* Override initialize
*
*/
public function __construct(&$dispatch) {
parent::__construct($dispatch);
$this->path = $this->params['working'] . DS . 'tests' . DS . 'fixtures' . DS;
public function __construct($stdout = null, $stderr = null, $stdin = null) {
parent::__construct($stdout, $stderr, $stdin);
$this->path = APP . 'tests' . DS . 'fixtures' . DS;
}
/**
* get the option parser.
*
* @return void
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__('Generate fixtures for use with the test suite. You can use `bake fixture all` to bake all fixtures.')
)->addArgument('name', array(
'help' => __('Name of the fixture to bake. Can use Plugin.name to bake plugin fixtures.')
))->addOption('count', array(
'help' => __('When using generated data, the number of records to include in the fixture(s).'),
'short' => 'n',
'default' => 10
))->addOption('connection', array(
'help' => __('Which database configuration to use for baking.'),
'short' => 'c',
'default' => 'default'
))->addOption('plugin', array(
'help' => __('CamelCased name of the plugin to bake fixtures for.'),
'short' => 'p',
))->addOption('records', array(
'help' => 'Used with --count and <name>/all commands to pull [n] records from the live tables, where [n] is either --count or the default of 10',
'short' => 'r',
'boolean' => true
))->epilog(__('Omitting all arguments and options will enter into an interactive mode.'));;
}
/**
@ -66,6 +95,7 @@ class FixtureTask extends BakeTask {
* @return void
*/
public function execute() {
parent::execute();
if (empty($this->args)) {
$this->_interactive();
}
@ -382,31 +412,4 @@ class FixtureTask extends BakeTask {
return $out;
}
/**
* Displays help contents
*
*/
public function help() {
$this->hr();
$this->out("Usage: cake bake fixture <arg1> <params>");
$this->hr();
$this->out('Arguments:');
$this->out();
$this->out("<name>");
$this->out("\tName of the fixture to bake. Can use Plugin.name");
$this->out("\tas a shortcut for plugin baking.");
$this->out();
$this->out('Commands:');
$this->out("\nfixture <name>\n\tbakes fixture with specified name.");
$this->out("\nfixture all\n\tbakes all fixtures.");
$this->out();
$this->out('Parameters:');
$this->out("\t-count When using generated data, the number of records to include in the fixture(s).");
$this->out("\t-connection Which database configuration to use for baking.");
$this->out("\t-plugin CamelCased name of plugin to bake fixtures for.");
$this->out("\t-records Used with -count and <name>/all commands to pull [n] records from the live tables");
$this->out("\t Where [n] is either -count or the default of 10.");
$this->out();
$this->_stop();
}
}

View file

@ -74,6 +74,7 @@ class ModelTask extends BakeTask {
*/
public function execute() {
App::import('Model', 'Model', false);
parent::execute();
if (empty($this->args)) {
$this->_interactive();
@ -873,31 +874,25 @@ class ModelTask extends BakeTask {
}
/**
* Displays help contents
* get the option parser.
*
* @return void
*/
public function help() {
$this->hr();
$this->out("Usage: cake bake model <arg1>");
$this->hr();
$this->out('Arguments:');
$this->out();
$this->out("<name>");
$this->out("\tName of the model to bake. Can use Plugin.name");
$this->out("\tas a shortcut for plugin baking.");
$this->out();
$this->out('Commands:');
$this->out();
$this->out("model");
$this->out("\tbakes model in interactive mode.");
$this->out();
$this->out("model <name>");
$this->out("\tbakes model file with no associations or validation");
$this->out();
$this->out("model all");
$this->out("\tbakes all model files with associations and validation");
$this->out();
$this->_stop();
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__('Bake models.')
)->addArgument('name', array(
'help' => __('Name of the model to bake. Can use Plugin.name to bake plugin models.')
))->addSubcommand('all', array(
'help' => __('Bake all model files with associations and validation.')
))->addOption('plugin', array(
'short' => 'p',
'help' => __('Plugin to bake the model into.')
))->addOption('connection', array(
'short' => 'c',
'help' => __('The connection the model table is on.')
))->epilog(__('Omitting all arguments and options will enter into an interactive mode.'));
}
/**

View file

@ -17,6 +17,7 @@
* @since CakePHP(tm) v 1.2
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Core', 'File');
/**
* Task class for creating a plugin
@ -26,12 +27,6 @@
*/
class PluginTask extends Shell {
/**
* Tasks
*
*/
public $tasks = array('Model', 'Controller', 'View');
/**
* path to CONTROLLERS directory
*
@ -55,45 +50,20 @@ class PluginTask extends Shell {
* @return void
*/
public function execute() {
if (empty($this->params['skel'])) {
$this->params['skel'] = '';
if (is_dir(CAKE_CORE_INCLUDE_PATH . DS . CAKE . 'console' . DS . 'templates' . DS . 'skel') === true) {
$this->params['skel'] = CAKE_CORE_INCLUDE_PATH . DS . CAKE . 'console' . DS . 'templates' . DS . 'skel';
}
}
$plugin = null;
if (isset($this->args[0])) {
$plugin = Inflector::camelize($this->args[0]);
$pluginPath = $this->_pluginPath($plugin);
$this->Dispatch->shiftArgs();
if (is_dir($pluginPath)) {
$this->out(sprintf(__('Plugin: %s'), $plugin));
$this->out(sprintf(__('Path: %s'), $pluginPath));
} elseif (isset($this->args[0])) {
$this->err(sprintf(__('%s in path %s not found.'), $plugin, $pluginPath));
$this->_stop();
} else {
$this->_interactive($plugin);
}
} else {
return $this->_interactive();
}
if (isset($this->args[0])) {
$task = Inflector::classify($this->args[0]);
$this->Dispatch->shiftArgs();
if (in_array($task, $this->tasks)) {
$this->{$task}->plugin = $plugin;
$this->{$task}->path = $pluginPath . Inflector::underscore(Inflector::pluralize($task)) . DS;
if (!is_dir($this->{$task}->path)) {
$this->err(sprintf(__("%s directory could not be found.\nBe sure you have created %s"), $task, $this->{$task}->path));
}
$this->{$task}->loadTasks();
return $this->{$task}->execute();
}
}
}
/**
@ -108,7 +78,7 @@ class PluginTask extends Shell {
}
if (!$this->bake($plugin)) {
$this->err(sprintf(__("An error occured trying to bake: %s in %s"), $plugin, $this->path . Inflector::underscore($pluginPath)));
$this->error(sprintf(__("An error occured trying to bake: %s in %s"), $plugin, $this->path . Inflector::underscore($pluginPath)));
}
}
@ -127,20 +97,19 @@ class PluginTask extends Shell {
$this->findPath($pathOptions);
}
$this->hr();
$this->out(sprintf(__("Plugin Name: %s"), $plugin));
$this->out(sprintf(__("Plugin Directory: %s"), $this->path . $pluginPath));
$this->out(sprintf(__("<info>Plugin Name:</info> %s"), $plugin));
$this->out(sprintf(__("<info>Plugin Directory:</info> %s"), $this->path . $pluginPath));
$this->hr();
$looksGood = $this->in(__('Look okay?'), array('y', 'n', 'q'), 'y');
if (strtolower($looksGood) == 'y') {
$verbose = $this->in(__('Do you want verbose output?'), array('y', 'n'), 'n');
$Folder =& new Folder($this->path . $pluginPath);
$directories = array(
'config' . DS . 'schema',
'models' . DS . 'behaviors',
'models' . DS . 'datasources',
'console' . DS . 'shells' . DS . 'tasks',
'controllers' . DS . 'components',
'libs',
'views' . DS . 'helpers',
@ -152,7 +121,6 @@ class PluginTask extends Shell {
'tests' . DS . 'groups',
'tests' . DS . 'fixtures',
'vendors',
'vendors' . DS . 'shells' . DS . 'tasks',
'webroot'
);
@ -162,10 +130,8 @@ class PluginTask extends Shell {
$File =& new File($dirPath . DS . 'empty', true);
}
if (strtolower($verbose) == 'y') {
foreach ($Folder->messages() as $message) {
$this->out($message);
}
foreach ($Folder->messages() as $message) {
$this->out($message, 1, Shell::VERBOSE);
}
$errors = $Folder->errors();
@ -190,8 +156,7 @@ class PluginTask extends Shell {
$this->createFile($this->path . $pluginPath . DS . $modelFileName, $out);
$this->hr();
$this->out(sprintf(__('Created: %s in %s'), $plugin, $this->path . $pluginPath));
$this->hr();
$this->out(sprintf(__('<success>Created:</success> %s in %s'), $plugin, $this->path . $pluginPath), 2);
}
return true;
@ -219,28 +184,19 @@ class PluginTask extends Shell {
}
/**
* Help
* get the option parser for the plugin task
*
* @return void
*/
public function help() {
$this->hr();
$this->out("Usage: cake bake plugin <arg1> <arg2>...");
$this->hr();
$this->out('Commands:');
$this->out();
$this->out("plugin <name>");
$this->out("\tbakes plugin directory structure");
$this->out();
$this->out("plugin <name> model");
$this->out("\tbakes model. Run 'cake bake model help' for more info.");
$this->out();
$this->out("plugin <name> controller");
$this->out("\tbakes controller. Run 'cake bake controller help' for more info.");
$this->out();
$this->out("plugin <name> view");
$this->out("\tbakes view. Run 'cake bake view help' for more info.");
$this->out();
$this->_stop();
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
'Create the directory structure, AppModel and AppController classes for a new plugin. ' .
'Can create plugins in any of your bootstrapped plugin paths.'
)->addArgument('name', array(
'help' => __('CamelCased name of the plugin to create.')
));
}
}

View file

@ -41,35 +41,34 @@ class ProjectTask extends Shell {
*
* @param string $project Project path
*/
public function execute($project = null) {
if ($project === null) {
if (isset($this->args[0])) {
$project = $this->args[0];
}
public function execute() {
$project = null;
if (isset($this->args[0])) {
$project = $this->args[0];
}
if ($project) {
$this->Dispatch->parseParams(array('-app', $project));
$project = $this->params['working'];
if ($project && isset($_SERVER['PWD'])) {
$project = $_SERVER['PWD'] . DS . $project;
}
if (empty($this->params['skel'])) {
$this->params['skel'] = '';
if (is_dir(CAKE . 'console' . DS . 'templates' . DS . 'skel') === true) {
$this->params['skel'] = CAKE . 'console' . DS . 'templates' . DS . 'skel';
$core = App::core('shells');
$skelPath = dirname($core[0]) . DS . 'templates' . DS . 'skel';
if (is_dir($skelPath) === true) {
$this->params['skel'] = $skelPath;
}
}
while (!$project) {
$prompt = __("What is the full path for this app including the app directory name?\n Example:");
$default = $this->params['working'] . DS . 'myapp';
$default = APP_PATH . 'myapp';
$project = $this->in($prompt . $default, null, $default);
}
if ($project) {
$response = false;
while ($response == false && is_dir($project) === true && file_exists($project . 'config' . 'core.php')) {
$prompt = sprintf(__('A project already exists in this location: %s Overwrite?'), $project);
$prompt = sprintf(__('<warning>A project already exists in this location:</warning> %s Overwrite?'), $project);
$response = $this->in($prompt, array('y','n'), 'n');
if (strtolower($response) === 'n') {
$response = $project = false;
@ -77,43 +76,57 @@ class ProjectTask extends Shell {
}
}
$success = true;
if ($this->bake($project)) {
$path = Folder::slashTerm($project);
if ($this->createHome($path)) {
$this->out(__('Welcome page created'));
$this->out(__(' * Welcome page created'));
} else {
$this->out(__('The Welcome page was NOT created'));
$this->err(__('The Welcome page was <error>NOT</error> created'));
$success = false;
}
if ($this->securitySalt($path) === true ) {
$this->out(__('Random hash key created for \'Security.salt\''));
if ($this->securitySalt($path) === true) {
$this->out(__(' * Random hash key created for \'Security.salt\''));
} else {
$this->err(sprintf(__('Unable to generate random hash for \'Security.salt\', you should change it in %s'), CONFIGS . 'core.php'));
$success = false;
}
if ($this->securityCipherSeed($path) === true ) {
$this->out(__('Random seed created for \'Security.cipherSeed\''));
if ($this->securityCipherSeed($path) === true) {
$this->out(__(' * Random seed created for \'Security.cipherSeed\''));
} else {
$this->err(sprintf(__('Unable to generate random seed for \'Security.cipherSeed\', you should change it in %s'), CONFIGS . 'core.php'));
$success = false;
}
$corePath = $this->corePath($path);
if ($corePath === true ) {
$this->out(sprintf(__('CAKE_CORE_INCLUDE_PATH set to %s in webroot/index.php'), CAKE_CORE_INCLUDE_PATH));
$this->out(sprintf(__('CAKE_CORE_INCLUDE_PATH set to %s in webroot/test.php'), CAKE_CORE_INCLUDE_PATH));
$this->out(__('Remember to check these value after moving to production server'));
} elseif ($corePath === false) {
if ($this->corePath($path) === true) {
$this->out(sprintf(__(' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/index.php'), CAKE_CORE_INCLUDE_PATH));
$this->out(sprintf(__(' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/test.php'), CAKE_CORE_INCLUDE_PATH));
$this->out(__(' * <warning>Remember to check these value after moving to production server</warning>'));
} else {
$this->err(sprintf(__('Unable to set CAKE_CORE_INCLUDE_PATH, you should change it in %s'), $path . 'webroot' .DS .'index.php'));
$success = false;
}
if ($this->consolePath($path) === true) {
$this->out(__(' * app/console/cake.php path set.'));
} else {
$this->err(__('Unable to set console path for app/console.'));
$success = false;
}
$Folder = new Folder($path);
if (!$Folder->chmod($path . 'tmp', 0777)) {
$this->err(sprintf(__('Could not set permissions on %s'), $path . DS .'tmp'));
$this->out(sprintf(__('chmod -R 0777 %s'), $path . DS .'tmp'));
$success = false;
}
$this->params['working'] = $path;
$this->params['app'] = basename($path);
return true;
if ($success) {
$this->out(__('<success>Project baked successfully!</success>'));
} else {
$this->out(__('Project baked but with <warning>some issues.</warning>.'));
}
return $path;
}
}
@ -135,7 +148,7 @@ class ProjectTask extends Shell {
while (!$skel) {
$skel = $this->in(sprintf(__("What is the path to the directory layout you wish to copy?\nExample: %s"), APP, null, ROOT . DS . 'myapp' . DS));
if ($skel == '') {
$this->out(__('The directory path you supplied was empty. Please try again.'));
$this->err(__('The directory path you supplied was empty. Please try again.'));
} else {
while (is_dir($skel) === false) {
$skel = $this->in(__('Directory path does not exist please choose another:'));
@ -145,33 +158,29 @@ class ProjectTask extends Shell {
$app = basename($path);
$this->out(__('Bake Project'));
$this->out(__('Skel Directory: ') . $skel);
$this->out(__('Will be copied to: ') . $path);
$this->out(__('<info>Skel Directory</info>: ') . $skel);
$this->out(__('<info>Will be copied to</info>: ') . $path);
$this->hr();
$looksGood = $this->in(__('Look okay?'), array('y', 'n', 'q'), 'y');
if (strtolower($looksGood) == 'y') {
$verbose = $this->in(__('Do you want verbose output?'), array('y', 'n'), 'n');
$Folder = new Folder($skel);
if (!empty($this->params['empty'])) {
$skip = array();
}
if ($Folder->copy(array('to' => $path, 'skip' => $skip))) {
$this->hr();
$this->out(sprintf(__('Created: %s in %s'), $app, $path));
$this->out(sprintf(__('<success>Created:</success> %s in %s'), $app, $path));
$this->hr();
} else {
$this->err(sprintf(__(" '%s' could not be created properly"), $app));
$this->err(sprintf(__("<error>Could not create</error> '%s' properly."), $app));
return false;
}
if (strtolower($verbose) == 'y') {
foreach ($Folder->messages() as $message) {
$this->out($message);
}
foreach ($Folder->messages() as $message) {
$this->out(String::wrap(' * ' . $message), 1, Shell::VERBOSE);
}
return true;
@ -197,6 +206,28 @@ class ProjectTask extends Shell {
return $this->createFile($path.'home.ctp', $output);
}
/**
* Generates the correct path to the CakePHP libs that are generating the project
* and points app/console/cake.php to the right place
*
* @param string $path Project path.
* @return boolean success
*/
public function consolePath($path) {
$File = new File($path . 'console' . DS . 'cake.php');
$contents = $File->read();
if (preg_match('/(__CAKE_PATH__)/', $contents, $match)) {
$path = CAKE_CORE_INCLUDE_PATH . DS . 'cake' . DS . 'console' . DS;
$replacement = "'" . str_replace(DS, "' . DIRECTORY_SEPARATOR . '", $path) . "'";
$result = str_replace($match[0], $replacement, $contents);
if ($File->write($result)) {
return true;
}
return false;
}
return false;
}
/**
* Generates and writes 'Security.salt'
*
@ -204,9 +235,9 @@ class ProjectTask extends Shell {
* @return boolean Success
*/
public function securitySalt($path) {
$File =& new File($path . 'config' . DS . 'core.php');
$File = new File($path . 'config' . DS . 'core.php');
$contents = $File->read();
if (preg_match('/([\\t\\x20]*Configure::write\\(\\\'Security.salt\\\',[\\t\\x20\'A-z0-9]*\\);)/', $contents, $match)) {
if (preg_match('/([\s]*Configure::write\(\'Security.salt\',[\s\'A-z0-9]*\);)/', $contents, $match)) {
if (!class_exists('Security')) {
require LIBS . 'security.php';
}
@ -220,28 +251,28 @@ class ProjectTask extends Shell {
return false;
}
/**
* Generates and writes 'Security.cipherSeed'
*
* @param string $path Project path
* @return boolean Success
*/
public function securityCipherSeed($path) {
$File =& new File($path . 'config' . DS . 'core.php');
$contents = $File->read();
if (preg_match('/([\\t\\x20]*Configure::write\\(\\\'Security.cipherSeed\\\',[\\t\\x20\'A-z0-9]*\\);)/', $contents, $match)) {
if (!class_exists('Security')) {
require LIBS . 'security.php';
}
$string = substr(bin2hex(Security::generateAuthKey()), 0, 30);
$result = str_replace($match[0], "\t" . 'Configure::write(\'Security.cipherSeed\', \''.$string.'\');', $contents);
if ($File->write($result)) {
return true;
}
return false;
/**
* Generates and writes 'Security.cipherSeed'
*
* @param string $path Project path
* @return boolean Success
*/
public function securityCipherSeed($path) {
$File = new File($path . 'config' . DS . 'core.php');
$contents = $File->read();
if (preg_match('/([\s]*Configure::write\(\'Security.cipherSeed\',[\s\'A-z0-9]*\);)/', $contents, $match)) {
if (!class_exists('Security')) {
require LIBS . 'security.php';
}
$string = substr(bin2hex(Security::generateAuthKey()), 0, 30);
$result = str_replace($match[0], "\t" . 'Configure::write(\'Security.cipherSeed\', \''.$string.'\');', $contents);
if ($File->write($result)) {
return true;
}
return false;
}
return false;
}
/**
* Generates and writes CAKE_CORE_INCLUDE_PATH
@ -251,9 +282,9 @@ class ProjectTask extends Shell {
*/
public function corePath($path) {
if (dirname($path) !== CAKE_CORE_INCLUDE_PATH) {
$File =& new File($path . 'webroot' . DS . 'index.php');
$File = new File($path . 'webroot' . DS . 'index.php');
$contents = $File->read();
if (preg_match('/([\\t\\x20]*define\\(\\\'CAKE_CORE_INCLUDE_PATH\\\',[\\t\\x20\'A-z0-9]*\\);)/', $contents, $match)) {
if (preg_match('/([\s]*define\(\'CAKE_CORE_INCLUDE_PATH\',[\s\'A-z0-9]*\);)/', $contents, $match)) {
$root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " DS . '" : "'";
$result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', " . $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "');", $contents);
if (!$File->write($result)) {
@ -263,9 +294,9 @@ class ProjectTask extends Shell {
return false;
}
$File =& new File($path . 'webroot' . DS . 'test.php');
$File = new File($path . 'webroot' . DS . 'test.php');
$contents = $File->read();
if (preg_match('/([\\t\\x20]*define\\(\\\'CAKE_CORE_INCLUDE_PATH\\\',[\\t\\x20\'A-z0-9]*\\);)/', $contents, $match)) {
if (preg_match('/([\s]*define\(\'CAKE_CORE_INCLUDE_PATH\',[\s\'A-z0-9]*\);)/', $contents, $match)) {
$result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', " . $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "');", $contents);
if (!$File->write($result)) {
return false;
@ -285,9 +316,9 @@ class ProjectTask extends Shell {
*/
public function cakeAdmin($name) {
$path = (empty($this->configPath)) ? CONFIGS : $this->configPath;
$File =& new File($path . 'core.php');
$File = new File($path . 'core.php');
$contents = $File->read();
if (preg_match('%([/\\t\\x20]*Configure::write\(\'Routing.prefixes\',[\\t\\x20\'a-z,\)\(]*\\);)%', $contents, $match)) {
if (preg_match('%([/\s]*Configure::write\(\'Routing.prefixes\',[\s\'a-z,\)\(]*\);)%', $contents, $match)) {
$result = str_replace($match[0], "\t" . 'Configure::write(\'Routing.prefixes\', array(\''.$name.'\'));', $contents);
if ($File->write($result)) {
Configure::write('Routing.prefixes', array($name));
@ -335,7 +366,7 @@ class ProjectTask extends Shell {
$admin = $this->in(__('Enter a routing prefix:'), null, 'admin');
}
if ($this->cakeAdmin($admin) !== true) {
$this->out(__('Unable to write to /app/config/core.php.'));
$this->out(__('<error>Unable to write to</error> /app/config/core.php.'));
$this->out('You need to enable Configure::write(\'Routing.prefixes\',array(\'admin\')) in /app/config/core.php to use prefix routing.');
$this->_stop();
}
@ -345,21 +376,21 @@ class ProjectTask extends Shell {
}
/**
* Help
* get the option parser.
*
* @return void
* @return ConsoleOptionParser
*/
public function help() {
$this->hr();
$this->out("Usage: cake bake project <arg1>");
$this->hr();
$this->out('Commands:');
$this->out();
$this->out("project <name>");
$this->out("\tbakes app directory structure.");
$this->out("\tif <name> begins with '/' path is absolute.");
$this->out();
$this->_stop();
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__('Generate a new CakePHP project skeleton.')
)->addArgument('name', array(
'help' => __('Application directory to make, if it starts with "/" the path is absolute.')
))->addOption('empty', array(
'help' => __('Create empty files in each of the directories. Good if you are using git')
))->addOption('skel', array(
'help' => __('The directory layout to use for the new application skeleton. Defaults to cake/console/templates/skel of CakePHP used to create the project.')
));
}
}

View file

@ -17,6 +17,8 @@
* @since CakePHP(tm) v 1.3
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Core', 'Folder');
class TemplateTask extends Shell {
/**
@ -55,7 +57,7 @@ class TemplateTask extends Shell {
$paths = App::path('shells');
$core = array_pop($paths);
$separator = DS === '/' ? '/' : '\\\\';
$core = preg_replace('#libs' . $separator . '$#', '', $core);
$core = preg_replace('#shells' . $separator . '$#', '', $core);
$paths[] = $core;
$Folder =& new Folder($core . 'templates' . DS . 'default');
$contents = $Folder->read();
@ -63,6 +65,7 @@ class TemplateTask extends Shell {
$plugins = App::objects('plugin');
foreach ($plugins as $plugin) {
$paths[] = $this->_pluginPath($plugin) . 'console' . DS . 'shells' . DS;
$paths[] = $this->_pluginPath($plugin) . 'vendors' . DS . 'shells' . DS;
}
@ -178,7 +181,7 @@ class TemplateTask extends Shell {
}
$index = $this->in(__('Which bake theme would you like to use?'), range(1, $i - 1), 1);
$themeNames = array_keys($this->templatePaths);
$this->Dispatch->params['theme'] = $themeNames[$index - 1];
$this->params['theme'] = $themeNames[$index - 1];
return $indexedPaths[$index];
}

View file

@ -60,12 +60,12 @@ class TestTask extends BakeTask {
*/
protected $_fixtures = array();
/**
* Execution method always used for tasks
*
*/
public function execute() {
parent::execute();
if (empty($this->args)) {
$this->_interactive();
}
@ -77,7 +77,7 @@ class TestTask extends BakeTask {
if (count($this->args) > 1) {
$type = Inflector::underscore($this->args[0]);
if ($this->bake($type, $this->args[1])) {
$this->out('done');
$this->out('<success>Done</success>');
}
}
}
@ -412,27 +412,21 @@ class TestTask extends BakeTask {
}
/**
* Show help file.
* get the option parser.
*
* @return void
*/
public function help() {
$this->hr();
$this->out("Usage: cake bake test <type> <class>");
$this->hr();
$this->out('Commands:');
$this->out("");
$this->out("test model post\n\tbakes a test case for the post model.");
$this->out("");
$this->out("test controller comments\n\tbakes a test case for the comments controller.");
$this->out("");
$this->out('Arguments:');
$this->out("\t<type> Can be any of the following 'controller', 'model', 'helper',\n\t'component', 'behavior'.");
$this->out("\t<class> Any existing class for the chosen type.");
$this->out("");
$this->out("Parameters:");
$this->out("\t-plugin CamelCased name of plugin to bake tests for.");
$this->out("");
$this->_stop();
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(__('Bake test case skeletons for classes.'))
->addArgument('type', array(
'help' => __('Type of class to bake, can be any of the following: controller, model, helper, component or behavior.'),
'choices' => array('controller', 'model', 'helper', 'component', 'behavior')
))->addArgument('name', array(
'help' => __('An existing class to bake tests for.')
))->addOption('plugin', array(
'short' => 'p',
'help' => __('CamelCased name of the plugin to bake tests for.')
))->epilog(__('Omitting all arguments and options will enter into an interactive mode.'));
}
}

View file

@ -97,6 +97,7 @@ class ViewTask extends BakeTask {
*
*/
public function execute() {
parent::execute();
if (empty($this->args)) {
$this->_interactive();
}
@ -421,43 +422,32 @@ class ViewTask extends BakeTask {
}
/**
* Displays help contents
* get the option parser for this task
*
* @return ConsoleOptionParser
*/
public function help() {
$this->hr();
$this->out("Usage: cake bake view <arg1> <arg2>...");
$this->hr();
$this->out('Arguments:');
$this->out();
$this->out("<controller>");
$this->out("\tName of the controller views to bake. Can use Plugin.name");
$this->out("\tas a shortcut for plugin baking.");
$this->out();
$this->out("<action>");
$this->out("\tName of the action view to bake");
$this->out();
$this->out('Commands:');
$this->out();
$this->out("view <controller>");
$this->out("\tWill read the given controller for methods");
$this->out("\tand bake corresponding views.");
$this->out("\tUsing the -admin flag will only bake views for actions");
$this->out("\tthat begin with Routing.prefixes.");
$this->out("\tIf var scaffold is found it will bake the CRUD actions");
$this->out("\t(index,view,add,edit)");
$this->out();
$this->out("view <controller> <action>");
$this->out("\tWill bake a template. core templates: (index, add, edit, view)");
$this->out();
$this->out("view <controller> <template> <alias>");
$this->out("\tWill use the template specified");
$this->out("\tbut name the file based on the alias");
$this->out();
$this->out("view all");
$this->out("\tBake all CRUD action views for all controllers.");
$this->out("\tRequires that models and controllers exist.");
$this->_stop();
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__('Bake views for a controller, using built-in or custom templates.')
)->addArgument('controller', array(
'help' => __('Name of the controller views to bake. Can be Plugin.name as a shortcut for plugin baking.')
))->addArgument('action', array(
'help' => __("Will bake a single action's file. core templates are (index, add, edit, view)")
))->addArgument('alias', array(
'help' => __('Will bake the template in <action> but create the filename after <alias>.')
))->addOption('plugin', array(
'short' => 'p',
'help' => __('Plugin to bake the view into.')
))->addOption('admin', array(
'help' => __('Set to only bake views for a prefix in Routing.prefixes'),
'boolean' => true
))->addOption('connection', array(
'short' => 'c',
'help' => __('The connection the connected model is on.')
))->addSubcommand('all', array(
'help' => __('Bake all CRUD action views for all controllers. Requires models and controllers to exist.')
))->epilog(__('Omitting all arguments and options will enter into an interactive mode.'));
}
/**

View file

@ -28,6 +28,29 @@ class TestSuiteShell extends Shell {
*/
protected $_dispatcher = null;
/**
* get the option parser for the test suite.
*
* @return void
*/
public function getOptionParser() {
$parser = new ConsoleOptionParser($this->name);
$parser->description(array(
'The CakePHP Testsuite allows you to run test cases from the command line',
'If run with no command line arguments, a list of available core test cases will be shown'
))->addArgument('category', array(
'help' => __('app, core or name of a plugin.'),
'required' => true
))->addArgument('file', array(
'help' => __('file name with folder prefix and without the test.php suffix.'),
'required' => true,
))->addOption('filter', array(
'help' => __('Filter which tests to run.'),
'default' => false
));
return $parser;
}
/**
* Initialization method installs Simpletest and loads all plugins
*
@ -74,9 +97,6 @@ class TestSuiteShell extends Shell {
if (isset($this->args[1])) {
$params['case'] = Inflector::underscore($this->args[1]);
}
if (isset($this->params['filter'])) {
$this->params['-filter'] = $this->params['filter'];
}
return $params;
}
@ -87,12 +107,13 @@ class TestSuiteShell extends Shell {
*/
protected function runnerOptions() {
$options = array();
foreach ($this->params as $param => $value) {
if ($param[0] === '-') {
$options[] = '-' . $param;
if (is_string($value)) {
$options[] = $value;
}
$params = $this->params;
unset($params['help']);
$params = array_filter($params);
foreach ($params as $param => $value) {
$options[] = '--' . $param;
if (is_string($value)) {
$options[] = $value;
}
}
return $options;

View file

@ -0,0 +1,26 @@
#!/bin/bash
################################################################################
#
# Bake is a shell script for running CakePHP bake script
# PHP 5
#
# CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
# Copyright 2005-2010, Cake Software Foundation, Inc.
#
# Licensed under The MIT License
# Redistributions of files must retain the above copyright notice.
#
# @copyright Copyright 2005-2010, Cake Software Foundation, Inc.
# @link http://cakephp.org CakePHP(tm) Project
# @package cake
# @subpackage cake.app.console
# @since CakePHP(tm) v 2.0
# @license MIT License (http://www.opensource.org/licenses/mit-license.php)
#
################################################################################
LIB=${0/%cake/}
APP=`pwd`
exec php -q ${LIB}cake.php -working "${APP}" "$@"
exit;

View file

@ -0,0 +1,33 @@
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Bake is a shell script for running CakePHP bake script
:: PHP 5
::
:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
:: Copyright 2005-2010, Cake Software Foundation, Inc.
::
:: Licensed under The MIT License
:: Redistributions of files must retain the above copyright notice.
::
:: @copyright Copyright 2005-2010, Cake Software Foundation, Inc.
:: @link http://cakephp.org CakePHP(tm) Project
:: @package cake
:: @subpackage cake.app.console
:: @since CakePHP(tm) v 2.0
:: @license MIT License (http://www.opensource.org/licenses/mit-license.php)
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: In order for this script to work as intended, the cake\console\ folder must be in your PATH
@echo.
@echo off
SET app=%0
SET lib=%~dp0
php -q "%lib%cake.php" -working "%CD%" %*
echo.
exit /B %ERRORLEVEL%

View file

@ -0,0 +1,25 @@
#!/usr/bin/php -q
<?php
/**
* Command-line code generation utility to automate programmer chores.
*
* Shell dispatcher class
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc.
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.console
* @since CakePHP(tm) v 1.2.0.5012
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
require_once(__CAKE_PATH__ . 'shell_dispatcher.php');
return ShellDispatcher::run($argv);

0
cake/console/templates/skel/tmp/cache/models/empty vendored Normal file → Executable file
View file

0
cake/console/templates/skel/tmp/cache/persistent/empty vendored Normal file → Executable file
View file

0
cake/console/templates/skel/tmp/cache/views/empty vendored Normal file → Executable file
View file

View file

@ -587,7 +587,11 @@ class App {
'views' => array(VIEWS),
'helpers' => array(HELPERS),
'locales' => array(APP . 'locale' . DS),
'shells' => array(APP . 'vendors' . DS . 'shells' . DS, VENDORS . 'shells' . DS),
'shells' => array(
APP . 'console' . DS . 'shells' . DS,
APP . 'vendors' . DS . 'shells' . DS,
VENDORS . 'shells' . DS
),
'vendors' => array(APP . 'vendors' . DS, VENDORS),
'plugins' => array(APP . 'plugins' . DS)
);
@ -690,7 +694,9 @@ class App {
$paths['helpers'][] = $libs . 'view' . DS . 'helpers' . DS;
$paths['plugins'][] = $path . 'plugins' . DS;
$paths['vendors'][] = $path . 'vendors' . DS;
$paths['shells'][] = $cake . 'console' . DS . 'libs' . DS;
$paths['shells'][] = $cake . 'console' . DS . 'shells' . DS;
// Provide BC path to vendors/shells
$paths['shells'][] = $path . 'vendors' . DS . 'shells' . DS;
Cache::write('core_paths', array_filter($paths), '_cake_core_');
}
@ -1136,6 +1142,15 @@ class App {
}
return array('class' => $type, 'suffix' => null, 'path' => $path);
break;
case 'shell':
if (!class_exists('Shell')) {
App::import($type, 'Shell', false);
}
if ($plugin) {
$path = $pluginPath . DS . 'console' . DS . 'shells' . DS;
}
return array('class' => $type, 'suffix' => null, 'path' => $path);
break;
case 'vendor':
if ($plugin) {
$path = $pluginPath . DS . 'vendors' . DS;

View file

@ -333,6 +333,33 @@ class MissingTaskClassException extends CakeException {
protected $_messageTemplate = 'Task class "%s" is missing.';
}
/**
* Used when a shell method cannot be found.
*
* @package cake.libs
*/
class MissingShellMethodException extends CakeException {
protected $_messageTemplate = "Unknown command %1\$s %2\$s.\nFor usage try `cake %1\$s --help`";
}
/**
* Used when a shell class cannot be found.
*
* @package cake.libs
*/
class MissingShellClassException extends CakeException {
protected $_messageTemplate = "Shell class %s could not be loaded.";
}
/**
* Used when a shell class cannot be found.
*
* @package cake.libs
*/
class MissingShellFileException extends CakeException {
protected $_messageTemplate = "Shell file %s could not be loaded.";
}
/**
* Exception class to be thrown when a database table is not found in the datasource
*

View file

@ -319,4 +319,38 @@ class String {
}
return $str;
}
/**
* Wraps text to a specific width, can optionally wrap at word breaks.
*
* ### Options
*
* - `width` The width to wrap to. Defaults to 72
* - `wordWrap` Only wrap on words breaks (spaces) Defaults to true.
* - `indent` String to indent with. Defaults to null.
* - `indentAt` 0 based index to start indenting at. Defaults to 0.
*
* @param string $text Text the text to format.
* @param mixed $options Array of options to use, or an integer to wrap the text to.
* @return string Formatted text.
*/
public static function wrap($text, $options = array()) {
if (is_numeric($options)) {
$options = array('width' => $options);
}
$options += array('width' => 72, 'wordWrap' => true, 'indent' => null, 'indentAt' => 0);
if ($options['wordWrap']) {
$wrapped = wordwrap($text, $options['width'], "\n");
} else {
$wrapped = trim(chunk_split($text, $options['width'] - 1, "\n"));
}
if (!empty($options['indent'])) {
$chunks = explode("\n", $wrapped);
for ($i = $options['indentAt'], $len = count($chunks); $i < $len; $i++) {
$chunks[$i] = $options['indent'] . $chunks[$i];
}
$wrapped = implode("\n", $chunks);
}
return $wrapped;
}
}

View file

@ -585,7 +585,7 @@ class BasicsTest extends CakeTestCase {
ob_start();
debug('this-is-a-test');
$result = ob_get_clean();
$pattern = '/.*\>(.+?tests(\/|\\\)cases(\/|\\\)basics\.test\.php|';
$pattern = '/(.+?tests(\/|\\\)cases(\/|\\\)basics\.test\.php|';
$pattern .= preg_quote(substr(__FILE__, 1), '/') . ')';
$pattern .= '.*line.*' . (__LINE__ - 4) . '.*this-is-a-test.*/s';
$this->assertPattern($pattern, $result);
@ -593,7 +593,7 @@ class BasicsTest extends CakeTestCase {
ob_start();
debug('<div>this-is-a-test</div>', true);
$result = ob_get_clean();
$pattern = '/.*\>(.+?tests(\/|\\\)cases(\/|\\\)basics\.test\.php|';
$pattern = '/(.+?tests(\/|\\\)cases(\/|\\\)basics\.test\.php|';
$pattern .= preg_quote(substr(__FILE__, 1), '/') . ')';
$pattern .= '.*line.*' . (__LINE__ - 4) . '.*&lt;div&gt;this-is-a-test&lt;\/div&gt;.*/s';
$this->assertPattern($pattern, $result);

View file

@ -0,0 +1,46 @@
<?php
/**
* AllConsoleTest file
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.tests.cases
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* AllConsoleTest class
*
* This test group will run all console classes.
*
* @package cake
* @subpackage cake.tests.cases.console
*/
class AllConsoleTest extends PHPUnit_Framework_TestSuite {
/**
* suite method, defines tests for this suite.
*
* @return void
*/
public static function suite() {
$suite = new CakeTestSuite('All console classes');
$path = CORE_TEST_CASES . DS . 'console' . DS;
$suite->addTestFile($path . 'all_console_libs.test.php');
$suite->addTestFile($path . 'all_shells.test.php');
$suite->addTestFile($path . 'all_tasks.test.php');
return $suite;
}
}

View file

@ -0,0 +1,44 @@
<?php
/**
* AllConsoleLibsTest file
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package cake
* @subpackage cake.tests.cases
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* AllConsoleLibsTest class
*
* This test group will run all console lib classes.
*
* @package cake
* @subpackage cake.tests.cases.console
*/
class AllConsoleLibsTest extends PHPUnit_Framework_TestSuite {
/**
* suite method, defines tests for this suite.
*
* @return void
*/
public static function suite() {
$suite = new CakeTestSuite('All console lib classes');
$path = CORE_TEST_CASES . DS . 'console' . DS . 'libs' . DS;
$suite->addTestDirectory($path);
return $suite;
}
}

View file

@ -36,10 +36,8 @@ class AllShellsTest extends PHPUnit_Framework_TestSuite {
public static function suite() {
$suite = new CakeTestSuite('All shell classes');
$path = CORE_TEST_CASES . DS . 'console' . DS . 'libs' . DS;
$path = CORE_TEST_CASES . DS . 'console' . DS . 'shells' . DS;
$suite->addTestFile(CORE_TEST_CASES . DS . 'console' . DS . 'cake.test.php');
$suite->addTestFile(CORE_TEST_CASES . DS . 'console' . DS . 'console_error_handler.test.php');
$suite->addTestDirectory($path);
return $suite;
}

View file

@ -36,9 +36,7 @@ class AllTasksTest extends PHPUnit_Framework_TestSuite {
public static function suite() {
$suite = new CakeTestSuite('All Tasks tests');
$path = CORE_TEST_CASES . DS . 'console' . DS . 'libs' . DS . 'tasks' . DS;
$suite->addTestFile(CORE_TEST_CASES . DS . 'console' . DS . 'libs' . DS . 'bake.test.php');
$path = CORE_TEST_CASES . DS . 'console' . DS . 'shells' . DS . 'tasks' . DS;
$suite->addTestDirectory($path);
return $suite;
}

View file

@ -1,932 +0,0 @@
<?php
/**
* ShellDispatcherTest file
*
* PHP 5
*
* CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
* Copyright 2005-2010, Cake Software Foundation, Inc.
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc.
* @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
* @package cake
* @subpackage cake.tests.cases.console
* @since CakePHP(tm) v 1.2.0.5432
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CONSOLE_LIBS . 'shell.php';
/**
* TestShellDispatcher class
*
* @package cake
* @subpackage cake.tests.cases.console
*/
class TestShellDispatcher extends ShellDispatcher {
/**
* params property
*
* @var array
* @access public
*/
public $params = array();
/**
* stdout property
*
* @var string
* @access public
*/
public $stdout = '';
/**
* stderr property
*
* @var string
* @access public
*/
public $stderr = '';
/**
* stopped property
*
* @var string
* @access public
*/
public $stopped = null;
/**
* TestShell
*
* @var mixed
* @access public
*/
public $TestShell;
/**
* _initEnvironment method
*
* @return void
*/
protected function _initEnvironment() {
}
/**
* stderr method
*
* @return void
*/
public function stderr($string) {
$this->stderr .= rtrim($string, ' ');
}
/**
* stdout method
*
* @return void
*/
public function stdout($string, $newline = true) {
if ($newline) {
$this->stdout .= rtrim($string, ' ') . "\n";
} else {
$this->stdout .= rtrim($string, ' ');
}
}
/**
* clear method
*
* @return void
*/
public function clear() {
}
/**
* _stop method
*
* @return void
*/
protected function _stop($status = 0) {
$this->stopped = 'Stopped with status: ' . $status;
return $status;
}
/**
* getShell
*
* @param mixed $plugin
* @return mixed
*/
public function getShell($plugin = null) {
return $this->_getShell($plugin);
}
/**
* _getShell
*
* @param mixed $plugin
* @return mixed
*/
protected function _getShell($plugin = null) {
if (isset($this->TestShell)) {
return $this->TestShell;
}
return parent::_getShell($plugin);
}
}
/**
* ShellDispatcherTest
*
* @package cake
* @subpackage cake.tests.cases.libs
*/
class ShellDispatcherTest extends CakeTestCase {
/**
* setUp method
*
* @return void
*/
public function setUp() {
parent::setUp();
App::build(array(
'plugins' => array(
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS
),
'shells' => array(
CORE_PATH ? CONSOLE_LIBS : ROOT . DS . CONSOLE_LIBS,
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'vendors' . DS . 'shells' . DS
)
), true);
}
/**
* testParseParams method
*
* @return void
*/
public function testParseParams() {
$Dispatcher = new TestShellDispatcher();
$params = array(
'/cake/1.2.x.x/cake/console/cake.php',
'bake',
'-app',
'new',
'-working',
'/var/www/htdocs'
);
$expected = array(
'app' => 'new',
'webroot' => 'webroot',
'working' => '/var/www/htdocs/new',
'root' => '/var/www/htdocs'
);
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array('cake.php');
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'app'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH),
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'cake.php',
'-app',
'new',
);
$expected = array(
'app' => 'new',
'webroot' => 'webroot',
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'new'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH)
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'./cake.php',
'bake',
'-app',
'new',
'-working',
'/cake/1.2.x.x/cake/console'
);
$expected = array(
'app' => 'new',
'webroot' => 'webroot',
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'new'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH)
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'./console/cake.php',
'bake',
'-app',
'new',
'-working',
'/cake/1.2.x.x/cake'
);
$expected = array(
'app' => 'new',
'webroot' => 'webroot',
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'new'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH)
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'./console/cake.php',
'bake',
'-app',
'new',
'-dry',
'-working',
'/cake/1.2.x.x/cake'
);
$expected = array(
'app' => 'new',
'dry' => true,
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'new'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH),
'webroot' => 'webroot'
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEquals($expected, $Dispatcher->params);
$params = array(
'./console/cake.php',
'-working',
'/cake/1.2.x.x/cake',
'schema',
'run',
'create',
'-dry',
'-f',
'-name',
'DbAcl'
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'app'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH),
'dry' => true,
'f' => true,
'name' => 'DbAcl'
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$expected = array('./console/cake.php', 'schema', 'run', 'create');
$this->assertEqual($expected, $Dispatcher->args);
$params = array(
'/cake/1.2.x.x/cake/console/cake.php',
'-working',
'/cake/1.2.x.x/app',
'schema',
'run',
'create',
'-dry',
'-name',
'DbAcl'
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => '/cake/1.2.x.x/app',
'root' => '/cake/1.2.x.x',
'dry' => true,
'name' => 'DbAcl'
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$expected = array('/cake/1.2.x.x/cake/console/cake.php', 'schema', 'run', 'create');
$this->assertEqual($expected, $Dispatcher->args);
$params = array(
'cake.php',
'-working',
'C:/wamp/www/cake/app',
'bake',
'-app',
'C:/wamp/www/apps/cake/app',
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => 'C:\wamp\www\apps\cake\app',
'root' => 'C:\wamp\www\apps\cake'
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'cake.php',
'-working',
'C:\wamp\www\cake\app',
'bake',
'-app',
'C:\wamp\www\apps\cake\app',
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => 'C:\wamp\www\apps\cake\app',
'root' => 'C:\wamp\www\apps\cake'
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'cake.php',
'-working',
'C:\wamp\www\apps',
'bake',
'-app',
'cake\app',
'-url',
'http://example.com/some/url/with/a/path'
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => 'C:\wamp\www\apps\cake\app',
'root' => 'C:\wamp\www\apps\cake',
'url' => 'http://example.com/some/url/with/a/path'
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'/home/amelo/dev/cake-common/cake/console/cake.php',
'-root',
'/home/amelo/dev/lsbu-vacancy',
'-working',
'/home/amelo/dev/lsbu-vacancy',
'-app',
'app',
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => '/home/amelo/dev/lsbu-vacancy/app',
'root' => '/home/amelo/dev/lsbu-vacancy',
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'cake.php',
'-working',
'D:\www',
'bake',
'my_app',
);
$expected = array(
'working' => 'D:\www',
'app' => 'www',
'root' => 'D:',
'webroot' => 'webroot'
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
}
/**
* testBuildPaths method
*
* @return void
*/
public function testBuildPaths() {
$Dispatcher = new TestShellDispatcher();
$result = $Dispatcher->shellPaths;
$expected = array(
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS . 'test_plugin' . DS . 'vendors' . DS . 'shells' . DS,
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS . 'test_plugin_two' . DS . 'vendors' . DS . 'shells' . DS,
APP . 'vendors' . DS . 'shells' . DS,
VENDORS . 'shells' . DS,
CORE_PATH ? CONSOLE_LIBS : ROOT . DS . CONSOLE_LIBS,
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'vendors' . DS . 'shells' . DS,
);
$this->assertIdentical(array_diff($result, $expected), array());
$this->assertIdentical(array_diff($expected, $result), array());
}
/**
* Verify loading of (plugin-) shells
*
* @return void
*/
public function testGetShell() {
$this->skipIf(class_exists('SampleShell'), '%s SampleShell Class already loaded');
$this->skipIf(class_exists('ExampleShell'), '%s ExampleShell Class already loaded');
$Dispatcher = new TestShellDispatcher();
$Dispatcher->shell = 'sample';
$Dispatcher->shellName = 'Sample';
$Dispatcher->shellClass = 'SampleShell';
$result = $Dispatcher->getShell();
$this->assertIsA($result, 'SampleShell');
$Dispatcher = new TestShellDispatcher();
$Dispatcher->shell = 'example';
$Dispatcher->shellName = 'Example';
$Dispatcher->shellClass = 'ExampleShell';
$result = $Dispatcher->getShell('test_plugin');
$this->assertIsA($result, 'ExampleShell');
}
/**
* Verify correct dispatch of Shell subclasses with a main method
*
* @return void
*/
public function testDispatchShellWithMain() {
$Dispatcher = new TestShellDispatcher();
$methods = get_class_methods('Shell');
array_push($methods, 'main', '_secret');
$Mock = $this->getMock('Shell', $methods, array(&$Dispatcher), 'MockWithMainShell');
$Mock->expects($this->once())->method('main')->will($this->returnValue(true));
$Mock->expects($this->once())->method('initialize');
$Mock->expects($this->once())->method('loadTasks');
$Mock->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Mock;
$Dispatcher->args = array('mock_with_main');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array());
$Shell = new MockWithMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main', 'initdb');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array('initdb'));
$Shell = new MockWithMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('startup');
$Shell->expects($this->once())->method('help');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main', 'help');
$result = $Dispatcher->dispatch();
$this->assertNull($result);
$this->assertEqual($Dispatcher->args, array());
$Shell = new MockWithMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Shell->expects($this->never())->method('hr');
$Shell->expects($this->once())->method('startup');
$Shell->expects($this->once())->method('main');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main', 'hr');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array('hr'));
$Shell = new MockWithMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main', 'dispatch');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array('dispatch'));
$Shell = new MockWithMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main', 'idontexist');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array('idontexist'));
$Shell = new MockWithMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->never())->method('main');
$Shell->expects($this->never())->method('startup');
$Shell->expects($this->never())->method('_secret');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main', '_secret');
$result = $Dispatcher->dispatch();
$this->assertFalse($result);
}
/**
* Verify correct dispatch of Shell subclasses without a main method
*
* @return void
*/
public function testDispatchShellWithoutMain() {
$Dispatcher = new TestShellDispatcher();
$methods = get_class_methods('Shell');
array_push($methods, 'initDb', '_secret');
$Shell = $this->getMock('Shell', $methods, array(&$Dispatcher), 'MockWithoutMainShell');
$Shell->expects($this->once())->method('initialize');
$Shell->expects($this->once())->method('loadTasks');
$Shell->expects($this->never())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main');
$result = $Dispatcher->dispatch();
$this->assertFalse($result);
$this->assertEqual($Dispatcher->args, array());
$Shell = new MockWithoutMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('initDb')->will($this->returnValue(true));
$Shell->expects($this->once())->method('initialize');
$Shell->expects($this->once())->method('loadTasks');
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main', 'initdb');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array());
$Shell = new MockWithoutMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->never())->method('hr');
$Shell->expects($this->never())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main', 'hr');
$result = $Dispatcher->dispatch();
$this->assertFalse($result);
$this->assertEqual($Dispatcher->args, array('hr'));
$Shell = new MockWithoutMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->never())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main', 'dispatch');
$result = $Dispatcher->dispatch();
$this->assertFalse($result);
$Shell = new MockWithoutMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->never())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main', 'idontexist');
$result = $Dispatcher->dispatch();
$this->assertFalse($result);
$Shell = new MockWithoutMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->never())->method('startup');
$Shell->expects($this->never())->method('_secret');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main', '_secret');
$result = $Dispatcher->dispatch();
$this->assertFalse($result);
}
/**
* Verify correct dispatch of custom classes with a main method
*
* @return void
*/
public function testDispatchNotAShellWithMain() {
$Dispatcher = new TestShellDispatcher();
$methods = get_class_methods('Object');
array_push($methods, 'main', 'initdb', 'initialize', 'loadTasks', 'startup', '_secret');
$Shell = $this->getMock('Object', $methods, array(&$Dispatcher), 'MockWithMainNotAShell');
$Shell->expects($this->never())->method('initialize');
$Shell->expects($this->never())->method('loadTasks');
$Shell->expects($this->once())->method('startup');
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main_not_a');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array());
$Shell = new MockWithMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('initdb')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main_not_a', 'initdb');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$Shell = new MockWithMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main_not_a', 'hr');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array('hr'));
$Shell = new MockWithMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main_not_a', 'dispatch');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array('dispatch'));
$Shell = new MockWithMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main_not_a', 'idontexist');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array('idontexist'));
$Shell = new MockWithMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->never())->method('_secret');
$Shell->expects($this->never())->method('main');
$Shell->expects($this->never())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main_not_a', '_secret');
$result = $Dispatcher->dispatch();
$this->assertFalse($result);
}
/**
* Verify correct dispatch of custom classes without a main method
*
* @return void
*/
public function testDispatchNotAShellWithoutMain() {
$Dispatcher = new TestShellDispatcher();
$methods = get_class_methods('Object');
array_push($methods, 'main', 'initdb', 'initialize', 'loadTasks', 'startup', '_secret');
$Shell = $this->getMock('Object', $methods, array(&$Dispatcher), 'MockWithoutMainNotAShell');
$Shell->expects($this->never())->method('initialize');
$Shell->expects($this->never())->method('loadTasks');
$Shell->expects($this->once())->method('startup');
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main_not_a');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array());
$Shell = new MockWithoutMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('initdb')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main_not_a', 'initdb');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$Shell = new MockWithoutMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main_not_a', 'hr');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array('hr'));
$Shell = new MockWithoutMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main_not_a', 'dispatch');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array('dispatch'));
$Shell = new MockWithoutMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main_not_a', 'idontexist');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array('idontexist'));
$Shell = new MockWithoutMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->never())->method('_secret');
$Shell->expects($this->never())->method('main');
$Shell->expects($this->never())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main_not_a', '_secret');
$result = $Dispatcher->dispatch();
$this->assertFalse($result);
}
/**
* Verify that a task is called instead of the shell if the first arg equals
* the name of the task
*
* @return void
*/
public function testDispatchTask() {
$Dispatcher = new TestShellDispatcher();
$mainMethods = $executeMethods = get_class_methods('Shell');
array_push($mainMethods, 'main');
array_push($executeMethods, 'execute');
$Week = $this->getMock('Shell', $mainMethods, array(&$Dispatcher), 'MockWeekShell');
$Sunday = $this->getMock('Shell', $executeMethods, array(&$Dispatcher), 'MockOnSundayTask');
$Shell = new MockWeekShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('initialize');
$Shell->expects($this->once())->method('loadTasks');
$Shell->expects($this->never())->method('startup');
$Shell->expects($this->never())->method('main');
$Task = new MockOnSundayTask($Dispatcher);
$this->mockObjects[] = $Task;
$Task->expects($this->once())->method('execute')->will($this->returnValue(true));
$Task->expects($this->once())->method('initialize');;
$Task->expects($this->once())->method('loadTasks');
$Task->expects($this->once())->method('startup');
$Task->expects($this->once())->method('execute');
$Shell->MockOnSunday = $Task;
$Shell->taskNames = array('MockOnSunday');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_week', 'mock_on_sunday');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array());
$Shell = new MockWeekShell($Dispatcher);
$Task = new MockOnSundayTask($Dispatcher);
array_push($this->mockObjects, $Shell, $Task);
$Task->expects($this->never())->method('execute');
$Task->expects($this->once())->method('help');
$Shell->MockOnSunday = $Task;
$Shell->taskNames = array('MockOnSunday');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_week', 'mock_on_sunday', 'help');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
}
/**
* Verify shifting of arguments
*
* @return void
*/
public function testShiftArgs() {
$Dispatcher = new TestShellDispatcher();
$Dispatcher->args = array('a', 'b', 'c');
$this->assertEqual($Dispatcher->shiftArgs(), 'a');
$this->assertIdentical($Dispatcher->args, array('b', 'c'));
$Dispatcher->args = array('a' => 'b', 'c', 'd');
$this->assertEqual($Dispatcher->shiftArgs(), 'b');
$this->assertIdentical($Dispatcher->args, array('c', 'd'));
$Dispatcher->args = array('a', 'b' => 'c', 'd');
$this->assertEqual($Dispatcher->shiftArgs(), 'a');
$this->assertIdentical($Dispatcher->args, array('b' => 'c', 'd'));
$Dispatcher->args = array(0 => 'a', 2 => 'b', 30 => 'c');
$this->assertEqual($Dispatcher->shiftArgs(), 'a');
$this->assertIdentical($Dispatcher->args, array(0 => 'b', 1 => 'c'));
$Dispatcher->args = array();
$this->assertNull($Dispatcher->shiftArgs());
$this->assertIdentical($Dispatcher->args, array());
}
/**
* testHelpCommand method
*
* @return void
*/
public function testHelpCommand() {
$Dispatcher = new TestShellDispatcher();
$expected = "/example \[.*TestPlugin, TestPluginTwo.*\]/";
$this->assertPattern($expected, $Dispatcher->stdout);
$expected = "/welcome \[.*TestPluginTwo.*\]/";
$this->assertPattern($expected, $Dispatcher->stdout);
$expected = "/acl \[.*CORE.*\]/";
$this->assertPattern($expected, $Dispatcher->stdout);
$expected = "/api \[.*CORE.*\]/";
$this->assertPattern($expected, $Dispatcher->stdout);
$expected = "/bake \[.*CORE.*\]/";
$this->assertPattern($expected, $Dispatcher->stdout);
$expected = "/console \[.*CORE.*\]/";
$this->assertPattern($expected, $Dispatcher->stdout);
$expected = "/i18n \[.*CORE.*\]/";
$this->assertPattern($expected, $Dispatcher->stdout);
$expected = "/schema \[.*CORE.*\]/";
$this->assertPattern($expected, $Dispatcher->stdout);
$expected = "/testsuite \[.*CORE.*\]/";
$this->assertPattern($expected, $Dispatcher->stdout);
$expected = "/sample \[.*test_app.*\]/";
$this->assertPattern($expected, $Dispatcher->stdout);
}
}

View file

@ -17,7 +17,7 @@
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
require_once CAKE . 'console' . DS . 'console_error_handler.php';
require_once CONSOLE_LIBS . 'console_error_handler.php';
/**
* ConsoleErrorHandler Test case.
@ -32,7 +32,9 @@ class ConsoleErrorHandlerTest extends CakeTestCase {
* @return Mock object
*/
function getErrorHandler($exception) {
return $this->getMock('ConsoleErrorHandler', array('stderr'), array($exception));
$error = new ConsoleErrorHandler($exception);
$error->stderr = $this->getMock('ConsoleOutput', array(), array(), '', false);
return $error;
}
/**
@ -44,7 +46,7 @@ class ConsoleErrorHandlerTest extends CakeTestCase {
$exception = new MissingActionException('Missing action');
$error = $this->getErrorHandler($exception);
$error->expects($this->once())->method('stderr')
$error->stderr->expects($this->once())->method('write')
->with($this->stringContains('Missing action'));
$error->render();
@ -59,7 +61,7 @@ class ConsoleErrorHandlerTest extends CakeTestCase {
$exception = new InvalidArgumentException('Too many parameters.');
$error = $this->getErrorHandler($exception);
$error->expects($this->once())->method('stderr')
$error->stderr->expects($this->once())->method('write')
->with($this->stringContains('Too many parameters.'));
$error->render();
@ -74,7 +76,7 @@ class ConsoleErrorHandlerTest extends CakeTestCase {
$exception = new NotFoundException('dont use me in cli.');
$error = $this->getErrorHandler($exception);
$error->expects($this->once())->method('stderr')
$error->stderr->expects($this->once())->method('write')
->with($this->stringContains('dont use me in cli.'));
$error->render();
@ -89,7 +91,7 @@ class ConsoleErrorHandlerTest extends CakeTestCase {
$exception = new InternalErrorException('dont use me in cli.');
$error = $this->getErrorHandler($exception);
$error->expects($this->once())->method('stderr')
$error->stderr->expects($this->once())->method('write')
->with($this->stringContains('dont use me in cli.'));
$error->render();
@ -104,6 +106,6 @@ class ConsoleErrorHandlerTest extends CakeTestCase {
$exception = new InternalErrorException('dont use me in cli.');
$error = new ConsoleErrorHandler($exception);
$this->assertTrue(is_resource($error->stderr), 'No handle.');
$this->assertType('ConsoleOutput', $error->stderr, 'No handle.');
}
}

View file

@ -0,0 +1,495 @@
<?php
/**
* ConsoleOptionParserTest file
*
* PHP 5
*
* CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
* Copyright 2005-2010, Cake Software Foundation, Inc.
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc.
* @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
* @package cake
* @subpackage cake.tests.cases.console
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
require_once CONSOLE_LIBS . 'console_option_parser.php';
class ConsoleOptionParserTest extends CakeTestCase {
/**
* test setting the console description
*
* @return void
*/
function testDescription() {
$parser = new ConsoleOptionParser('test', false);
$result = $parser->description('A test');
$this->assertEquals($parser, $result, 'Setting description is not chainable');
$this->assertEquals('A test', $parser->description(), 'getting value is wrong.');
$result = $parser->description(array('A test', 'something'));
$this->assertEquals("A test\nsomething", $parser->description(), 'getting value is wrong.');
}
/**
* test setting the console epliog
*
* @return void
*/
function testEpilog() {
$parser = new ConsoleOptionParser('test', false);
$result = $parser->epilog('A test');
$this->assertEquals($parser, $result, 'Setting epilog is not chainable');
$this->assertEquals('A test', $parser->epilog(), 'getting value is wrong.');
$result = $parser->epilog(array('A test', 'something'));
$this->assertEquals("A test\nsomething", $parser->epilog(), 'getting value is wrong.');
}
/**
* test adding an option returns self.
*
* @return void
*/
function testAddOptionReturnSelf() {
$parser = new ConsoleOptionParser('test', false);
$result = $parser->addOption('test');
$this->assertEquals($parser, $result, 'Did not return $this from addOption');
}
/**
* test adding an option and using the long value for parsing.
*
* @return void
*/
function testAddOptionLong() {
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('test', array(
'short' => 't'
));
$result = $parser->parse(array('--test', 'value'));
$this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Long parameter did not parse out');
}
/**
* test adding an option and using the long value for parsing.
*
* @return void
*/
function testAddOptionLongEquals() {
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('test', array(
'short' => 't'
));
$result = $parser->parse(array('--test=value'));
$this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Long parameter did not parse out');
}
/**
* test adding an option and using the default.
*
* @return void
*/
function testAddOptionDefault() {
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('test', array(
'default' => 'default value',
));
$result = $parser->parse(array('--test'));
$this->assertEquals(array('test' => 'default value', 'help' => false), $result[0], 'Default value did not parse out');
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('test', array(
'default' => 'default value',
));
$result = $parser->parse(array());
$this->assertEquals(array('test' => 'default value', 'help' => false), $result[0], 'Default value did not parse out');
}
/**
* test adding an option and using the short value for parsing.
*
* @return void
*/
function testAddOptionShort() {
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('test', array(
'short' => 't'
));
$result = $parser->parse(array('-t', 'value'));
$this->assertEquals(array('test' => 'value', 'help' => false), $result[0], 'Short parameter did not parse out');
}
/**
* test adding and using boolean options.
*
* @return void
*/
function testAddOptionBoolean() {
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('test', array(
'boolean' => true,
));
$result = $parser->parse(array('--test', 'value'));
$expected = array(array('test' => true, 'help' => false), array('value'));
$this->assertEquals($expected, $result);
$result = $parser->parse(array('value'));
$expected = array(array('test' => false, 'help' => false), array('value'));
$this->assertEquals($expected, $result);
}
/**
* test adding an multiple shorts.
*
* @return void
*/
function testAddOptionMultipleShort() {
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('test', array('short' => 't', 'boolean' => true))
->addOption('file', array('short' => 'f', 'boolean' => true))
->addOption('output', array('short' => 'o', 'boolean' => true));
$result = $parser->parse(array('-o', '-t', '-f'));
$expected = array('file' => true, 'test' => true, 'output' => true, 'help' => false);
$this->assertEquals($expected, $result[0], 'Short parameter did not parse out');
$result = $parser->parse(array('-otf'));
$this->assertEquals($expected, $result[0], 'Short parameter did not parse out');
}
/**
* test multiple options at once.
*
* @return void
*/
function testMultipleOptions() {
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('test')
->addOption('connection')
->addOption('table', array('short' => 't', 'default' => true));
$result = $parser->parse(array('--test', 'value', '-t', '--connection', 'postgres'));
$expected = array('test' => 'value', 'table' => true, 'connection' => 'postgres', 'help' => false);
$this->assertEquals($expected, $result[0], 'multiple options did not parse');
}
/**
* Test adding multiple options.
*
* @return void
*/
function testAddOptions() {
$parser = new ConsoleOptionParser('something', false);
$result = $parser->addOptions(array(
'name' => array('help' => 'The name'),
'other' => array('help' => 'The other arg')
));
$this->assertEquals($parser, $result, 'addOptions is not chainable.');
$result = $parser->options();
$this->assertEquals(3, count($result), 'Not enough options');
}
/**
* test that boolean options work
*
* @return void
*/
function testOptionWithBooleanParam() {
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('no-commit', array('boolean' => true))
->addOption('table', array('short' => 't'));
$result = $parser->parse(array('--table', 'posts', '--no-commit', 'arg1', 'arg2'));
$expected = array(array('table' => 'posts', 'no-commit' => true, 'help' => false), array('arg1', 'arg2'));
$this->assertEquals($expected, $result, 'Boolean option did not parse correctly.');
}
/**
* test parsing options that do not exist.
*
* @expectedException InvalidArgumentException
*/
function testOptionThatDoesNotExist() {
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('no-commit', array('boolean' => true));
$result = $parser->parse(array('--fail', 'other'));
}
/**
* test that options with choices enforce them.
*
* @expectedException InvalidArgumentException
* @return void
*/
function testOptionWithChoices() {
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('name', array('choices' => array('mark', 'jose')));
$result = $parser->parse(array('--name', 'mark'));
$expected = array('name' => 'mark', 'help' => false);
$this->assertEquals($expected, $result[0], 'Got the correct value.');
$result = $parser->parse(array('--name', 'jimmy'));
}
/**
* test positional argument parsing.
*
* @return void
*/
function testPositionalArgument() {
$parser = new ConsoleOptionParser('test', false);
$result = $parser->addArgument('name', array('help' => 'An argument'));
$this->assertEquals($parser, $result, 'Should returnn this');
}
/**
* test overwriting positional arguments.
*
* @return void
*/
function testPositionalArgOverwrite() {
$parser = new ConsoleOptionParser('test', false);
$parser->addArgument('name', array('help' => 'An argument'))
->addArgument('other', array('index' => 0));
$result = $parser->arguments();
$this->assertEquals(1, count($result), 'Overwrite did not occur');
}
/**
* test parsing arguments.
*
* @expectedException InvalidArgumentException
* @return void
*/
function testParseArgumentTooMany() {
$parser = new ConsoleOptionParser('test', false);
$parser->addArgument('name', array('help' => 'An argument'))
->addArgument('other');
$expected = array('one', 'two');
$result = $parser->parse($expected);
$this->assertEquals($expected, $result[1], 'Arguments are not as expected');
$result = $parser->parse(array('one', 'two', 'three'));
}
/**
* test that when there are not enough arguments an exception is raised
*
* @expectedException RuntimeException
* @return void
*/
function testPositionalArgNotEnough() {
$parser = new ConsoleOptionParser('test', false);
$parser->addArgument('name', array('required' => true))
->addArgument('other', array('required' => true));
$parser->parse(array('one'));
}
/**
* test that arguments with choices enforce them.
*
* @expectedException InvalidArgumentException
* @return void
*/
function testPositionalArgWithChoices() {
$parser = new ConsoleOptionParser('test', false);
$parser->addArgument('name', array('choices' => array('mark', 'jose')))
->addArgument('alias', array('choices' => array('cowboy', 'samurai')))
->addArgument('weapon', array('choices' => array('gun', 'sword')));
$result = $parser->parse(array('mark', 'samurai', 'sword'));
$expected = array('mark', 'samurai', 'sword');
$this->assertEquals($expected, $result[1], 'Got the correct value.');
$result = $parser->parse(array('jose', 'coder'));
}
/**
* Test adding multiple arguments.
*
* @return void
*/
function testAddArguments() {
$parser = new ConsoleOptionParser('test', false);
$result = $parser->addArguments(array(
'name' => array('help' => 'The name'),
'other' => array('help' => 'The other arg')
));
$this->assertEquals($parser, $result, 'addArguments is not chainable.');
$result = $parser->arguments();
$this->assertEquals(2, count($result), 'Not enough arguments');
}
/**
* test setting a subcommand up.
*
* @return void
*/
function testSubcommand() {
$parser = new ConsoleOptionParser('test', false);
$result = $parser->addSubcommand('initdb', array(
'help' => 'Initialize the database'
));
$this->assertEquals($parser, $result, 'Adding a subcommand is not chainable');
}
/**
* test adding multiple subcommands
*
* @return void
*/
function testAddSubcommands() {
$parser = new ConsoleOptionParser('test', false);
$result = $parser->addSubcommands(array(
'initdb' => array('help' => 'Initialize the database'),
'create' => array('help' => 'Create something')
));
$this->assertEquals($parser, $result, 'Adding a subcommands is not chainable');
$result = $parser->subcommands();
$this->assertEquals(2, count($result), 'Not enough subcommands');
}
/**
* test that no exception is triggered when help is being generated
*
* @return void
*/
function testHelpNoExceptionWhenGettingHelp() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->addOption('test', array('help' => 'A test option.'))
->addArgument('model', array('help' => 'The model to make.', 'required' => true));
$result = $parser->parse(array('--help'));
$this->assertTrue($result[0]['help']);
}
/**
* test that help() with a command param shows the help for a subcommand
*
* @return void
*/
function testHelpSubcommandHelp() {
$subParser = new ConsoleOptionParser('method', false);
$subParser->addOption('connection', array('help' => 'Db connection.'));
$parser = new ConsoleOptionParser('mycommand', false);
$parser->addSubcommand('method', array(
'help' => 'This is another command',
'parser' => $subParser
))
->addOption('test', array('help' => 'A test option.'));
$result = $parser->help('method');
$expected = <<<TEXT
<info>Usage:</info>
cake mycommand method [-h] [--connection]
<info>Options:</info>
--help, -h Display this help.
--connection Db connection.
TEXT;
$this->assertEquals($expected, $result, 'Help is not correct.');
}
/**
* test building a parser from an array.
*
* @return void
*/
function testBuildFromArray() {
$spec = array(
'command' => 'test',
'arguments' => array(
'name' => array('help' => 'The name'),
'other' => array('help' => 'The other arg')
),
'options' => array(
'name' => array('help' => 'The name'),
'other' => array('help' => 'The other arg')
),
'subcommands' => array(
'initdb' => array('help' => 'make database')
),
'description' => 'description text',
'epilog' => 'epilog text'
);
$parser = ConsoleOptionParser::buildFromArray($spec);
$this->assertEquals($spec['description'], $parser->description());
$this->assertEquals($spec['epilog'], $parser->epilog());
$options = $parser->options();
$this->assertTrue(isset($options['name']));
$this->assertTrue(isset($options['other']));
$args = $parser->arguments();
$this->assertEquals(2, count($args));
$commands = $parser->subcommands();
$this->assertEquals(1, count($commands));
}
/**
* test that create() returns instances
*
* @return void
*/
function testCreateFactory() {
$parser = ConsoleOptionParser::create('factory', false);
$this->assertInstanceOf('ConsoleOptionParser', $parser);
$this->assertEquals('factory', $parser->command());
}
/**
* test that parse() takes a subcommand argument, and that the subcommand parser
* is used.
*
* @return void
*/
function testParsingWithSubParser() {
$parser = new ConsoleOptionParser('test', false);
$parser->addOption('primary')
->addArgument('one', array('required' => true, 'choices' => array('a', 'b')))
->addArgument('two', array('required' => true))
->addSubcommand('sub', array(
'parser' => array(
'options' => array(
'secondary' => array('boolean' => true),
'fourth' => array('help' => 'fourth option')
),
'arguments' => array(
'sub_arg' => array('choices' => array('c', 'd'))
)
)
));
$result = $parser->parse(array('--secondary', '--fourth', '4', 'c'), 'sub');
$expected = array(array(
'secondary' => true,
'fourth' => '4',
'help' => false,
'verbose' => false,
'quiet' => false), array('c'));
$this->assertEquals($expected, $result, 'Sub parser did not parse request.');
}
}

View file

@ -0,0 +1,228 @@
<?php
/**
* ConsoleOutputTest file
*
* PHP 5
*
* CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
* Copyright 2005-2010, Cake Software Foundation, Inc.
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc.
* @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
* @package cake
* @subpackage cake.tests.cases.console
* @since CakePHP(tm) v 1.2.0.5432
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
require_once CONSOLE_LIBS . 'console_output.php';
class ConsoleOutputTest extends CakeTestCase {
/**
* setup
*
* @return void
*/
function setUp() {
parent::setUp();
$this->output = $this->getMock('ConsoleOutput', array('_write'));
}
/**
* tearDown
*
* @return void
*/
function tearDown() {
unset($this->output);
}
/**
* test writing with no new line
*
* @return void
*/
function testWriteNoNewLine() {
$this->output->expects($this->once())->method('_write')
->with('Some output');
$this->output->write('Some output', false);
}
/**
* test writing with no new line
*
* @return void
*/
function testWriteNewLine() {
$this->output->expects($this->once())->method('_write')
->with('Some output' . PHP_EOL);
$this->output->write('Some output');
}
/**
* test write() with multiple new lines
*
* @return void
*/
function testWriteMultipleNewLines() {
$this->output->expects($this->once())->method('_write')
->with('Some output' . PHP_EOL . PHP_EOL . PHP_EOL . PHP_EOL);
$this->output->write('Some output', 4);
}
/**
* test writing an array of messages.
*
* @return void
*/
function testWriteArray() {
$this->output->expects($this->once())->method('_write')
->with('Line' . PHP_EOL . 'Line' . PHP_EOL . 'Line' . PHP_EOL);
$this->output->write(array('Line', 'Line', 'Line'));
}
/**
* test getting a style.
*
* @return void
*/
function testStylesGet() {
$result = $this->output->styles('error');
$expected = array('text' => 'red', 'underline' => true);
$this->assertEqual($result, $expected);
$this->assertNull($this->output->styles('made_up_goop'));
$result = $this->output->styles();
$this->assertNotEmpty($result, 'error', 'Error is missing');
$this->assertNotEmpty($result, 'warning', 'Warning is missing');
}
/**
* test adding a style.
*
* @return void
*/
function testStylesAdding() {
$this->output->styles('test', array('text' => 'red', 'background' => 'black'));
$result = $this->output->styles('test');
$expected = array('text' => 'red', 'background' => 'black');
$this->assertEquals($expected, $result);
$this->assertTrue($this->output->styles('test', false), 'Removing a style should return true.');
$this->assertNull($this->output->styles('test'), 'Removed styles should be null.');
}
/**
* test formatting text with styles.
*
* @return void
*/
function testFormattingSimple() {
$this->output->expects($this->once())->method('_write')
->with("\033[31;4mError:\033[0m Something bad");
$this->output->write('<error>Error:</error> Something bad', false);
}
/**
* test that formatting doesn't eat tags it doesn't know about.
*
* @return void
*/
function testFormattingNotEatingTags() {
$this->output->expects($this->once())->method('_write')
->with("<red> Something bad");
$this->output->write('<red> Something bad', false);
}
/**
* test formatting with custom styles.
*
* @return void
*/
function testFormattingCustom() {
$this->output->styles('annoying', array(
'text' => 'magenta',
'background' => 'cyan',
'blink' => true,
'underline' => true
));
$this->output->expects($this->once())->method('_write')
->with("\033[35;46;5;4mAnnoy:\033[0m Something bad");
$this->output->write('<annoying>Annoy:</annoying> Something bad', false);
}
/**
* test formatting text with missing styles.
*
* @return void
*/
function testFormattingMissingStyleName() {
$this->output->expects($this->once())->method('_write')
->with("<not_there>Error:</not_there> Something bad");
$this->output->write('<not_there>Error:</not_there> Something bad', false);
}
/**
* test formatting text with multiple styles.
*
* @return void
*/
function testFormattingMultipleStylesName() {
$this->output->expects($this->once())->method('_write')
->with("\033[31;4mBad\033[0m \033[33mWarning\033[0m Regular");
$this->output->write('<error>Bad</error> <warning>Warning</warning> Regular', false);
}
/**
* test that multiple tags of the same name work in one string.
*
* @return void
*/
function testFormattingMultipleSameTags() {
$this->output->expects($this->once())->method('_write')
->with("\033[31;4mBad\033[0m \033[31;4mWarning\033[0m Regular");
$this->output->write('<error>Bad</error> <error>Warning</error> Regular', false);
}
/**
* test raw output not getting tags replaced.
*
* @return void
*/
function testOutputAsRaw() {
$this->output->outputAs(ConsoleOutput::RAW);
$this->output->expects($this->once())->method('_write')
->with('<error>Bad</error> Regular');
$this->output->write('<error>Bad</error> Regular', false);
}
/**
* test plain output.
*
* @return void
*/
function testOutputAsPlain() {
$this->output->outputAs(ConsoleOutput::PLAIN);
$this->output->expects($this->once())->method('_write')
->with('Bad Regular');
$this->output->write('<error>Bad</error> Regular', false);
}
}

View file

@ -0,0 +1,440 @@
<?php
require_once CONSOLE_LIBS . 'console_option_parser.php';
require_once CONSOLE_LIBS . 'help_formatter.php';
class HelpFormatterTest extends CakeTestCase {
/**
* test that the console max width is respected when generating help.
*
* @return void
*/
function testWidthFormatting() {
$parser = new ConsoleOptionParser('test', false);
$parser->description(__('This is fifteen This is fifteen This is fifteen'))
->addOption('four', array('help' => 'this is help text this is help text'))
->addArgument('four', array('help' => 'this is help text this is help text'))
->addSubcommand('four', array('help' => 'this is help text this is help text'));
$formatter = new HelpFormatter($parser);
$result = $formatter->text(30);
$expected = <<<TEXT
This is fifteen This is
fifteen This is fifteen
<info>Usage:</info>
cake test [subcommand] [-h] [--four] [<four>]
<info>Subcommands:</info>
four this is help text this
is help text
To see help on a subcommand use <info>`cake test [subcommand] --help`</info>
<info>Options:</info>
--help, -h Display this help.
--four this is help text
this is help text
<info>Arguments:</info>
four this is help text this
is help text
<comment>(optional)</comment>
TEXT;
$this->assertEquals($expected, $result, 'Generated help is too wide');
}
/**
* test help() with options and arguments that have choices.
*
* @return void
*/
function testHelpWithChoices() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->addOption('test', array('help' => 'A test option.', 'choices' => array('one', 'two')))
->addArgument('type', array(
'help' => 'Resource type.',
'choices' => array('aco', 'aro'),
'required' => true
))
->addArgument('other_longer', array('help' => 'Another argument.'));
$formatter = new HelpFormatter($parser);
$result = $formatter->text();
$expected = <<<TEXT
<info>Usage:</info>
cake mycommand [-h] [--test one|two] <aco|aro> [<other_longer>]
<info>Options:</info>
--help, -h Display this help.
--test A test option. <comment>(choices: one|two)</comment>
<info>Arguments:</info>
type Resource type. <comment>(choices: aco|aro)</comment>
other_longer Another argument. <comment>(optional)</comment>
TEXT;
$this->assertEquals($expected, $result, 'Help does not match');
}
/**
* test description and epilog in the help
*
* @return void
*/
function testHelpDescriptionAndEpilog() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->description('Description text')
->epilog('epilog text')
->addOption('test', array('help' => 'A test option.'))
->addArgument('model', array('help' => 'The model to make.', 'required' => true));
$formatter = new HelpFormatter($parser);
$result = $formatter->text();
$expected = <<<TEXT
Description text
<info>Usage:</info>
cake mycommand [-h] [--test] <model>
<info>Options:</info>
--help, -h Display this help.
--test A test option.
<info>Arguments:</info>
model The model to make.
epilog text
TEXT;
$this->assertEquals($expected, $result, 'Help is wrong.');
}
/**
* test that help() outputs subcommands.
*
* @return void
*/
function testHelpSubcommand() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->addSubcommand('method', array('help' => 'This is another command'))
->addOption('test', array('help' => 'A test option.'));
$formatter = new HelpFormatter($parser);
$result = $formatter->text();
$expected = <<<TEXT
<info>Usage:</info>
cake mycommand [subcommand] [-h] [--test]
<info>Subcommands:</info>
method This is another command
To see help on a subcommand use <info>`cake mycommand [subcommand] --help`</info>
<info>Options:</info>
--help, -h Display this help.
--test A test option.
TEXT;
$this->assertEquals($expected, $result, 'Help is not correct.');
}
/**
* test getting help with defined options.
*
* @return void
*/
function testHelpWithOptions() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->addOption('test', array('help' => 'A test option.'))
->addOption('connection', array(
'short' => 'c', 'help' => 'The connection to use.', 'default' => 'default'
));
$formatter = new HelpFormatter($parser);
$result = $formatter->text();
$expected = <<<TEXT
<info>Usage:</info>
cake mycommand [-h] [--test] [-c default]
<info>Options:</info>
--help, -h Display this help.
--test A test option.
--connection, -c The connection to use. <comment>(default:
default)</comment>
TEXT;
$this->assertEquals($expected, $result, 'Help does not match');
}
/**
* test getting help with defined options.
*
* @return void
*/
function testHelpWithOptionsAndArguments() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->addOption('test', array('help' => 'A test option.'))
->addArgument('model', array('help' => 'The model to make.', 'required' => true))
->addArgument('other_longer', array('help' => 'Another argument.'));
$formatter = new HelpFormatter($parser);
$result = $formatter->text();
$expected = <<<TEXT
<info>Usage:</info>
cake mycommand [-h] [--test] <model> [<other_longer>]
<info>Options:</info>
--help, -h Display this help.
--test A test option.
<info>Arguments:</info>
model The model to make.
other_longer Another argument. <comment>(optional)</comment>
TEXT;
$this->assertEquals($expected, $result, 'Help does not match');
}
/**
* test help() with options and arguments that have choices.
*
* @return void
*/
function testXmlHelpWithChoices() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->addOption('test', array('help' => 'A test option.', 'choices' => array('one', 'two')))
->addArgument('type', array(
'help' => 'Resource type.',
'choices' => array('aco', 'aro'),
'required' => true
))
->addArgument('other_longer', array('help' => 'Another argument.'));
$formatter = new HelpFormatter($parser);
$result = $formatter->xml();
$expected = <<<TEXT
<?xml version="1.0"?>
<shell>
<name>mycommand</name>
<description>Description text</description>
<subcommands />
<options>
<option name="--help" short="-h" help="Display this help." boolean="1">
<default></default>
<choices></choices>
</option>
<option name="--test" short="" help="A test option." boolean="0">
<default></default>
<choices>
<choice>one</choice>
<choice>two</choice>
</choices>
</option>
</options>
<arguments>
<argument name="type" help="Resource type." required="1">
<choices>
<choice>aco</choice>
<choice>aro</choice>
</choices>
</argument>
</arguments>
<epilog>epilog text</epilog>
</shell>
TEXT;
$this->assertEquals(new DomDocument($expected), new DomDocument($result), 'Help does not match');
}
/**
* test description and epilog in the help
*
* @return void
*/
function testXmlHelpDescriptionAndEpilog() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->description('Description text')
->epilog('epilog text')
->addOption('test', array('help' => 'A test option.'))
->addArgument('model', array('help' => 'The model to make.', 'required' => true));
$formatter = new HelpFormatter($parser);
$result = $formatter->xml();
$expected = <<<TEXT
<?xml version="1.0"?>
<shell>
<name>mycommand</name>
<description>Description text</description>
<subcommands />
<options>
<option name="--help" short="-h" help="Display this help." boolean="1">
<default></default>
<choices></choices>
</option>
<option name="--test" short="" help="A test option." boolean="0">
<default></default>
<choices></choices>
</option>
</options>
<arguments>
<argument name="model" help="The model to make." required="1">
<choices></choices>
</argument>
</arguments>
<epilog>epilog text</epilog>
</shell>
TEXT;
$this->assertEquals(new DomDocument($expected), new DomDocument($result), 'Help does not match');
}
/**
* test that help() outputs subcommands.
*
* @return void
*/
function testXmlHelpSubcommand() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->addSubcommand('method', array('help' => 'This is another command'))
->addOption('test', array('help' => 'A test option.'));
$formatter = new HelpFormatter($parser);
$result = $formatter->xml();
$expected = <<<TEXT
<?xml version="1.0"?>
<shell>
<name>mycommand</name>
<description/>
<subcommands>
<command name="method" help="This is another command" />
</subcommands>
<options>
<option name="--help" short="-h" help="Display this help." boolean="1">
<default></default>
<choices></choices>
</option>
<option name="--test" short="" help="A test option." boolean="0">
<default></default>
<choices></choices>
</option>
</options>
<arguments/>
<epilog/>
</shell>
TEXT;
$this->assertEquals(new DomDocument($expected), new DomDocument($result), 'Help does not match');
}
/**
* test getting help with defined options.
*
* @return void
*/
function testXmlHelpWithOptions() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->addOption('test', array('help' => 'A test option.'))
->addOption('connection', array(
'short' => 'c', 'help' => 'The connection to use.', 'default' => 'default'
));
$formatter = new HelpFormatter($parser);
$result = $formatter->xml();
$expected = <<<TEXT
<?xml version="1.0"?>
<shell>
<name>mycommand</name>
<description/>
<subcommands/>
<options>
<option name="--help" short="-h" help="Display this help." boolean="1">
<default></default>
<choices></choices>
</option>
<option name="--test" short="" help="A test option." boolean="0">
<default></default>
<choices></choices>
</option>
<option name="--connection" short="-c" help="The connection to use." boolean="0">
<default>default</default>
<choices></choices>
</option>
</options>
<arguments/>
<epilog/>
</shell>
TEXT;
$this->assertEquals(new DomDocument($expected), new DomDocument($result), 'Help does not match');
}
/**
* test getting help with defined options.
*
* @return void
*/
function testXmlHelpWithOptionsAndArguments() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->addOption('test', array('help' => 'A test option.'))
->addArgument('model', array('help' => 'The model to make.', 'required' => true))
->addArgument('other_longer', array('help' => 'Another argument.'));
$formatter = new HelpFormatter($parser);
$result = $formatter->xml();
$expected = <<<TEXT
<?xml version="1.0"?>
<shell>
<name>mycommand</name>
<description/>
<subcommands/>
<options>
<option name="--help" short="-h" help="Display this help." boolean="1">
<default></default>
<choices></choices>
</option>
<option name="--test" short="" help="A test option." boolean="0">
<default></default>
<choices></choices>
</option>
</options>
<arguments>
<argument name="model" help="The model to make." required="1">
<choices></choices>
</argument>
<argument name="other_longer" help="Another argument." required="0">
<choices></choices>
</argument>
</arguments>
<epilog/>
</shell>
TEXT;
$this->assertEquals(new DomDocument($expected), new DomDocument($result), 'Help does not match');
}
/**
* Test xml help as object
*
* @return void
*/
function testXmlHelpAsObject() {
$parser = new ConsoleOptionParser('mycommand', false);
$parser->addOption('test', array('help' => 'A test option.'))
->addArgument('model', array('help' => 'The model to make.', 'required' => true))
->addArgument('other_longer', array('help' => 'Another argument.'));
$formatter = new HelpFormatter($parser);
$result = $formatter->xml(false);
$this->assertType('SimpleXmlElement', $result);
}
}

View file

@ -22,18 +22,7 @@
App::import('Core', 'Folder');
App::import('Shell', 'Shell', false);
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
/**
* TestShell class
@ -50,6 +39,7 @@ class TestShell extends Shell {
* @access public
*/
public $name = 'TestShell';
/**
* stopped property
*
@ -67,6 +57,18 @@ class TestShell extends Shell {
protected function _stop($status = 0) {
$this->stopped = $status;
}
public function do_something() {
}
public function _secret() {
}
protected function no_access() {
}
}
/**
@ -114,21 +116,10 @@ class ShellTest extends CakeTestCase {
public function setUp() {
parent::setUp();
$this->Dispatcher = $this->getMock(
'ShellDispatcher',
array('getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear')
);
$this->Shell =& new TestShell($this->Dispatcher);
}
/**
* tearDown method
*
* @return void
*/
public function tearDown() {
parent::tearDown();
ClassRegistry::flush();
$output = $this->getMock('ConsoleOutput', array(), array(), '', false);
$error = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Shell =& new TestShell($output, $error, $in);
}
/**
@ -137,9 +128,10 @@ class ShellTest extends CakeTestCase {
* @return void
*/
public function testConstruct() {
$this->assertEquals($this->Dispatcher, $this->Shell->Dispatch);
$this->assertEqual($this->Shell->name, 'TestShell');
$this->assertEqual($this->Shell->alias, 'TestShell');
$this->assertType('ConsoleInput', $this->Shell->stdin);
$this->assertType('ConsoleOutput', $this->Shell->stdout);
$this->assertType('ConsoleOutput', $this->Shell->stderr);
}
/**
@ -166,11 +158,6 @@ class ShellTest extends CakeTestCase {
$this->assertIsA($this->Shell->Comment, 'Comment');
$this->assertEqual($this->Shell->modelClass, 'Comment');
$this->Shell->uses = true;
$this->Shell->initialize();
$this->assertTrue(isset($this->Shell->AppModel));
$this->assertIsA($this->Shell->AppModel, 'AppModel');
App::build();
}
@ -180,29 +167,24 @@ class ShellTest extends CakeTestCase {
* @return void
*/
public function testIn() {
$this->Dispatcher->expects($this->at(0))
->method('getInput')
->with('Just a test?', array('y', 'n'), 'n')
$this->Shell->stdin->expects($this->at(0))
->method('read')
->will($this->returnValue('n'));
$this->Dispatcher->expects($this->at(1))
->method('getInput')
->with('Just a test?', array('y', 'n'), 'n')
$this->Shell->stdin->expects($this->at(1))
->method('read')
->will($this->returnValue('Y'));
$this->Dispatcher->expects($this->at(2))
->method('getInput')
->with('Just a test?', 'y,n', 'n')
$this->Shell->stdin->expects($this->at(2))
->method('read')
->will($this->returnValue('y'));
$this->Dispatcher->expects($this->at(3))
->method('getInput')
->with('Just a test?', 'y/n', 'n')
$this->Shell->stdin->expects($this->at(3))
->method('read')
->will($this->returnValue('y'));
$this->Dispatcher->expects($this->at(4))
->method('getInput')
->with('Just a test?', 'y', 'y')
$this->Shell->stdin->expects($this->at(4))
->method('read')
->will($this->returnValue('y'));
$result = $this->Shell->in('Just a test?', array('y', 'n'), 'n');
@ -232,21 +214,21 @@ class ShellTest extends CakeTestCase {
* @return void
*/
public function testOut() {
$this->Shell->Dispatch->expects($this->at(0))
->method('stdout')
->with("Just a test\n", false);
$this->Shell->stdout->expects($this->at(0))
->method('write')
->with("Just a test", 1);
$this->Shell->Dispatch->expects($this->at(1))
->method('stdout')
->with("Just\na\ntest\n", false);
$this->Shell->stdout->expects($this->at(1))
->method('write')
->with(array('Just', 'a', 'test'), 1);
$this->Shell->Dispatch->expects($this->at(2))
->method('stdout')
->with("Just\na\ntest\n\n", false);
$this->Shell->stdout->expects($this->at(2))
->method('write')
->with(array('Just', 'a', 'test'), 2);
$this->Shell->Dispatch->expects($this->at(3))
->method('stdout')
->with("\n", false);
$this->Shell->stdout->expects($this->at(3))
->method('write')
->with('', 1);
$this->Shell->out('Just a test');
@ -257,27 +239,65 @@ class ShellTest extends CakeTestCase {
$this->Shell->out();
}
/**
* test that verbose and quiet output levels work
*
* @return void
*/
function testVerboseOutput() {
$this->Shell->stdout->expects($this->at(0))->method('write')
->with('Verbose', 1);
$this->Shell->stdout->expects($this->at(1))->method('write')
->with('Normal', 1);
$this->Shell->stdout->expects($this->at(2))->method('write')
->with('Quiet', 1);
$this->Shell->params['verbose'] = true;
$this->Shell->params['quiet'] = false;
$this->Shell->out('Verbose', 1, Shell::VERBOSE);
$this->Shell->out('Normal', 1, Shell::NORMAL);
$this->Shell->out('Quiet', 1, Shell::QUIET);
}
/**
* test that verbose and quiet output levels work
*
* @return void
*/
function testQuietOutput() {
$this->Shell->stdout->expects($this->once())->method('write')
->with('Quiet', 1);
$this->Shell->params['verbose'] = false;
$this->Shell->params['quiet'] = true;
$this->Shell->out('Verbose', 1, Shell::VERBOSE);
$this->Shell->out('Normal', 1, Shell::NORMAL);
$this->Shell->out('Quiet', 1, Shell::QUIET);
}
/**
* testErr method
*
* @return void
*/
public function testErr() {
$this->Shell->Dispatch->expects($this->at(0))
->method('stderr')
->with("Just a test\n");
$this->Shell->stderr->expects($this->at(0))
->method('write')
->with("Just a test", 1);
$this->Shell->Dispatch->expects($this->at(1))
->method('stderr')
->with("Just\na\ntest\n");
$this->Shell->stderr->expects($this->at(1))
->method('write')
->with(array('Just', 'a', 'test'), 1);
$this->Shell->Dispatch->expects($this->at(2))
->method('stderr')
->with("Just\na\ntest\n\n");
$this->Shell->stderr->expects($this->at(2))
->method('write')
->with(array('Just', 'a', 'test'), 2);
$this->Shell->Dispatch->expects($this->at(3))
->method('stderr')
->with("\n");
$this->Shell->stderr->expects($this->at(3))
->method('write')
->with('', 1);
$this->Shell->err('Just a test');
@ -309,17 +329,17 @@ class ShellTest extends CakeTestCase {
public function testHr() {
$bar = '---------------------------------------------------------------';
$this->Shell->Dispatch->expects($this->at(0))->method('stdout')->with('', false);
$this->Shell->Dispatch->expects($this->at(1))->method('stdout')->with($bar . "\n", false);
$this->Shell->Dispatch->expects($this->at(2))->method('stdout')->with('', false);
$this->Shell->stdout->expects($this->at(0))->method('write')->with('', 0);
$this->Shell->stdout->expects($this->at(1))->method('write')->with($bar, 1);
$this->Shell->stdout->expects($this->at(2))->method('write')->with('', 0);
$this->Shell->Dispatch->expects($this->at(3))->method('stdout')->with("\n", false);
$this->Shell->Dispatch->expects($this->at(4))->method('stdout')->with($bar . "\n", false);
$this->Shell->Dispatch->expects($this->at(5))->method('stdout')->with("\n", false);
$this->Shell->stdout->expects($this->at(3))->method('write')->with("", true);
$this->Shell->stdout->expects($this->at(4))->method('write')->with($bar, 1);
$this->Shell->stdout->expects($this->at(5))->method('write')->with("", true);
$this->Shell->Dispatch->expects($this->at(6))->method('stdout')->with("\n\n", false);
$this->Shell->Dispatch->expects($this->at(7))->method('stdout')->with($bar . "\n", false);
$this->Shell->Dispatch->expects($this->at(8))->method('stdout')->with("\n\n", false);
$this->Shell->stdout->expects($this->at(6))->method('write')->with("", 2);
$this->Shell->stdout->expects($this->at(7))->method('write')->with($bar, 1);
$this->Shell->stdout->expects($this->at(8))->method('write')->with("", 2);
$this->Shell->hr();
@ -334,17 +354,17 @@ class ShellTest extends CakeTestCase {
* @return void
*/
public function testError() {
$this->Shell->Dispatch->expects($this->at(0))
->method('stderr')
->with("Error: Foo Not Found\n");
$this->Shell->stderr->expects($this->at(0))
->method('write')
->with("<error>Error:</error> Foo Not Found", 1);
$this->Shell->Dispatch->expects($this->at(1))
->method('stderr')
->with("Error: Foo Not Found\n");
$this->Shell->stderr->expects($this->at(1))
->method('write')
->with("<error>Error:</error> Foo Not Found", 1);
$this->Shell->Dispatch->expects($this->at(2))
->method('stderr')
->with("Searched all...\n");
$this->Shell->stderr->expects($this->at(2))
->method('write')
->with("Searched all...", 1);
$this->Shell->error('Foo Not Found');
$this->assertIdentical($this->Shell->stopped, 1);
@ -377,19 +397,37 @@ class ShellTest extends CakeTestCase {
$this->Shell->tasks = array('TestApple');
$this->assertTrue($this->Shell->loadTasks());
$this->assertIsA($this->Shell->TestApple, 'TestAppleTask');
$this->assertInstanceOf('TestAppleTask', $this->Shell->TestApple);
$this->Shell->tasks = 'TestBanana';
$this->assertTrue($this->Shell->loadTasks());
$this->assertIsA($this->Shell->TestApple, 'TestAppleTask');
$this->assertIsA($this->Shell->TestBanana, 'TestBananaTask');
$this->assertInstanceOf('TestAppleTask', $this->Shell->TestApple);
$this->assertInstanceOf('TestBananaTask', $this->Shell->TestBanana);
unset($this->Shell->ShellTestApple, $this->Shell->TestBanana);
$this->Shell->tasks = array('TestApple', 'TestBanana');
$this->assertTrue($this->Shell->loadTasks());
$this->assertIsA($this->Shell->TestApple, 'TestAppleTask');
$this->assertIsA($this->Shell->TestBanana, 'TestBananaTask');
$this->assertInstanceOf('TestAppleTask', $this->Shell->TestApple);
$this->assertInstanceOf('TestBananaTask', $this->Shell->TestBanana);
}
/**
* test that __get() makes args and params references
*
* @return void
*/
function test__getArgAndParamReferences() {
$this->Shell->tasks = array('TestApple');
$this->Shell->args = array('one');
$this->Shell->params = array('help' => false);
$this->Shell->loadTasks();
$result = $this->Shell->TestApple;
$this->Shell->args = array('one', 'two');
$this->assertSame($this->Shell->args, $result->args);
$this->assertSame($this->Shell->params, $result->params);
}
/**
@ -477,14 +515,12 @@ class ShellTest extends CakeTestCase {
$this->Shell->interactive = true;
$this->Shell->Dispatch->expects($this->at(5))
->method('getInput')
->withAnyParameters()
$this->Shell->stdin->expects($this->at(0))
->method('read')
->will($this->returnValue('n'));
$this->Shell->Dispatch->expects($this->at(9))
->method('getInput')
->withAnyParameters()
$this->Shell->stdin->expects($this->at(1))
->method('read')
->will($this->returnValue('y'));
@ -578,4 +614,161 @@ class ShellTest extends CakeTestCase {
$Folder->delete();
}
/**
* test hasTask method
*
* @return void
*/
function testHasTask() {
$this->Shell->tasks = array('Extract', 'DbConfig');
$this->Shell->loadTasks();
$this->assertTrue($this->Shell->hasTask('extract'));
$this->assertTrue($this->Shell->hasTask('Extract'));
$this->assertFalse($this->Shell->hasTask('random'));
$this->assertTrue($this->Shell->hasTask('db_config'));
$this->assertTrue($this->Shell->hasTask('DbConfig'));
}
/**
* test the hasMethod
*
* @return void
*/
function testHasMethod() {
$this->assertTrue($this->Shell->hasMethod('do_something'));
$this->assertFalse($this->Shell->hasMethod('hr'), 'hr is callable');
$this->assertFalse($this->Shell->hasMethod('_secret'), '_secret is callable');
$this->assertFalse($this->Shell->hasMethod('no_access'), 'no_access is callable');
}
/**
* test run command calling main.
*
* @return void
*/
function testRunCommandMain() {
$methods = get_class_methods('Shell');
$Mock = $this->getMock('Shell', array('main', 'startup'), array(), '', false);
$Mock->expects($this->once())->method('main')->will($this->returnValue(true));
$result = $Mock->runCommand(null, array());
$this->assertTrue($result);
}
/**
* test run command calling a legit method.
*
* @return void
*/
function testRunCommandWithMethod() {
$methods = get_class_methods('Shell');
$Mock = $this->getMock('Shell', array('hit_me', 'startup'), array(), '', false);
$Mock->expects($this->once())->method('hit_me')->will($this->returnValue(true));
$result = $Mock->runCommand('hit_me', array());
$this->assertTrue($result);
}
/**
* test run command causing exception on Shell method.
*
* @return void
*/
function testRunCommandBaseclassMethod() {
$Mock = $this->getMock('Shell', array('startup', 'getOptionParser', 'out'), array(), '', false);
$Parser = $this->getMock('ConsoleOptionParser', array(), array(), '', false);
$Parser->expects($this->once())->method('help');
$Mock->expects($this->once())->method('getOptionParser')
->will($this->returnValue($Parser));
$Mock->expects($this->never())->method('hr');
$Mock->expects($this->once())->method('out');
$result = $Mock->runCommand('hr', array());
}
/**
* test run command causing exception on Shell method.
*
* @return void
*/
function testRunCommandMissingMethod() {
$methods = get_class_methods('Shell');
$Mock = $this->getMock('Shell', array('startup', 'getOptionParser', 'out'), array(), '', false);
$Parser = $this->getMock('ConsoleOptionParser', array(), array(), '', false);
$Parser->expects($this->once())->method('help');
$Mock->expects($this->never())->method('idontexist');
$Mock->expects($this->once())->method('getOptionParser')
->will($this->returnValue($Parser));
$Mock->expects($this->once())->method('out');
$result = $Mock->runCommand('idontexist', array());
}
/**
* test that a --help causes help to show.
*
* @return void
*/
function testRunCommandTriggeringHelp() {
$Parser = $this->getMock('ConsoleOptionParser', array(), array(), '', false);
$Parser->expects($this->once())->method('parse')
->with(array('--help'))
->will($this->returnValue(array(array('help' => true), array())));
$Parser->expects($this->once())->method('help');
$Shell = $this->getMock('Shell', array('getOptionParser', 'out', 'startup', '_welcome'), array(), '', false);
$Shell->expects($this->once())->method('getOptionParser')
->will($this->returnValue($Parser));
$Shell->expects($this->once())->method('out');
$Shell->runCommand(null, array('--help'));
}
/**
* test that runCommand will call runCommand on the task.
*
* @return void
*/
function testRunCommandHittingTask() {
$Shell = $this->getMock('Shell', array('hasTask', 'startup'), array(), '', false);
$task = $this->getMock('Shell', array('execute', 'runCommand'), array(), '', false);
$task->expects($this->any())->method('runCommand')
->with('execute', array('one', 'value'));
$Shell->expects($this->once())->method('startup');
$Shell->expects($this->any())->method('hasTask')->will($this->returnValue(true));
$Shell->RunCommand = $task;
$Shell->runCommand('run_command', array('run_command', 'one', 'value'));
}
/**
* test wrapBlock wrapping text.
*
* @return void
*/
function testWrapText() {
$text = 'This is the song that never ends. This is the song that never ends. This is the song that never ends.';
$result = $this->Shell->wrapText($text, 33);
$expected = <<<TEXT
This is the song that never ends.
This is the song that never ends.
This is the song that never ends.
TEXT;
$this->assertEquals($expected, $result, 'Text not wrapped.');
$result = $this->Shell->wrapText($text, array('indent' => ' ', 'width' => 33));
$expected = <<<TEXT
This is the song that never ends.
This is the song that never ends.
This is the song that never ends.
TEXT;
$this->assertEquals($expected, $result, 'Text not wrapped.');
}
}

View file

@ -17,15 +17,7 @@
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
App::import('Shell', 'TaskCollection', false);
App::import('Shell', 'Shell', false);
@ -36,9 +28,9 @@ class TaskCollectionTest extends CakeTestCase {
* @return void
*/
function setup() {
$shell = $this->getMock('Shell', array(), array(), '', false);
$dispatcher = $this->getMock('ShellDispatcher', array(), array(), '', false);
$dispatcher->shellPaths = App::path('shells');
$this->Tasks = new TaskCollection($dispatcher);
$this->Tasks = new TaskCollection($shell, $dispatcher);
}
/**
@ -95,9 +87,11 @@ class TaskCollectionTest extends CakeTestCase {
*/
function testLoadPluginTask() {
$dispatcher = $this->getMock('ShellDispatcher', array(), array(), '', false);
$dispatcher->shellPaths = App::path('shells');
$dispatcher->shellPaths[] = TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS . 'test_plugin' . DS . 'vendors' . DS . 'shells' . DS;
$this->Tasks = new TaskCollection($dispatcher);
$shell = $this->getMock('Shell', array(), array(), '', false);
App::build(array(
'plugins' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS)
));
$this->Tasks = new TaskCollection($shell, $dispatcher);
$result = $this->Tasks->load('TestPlugin.OtherTask');
$this->assertType('OtherTaskTask', $result, 'Task class is wrong.');

View file

@ -1,249 +0,0 @@
<?php
/**
* PluginTask Test file
*
* Test Case for plugin generation shell task
*
* PHP 5
*
* CakePHP : Rapid Development Framework (http://cakephp.org)
* Copyright 2006-2010, Cake Software Foundation, Inc.
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2006-2010, Cake Software Foundation, Inc.
* @link http://cakephp.org CakePHP Project
* @package cake
* @subpackage cake.tests.cases.console.libs.tasks
* @since CakePHP v 1.3.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Core', array('File'));
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'plugin.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'model.php';
/**
* PluginTaskPlugin class
*
* @package cake
* @subpackage cake.tests.cases.console.libs.tasks
*/
class PluginTaskTest extends CakeTestCase {
/**
* setup method
*
* @return void
*/
public function setUp() {
parent::setUp();
$this->Dispatcher = $this->getMock('ShellDispatcher', array(
'getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear'
));
$this->Task = $this->getMock('PluginTask',
array('in', 'err', 'createFile', '_stop'),
array(&$this->Dispatcher)
);
$this->Task->path = TMP . 'tests' . DS;
$this->_paths = $paths = App::path('plugins');
$this->_testPath = array_push($paths, TMP . 'tests' . DS);
App::build(array('plugins' => $paths));
}
/**
* teardown
*
* @return void
*/
public function tearDown() {
parent::tearDown();
App::build(array('plugins' => $this->_paths));
}
/**
* test bake()
*
* @return void
*/
public function testBakeFoldersAndFiles() {
$this->Task->expects($this->at(0))->method('in')->will($this->returnValue($this->_testPath));
$this->Task->expects($this->at(1))->method('in')->will($this->returnValue('y'));
$path = $this->Task->path . 'bake_test_plugin';
$file = $path . DS . 'bake_test_plugin_app_controller.php';
$this->Task->expects($this->at(3))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$file = $path . DS . 'bake_test_plugin_app_model.php';
$this->Task->expects($this->at(4))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$this->Task->bake('BakeTestPlugin');
$path = $this->Task->path . 'bake_test_plugin';
$this->assertTrue(is_dir($path), 'No plugin dir %s');
$this->assertTrue(is_dir($path . DS . 'config'), 'No config dir %s');
$this->assertTrue(is_dir($path . DS . 'config' . DS . 'schema'), 'No schema dir %s');
$this->assertTrue(file_exists($path . DS . 'config' . DS . 'schema' . DS . 'empty'), 'No empty file %s');
$this->assertTrue(is_dir($path . DS . 'controllers'), 'No controllers dir %s');
$this->assertTrue(is_dir($path . DS . 'controllers' . DS .'components'), 'No components dir %s');
$this->assertTrue(file_exists($path . DS . 'controllers' . DS . 'components' . DS . 'empty'), 'No empty file %s');
$this->assertTrue(is_dir($path . DS . 'models'), 'No models dir %s');
$this->assertTrue(file_exists($path . DS . 'models' . DS . 'behaviors' . DS . 'empty'), 'No empty file %s');
$this->assertTrue(is_dir($path . DS . 'models' . DS . 'datasources'), 'No datasources dir %s');
$this->assertTrue(file_exists($path . DS . 'models' . DS . 'datasources' . DS . 'empty'), 'No empty file %s');
$this->assertTrue(is_dir($path . DS . 'views'), 'No views dir %s');
$this->assertTrue(is_dir($path . DS . 'views' . DS . 'helpers'), 'No helpers dir %s');
$this->assertTrue(file_exists($path . DS . 'views' . DS . 'helpers' . DS . 'empty'), 'No empty file %s');
$this->assertTrue(is_dir($path . DS . 'tests'), 'No tests dir %s');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'cases'), 'No cases dir %s');
$this->assertTrue(
is_dir($path . DS . 'tests' . DS . 'cases' . DS . 'components'), 'No components cases dir %s'
);
$this->assertTrue(
file_exists($path . DS . 'tests' . DS . 'cases' . DS . 'components' . DS . 'empty'), 'No empty file %s'
);
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'cases' . DS . 'behaviors'), 'No behaviors cases dir %s');
$this->assertTrue(
file_exists($path . DS . 'tests' . DS . 'cases' . DS . 'behaviors' . DS . 'empty'), 'No empty file %s'
);
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'cases' . DS . 'helpers'), 'No helpers cases dir %s');
$this->assertTrue(
file_exists($path . DS . 'tests' . DS . 'cases' . DS . 'helpers' . DS . 'empty'), 'No empty file %s'
);
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'cases' . DS . 'models'), 'No models cases dir %s');
$this->assertTrue(
file_exists($path . DS . 'tests' . DS . 'cases' . DS . 'models' . DS . 'empty'), 'No empty file %s'
);
$this->assertTrue(
is_dir($path . DS . 'tests' . DS . 'cases' . DS . 'controllers'),
'No controllers cases dir %s'
);
$this->assertTrue(
file_exists($path . DS . 'tests' . DS . 'cases' . DS . 'controllers' . DS . 'empty'), 'No empty file %s'
);
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'groups'), 'No groups dir %s');
$this->assertTrue(file_exists($path . DS . 'tests' . DS . 'groups' . DS . 'empty'), 'No empty file %s');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'fixtures'), 'No fixtures dir %s');
$this->assertTrue(file_exists($path . DS . 'tests' . DS . 'fixtures' . DS . 'empty'), 'No empty file %s');
$this->assertTrue(is_dir($path . DS . 'vendors'), 'No vendors dir %s');
$this->assertTrue(is_dir($path . DS . 'vendors' . DS . 'shells'), 'No vendors shells dir %s');
$this->assertTrue(is_dir($path . DS . 'vendors' . DS . 'shells' . DS . 'tasks'), 'No vendors shells tasks dir %s');
$this->assertTrue(file_exists($path . DS . 'vendors' . DS . 'shells' . DS . 'tasks' . DS . 'empty'), 'No empty file %s');
$this->assertTrue(is_dir($path . DS . 'libs'), 'No libs dir %s');
$this->assertTrue(is_dir($path . DS . 'webroot'), 'No webroot dir %s');
$Folder = new Folder($this->Task->path . 'bake_test_plugin');
$Folder->delete();
}
/**
* test execute with no args, flowing into interactive,
*
* @return void
*/
public function testExecuteWithNoArgs() {
$this->Task->expects($this->at(0))->method('in')->will($this->returnValue('TestPlugin'));
$this->Task->expects($this->at(1))->method('in')->will($this->returnValue('3'));
$this->Task->expects($this->at(2))->method('in')->will($this->returnValue('y'));
$this->Task->expects($this->at(3))->method('in')->will($this->returnValue('n'));
$path = $this->Task->path . 'test_plugin';
$file = $path . DS . 'test_plugin_app_controller.php';
$this->Task->expects($this->at(4))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$file = $path . DS . 'test_plugin_app_model.php';
$this->Task->expects($this->at(5))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$this->Task->args = array();
$this->Task->execute();
$Folder = new Folder($path);
$Folder->delete();
}
/**
* Test Execute
*
* @return void
*/
public function testExecuteWithOneArg() {
$this->Task->expects($this->at(0))->method('in')
->will($this->returnValue($this->_testPath));
$this->Task->expects($this->at(1))->method('in')
->will($this->returnValue('y'));
$path = $this->Task->path . 'bake_test_plugin';
$file = $path . DS . 'bake_test_plugin_app_controller.php';
$this->Task->expects($this->at(3))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$path = $this->Task->path . 'bake_test_plugin';
$file = $path . DS . 'bake_test_plugin_app_model.php';
$this->Task->expects($this->at(4))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$this->Task->Dispatch->args = array('BakeTestPlugin');
$this->Task->args =& $this->Task->Dispatch->args;
$this->Task->execute();
$Folder = new Folder($this->Task->path . 'bake_test_plugin');
$Folder->delete();
}
/**
* test execute chaining into MVC parts
*
* @return void
*/
public function testExecuteWithTwoArgs() {
$this->Task->Model = $this->getMock('ModelTask', array(), array(&$this->Dispatcher));
$this->Task->expects($this->at(0))->method('in')->will($this->returnValue($this->_testPath));
$this->Task->Model->expects($this->once())->method('loadTasks');
$this->Task->Model->expects($this->once())->method('execute');
$Folder = new Folder($this->Task->path . 'bake_test_plugin', true);
$this->Task->Dispatch->args = array('BakeTestPlugin', 'model');
$this->Task->args = $this->Task->Dispatch->args;
$this->Task->execute();
$Folder->delete();
}
}

View file

@ -0,0 +1,544 @@
<?php
/**
* ShellDispatcherTest file
*
* PHP 5
*
* CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
* Copyright 2005-2010, Cake Software Foundation, Inc.
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice
*
* @copyright Copyright 2005-2010, Cake Software Foundation, Inc.
* @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
* @package cake
* @subpackage cake.tests.cases.console
* @since CakePHP(tm) v 1.2.0.5432
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
/**
* TestShellDispatcher class
*
* @package cake
* @subpackage cake.tests.cases.console
*/
class TestShellDispatcher extends ShellDispatcher {
/**
* params property
*
* @var array
* @access public
*/
public $params = array();
/**
* stopped property
*
* @var string
* @access public
*/
public $stopped = null;
/**
* TestShell
*
* @var mixed
* @access public
*/
public $TestShell;
/**
* _initEnvironment method
*
* @return void
*/
protected function _initEnvironment() {
}
/**
* clear method
*
* @return void
*/
public function clear() {
}
/**
* _stop method
*
* @return void
*/
protected function _stop($status = 0) {
$this->stopped = 'Stopped with status: ' . $status;
return $status;
}
/**
* getShell
*
* @param mixed $shell
* @return mixed
*/
public function getShell($shell) {
return $this->_getShell($shell);
}
/**
* _getShell
*
* @param mixed $plugin
* @return mixed
*/
protected function _getShell($shell) {
if (isset($this->TestShell)) {
return $this->TestShell;
}
return parent::_getShell($shell);
}
}
/**
* ShellDispatcherTest
*
* @package cake
* @subpackage cake.tests.cases.libs
*/
class ShellDispatcherTest extends CakeTestCase {
/**
* setUp method
*
* @return void
*/
public function setUp() {
parent::setUp();
App::build(array(
'plugins' => array(
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS
),
'shells' => array(
CORE_PATH ? CONSOLE_LIBS : ROOT . DS . CONSOLE_LIBS,
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'console' . DS . 'shells' . DS
)
), true);
}
/**
* testParseParams method
*
* @return void
*/
public function testParseParams() {
$Dispatcher = new TestShellDispatcher();
$params = array(
'/cake/1.2.x.x/cake/console/cake.php',
'bake',
'-app',
'new',
'-working',
'/var/www/htdocs'
);
$expected = array(
'app' => 'new',
'webroot' => 'webroot',
'working' => '/var/www/htdocs/new',
'root' => '/var/www/htdocs'
);
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array('cake.php');
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'app'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH),
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'cake.php',
'-app',
'new',
);
$expected = array(
'app' => 'new',
'webroot' => 'webroot',
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'new'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH)
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'./cake.php',
'bake',
'-app',
'new',
'-working',
'/cake/1.2.x.x/cake/console'
);
$expected = array(
'app' => 'new',
'webroot' => 'webroot',
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'new'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH)
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'./console/cake.php',
'bake',
'-app',
'new',
'-working',
'/cake/1.2.x.x/cake'
);
$expected = array(
'app' => 'new',
'webroot' => 'webroot',
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'new'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH)
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'./console/cake.php',
'bake',
'-app',
'new',
'-dry',
'-working',
'/cake/1.2.x.x/cake'
);
$expected = array(
'app' => 'new',
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'new'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH),
'webroot' => 'webroot'
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEquals($expected, $Dispatcher->params);
$params = array(
'./console/cake.php',
'-working',
'/cake/1.2.x.x/cake',
'schema',
'run',
'create',
'-dry',
'-f',
'-name',
'DbAcl'
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH . DS . 'app'),
'root' => str_replace('\\', '/', CAKE_CORE_INCLUDE_PATH),
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$expected = array(
'./console/cake.php', 'schema', 'run', 'create', '-dry', '-f', '-name', 'DbAcl'
);
$this->assertEqual($expected, $Dispatcher->args);
$params = array(
'/cake/1.2.x.x/cake/console/cake.php',
'-working',
'/cake/1.2.x.x/app',
'schema',
'run',
'create',
'-dry',
'-name',
'DbAcl'
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => '/cake/1.2.x.x/app',
'root' => '/cake/1.2.x.x',
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'cake.php',
'-working',
'C:/wamp/www/cake/app',
'bake',
'-app',
'C:/wamp/www/apps/cake/app',
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => 'C:\wamp\www\apps\cake\app',
'root' => 'C:\wamp\www\apps\cake'
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'cake.php',
'-working',
'C:\wamp\www\cake\app',
'bake',
'-app',
'C:\wamp\www\apps\cake\app',
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => 'C:\wamp\www\apps\cake\app',
'root' => 'C:\wamp\www\apps\cake'
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'cake.php',
'-working',
'C:\wamp\www\apps',
'bake',
'-app',
'cake\app',
'-url',
'http://example.com/some/url/with/a/path'
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => 'C:\wamp\www\apps\cake\app',
'root' => 'C:\wamp\www\apps\cake',
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'/home/amelo/dev/cake-common/cake/console/cake.php',
'-root',
'/home/amelo/dev/lsbu-vacancy',
'-working',
'/home/amelo/dev/lsbu-vacancy',
'-app',
'app',
);
$expected = array(
'app' => 'app',
'webroot' => 'webroot',
'working' => '/home/amelo/dev/lsbu-vacancy/app',
'root' => '/home/amelo/dev/lsbu-vacancy',
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
$params = array(
'cake.php',
'-working',
'D:\www',
'bake',
'my_app',
);
$expected = array(
'working' => 'D:\www',
'app' => 'www',
'root' => 'D:',
'webroot' => 'webroot'
);
$Dispatcher->params = $Dispatcher->args = array();
$Dispatcher->parseParams($params);
$this->assertEqual($expected, $Dispatcher->params);
}
/**
* Verify loading of (plugin-) shells
*
* @return void
*/
public function testGetShell() {
$this->skipIf(class_exists('SampleShell'), '%s SampleShell Class already loaded');
$this->skipIf(class_exists('ExampleShell'), '%s ExampleShell Class already loaded');
$Dispatcher = new TestShellDispatcher();
$result = $Dispatcher->getShell('sample');
$this->assertInstanceOf('SampleShell', $result);
$Dispatcher = new TestShellDispatcher();
$result = $Dispatcher->getShell('test_plugin.example');
$this->assertInstanceOf('ExampleShell', $result);
}
/**
* Verify correct dispatch of Shell subclasses with a main method
*
* @return void
*/
public function testDispatchShellWithMain() {
$Dispatcher = new TestShellDispatcher();
$Mock = $this->getMock('Shell', array(), array(&$Dispatcher), 'MockWithMainShell');
$Mock->expects($this->once())->method('initialize');
$Mock->expects($this->once())->method('loadTasks');
$Mock->expects($this->once())->method('runCommand')
->with(null, array())
->will($this->returnValue(true));
$Dispatcher->TestShell = $Mock;
$Dispatcher->args = array('mock_with_main');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array());
}
/**
* Verify correct dispatch of Shell subclasses without a main method
*
* @return void
*/
public function testDispatchShellWithoutMain() {
$Dispatcher = new TestShellDispatcher();
$Shell = $this->getMock('Shell', array(), array(&$Dispatcher), 'MockWithoutMainShell');
$Shell = new MockWithoutMainShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('initialize');
$Shell->expects($this->once())->method('loadTasks');
$Shell->expects($this->once())->method('runCommand')
->with('initdb', array('initdb'))
->will($this->returnValue(true));
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main', 'initdb');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
}
/**
* Verify correct dispatch of custom classes with a main method
*
* @return void
*/
public function testDispatchNotAShellWithMain() {
$Dispatcher = new TestShellDispatcher();
$methods = get_class_methods('Object');
array_push($methods, 'main', 'initdb', 'initialize', 'loadTasks', 'startup', '_secret');
$Shell = $this->getMock('Object', $methods, array(), 'MockWithMainNotAShell');
$Shell->expects($this->never())->method('initialize');
$Shell->expects($this->never())->method('loadTasks');
$Shell->expects($this->once())->method('startup');
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main_not_a');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array());
$Shell = new MockWithMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('initdb')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_with_main_not_a', 'initdb');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
}
/**
* Verify correct dispatch of custom classes without a main method
*
* @return void
*/
public function testDispatchNotAShellWithoutMain() {
$Dispatcher = new TestShellDispatcher();
$methods = get_class_methods('Object');
array_push($methods, 'main', 'initdb', 'initialize', 'loadTasks', 'startup', '_secret');
$Shell = $this->getMock('Object', $methods, array(&$Dispatcher), 'MockWithoutMainNotAShell');
$Shell->expects($this->never())->method('initialize');
$Shell->expects($this->never())->method('loadTasks');
$Shell->expects($this->once())->method('startup');
$Shell->expects($this->once())->method('main')->will($this->returnValue(true));
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main_not_a');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
$this->assertEqual($Dispatcher->args, array());
$Shell = new MockWithoutMainNotAShell($Dispatcher);
$this->mockObjects[] = $Shell;
$Shell->expects($this->once())->method('initdb')->will($this->returnValue(true));
$Shell->expects($this->once())->method('startup');
$Dispatcher->TestShell = $Shell;
$Dispatcher->args = array('mock_without_main_not_a', 'initdb');
$result = $Dispatcher->dispatch();
$this->assertTrue($result);
}
/**
* Verify shifting of arguments
*
* @return void
*/
public function testShiftArgs() {
$Dispatcher = new TestShellDispatcher();
$Dispatcher->args = array('a', 'b', 'c');
$this->assertEqual($Dispatcher->shiftArgs(), 'a');
$this->assertIdentical($Dispatcher->args, array('b', 'c'));
$Dispatcher->args = array('a' => 'b', 'c', 'd');
$this->assertEqual($Dispatcher->shiftArgs(), 'b');
$this->assertIdentical($Dispatcher->args, array('c', 'd'));
$Dispatcher->args = array('a', 'b' => 'c', 'd');
$this->assertEqual($Dispatcher->shiftArgs(), 'a');
$this->assertIdentical($Dispatcher->args, array('b' => 'c', 'd'));
$Dispatcher->args = array(0 => 'a', 2 => 'b', 30 => 'c');
$this->assertEqual($Dispatcher->shiftArgs(), 'a');
$this->assertIdentical($Dispatcher->args, array(0 => 'b', 1 => 'c'));
$Dispatcher->args = array();
$this->assertNull($Dispatcher->shiftArgs());
$this->assertIdentical($Dispatcher->args, array());
}
}

View file

@ -18,21 +18,9 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', 'Acl');
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
if (!class_exists('AclShell')) {
require CAKE . 'console' . DS . 'libs' . DS . 'acl.php';
}
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
/**
* AclShellTest class
@ -61,14 +49,13 @@ class AclShellTest extends CakeTestCase {
Configure::write('Acl.database', 'test');
Configure::write('Acl.classname', 'DbAcl');
$this->Dispatcher = $this->getMock(
'ShellDispatcher',
array('getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'dispatch', 'clear')
);
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock(
'AclShell',
array('in', 'out', 'hr', 'createFile', 'error', 'err'),
array(&$this->Dispatcher)
array('in', 'out', 'hr', 'createFile', 'error', 'err', 'clear', 'dispatchShell'),
array($out, $out, $in)
);
$collection = new ComponentCollection();
$this->Task->Acl = new AclComponent($collection);
@ -145,9 +132,9 @@ class AclShellTest extends CakeTestCase {
*/
public function testCreate() {
$this->Task->args = array('aro', 'root', 'User.1');
$this->Task->expects($this->at(0))->method('out')->with("New Aro 'User.1' created.\n", true);
$this->Task->expects($this->at(1))->method('out')->with("New Aro 'User.3' created.\n", true);
$this->Task->expects($this->at(2))->method('out')->with("New Aro 'somealias' created.\n", true);
$this->Task->expects($this->at(0))->method('out')->with("<success>New Aro</success> 'User.1' created.", 2);
$this->Task->expects($this->at(1))->method('out')->with("<success>New Aro</success> 'User.3' created.", 2);
$this->Task->expects($this->at(2))->method('out')->with("<success>New Aro</success> 'somealias' created.", 2);
$this->Task->create();
@ -187,7 +174,7 @@ class AclShellTest extends CakeTestCase {
public function testDelete() {
$this->Task->args = array('aro', 'AuthUser.1');
$this->Task->expects($this->at(0))->method('out')
->with("Aro deleted.\n", true);
->with("<success>Aro deleted.</success>", 2);
$this->Task->delete();
$Aro = ClassRegistry::init('Aro');
@ -217,7 +204,7 @@ class AclShellTest extends CakeTestCase {
public function testGrant() {
$this->Task->args = array('AuthUser.2', 'ROOT/Controller1', 'create');
$this->Task->expects($this->at(0))->method('out')
->with(new PHPUnit_Framework_Constraint_PCREMatch('/Permission granted/'), true);
->with($this->matchesRegularExpression('/granted/'), true);
$this->Task->grant();
$node = $this->Task->Acl->Aro->read(null, 4);
@ -249,13 +236,13 @@ class AclShellTest extends CakeTestCase {
*/
public function testCheck() {
$this->Task->expects($this->at(0))->method('out')
->with(new PHPUnit_Framework_Constraint_PCREMatch('/not allowed/'), true);
->with($this->matchesRegularExpression('/not allowed/'), true);
$this->Task->expects($this->at(1))->method('out')
->with(new PHPUnit_Framework_Constraint_PCREMatch('/Permission granted/'), true);
->with($this->matchesRegularExpression('/granted/'), true);
$this->Task->expects($this->at(2))->method('out')
->with(new PHPUnit_Framework_Constraint_PCREMatch('/is allowed/'), true);
->with($this->matchesRegularExpression('/is.*allowed/'), true);
$this->Task->expects($this->at(3))->method('out')
->with(new PHPUnit_Framework_Constraint_PCREMatch('/not allowed/'), true);
->with($this->matchesRegularExpression('/not.*allowed/'), true);
$this->Task->args = array('AuthUser.2', 'ROOT/Controller1', '*');
$this->Task->check();
@ -277,9 +264,9 @@ class AclShellTest extends CakeTestCase {
*/
public function testInherit() {
$this->Task->expects($this->at(0))->method('out')
->with(new PHPUnit_Framework_Constraint_PCREMatch('/Permission granted/'), true);
->with($this->matchesRegularExpression('/Permission .*granted/'), true);
$this->Task->expects($this->at(1))->method('out')
->with(new PHPUnit_Framework_Constraint_PCREMatch('/Permission inherited/'), true);
->with($this->matchesRegularExpression('/Permission .*inherited/'), true);
$this->Task->args = array('AuthUser.2', 'ROOT/Controller1', 'create');
$this->Task->grant();
@ -311,9 +298,9 @@ class AclShellTest extends CakeTestCase {
* @return void
*/
function testInitDb() {
$this->Task->Dispatch->expects($this->once())->method('dispatch');
$this->Task->expects($this->once())->method('dispatchShell')
->with('schema create DbAcl');
$this->Task->initdb();
$this->assertEqual($this->Task->Dispatch->args, array('schema', 'create', 'DbAcl'));
}
}

View file

@ -18,21 +18,10 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', 'Api');
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
if (!class_exists('ApiShell')) {
require CAKE . 'console' . DS . 'libs' . DS . 'api.php';
}
/**
* ApiShellTest class
@ -49,14 +38,13 @@ class ApiShellTest extends CakeTestCase {
*/
public function setUp() {
parent::setUp();
$this->Dispatcher = $this->getMock(
'ShellDispatcher',
array('getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'dispatch', 'clear')
);
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Shell = $this->getMock(
'ApiShell',
array('in', 'out', 'createFile', 'hr', '_stop'),
array(&$this->Dispatcher)
array( $out, $out, $in)
);
}

View file

@ -19,23 +19,13 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', 'Bake', false);
App::import('Shell', 'tasks/model', false);
App::import('Shell', 'tasks/controller', false);
App::import('Shell', 'tasks/db_config', false);
App::import('Core', 'Controller');
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'bake.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'model.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'controller.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'db_config.php';
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
if (!class_exists('UsersController')) {
class UsersController extends Controller {
@ -60,16 +50,14 @@ class BakeShellTest extends CakeTestCase {
*/
public function setUp() {
parent::setUp();
$this->Dispatcher = $this->getMock(
'ShellDispatcher',
array('getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear')
);
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Shell = $this->getMock(
'BakeShell',
array('in', 'out', 'hr', 'err', 'createFile', '_stop', '_checkUnitTest'),
array(&$this->Dispatcher)
array($out, $out, $in)
);
$this->Shell->Dispatch->shellPaths = App::path('shells');
}
/**

View file

@ -0,0 +1,156 @@
<?php
/**
* CommandList file
*
* PHP 5
*
* CakePHP : Rapid Development Framework (http://cakephp.org)
* Copyright 2006-2010, Cake Software Foundation, Inc.
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2006-2010, Cake Software Foundation, Inc.
* @link http://cakephp.org CakePHP Project
* @package cake
* @subpackage cake.tests.cases.console.libs
* @since CakePHP v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'CommandList', false);
class TestStringOutput extends ConsoleOutput {
public $output = '';
protected function _write($message) {
$this->output .= $message;
}
}
class CommandListTest extends CakeTestCase {
/**
* setUp method
*
* @return void
*/
public function setUp() {
parent::setUp();
App::build(array(
'plugins' => array(
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS
),
'shells' => array(
CORE_PATH ?
CORE_PATH . CAKE . 'console' . DS . 'shells' . DS :
CAKE_CORE_INCLUDE_PATH . DS . 'cake' . DS . 'console' . DS . 'shells' .DS,
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'console' . DS . 'shells' . DS
)
), true);
App::objects('plugin', null, false);
$out = new TestStringOutput();
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Shell = $this->getMock(
'CommandListShell',
array('in', '_stop', 'clear'),
array($out, $out, $in)
);
}
/**
* teardown
*
* @return void
*/
function tearDown() {
parent::tearDown();
unset($this->Shell);
}
/**
* test that main finds core shells.
*
* @return void
*/
function testMain() {
$this->Shell->main();
$output = $this->Shell->stdout->output;
$expected = "/example \[.*TestPlugin, TestPluginTwo.*\]/";
$this->assertPattern($expected, $output);
$expected = "/welcome \[.*TestPluginTwo.*\]/";
$this->assertPattern($expected, $output);
$expected = "/acl \[.*CORE.*\]/";
$this->assertPattern($expected, $output);
$expected = "/api \[.*CORE.*\]/";
$this->assertPattern($expected, $output);
$expected = "/bake \[.*CORE.*\]/";
$this->assertPattern($expected, $output);
$expected = "/console \[.*CORE.*\]/";
$this->assertPattern($expected, $output);
$expected = "/i18n \[.*CORE.*\]/";
$this->assertPattern($expected, $output);
$expected = "/schema \[.*CORE.*\]/";
$this->assertPattern($expected, $output);
$expected = "/testsuite \[.*CORE.*\]/";
$this->assertPattern($expected, $output);
$expected = "/sample \[.*app.*\]/";
$this->assertPattern($expected, $output);
}
/**
* Test the sort param
*
* @return void
*/
function testSortPlugin() {
$this->Shell->params['sort'] = true;
$this->Shell->main();
$output = $this->Shell->stdout->output;
$expected = "/\[.*App.*\]\n[ ]+sample/";
$this->assertPattern($expected, $output);
$expected = "/\[.*TestPluginTwo.*\]\n[ ]+example, welcome/";
$this->assertPattern($expected, $output);
$expected = "/\[.*TestPlugin.*\]\n[ ]+example/";
$this->assertPattern($expected, $output);
$expected = "/\[.*Core.*\]\n[ ]+acl, api, bake, command_list, console, i18n, schema, testsuite/";
$this->assertPattern($expected, $output);
}
/**
* test xml output.
*
* @return void
*/
function testMainXml() {
$this->Shell->params['xml'] = true;
$this->Shell->main();
$output = $this->Shell->stdout->output;
$find = '<shell name="sample" call_as="sample" provider="app" help="sample -h"/>';
$this->assertContains($find, $output);
$find = '<shell name="bake" call_as="bake" provider="CORE" help="bake -h"/>';
$this->assertContains($find, $output);
$find = '<shell name="welcome" call_as="test_plugin_two.welcome" provider="TestPluginTwo" help="test_plugin_two.welcome -h"/>';
$this->assertContains($find, $output);
}
}

View file

@ -18,22 +18,12 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', 'Schema', false);
App::import('Model', 'CakeSchema', false);
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
if (!class_exists('SchemaShell')) {
require CAKE . 'console' . DS . 'libs' . DS . 'schema.php';
}
/**
* Test for Schema database management
@ -119,15 +109,15 @@ class SchemaShellTest extends CakeTestCase {
*
* @return void
*/
public function setup() {
$this->Dispatcher = $this->getMock(
'ShellDispatcher',
array('getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear')
);
public function setUp() {
parent::setUp();
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Shell = $this->getMock(
'SchemaShell',
array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop'),
array(&$this->Dispatcher)
array($out, $out, $in)
);
}
@ -136,13 +126,12 @@ class SchemaShellTest extends CakeTestCase {
*
* @return void
*/
public function teardown() {
ClassRegistry::flush();
public function tearDown() {
parent::tearDown();
if (!empty($this->file) && $this->file instanceof File) {
$this->file->delete();
unset($this->file);
}
App::build();
}
/**
@ -157,7 +146,7 @@ class SchemaShellTest extends CakeTestCase {
$this->assertEqual(strtolower($this->Shell->Schema->name), strtolower(APP_DIR));
$this->assertEqual($this->Shell->Schema->file, 'schema.php');
unset($this->Shell->Schema);
$this->Shell->Schema = null;
$this->Shell->params = array(
'name' => 'TestSchema'
);
@ -167,7 +156,7 @@ class SchemaShellTest extends CakeTestCase {
$this->assertEqual($this->Shell->Schema->connection, 'default');
$this->assertEqual($this->Shell->Schema->path, APP . 'config' . DS . 'schema');
unset($this->Shell->Schema);
$this->Shell->Schema = null;
$this->Shell->params = array(
'file' => 'other_file.php',
'connection' => 'test',
@ -264,7 +253,7 @@ class SchemaShellTest extends CakeTestCase {
$this->file =& new File(TMP . 'tests' . DS . 'dump_test.sql');
$contents = $this->file->read();
$this->assertPattern('/CREATE TABLE `acos`/', $contents);
$this->assertPattern('/CREATE TABLE `test_plugin_acos`/', $contents);
$this->assertPattern('/id/', $contents);
$this->assertPattern('/model/', $contents);
@ -419,6 +408,9 @@ class SchemaShellTest extends CakeTestCase {
$this->assertTrue(in_array($db->config['prefix'] . 'acos', $sources), 'acos should be present.');
$this->assertFalse(in_array($db->config['prefix'] . 'aros', $sources), 'aros should not be found.');
$this->assertFalse(in_array('aros_acos', $sources), 'aros_acos should not be found.');
$schema = new DbAclSchema();
$db->execute($db->dropSchema($schema, 'acos'));
}
/**
@ -435,7 +427,7 @@ class SchemaShellTest extends CakeTestCase {
$this->Shell->params = array(
'connection' => 'test',
'f' => true
'force' => true
);
$this->Shell->args = array('SchemaShellTest', 'articles');
$this->Shell->startup();
@ -483,6 +475,9 @@ class SchemaShellTest extends CakeTestCase {
$db =& ConnectionManager::getDataSource('test');
$sources = $db->listSources();
$this->assertTrue(in_array($db->config['prefix'] . 'acos', $sources));
$this->assertTrue(in_array($db->config['prefix'] . 'test_plugin_acos', $sources));
$schema = new TestPluginAppSchema();
$db->execute($db->dropSchema($schema, 'test_plugin_acos'));
}
}

View file

@ -20,24 +20,15 @@
App::import('Core', 'ClassRegistry');
App::import('View', 'Helper', false);
App::import('Shell', 'Shell', false);
App::import('Shell', array(
'tasks/project',
'tasks/controller',
'tasks/model',
'tasks/template',
'tasks/test'
));
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'project.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'controller.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'model.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'template.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'test.php';
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
$imported = App::import('Model', 'BakeArticle');
$imported = $imported || App::import('Model', 'BakeComment');
@ -77,27 +68,25 @@ class ControllerTaskTest extends CakeTestCase {
* @return void
*/
public function setUp() {
$this->Dispatcher = $this->getMock('ShellDispatcher', array(
'getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear'
));
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock('ControllerTask',
array('in', 'out', 'err', 'hr', 'createFile', '_stop', '_checkUnitTest'),
array(&$this->Dispatcher)
array($out, $out, $in)
);
$this->Task->name = 'ControllerTask';
$this->Task->Dispatch->shellPaths = App::path('shells');
$this->Task->Template =& new TemplateTask($this->Task->Dispatch);
$this->Task->name = 'Controller';
$this->Task->Template = new TemplateTask($out, $out, $in);
$this->Task->Template->params['theme'] = 'default';
$this->Task->Model = $this->getMock('ModelTask',
array('in', 'out', 'err', 'createFile', '_stop', '_checkUnitTest'),
array(&$this->Dispatcher)
array($out, $out, $in)
);
$this->Task->Project = $this->getMock('ProjectTask',
array('in', 'out', 'err', 'createFile', '_stop', '_checkUnitTest', 'getPrefix'),
array(&$this->Dispatcher)
array($out, $out, $in)
);
$this->Task->Test = $this->getMock('TestTask', array(), array(&$this->Dispatcher));
$this->Task->Test = $this->getMock('TestTask', array(), array($out, $out, $in));
}
/**
@ -106,7 +95,7 @@ class ControllerTaskTest extends CakeTestCase {
* @return void
*/
public function teardown() {
unset($this->Task, $this->Dispatcher);
unset($this->Task);
ClassRegistry::flush();
}
@ -600,7 +589,8 @@ class ControllerTaskTest extends CakeTestCase {
}
$this->Task->connection = 'test';
$this->Task->path = '/my/path/';
$this->Task->args = array('BakeArticles', 'public');
$this->Task->args = array('BakeArticles');
$this->Task->params = array('public' => true);
$filename = '/my/path/bake_articles_controller.php';
$expected = new PHPUnit_Framework_Constraint_Not(new PHPUnit_Framework_Constraint_PCREMatch('/\$scaffold/'));
@ -622,7 +612,8 @@ class ControllerTaskTest extends CakeTestCase {
$this->Task->Project->expects($this->any())->method('getPrefix')->will($this->returnValue('admin_'));
$this->Task->connection = 'test';
$this->Task->path = '/my/path/';
$this->Task->args = array('BakeArticles', 'public', 'admin');
$this->Task->args = array('BakeArticles');
$this->Task->params = array('public' => true, 'admin' => true);
$filename = '/my/path/bake_articles_controller.php';
$this->Task->expects($this->once())->method('createFile')->with(
@ -643,7 +634,8 @@ class ControllerTaskTest extends CakeTestCase {
$this->Task->Project->expects($this->any())->method('getPrefix')->will($this->returnValue('admin_'));
$this->Task->connection = 'test';
$this->Task->path = '/my/path/';
$this->Task->args = array('BakeArticles', 'admin');
$this->Task->args = array('BakeArticles');
$this->Task->params = array('admin' => true);
$filename = '/my/path/bake_articles_controller.php';
$this->Task->expects($this->once())->method('createFile')->with(

View file

@ -18,19 +18,9 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', 'tasks/DbConfig');
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'db_config.php';
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
class TEST_DATABASE_CONFIG {
@ -70,16 +60,15 @@ class DbConfigTaskTest extends CakeTestCase {
*/
public function setUp() {
parent::setUp();
$this->Dispatcher = $this->getMock('ShellDispatcher', array(
'getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear'
));
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock('DbConfigTask',
array('in', 'out', 'err', 'hr', 'createFile', '_stop', '_checkUnitTest', '_verify'),
array(&$this->Dispatcher)
array($out, $out, $in)
);
$this->Task->Dispatch->shellPaths = App::path('shells');
$this->Task->params['working'] = rtrim(APP, DS);
$this->Task->path = APP . 'config' . DS;
$this->Task->databaseClassName = 'TEST_DATABASE_CONFIG';
}
@ -90,7 +79,7 @@ class DbConfigTaskTest extends CakeTestCase {
*/
public function tearDown() {
parent::tearDown();
unset($this->Task, $this->Dispatcher);
unset($this->Task);
}
/**
@ -101,7 +90,7 @@ class DbConfigTaskTest extends CakeTestCase {
public function testGetConfig() {
$this->Task->expects($this->at(0))->method('in')->will($this->returnValue('otherOne'));
$result = $this->Task->getConfig();
$this->assertEqual($result, 'otherOne');
$this->assertEquals('otherOne', $result);
}
/**
@ -110,11 +99,9 @@ class DbConfigTaskTest extends CakeTestCase {
* @return void
*/
public function testInitialize() {
$this->assertTrue(empty($this->Task->path));
$this->Task->initialize();
$this->assertFalse(empty($this->Task->path));
$this->assertEqual($this->Task->path, APP . 'config' . DS);
$this->assertEquals(APP . 'config' . DS, $this->Task->path);
}
/**
@ -124,7 +111,13 @@ class DbConfigTaskTest extends CakeTestCase {
*/
public function testExecuteIntoInteractive() {
$this->Task->initialize();
$this->Task = $this->getMock('DbConfigTask', array('in', '_stop', 'createFile'), array(&$this->Dispatcher));
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock(
'DbConfigTask',
array('in', '_stop', 'createFile', 'bake'), array($out, $out, $in)
);
$this->Task->expects($this->once())->method('_stop');
$this->Task->expects($this->at(0))->method('in')->will($this->returnValue('default')); //name
@ -139,6 +132,22 @@ class DbConfigTaskTest extends CakeTestCase {
$this->Task->expects($this->at(12))->method('in')->will($this->returnValue('n')); //encoding
$this->Task->expects($this->at(13))->method('in')->will($this->returnValue('y')); //looks good
$this->Task->expects($this->at(14))->method('in')->will($this->returnValue('n')); //another
$this->Task->expects($this->at(15))->method('bake')
->with(array(
array(
'name' => 'default',
'driver' => 'mysql',
'persistent' => 'false',
'host' => 'localhost',
'login' => 'root',
'password' => 'password',
'database' => 'cake_test',
'prefix' => null,
'encoding' => null,
'port' => '',
'schema' => null
)
));
$result = $this->Task->execute();
}

View file

@ -21,19 +21,9 @@
*/
App::import('Core', 'Folder');
App::import('Shell', 'Shell', false);
App::import('Shell', 'tasks/Extract', false);
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'extract.php';
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
/**
* ExtractTaskTest class
@ -49,10 +39,16 @@ class ExtractTaskTest extends CakeTestCase {
* @return void
*/
public function setUp() {
$this->Dispatcher = $this->getMock('ShellDispatcher', array(
'getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear'
));
$this->Task =& new ExtractTask($this->Dispatcher);
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock(
'ExtractTask',
array('in', 'out', 'err', '_stop'),
array($out, $out, $in)
);
$this->path = TMP . 'tests' . DS . 'extract_task_test';
$Folder = new Folder($this->path . DS . 'locale', true);
}
/**
@ -61,7 +57,11 @@ class ExtractTaskTest extends CakeTestCase {
* @return void
*/
public function tearDown() {
ClassRegistry::flush();
parent::tearDown();
unset($this->Task);
$Folder = new Folder($this->path);
$Folder->delete();
}
/**
@ -70,19 +70,18 @@ class ExtractTaskTest extends CakeTestCase {
* @return void
*/
public function testExecute() {
$path = TMP . 'tests' . DS . 'extract_task_test';
new Folder($path . DS . 'locale', true);
$this->Task->interactive = false;
$this->Task->params['paths'] = TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views' . DS . 'pages';
$this->Task->params['output'] = $path . DS;
$this->Dispatcher->expects($this->never())->method('stderr');
$this->Dispatcher->expects($this->never())->method('_stop');
$this->Task->params['output'] = $this->path . DS;
$this->Task->expects($this->never())->method('err');
$this->Task->expects($this->any())->method('in')
->will($this->returnValue('y'));
$this->Task->expects($this->never())->method('_stop');
$this->Task->execute();
$this->assertTrue(file_exists($path . DS . 'default.pot'));
$result = file_get_contents($path . DS . 'default.pot');
$this->assertTrue(file_exists($this->path . DS . 'default.pot'));
$result = file_get_contents($this->path . DS . 'default.pot');
$pattern = '/"Content-Type\: text\/plain; charset\=utf-8/';
$this->assertPattern($pattern, $result);
@ -134,7 +133,7 @@ class ExtractTaskTest extends CakeTestCase {
$this->assertPattern($pattern, $result);
// extract.ctp - reading the domain.pot
$result = file_get_contents($path . DS . 'domain.pot');
$result = file_get_contents($this->path . DS . 'domain.pot');
$pattern = '/msgid "You have %d new message."\nmsgid_plural "You have %d new messages."/';
$this->assertNoPattern($pattern, $result);
@ -145,9 +144,32 @@ class ExtractTaskTest extends CakeTestCase {
$this->assertPattern($pattern, $result);
$pattern = '/msgid "You deleted %d message \(domain\)."\nmsgid_plural "You deleted %d messages \(domain\)."/';
$this->assertPattern($pattern, $result);
}
$Folder = new Folder($path);
$Folder->delete();
/**
* test exclusions
*
* @return void
*/
function testExtractWithExclude() {
$this->Task->interactive = false;
$this->Task->params['paths'] = TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views';
$this->Task->params['output'] = $this->path . DS;
$this->Task->params['exclude'] = 'pages,layouts';
$this->Task->expects($this->any())->method('in')
->will($this->returnValue('y'));
$this->Task->execute();
$this->assertTrue(file_exists($this->path . DS . 'default.pot'));
$result = file_get_contents($this->path . DS . 'default.pot');
$pattern = '/\#: .*extract\.ctp:6\n/';
$this->assertNotRegExp($pattern, $result);
$pattern = '/\#: .*default\.ctp:26\n/';
$this->assertNotRegExp($pattern, $result);
}
/**
@ -156,21 +178,18 @@ class ExtractTaskTest extends CakeTestCase {
* @return void
*/
function testExtractMultiplePaths() {
$path = TMP . 'tests' . DS . 'extract_task_test';
new Folder($path . DS . 'locale', true);
$this->Task->interactive = false;
$this->Task->params['paths'] =
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views' . DS . 'pages,' .
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views' . DS . 'posts';
$this->Task->params['output'] = $path . DS;
$this->Task->Dispatch->expects($this->never())->method('stderr');
$this->Task->Dispatch->expects($this->never())->method('_stop');
$this->Task->params['output'] = $this->path . DS;
$this->Task->expects($this->never())->method('err');
$this->Task->expects($this->never())->method('_stop');
$this->Task->execute();
$result = file_get_contents($path . DS . 'default.pot');
$result = file_get_contents($this->path . DS . 'default.pot');
$pattern = '/msgid "Add User"/';
$this->assertPattern($pattern, $result);

View file

@ -18,20 +18,13 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', array(
'tasks/fixture',
'tasks/template',
'tasks/db_config'
));
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'template.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'fixture.php';
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
/**
* FixtureTaskTest class
@ -56,19 +49,19 @@ class FixtureTaskTest extends CakeTestCase {
*/
public function setUp() {
parent::setUp();
$this->Dispatcher = $this->getMock('ShellDispatcher', array(
'getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear'
));
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock('FixtureTask',
array('in', 'err', 'createFile', '_stop'),
array(&$this->Dispatcher)
array('in', 'err', 'createFile', '_stop', 'clear'),
array($out, $out, $in)
);
$this->Task->Model = $this->getMock('Shell',
array('in', 'out', 'erro', 'createFile', 'getName', 'getTable', 'listAll'),
array(&$this->Dispatcher)
array('in', 'out', 'error', 'createFile', 'getName', 'getTable', 'listAll'),
array($out, $out, $in)
);
$this->Task->Template =& new TemplateTask($this->Dispatcher);
$this->Task->Dispatch->shellPaths = App::path('shells');
$this->Task->Template = new TemplateTask($out, $out, $in);
$this->Task->DbConfig = $this->getMock('DbConfigTask', array(), array($out, $out, $in));
$this->Task->Template->initialize();
}
@ -79,7 +72,7 @@ class FixtureTaskTest extends CakeTestCase {
*/
public function tearDown() {
parent::tearDown();
unset($this->Task, $this->Dispatcher);
unset($this->Task);
}
/**
@ -88,11 +81,11 @@ class FixtureTaskTest extends CakeTestCase {
* @return void
*/
public function testConstruct() {
$this->Dispatcher->params['working'] = DS . 'my' . DS . 'path';
$Task = new FixtureTask($this->Dispatcher);
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$expected = DS . 'my' . DS . 'path' . DS . 'tests' . DS . 'fixtures' . DS;
$this->assertEqual($Task->path, $expected);
$Task = new FixtureTask($out, $out, $in);
$this->assertEqual($Task->path, APP . 'tests' . DS . 'fixtures' . DS);
}
/**
@ -143,7 +136,7 @@ class FixtureTaskTest extends CakeTestCase {
*
* @return void
*/
public function testImportRecordsFromDatabaseWithConditions() {
public function testImportRecordsFromDatabaseWithConditionsPoo() {
$this->Task->interactive = true;
$this->Task->expects($this->at(0))->method('in')
->will($this->returnValue('WHERE 1=1 LIMIT 10'));

View file

@ -20,21 +20,13 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', array(
'tasks/model',
'tasks/fixture',
'tasks/template'
));
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'model.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'fixture.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'template.php';
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
/**
* ModelTaskTest class
@ -59,12 +51,12 @@ class ModelTaskTest extends CakeTestCase {
*/
public function setUp() {
parent::setUp();
$this->Dispatcher = $this->getMock('ShellDispatcher', array(
'getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear'
));
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock('ModelTask',
array('in', 'err', 'createFile', '_stop', '_checkUnitTest'),
array(&$this->Dispatcher)
array($out, $out, $in)
);
$this->_setupOtherMocks();
}
@ -75,9 +67,12 @@ class ModelTaskTest extends CakeTestCase {
* @return void
*/
protected function _useMockedOut() {
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock('ModelTask',
array('in', 'out', 'err', 'hr', 'createFile', '_stop', '_checkUnitTest'),
array(&$this->Dispatcher)
array($out, $out, $in)
);
$this->_setupOtherMocks();
}
@ -88,13 +83,15 @@ class ModelTaskTest extends CakeTestCase {
* @return void
*/
protected function _setupOtherMocks() {
$this->Task->Fixture = $this->getMock('FixtureTask', array(), array(&$this->Dispatcher));
$this->Task->Test = $this->getMock('FixtureTask', array(), array(&$this->Dispatcher));
$this->Task->Template =& new TemplateTask($this->Task->Dispatch);
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task->name = 'ModelTask';
$this->Task->Fixture = $this->getMock('FixtureTask', array(), array($out, $out, $in));
$this->Task->Test = $this->getMock('FixtureTask', array(), array($out, $out, $in));
$this->Task->Template = new TemplateTask($out, $out, $in);
$this->Task->name = 'Model';
$this->Task->interactive = true;
$this->Task->Dispatch->shellPaths = App::path('shells');
}
/**
@ -104,7 +101,7 @@ class ModelTaskTest extends CakeTestCase {
*/
public function tearDown() {
parent::tearDown();
unset($this->Task, $this->Dispatcher);
unset($this->Task);
}
/**

View file

@ -0,0 +1,166 @@
<?php
/**
* PluginTask Test file
*
* Test Case for plugin generation shell task
*
* PHP 5
*
* CakePHP : Rapid Development Framework (http://cakephp.org)
* Copyright 2006-2009, Cake Software Foundation, Inc.
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2006-2009, Cake Software Foundation, Inc.
* @link http://cakephp.org CakePHP Project
* @package cake
* @subpackage cake.tests.cases.console.libs.tasks
* @since CakePHP v 1.3.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', array(
'tasks/plugin',
'tasks/model'
));
App::import('Core', array('File'));
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
/**
* PluginTaskPlugin class
*
* @package cake
* @subpackage cake.tests.cases.console.libs.tasks
*/
class PluginTaskTest extends CakeTestCase {
/**
* setup method
*
* @return void
*/
public function setUp() {
parent::setUp();
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock('PluginTask',
array('in', 'err', 'createFile', '_stop', 'clear'),
array($out, $out, $in)
);
$this->Task->path = TMP . 'tests' . DS;
$this->_paths = $paths = App::path('plugins');
$this->_testPath = array_push($paths, TMP . 'tests' . DS);
App::build(array('plugins' => $paths));
}
/**
* test bake()
*
* @return void
*/
public function testBakeFoldersAndFiles() {
$this->Task->expects($this->at(0))->method('in')->will($this->returnValue($this->_testPath));
$this->Task->expects($this->at(1))->method('in')->will($this->returnValue('y'));
$path = $this->Task->path . 'bake_test_plugin';
$file = $path . DS . 'bake_test_plugin_app_controller.php';
$this->Task->expects($this->at(2))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$file = $path . DS . 'bake_test_plugin_app_model.php';
$this->Task->expects($this->at(3))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$this->Task->bake('BakeTestPlugin');
$path = $this->Task->path . 'bake_test_plugin';
$this->assertTrue(is_dir($path), 'No plugin dir %s');
$directories = array(
'config' . DS . 'schema',
'models' . DS . 'behaviors',
'models' . DS . 'datasources',
'console' . DS . 'shells' . DS . 'tasks',
'controllers' . DS . 'components',
'libs',
'views' . DS . 'helpers',
'tests' . DS . 'cases' . DS . 'components',
'tests' . DS . 'cases' . DS . 'helpers',
'tests' . DS . 'cases' . DS . 'behaviors',
'tests' . DS . 'cases' . DS . 'controllers',
'tests' . DS . 'cases' . DS . 'models',
'tests' . DS . 'groups',
'tests' . DS . 'fixtures',
'vendors',
'webroot'
);
foreach ($directories as $dir) {
$this->assertTrue(is_dir($path . DS . $dir), 'Missing directory for ' . $dir);
}
$Folder = new Folder($this->Task->path . 'bake_test_plugin');
$Folder->delete();
}
/**
* test execute with no args, flowing into interactive,
*
* @return void
*/
public function testExecuteWithNoArgs() {
$this->Task->expects($this->at(0))->method('in')->will($this->returnValue('TestPlugin'));
$this->Task->expects($this->at(1))->method('in')->will($this->returnValue('3'));
$this->Task->expects($this->at(2))->method('in')->will($this->returnValue('y'));
$path = $this->Task->path . 'test_plugin';
$file = $path . DS . 'test_plugin_app_controller.php';
$this->Task->expects($this->at(3))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$file = $path . DS . 'test_plugin_app_model.php';
$this->Task->expects($this->at(4))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$this->Task->args = array();
$this->Task->execute();
$Folder = new Folder($path);
$Folder->delete();
}
/**
* Test Execute
*
* @return void
*/
public function testExecuteWithOneArg() {
$this->Task->expects($this->at(0))->method('in')
->will($this->returnValue($this->_testPath));
$this->Task->expects($this->at(1))->method('in')
->will($this->returnValue('y'));
$path = $this->Task->path . 'bake_test_plugin';
$file = $path . DS . 'bake_test_plugin_app_controller.php';
$this->Task->expects($this->at(2))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$path = $this->Task->path . 'bake_test_plugin';
$file = $path . DS . 'bake_test_plugin_app_model.php';
$this->Task->expects($this->at(3))->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$this->Task->args = array('BakeTestPlugin');
$this->Task->execute();
$Folder = new Folder($this->Task->path . 'bake_test_plugin');
$Folder->delete();
}
}

View file

@ -20,21 +20,11 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', 'tasks/project');
App::import('Core', 'File');
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'project.php';
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
/**
* ProjectTask Test class
@ -51,14 +41,13 @@ class ProjectTaskTest extends CakeTestCase {
*/
public function setUp() {
parent::setUp();
$this->Dispatcher = $this->getMock('ShellDispatcher', array(
'getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear'
));
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock('ProjectTask',
array('in', 'err', 'createFile', '_stop'),
array(&$this->Dispatcher)
array($out, $out, $in)
);
$this->Dispatcher->shellPaths = App::path('shells');
$this->Task->path = TMP . 'tests' . DS;
}
@ -72,7 +61,7 @@ class ProjectTaskTest extends CakeTestCase {
$Folder = new Folder($this->Task->path . 'bake_test_app');
$Folder->delete();
unset($this->Dispatcher, $this->Task);
unset($this->Task);
}
/**
@ -83,7 +72,6 @@ class ProjectTaskTest extends CakeTestCase {
protected function _setupTestProject() {
$skel = CAKE_CORE_INCLUDE_PATH . DS . CAKE . 'console' . DS . 'templates' . DS . 'skel';
$this->Task->expects($this->at(0))->method('in')->will($this->returnValue('y'));
$this->Task->expects($this->at(1))->method('in')->will($this->returnValue('n'));
$this->Task->bake($this->Task->path . 'bake_test_app', $skel);
}
@ -94,18 +82,32 @@ class ProjectTaskTest extends CakeTestCase {
*/
public function testBake() {
$this->_setupTestProject();
$path = $this->Task->path . 'bake_test_app';
$this->assertTrue(is_dir($path), 'No project dir %s');
$this->assertTrue(is_dir($path . DS . 'controllers'), 'No controllers dir %s');
$this->assertTrue(is_dir($path . DS . 'controllers' . DS .'components'), 'No components dir %s');
$this->assertTrue(is_dir($path . DS . 'models'), 'No models dir %s');
$this->assertTrue(is_dir($path . DS . 'views'), 'No views dir %s');
$this->assertTrue(is_dir($path . DS . 'views' . DS . 'helpers'), 'No helpers dir %s');
$this->assertTrue(is_dir($path . DS . 'tests'), 'No tests dir %s');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'cases'), 'No cases dir %s');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'groups'), 'No groups dir %s');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'fixtures'), 'No fixtures dir %s');
$dirs = array(
'config',
'config' . DS . 'schema',
'console',
'console' . DS . 'shells',
'console' . DS . 'shells' . DS . 'tasks',
'controllers',
'models',
'views',
'views' . DS . 'helpers',
'tests',
'tests' . DS . 'cases',
'tests' . DS . 'cases' . DS . 'models',
'tests' . DS . 'cases',
'tests' . DS . 'fixtures',
'tmp',
'webroot',
'webroot' . DS . 'js',
'webroot' . DS . 'css',
);
foreach ($dirs as $dir) {
$this->assertTrue(is_dir($path . DS . $dir), 'Missing ' . $dir);
}
}
/**
@ -117,36 +119,24 @@ class ProjectTaskTest extends CakeTestCase {
$this->Task->params['empty'] = true;
$this->_setupTestProject();
$path = $this->Task->path . 'bake_test_app';
$this->assertTrue(is_dir($path), 'No project dir %s');
$this->assertTrue(is_dir($path . DS . 'controllers'), 'No controllers dir %s');
$this->assertTrue(is_dir($path . DS . 'controllers' . DS .'components'), 'No components dir %s');
$this->assertTrue(is_dir($path . DS . 'models'), 'No models dir %s');
$this->assertTrue(is_dir($path . DS . 'views'), 'No views dir %s');
$this->assertTrue(is_dir($path . DS . 'views' . DS . 'helpers'), 'No helpers dir %s');
$this->assertTrue(is_dir($path . DS . 'tests'), 'No tests dir %s');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'cases'), 'No cases dir %s');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'groups'), 'No groups dir %s');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'fixtures'), 'No fixtures dir %s');
$this->assertTrue(is_file($path . DS . 'controllers' . DS .'components' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'locale' . DS . 'eng' . DS . 'LC_MESSAGES' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'models' . DS . 'behaviors' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'models' . DS . 'datasources' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'plugins' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'tests' . DS . 'cases' . DS . 'behaviors' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'tests' . DS . 'cases' . DS . 'components' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'tests' . DS . 'cases' . DS . 'controllers' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'tests' . DS . 'cases' . DS . 'datasources' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'tests' . DS . 'cases' . DS . 'helpers' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'tests' . DS . 'cases' . DS . 'models' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'tests' . DS . 'cases' . DS . 'shells' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'tests' . DS . 'fixtures' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'tests' . DS . 'groups' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'vendors' . DS . 'shells' . DS . 'tasks' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'views' . DS . 'errors' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'views' . DS . 'helpers' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'views' . DS . 'scaffolds' . DS . 'empty'), 'No empty file in dir %s');
$this->assertTrue(is_file($path . DS . 'webroot' . DS . 'js' . DS . 'empty'), 'No empty file in dir %s');
$empty = array(
'console' . DS . 'shells' . DS . 'tasks',
'controllers' . DS . 'components',
'models' . DS . 'behaviors',
'views' . DS . 'helpers',
'views' . DS . 'errors',
'views' . DS . 'scaffolds',
'tests' . DS . 'cases' . DS . 'models',
'tests' . DS . 'cases' . DS . 'controllers',
'tests' . DS . 'cases' . DS . 'helpers',
'tests' . DS . 'fixtures',
'webroot' . DS . 'js'
);
foreach ($empty as $dir) {
$this->assertTrue(is_file($path . DS . $dir . DS . 'empty'), 'Missing empty file in ' . $dir);
}
}
/**
@ -275,14 +265,30 @@ class ProjectTaskTest extends CakeTestCase {
$this->Task->execute();
$this->assertTrue(is_dir($path), 'No project dir %s');
$this->assertTrue(is_dir($path . DS . 'controllers'), 'No controllers dir %s');
$this->assertTrue(is_dir($path . DS . 'controllers' . DS .'components'), 'No components dir %s');
$this->assertTrue(is_dir($path . DS . 'models'), 'No models dir %s');
$this->assertTrue(is_dir($path . DS . 'views'), 'No views dir %s');
$this->assertTrue(is_dir($path . DS . 'views' . DS . 'helpers'), 'No helpers dir %s');
$this->assertTrue(is_dir($path . DS . 'tests'), 'No tests dir %s');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'cases'), 'No cases dir %s');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'groups'), 'No groups dir %s');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'fixtures'), 'No fixtures dir %s');
$this->assertTrue(is_dir($path . DS . 'controllers'), 'No controllers dir ');
$this->assertTrue(is_dir($path . DS . 'controllers' . DS .'components'), 'No components dir ');
$this->assertTrue(is_dir($path . DS . 'models'), 'No models dir');
$this->assertTrue(is_dir($path . DS . 'views'), 'No views dir');
$this->assertTrue(is_dir($path . DS . 'views' . DS . 'helpers'), 'No helpers dir');
$this->assertTrue(is_dir($path . DS . 'tests'), 'No tests dir');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'cases'), 'No cases dir');
$this->assertTrue(is_dir($path . DS . 'tests' . DS . 'fixtures'), 'No fixtures dir');
}
/**
* test console path
*
* @return void
*/
function testConsolePath() {
$this->_setupTestProject();
$path = $this->Task->path . 'bake_test_app' . DS;
$result = $this->Task->consolePath($path);
$this->assertTrue($result);
$file = new File($path . 'console' . DS . 'cake.php');
$contents = $file->read();
$this->assertNoPattern('/__CAKE_PATH__/', $contents, 'Console path placeholder left behind.');
}
}

View file

@ -21,19 +21,9 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', 'tasks/template');
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'template.php';
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
/**
* TemplateTaskTest class
@ -49,14 +39,14 @@ class TemplateTaskTest extends CakeTestCase {
* @return void
*/
public function setup() {
$this->Dispatcher = $this->getMock('ShellDispatcher', array(
'getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear'
));
parent::setUp();
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock('TemplateTask',
array('in', 'err', 'createFile', '_stop'),
array(&$this->Dispatcher)
array('in', 'err', 'createFile', '_stop', 'clear'),
array($out, $out, $in)
);
$this->Task->Dispatch->shellPaths = App::path('shells');
}
/**
@ -64,10 +54,9 @@ class TemplateTaskTest extends CakeTestCase {
*
* @return void
*/
public function teardown() {
unset($this->Task, $this->Dispatcher);
ClassRegistry::flush();
App::build();
public function tearDown() {
parent::tearDown();
unset($this->Task);
}
/**
@ -100,7 +89,6 @@ class TemplateTaskTest extends CakeTestCase {
*/
public function testFindingInstalledThemesForBake() {
$consoleLibs = CAKE_CORE_INCLUDE_PATH . DS . CAKE . 'console' . DS;
$this->Task->Dispatch->shellPaths = array($consoleLibs);
$this->Task->initialize();
$this->assertEqual($this->Task->templatePaths, array('default' => $consoleLibs . 'templates' . DS . 'default' . DS));
}
@ -128,7 +116,7 @@ class TemplateTaskTest extends CakeTestCase {
$this->Task->params = array();
$result = $this->Task->getThemePath();
$this->assertEqual($result, $defaultTheme);
$this->assertEqual($this->Dispatcher->params['theme'], 'default');
$this->assertEqual($this->Task->params['theme'], 'default');
}
/**
@ -139,7 +127,7 @@ class TemplateTaskTest extends CakeTestCase {
public function testGenerate() {
App::build(array(
'shells' => array(
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'vendors' . DS . 'shells' . DS
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'console' . DS
)
));
$this->Task->initialize();
@ -159,7 +147,7 @@ class TemplateTaskTest extends CakeTestCase {
public function testGenerateWithTemplateFallbacks() {
App::build(array(
'shells' => array(
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'vendors' . DS . 'shells' . DS,
TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'console' . DS,
CAKE_CORE_INCLUDE_PATH . DS . 'console' . DS
)
));

View file

@ -20,22 +20,15 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', array(
'tasks/test',
'tasks/template'
));
App::import('Controller', 'Controller', false);
App::import('Model', 'Model', false);
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'test.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'template.php';
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
/**
* Test Article model
@ -249,16 +242,15 @@ class TestTaskTest extends CakeTestCase {
*/
public function setup() {
parent::setup();
$this->Dispatcher = $this->getMock('ShellDispatcher', array(
'getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear'
));
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock('TestTask',
array('in', 'err', 'createFile', '_stop', 'isLoadableClass'),
array(&$this->Dispatcher)
array($out, $out, $in)
);
$this->Dispatcher->shellPaths = App::path('shells');
$this->Task->name = 'TestTask';
$this->Task->Template = new TemplateTask($this->Dispatcher);
$this->Task->name = 'Test';
$this->Task->Template = new TemplateTask($out, $out, $in);
}
/**
@ -266,9 +258,9 @@ class TestTaskTest extends CakeTestCase {
*
* @return void
*/
public function teardown() {
parent::teardown();
ClassRegistry::flush();
public function tearDown() {
parent::tearDown();
unset($this->Task);
}
/**
@ -277,8 +269,8 @@ class TestTaskTest extends CakeTestCase {
* @return void
*/
public function testFilePathGenerationModelRepeated() {
$this->Dispatcher->expects($this->never())->method('stderr');
$this->Dispatcher->expects($this->never())->method('_stop');
$this->Task->expects($this->never())->method('err');
$this->Task->expects($this->never())->method('_stop');
$file = TESTS . 'cases' . DS . 'models' . DS . 'my_class.test.php';

View file

@ -20,23 +20,15 @@
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Shell', 'Shell', false);
App::import('Shell', array(
'tasks/view',
'tasks/controller',
'tasks/template',
'tasks/project',
'tasks/db_config'
));
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'view.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'controller.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'template.php';
require_once CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'project.php';
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
/**
* Test View Task Comment Model
@ -232,18 +224,18 @@ class ViewTaskTest extends CakeTestCase {
*/
public function setUp() {
parent::setUp();
$this->Dispatcher = $this->getMock('ShellDispatcher', array(
'getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear'
));
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Task = $this->getMock('ViewTask',
array('in', 'err', 'createFile', '_stop'),
array(&$this->Dispatcher)
array($out, $out, $in)
);
$this->Task->Template = new TemplateTask($this->Dispatcher);
$this->Task->Controller = $this->getMock('ControllerTask', array(), array(&$this->Dispatcher));
$this->Task->Project = $this->getMock('ProjectTask', array(), array(&$this->Dispatcher));
$this->Task->Template = new TemplateTask($out, $out, $in);
$this->Task->Controller = $this->getMock('ControllerTask', array(), array($out, $out, $in));
$this->Task->Project = $this->getMock('ProjectTask', array(), array($out, $out, $in));
$this->Task->DbConfig = $this->getMock('DbConfigTask', array(), array($out, $out, $in));
$this->Dispatcher->shellPaths = App::path('shells');
$this->Task->path = TMP;
$this->Task->Template->params['theme'] = 'default';
}
@ -401,7 +393,7 @@ class ViewTaskTest extends CakeTestCase {
$this->Task->controllerName = 'ViewTaskComments';
$this->Task->controllerPath = 'view_task_comments';
$this->Task->plugin = 'TestTest';
$this->Task->name = 'ViewTask';
$this->Task->name = 'View';
$path = APP . 'plugins' . DS . 'test_test' . DS . 'views' . DS . 'view_task_comments' . DS . 'view.ctp';
$this->Task->expects($this->once())->method('createFile')

View file

@ -19,19 +19,10 @@
*/
App::import('Shell', 'Shell', false);
App::import('Shell', 'Testsuite');
if (!defined('DISABLE_AUTO_DISPATCH')) {
define('DISABLE_AUTO_DISPATCH', true);
}
require_once CAKE . 'console' . DS . 'shell_dispatcher.php';
if (!class_exists('ShellDispatcher')) {
ob_start();
$argv = false;
require CAKE . 'console' . DS . 'cake.php';
ob_end_clean();
}
require_once CAKE . 'console' . DS . 'libs' . DS . 'testsuite.php';
class TestSuiteShellTest extends CakeTestCase {
@ -42,16 +33,14 @@ class TestSuiteShellTest extends CakeTestCase {
* @return void
*/
public function setUp() {
$this->Dispatcher = $this->getMock(
'ShellDispatcher',
array('getInput', 'stdout', 'stderr', '_stop', '_initEnvironment', 'clear')
);
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Shell = $this->getMock(
'TestSuiteShell',
array('in', 'out', 'hr', 'help', 'error', 'err', '_stop', 'initialize', 'run'),
array(&$this->Dispatcher)
array('in', 'out', 'hr', 'help', 'error', 'err', '_stop', 'initialize', 'run', 'clear'),
array($out, $out, $in)
);
$this->Shell->Dispatch->shellPaths = App::path('shells');
}
/**
@ -107,12 +96,12 @@ class TestSuiteShellTest extends CakeTestCase {
public function testRunnerOptions() {
$this->Shell->startup();
$this->Shell->args = array('core', 'Basics');
$this->Shell->params = array('filter' => 'myFilter', '-colors' => null, '-verbose' => null);
$this->Shell->params = array('filter' => 'myFilter', 'colors' => true, 'verbose' => true);
$this->Shell->expects($this->once())->method('run')
->with(
array('app' => false, 'plugin' => null, 'output' => 'text', 'case' => 'basics'),
array('--colors', '--verbose', '--filter', 'myFilter')
array('--filter', 'myFilter', '--colors', '--verbose')
);
$this->Shell->main();
}

View file

@ -38,6 +38,7 @@ class AllTests extends PHPUnit_Framework_TestSuite {
$path = CORE_TEST_CASES . DS . 'libs' . DS;
$console = CORE_TEST_CASES . DS . 'console' . DS;
$suite->addTestFile($console . 'all_console_libs.test.php');
$suite->addTestFile($console . 'all_shells.test.php');
$suite->addTestFile($console . 'all_tasks.test.php');

View file

@ -969,7 +969,7 @@ class CakeSchemaTest extends CakeTestCase {
));
$Other =& $this->Schema->load(array('name' => 'TestPluginApp', 'plugin' => 'TestPlugin'));
$this->assertEqual($Other->name, 'TestPluginApp');
$this->assertEqual(array_keys($Other->tables), array('acos'));
$this->assertEqual(array_keys($Other->tables), array('test_plugin_acos'));
App::build();
}

View file

@ -307,4 +307,46 @@ class StringTest extends CakeTestCase {
$result = String::insert($string, array('b' => 2, 'c' => 3), array('clean' => true));
$this->assertEqual($expected, $result);
}
/**
* test wrap method.
*
* @return void
*/
function testWrap() {
$text = 'This is the song that never ends. This is the song that never ends. This is the song that never ends.';
$result = String::wrap($text, 33);
$expected = <<<TEXT
This is the song that never ends.
This is the song that never ends.
This is the song that never ends.
TEXT;
$this->assertEquals($expected, $result, 'Text not wrapped.');
$result = String::wrap($text, array('width' => 20, 'wordWrap' => false));
$expected = <<<TEXT
This is the song th
at never ends. This
is the song that n
ever ends. This is
the song that never
ends.
TEXT;
$this->assertEquals($expected, $result, 'Text not wrapped.');
}
/**
* test wrap() indenting
*
* @return void
*/
function testWrapIndent() {
$text = 'This is the song that never ends. This is the song that never ends. This is the song that never ends.';
$result = String::wrap($text, array('width' => 33, 'indent' => "\t", 'indentAt' => 1));
$expected = <<<TEXT
This is the song that never ends.
This is the song that never ends.
This is the song that never ends.
TEXT;
}
}

View file

@ -23,7 +23,7 @@ class TestPluginAppSchema extends CakeSchema {
public $name = 'TestPluginApp';
public $acos = array(
public $test_plugin_acos = array(
'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'),
'parent_id' => array('type'=>'integer', 'null' => true, 'default' => NULL, 'length' => 10),
'model' => array('type'=>'string', 'null' => true),