Browse Source

Refactored the shell reflection portion into a seperate task.

wyrihaximus 12 years ago
parent
commit
ac9b7f3882

+ 8 - 43
lib/Cake/Console/Command/CommandListShell.php

@@ -25,6 +25,13 @@ App::uses('Inflector', 'Utility');
 class CommandListShell extends AppShell {
 
 /**
+ * Contains tasks to load and instantiate
+ *
+ * @var array
+ */
+	public $tasks = array('Command');
+
+/**
  * startup
  *
  * @return void
@@ -55,7 +62,7 @@ class CommandListShell extends AppShell {
 			$this->out(__d('cake_console', "<info>Available Shells:</info>"), 2);
 		}
 
-		$shellList = $this->_getShellList();
+		$shellList = $this->Command->getShellList();
 		if (empty($shellList)) {
 			return;
 		}
@@ -68,48 +75,6 @@ class CommandListShell extends AppShell {
 	}
 
 /**
- * Gets the shell command listing.
- *
- * @return array
- */
-	protected function _getShellList() {
-		$skipFiles = array('AppShell');
-
-		$plugins = CakePlugin::loaded();
-		$shellList = array_fill_keys($plugins, null) + array('CORE' => null, 'app' => null);
-
-		$corePath = App::core('Console/Command');
-		$shells = App::objects('file', $corePath[0]);
-		$shells = array_diff($shells, $skipFiles);
-		$this->_appendShells('CORE', $shells, $shellList);
-
-		$appShells = App::objects('Console/Command', null, false);
-		$appShells = array_diff($appShells, $shells, $skipFiles);
-		$this->_appendShells('app', $appShells, $shellList);
-
-		foreach ($plugins as $plugin) {
-			$pluginShells = App::objects($plugin . '.Console/Command');
-			$this->_appendShells($plugin, $pluginShells, $shellList);
-		}
-
-		return array_filter($shellList);
-	}
-
-/**
- * Scan the provided paths for shells, and append them into $shellList
- *
- * @param string $type
- * @param array $shells
- * @param array $shellList
- * @return void
- */
-	protected function _appendShells($type, $shells, &$shellList) {
-		foreach ($shells as $shell) {
-			$shellList[$type][] = Inflector::underscore(str_replace('Shell', '', $shell));
-		}
-	}
-
-/**
  * Output text.
  *
  * @param array $shellList

+ 16 - 115
lib/Cake/Console/Command/CompletionShell.php

@@ -14,14 +14,21 @@
  * @license       http://www.opensource.org/licenses/mit-license.php MIT License
  */
 
-App::uses('CommandListShell', 'Console/Command');
+App::uses('AppShell', 'Console/Command');
 
 /**
  * Provide command completion shells such as bash.
  * 
  * @package       Cake.Console.Command
  */
-class CompletionShell extends CommandListShell {
+class CompletionShell extends AppShell {
+
+/**
+ * Contains tasks to load and instantiate
+ *
+ * @var array
+ */
+	public $tasks = array('Command');
 
 /**
  * Echo no header by overriding the startup method
@@ -37,7 +44,7 @@ class CompletionShell extends CommandListShell {
  * @return void
  */
 	public function main() {
-		return $this->out($this->OptionParser->help());
+		return $this->out($this->getOptionParser()->help());
 	}
 
 /**
@@ -46,7 +53,7 @@ class CompletionShell extends CommandListShell {
  * @return void
  */
 	public function commands() {
-		$options = $this->_commands();
+		$options = $this->Command->commands();
 		return $this->_output($options);
 	}
 
@@ -56,26 +63,12 @@ class CompletionShell extends CommandListShell {
  * @return void
  */
 	public function options() {
-		if (!$this->args) {
-			$parser = new ConsoleOptionParser();
-		} else {
-			$Shell = $this->_getShell($this->args[0]);
-			if (!$Shell) {
-				$parser = new ConsoleOptionParser();
-			} else {
-				$parser = $Shell->getOptionParser();
-			}
+		$commandName = '';
+		if (!empty($this->args[0])) {
+			$commandName = $this->args[0];
 		}
+		$options = $this->Command->options($commandName);
 
-		$options = array();
-		$array = $parser->options();
-		foreach ($array as $name => $obj) {
-			$options[] = "--$name";
-			$short = $obj->short();
-			if ($short) {
-				$options[] = "-$short";
-			}
-		}
 		return $this->_output($options);
 	}
 
@@ -89,7 +82,7 @@ class CompletionShell extends CommandListShell {
 			return $this->_output();
 		}
 
-		$options = $this->_subCommands($this->args[0]);
+		$options = $this->Command->subCommands($this->args[0]);
 		return $this->_output($options);
 	}
 
@@ -149,98 +142,6 @@ class CompletionShell extends CommandListShell {
 	}
 
 /**
- * Return a list of all commands
- *
- * @return array
- */
-	protected function _commands() {
-		$shellList = $this->_getShellList();
-		unset($shellList['Completion']);
-
-		$options = array();
-		foreach ($shellList as $type => $commands) {
-			$prefix = '';
-			if (!in_array(strtolower($type), array('app', 'core'))) {
-				$prefix = $type . '.';
-			}
-
-			foreach ($commands as $shell) {
-				$options[] = $prefix . $shell;
-			}
-		}
-
-		return $options;
-	}
-
-/**
- * Return a list of subcommands for a given command
- *
- * @param string $commandName
- * @return array
- */
-	protected function _subCommands($commandName) {
-		$Shell = $this->_getShell($commandName);
-
-		if (!$Shell) {
-			return array();
-		}
-
-		$taskMap = TaskCollection::normalizeObjectArray((array)$Shell->tasks);
-		$return = array_keys($taskMap);
-		$return = array_map('Inflector::underscore', $return);
-
-		$ShellReflection = new ReflectionClass('AppShell');
-		$shellMethods = $ShellReflection->getMethods(ReflectionMethod::IS_PUBLIC);
-		$shellMethodNames = array('main', 'help');
-		foreach ($shellMethods as $method) {
-			$shellMethodNames[] = $method->getName();
-		}
-
-		$Reflection = new ReflectionClass($Shell);
-		$methods = $Reflection->getMethods(ReflectionMethod::IS_PUBLIC);
-		$methodNames = array();
-		foreach ($methods as $method) {
-			$methodNames[] = $method->getName();
-		}
-
-		$return += array_diff($methodNames, $shellMethodNames);
-		sort($return);
-
-		return $return;
-	}
-
-/**
- * Get Shell instance for the given command
- *
- * @param mixed $commandName
- * @return mixed
- */
-	protected function _getShell($commandName) {
-		list($pluginDot, $name) = pluginSplit($commandName, true);
-
-		if (in_array(strtolower($pluginDot), array('app.', 'core.'))) {
-			$commandName = $name;
-			$pluginDot = '';
-		}
-
-		if (!in_array($commandName, $this->_commands())) {
-			return false;
-		}
-
-		$name = Inflector::camelize($name);
-		$pluginDot = Inflector::camelize($pluginDot);
-		$class = $name . 'Shell';
-		APP::uses($class, $pluginDot . 'Console/Command');
-
-		$Shell = new $class();
-		$Shell->plugin = trim($pluginDot, '.');
-		$Shell->initialize();
-		$Shell->loadTasks();
-
-		return $Shell;
-	}
-
-/**
  * Emit results as a string, space delimited
  *
  * @param array $options

+ 183 - 0
lib/Cake/Console/Command/Task/CommandTask.php

@@ -0,0 +1,183 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @since         CakePHP(tm) v 2.5
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+App::uses('AppShell', 'Console/Command');
+
+/**
+ * Base class for Shell Command reflection.
+ *
+ * @package       Cake.Console.Command.Task
+ */
+class CommandTask extends AppShell {
+
+/**
+ * Gets the shell command listing.
+ *
+ * @return array
+ */
+	public function getShellList() {
+		$skipFiles = array('AppShell');
+
+		$plugins = CakePlugin::loaded();
+		$shellList = array_fill_keys($plugins, null) + array('CORE' => null, 'app' => null);
+
+		$corePath = App::core('Console/Command');
+		$shells = App::objects('file', $corePath[0]);
+		$shells = array_diff($shells, $skipFiles);
+		$this->_appendShells('CORE', $shells, $shellList);
+
+		$appShells = App::objects('Console/Command', null, false);
+		$appShells = array_diff($appShells, $shells, $skipFiles);
+		$this->_appendShells('app', $appShells, $shellList);
+
+		foreach ($plugins as $plugin) {
+			$pluginShells = App::objects($plugin . '.Console/Command');
+			$this->_appendShells($plugin, $pluginShells, $shellList);
+		}
+
+		return array_filter($shellList);
+	}
+
+/**
+ * Scan the provided paths for shells, and append them into $shellList
+ *
+ * @param string $type
+ * @param array $shells
+ * @param array $shellList
+ * @return void
+ */
+	protected function _appendShells($type, $shells, &$shellList) {
+		foreach ($shells as $shell) {
+			$shellList[$type][] = Inflector::underscore(str_replace('Shell', '', $shell));
+		}
+	}
+
+/**
+ * Return a list of all commands
+ *
+ * @return array
+ */
+	public function commands() {
+		$shellList = $this->getShellList();
+
+		$options = array();
+		foreach ($shellList as $type => $commands) {
+			$prefix = '';
+			if (!in_array(strtolower($type), array('app', 'core'))) {
+				$prefix = $type . '.';
+			}
+
+			foreach ($commands as $shell) {
+				$options[] = $prefix . $shell;
+			}
+		}
+
+		return $options;
+	}
+
+/**
+ * Return a list of subcommands for a given command
+ *
+ * @param string $commandName
+ * @return array
+ */
+	public function subCommands($commandName) {
+		$Shell = $this->getShell($commandName);
+
+		if (!$Shell) {
+			return array();
+		}
+
+		$taskMap = TaskCollection::normalizeObjectArray((array)$Shell->tasks);
+		$return = array_keys($taskMap);
+		$return = array_map('Inflector::underscore', $return);
+
+		$ShellReflection = new ReflectionClass('AppShell');
+		$shellMethods = $ShellReflection->getMethods(ReflectionMethod::IS_PUBLIC);
+		$shellMethodNames = array('main', 'help');
+		foreach ($shellMethods as $method) {
+			$shellMethodNames[] = $method->getName();
+		}
+
+		$Reflection = new ReflectionClass($Shell);
+		$methods = $Reflection->getMethods(ReflectionMethod::IS_PUBLIC);
+		$methodNames = array();
+		foreach ($methods as $method) {
+			$methodNames[] = $method->getName();
+		}
+
+		$return += array_diff($methodNames, $shellMethodNames);
+		sort($return);
+
+		return $return;
+	}
+
+/**
+ * Get Shell instance for the given command
+ *
+ * @param mixed $commandName
+ * @return mixed
+ */
+	public function getShell($commandName) {
+		list($pluginDot, $name) = pluginSplit($commandName, true);
+
+		if (in_array(strtolower($pluginDot), array('app.', 'core.'))) {
+			$commandName = $name;
+			$pluginDot = '';
+		}
+
+		if (!in_array($commandName, $this->commands())) {
+			return false;
+		}
+
+		$name = Inflector::camelize($name);
+		$pluginDot = Inflector::camelize($pluginDot);
+		$class = $name . 'Shell';
+		APP::uses($class, $pluginDot . 'Console/Command');
+
+		$Shell = new $class();
+		$Shell->plugin = trim($pluginDot, '.');
+		$Shell->initialize();
+
+		return $Shell;
+	}
+
+/**
+ * Get Shell instance for the given command
+ *
+ * @param mixed $commandName
+ * @return array
+ */
+	public function options($commandName) {
+		$Shell = $this->getShell($commandName);
+		if (!$Shell) {
+			$parser = new ConsoleOptionParser();
+		} else {
+			$parser = $Shell->getOptionParser();
+		}
+
+		$options = array();
+		$array = $parser->options();
+		foreach ($array as $name => $obj) {
+			$options[] = "--$name";
+			$short = $obj->short();
+			if ($short) {
+				$options[] = "-$short";
+			}
+		}
+		return $options;
+	}
+
+}

+ 7 - 0
lib/Cake/Test/Case/Console/Command/CommandListShellTest.php

@@ -22,6 +22,7 @@ App::uses('CommandListShell', 'Console/Command');
 App::uses('ConsoleOutput', 'Console');
 App::uses('ConsoleInput', 'Console');
 App::uses('Shell', 'Console');
+App::uses('CommandTask', 'Console/Command/Task');
 
 /**
  * Class TestStringOutput
@@ -70,6 +71,12 @@ class CommandListShellTest extends CakeTestCase {
 			array('in', '_stop', 'clear'),
 			array($out, $out, $in)
 		);
+
+		$this->Shell->Command = $this->getMock(
+			'CommandTask',
+			array('in', '_stop', 'clear'),
+			array($out, $out, $in)
+		);
 	}
 
 /**

+ 7 - 0
lib/Cake/Test/Case/Console/Command/CompletionShellTest.php

@@ -22,6 +22,7 @@ App::uses('CompletionShell', 'Console/Command');
 App::uses('ConsoleOutput', 'Console');
 App::uses('ConsoleInput', 'Console');
 App::uses('Shell', 'Console');
+App::uses('CommandTask', 'Console/Command/Task');
 
 /**
  * Class TestCompletionStringOutput
@@ -70,6 +71,12 @@ class CompletionShellTest extends CakeTestCase {
 			array('in', '_stop', 'clear'),
 			array($out, $out, $in)
 		);
+
+		$this->Shell->Command = $this->getMock(
+			'CommandTask',
+			array('in', '_stop', 'clear'),
+			array($out, $out, $in)
+		);
 	}
 
 /**

+ 240 - 0
lib/Cake/Test/Case/Console/Command/Task/CommandTaskTest.php

@@ -0,0 +1,240 @@
+<?php
+/**
+ * CakePHP : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP Project
+ * @package       Cake.Test.Case.Console.Command
+ * @since         CakePHP v 2.5
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+App::uses('CommandTask', 'Console/Command/Task');
+
+/**
+ * CommandTaskTest class
+ *
+ * @package   Cake.Test.Case.Console.Command.Task
+ */
+class CommandTaskTest extends CakeTestCase {
+
+/**
+ * setUp method
+ *
+ * @return void
+ */
+	public function setUp() {
+		parent::setUp();
+		App::build(array(
+			'Plugin' => array(
+				CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS
+			),
+			'Console/Command' => array(
+				CAKE . 'Test' . DS . 'test_app' . DS . 'Console' . DS . 'Command' . DS
+			)
+		), App::RESET);
+		CakePlugin::load(array('TestPlugin', 'TestPluginTwo'));
+
+		$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
+		$in = $this->getMock('ConsoleInput', array(), array(), '', false);
+
+		$this->CommandTask = $this->getMock(
+			'CommandTask',
+			array('in', '_stop', 'clear'),
+			array($out, $out, $in)
+		);
+	}
+
+/**
+ * tearDown
+ *
+ * @return void
+ */
+	public function tearDown() {
+		parent::tearDown();
+		unset($this->CommandTask);
+		CakePlugin::unload();
+	}
+
+/**
+ * Test the resulting list of shells
+ *
+ * @return void
+ */
+	public function testGetShellList() {
+		$result = $this->CommandTask->getShellList();
+
+		$expected = array(
+			'CORE' => array(
+				'acl',
+				'api',
+				'bake',
+				'command_list',
+				'completion',
+				'console',
+				'i18n',
+				'schema',
+				'server',
+				'test',
+				'testsuite',
+				'upgrade'
+			),
+			'TestPlugin' => array(
+				'example'
+			),
+				'TestPluginTwo' => array(
+				'example',
+				'welcome'
+			),
+			'app' => array(
+				'sample'
+			),
+		);
+		$this->assertEquals($expected, $result);
+	}
+
+/**
+ * Test the resulting list of commands
+ *
+ * @return void
+ */
+	public function testCommands() {
+		$result = $this->CommandTask->commands();
+
+		$expected = array(
+			'TestPlugin.example',
+			'TestPluginTwo.example',
+			'TestPluginTwo.welcome',
+			'acl',
+			'api',
+			'bake',
+			'command_list',
+			'completion',
+			'console',
+			'i18n',
+			'schema',
+			'server',
+			'test',
+			'testsuite',
+			'upgrade',
+			'sample'
+		);
+		$this->assertEquals($expected, $result);
+	}
+
+/**
+ * Test the resulting list of subcommands for the given command
+ *
+ * @return void
+ */
+	public function testSubCommands() {
+		$result = $this->CommandTask->subCommands('acl');
+
+		$expected = array(
+			'check',
+			'create',
+			'db_config',
+			'delete',
+			'deny',
+			'getPath',
+			'grant',
+			'inherit',
+			'initdb',
+			'nodeExists',
+			'parseIdentifier',
+			'setParent',
+			'view'
+		);
+		$this->assertEquals($expected, $result);
+	}
+
+/**
+ * Test that unknown commands return an empty array
+ *
+ * @return void
+ */
+	public function testSubCommandsUnknownCommand() {
+		$result = $this->CommandTask->subCommands('yoghurt');
+
+		$expected = array();
+		$this->assertEquals($expected, $result);
+	}
+
+/**
+ * Test that getting a existing shell returns the shell instance
+ *
+ * @return void
+ */
+	public function testGetShell() {
+		$result = $this->CommandTask->getShell('acl');
+		$this->assertInstanceOf('AclShell', $result);
+	}
+
+/**
+ * Test that getting a non-existing shell returns false
+ *
+ * @return void
+ */
+	public function testGetShellNonExisting() {
+		$result = $this->CommandTask->getShell('strawberry');
+		$this->assertFalse($result);
+	}
+
+/**
+ * Test that getting a existing core shell with 'core.' prefix returns the correct shell instance
+ *
+ * @return void
+ */
+	public function testGetShellCore() {
+		$result = $this->CommandTask->getShell('core.bake');
+		$this->assertInstanceOf('BakeShell', $result);
+	}
+
+/**
+ * Test the options array for a known command
+ *
+ * @return void
+ */
+	public function testOptions() {
+		$result = $this->CommandTask->options('bake');
+
+		$expected = array(
+			'--help',
+			'-h',
+			'--verbose',
+			'-v',
+			'--quiet',
+			'-q',
+			'--connection',
+			'-c',
+			'--theme',
+			'-t'
+		);
+		$this->assertEquals($expected, $result);
+	}
+
+/**
+ * Test the options array for an unknown command
+ *
+ * @return void
+ */
+	public function testOptionsUnknownCommand() {
+		$result = $this->CommandTask->options('pie');
+
+		$expected = array(
+			'--help',
+			'-h',
+			'--verbose',
+			'-v',
+			'--quiet',
+			'-q'
+		);
+		$this->assertEquals($expected, $result);
+	}
+
+}