Browse Source

Merge pull request #10834 from cakephp/help-shell

3.next - Add Help shell
Mark Story 8 years ago
parent
commit
9db27f2fd6

+ 13 - 5
src/Console/CommandRunner.php

@@ -19,6 +19,7 @@ use Cake\Console\ConsoleIo;
 use Cake\Console\Exception\StopException;
 use Cake\Console\Shell;
 use Cake\Http\BaseApplication;
+use Cake\Shell\HelpShell;
 use Cake\Shell\VersionShell;
 use RuntimeException;
 
@@ -59,7 +60,9 @@ class CommandRunner
         $this->app = $app;
         $this->root = $root;
         $this->aliases = [
-            '--version' => 'version'
+            '--version' => 'version',
+            '--help' => 'help',
+            '-h' => 'help',
         ];
     }
 
@@ -100,6 +103,7 @@ class CommandRunner
 
         $commands = new CommandCollection([
             'version' => VersionShell::class,
+            'help' => HelpShell::class,
         ]);
         $commands = $this->app->console($commands);
         if (!($commands instanceof CommandCollection)) {
@@ -157,11 +161,15 @@ class CommandRunner
                 " Run `{$this->root} --help` to get the list of valid commands."
             );
         }
-        $classOrInstance = $commands->get($name);
-        if (is_string($classOrInstance)) {
-            return new $classOrInstance($io);
+        $instance = $commands->get($name);
+        if (is_string($instance)) {
+            $instance = new $instance($io);
+        }
+        // Moving to an interface/method on Shell soon.
+        if (method_exists($instance, 'setCommandCollection')) {
+            $instance->setCommandCollection($commands);
         }
 
-        return $classOrInstance;
+        return $instance;
     }
 }

+ 2 - 1
src/Shell/CommandListShell.php

@@ -25,6 +25,7 @@ use SimpleXmlElement;
  * Shows a list of commands available from the console.
  *
  * @property \Cake\Shell\Task\CommandTask $Command
+ * @deprecated 3.5.0 Replaced by Cake\Shell\HelpShell
  */
 class CommandListShell extends Shell
 {
@@ -145,7 +146,7 @@ class CommandListShell extends Shell
             'help' => 'Get the listing as XML.',
             'boolean' => true
         ])->addOption('version', [
-            'help' => 'Prints the currently installed version of CakePHP.',
+            'help' => 'Prints the currently installed version of CakePHP. (deprecated - use `cake --version` instead)',
             'boolean' => true
         ]);
 

+ 144 - 0
src/Shell/HelpShell.php

@@ -0,0 +1,144 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (https://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. (https://cakefoundation.org)
+ * @link          https://cakephp.org CakePHP(tm) Project
+ * @since         3.5.0
+ * @license       https://opensource.org/licenses/mit-license.php MIT License
+ */
+
+namespace Cake\Shell;
+
+use Cake\Console\CommandCollection;
+use Cake\Console\ConsoleOutput;
+use Cake\Console\Shell;
+use SimpleXmlElement;
+
+/**
+ * Print out command list
+ */
+class HelpShell extends Shell
+{
+    /**
+     * The command collection to get help on.
+     *
+     * @var \Cake\Console\CommandCollection
+     */
+    protected $commands;
+
+    /**
+     * startup
+     *
+     * @return void
+     */
+    public function startup()
+    {
+        if (!$this->param('xml')) {
+            parent::startup();
+        }
+    }
+
+    /**
+     * Set the command collection being used.
+     *
+     * @param \Cake\Console\CommandCollection $commands The commands to use.
+     * @return void
+     */
+    public function setCommandCollection(CommandCollection $commands)
+    {
+        $this->commands = $commands;
+    }
+
+    /**
+     * Main function Prints out the list of shells.
+     *
+     * @return void
+     */
+    public function main()
+    {
+        if (!$this->param('xml')) {
+            $this->out('<info>Current Paths:</info>', 2);
+            $this->out('* app:  ' . APP_DIR);
+            $this->out('* root: ' . rtrim(ROOT, DIRECTORY_SEPARATOR));
+            $this->out('* core: ' . rtrim(CORE_PATH, DIRECTORY_SEPARATOR));
+            $this->out('');
+
+            $this->out('<info>Available Commands:</info>', 2);
+        }
+
+        if (!$this->commands) {
+            $this->err('Could not print command list, no CommandCollection was set using setCommandCollection()');
+
+            return;
+        }
+
+        if ($this->param('xml')) {
+            $this->asXml($this->commands);
+
+            return;
+        }
+        $this->asText($this->commands);
+    }
+
+    /**
+     * Output text.
+     *
+     * @param \Cake\Console\CommandCollection $commands The command collection to output.
+     * @return void
+     */
+    protected function asText($commands)
+    {
+        foreach ($commands as $name => $class) {
+            $this->out('- ' . $name);
+        }
+        $this->out('');
+
+        $this->out('To run a command, type <info>`cake shell_name [args|options]`</info>');
+        $this->out('To get help on a specific command, type <info>`cake shell_name --help`</info>', 2);
+    }
+
+    /**
+     * Output as XML
+     *
+     * @param \Cake\Console\CommandCollection $commands The command collection to output
+     * @return void
+     */
+    protected function asXml($commands)
+    {
+        $shells = new SimpleXmlElement('<shells></shells>');
+        foreach ($commands as $name => $class) {
+            $shell = $shells->addChild('shell');
+            $shell->addAttribute('name', $name);
+            $shell->addAttribute('call_as', $name);
+            $shell->addAttribute('provider', $class);
+            $shell->addAttribute('help', $name . ' -h');
+        }
+        $this->_io->setOutputAs(ConsoleOutput::RAW);
+        $this->out($shells->saveXML());
+    }
+
+    /**
+     * Gets the option parser instance and configures it.
+     *
+     * @return \Cake\Console\ConsoleOptionParser
+     */
+    public function getOptionParser()
+    {
+        $parser = parent::getOptionParser();
+
+        $parser->setDescription(
+            'Get the list of available shells for this application.'
+        )->addOption('xml', [
+            'help' => 'Get the listing as XML.',
+            'boolean' => true
+        ]);
+
+        return $parser;
+    }
+}

+ 25 - 2
tests/TestCase/Console/CommandRunnerTest.php

@@ -120,7 +120,19 @@ class CommandRunnerTest extends TestCase
      */
     public function testRunHelpLongOption()
     {
-        $this->markTestIncomplete();
+        $app = $this->getMockBuilder(BaseApplication::class)
+            ->setMethods(['middleware', 'bootstrap'])
+            ->setConstructorArgs([$this->config])
+            ->getMock();
+
+        $output = new ConsoleOutput();
+        $runner = new CommandRunner($app, 'cake');
+        $result = $runner->run(['cake', '--help'], $this->getMockIo($output));
+        $this->assertSame(0, $result);
+        $messages = implode("\n", $output->messages());
+        $this->assertContains('Current Paths', $messages);
+        $this->assertContains('- i18n', $messages);
+        $this->assertContains('Available Commands', $messages);
     }
 
     /**
@@ -130,7 +142,18 @@ class CommandRunnerTest extends TestCase
      */
     public function testRunHelpShortOption()
     {
-        $this->markTestIncomplete();
+        $app = $this->getMockBuilder(BaseApplication::class)
+            ->setMethods(['middleware', 'bootstrap'])
+            ->setConstructorArgs([$this->config])
+            ->getMock();
+
+        $output = new ConsoleOutput();
+        $runner = new CommandRunner($app, 'cake');
+        $result = $runner->run(['cake', '-h'], $this->getMockIo($output));
+        $this->assertSame(0, $result);
+        $messages = implode("\n", $output->messages());
+        $this->assertContains('- i18n', $messages);
+        $this->assertContains('Available Commands', $messages);
     }
 
     /**

+ 2 - 2
tests/TestCase/Shell/CommandListShellTest.php

@@ -79,7 +79,7 @@ class CommandListShellTest extends TestCase
         $expected = "/\[.*TestPluginTwo.*\] example, unique, welcome/";
         $this->assertRegExp($expected, $output);
 
-        $expected = "/\[.*CORE.*\] cache, i18n, orm_cache, plugin, routes, server/";
+        $expected = "/\[.*CORE.*\] cache, help, i18n, orm_cache, plugin, routes, server/";
         $this->assertRegExp($expected, $output);
 
         $expected = "/\[.*app.*\] i18m, sample/";
@@ -100,7 +100,7 @@ class CommandListShellTest extends TestCase
         $output = implode("\n", $output);
         rename(APP . 'Shell' . DS . 'I18nShell.php', APP . 'Shell' . DS . 'I18mShell.php');
 
-        $expected = "/\[.*CORE.*\] cache, orm_cache, plugin, routes, server/";
+        $expected = "/\[.*CORE.*\] cache, help, orm_cache, plugin, routes, server/";
         $this->assertRegExp($expected, $output);
 
         $expected = "/\[.*app.*\] i18n, sample/";

+ 1 - 1
tests/TestCase/Shell/CompletionShellTest.php

@@ -116,7 +116,7 @@ class CompletionShellTest extends TestCase
         $output = $this->out->output;
 
         $expected = 'TestPlugin.example TestPlugin.sample TestPluginTwo.example unique welcome ' .
-            "cache i18n orm_cache plugin routes server version i18m sample testing_dispatch\n";
+            "cache help i18n orm_cache plugin routes server version i18m sample testing_dispatch\n";
         $this->assertTextEquals($expected, $output);
     }
 

+ 102 - 0
tests/TestCase/Shell/HelpShellTest.php

@@ -0,0 +1,102 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (https://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. (https://cakefoundation.org)
+ * @link          https://cakephp.org CakePHP(tm) Project
+ * @since         3.5.0
+ * @license       https://opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Test\TestCase\Shell;
+
+use Cake\Console\CommandCollection;
+use Cake\Console\ConsoleIo;
+use Cake\Core\Plugin;
+use Cake\Shell\HelpShell;
+use Cake\TestSuite\Stub\ConsoleOutput;
+use Cake\TestSuite\TestCase;
+
+/**
+ * HelpShell test.
+ */
+class HelpShellTest extends TestCase
+{
+    /**
+     * setup method
+     *
+     * @return void
+     */
+    public function setUp()
+    {
+        parent::setUp();
+        $this->setAppNamespace();
+        Plugin::load('TestPlugin');
+
+        $this->out = new ConsoleOutput();
+        $this->err = new ConsoleOutput();
+        $this->io = new ConsoleIo($this->out, $this->err);
+        $this->shell = new HelpShell($this->io);
+
+        $commands = new CommandCollection();
+        $commands->addMany($commands->autoDiscover());
+        $this->shell->setCommandCollection($commands);
+    }
+
+    /**
+     * Test the command listing
+     *
+     * @return void
+     */
+    public function testMainNoCommands()
+    {
+        $shell = new HelpShell($this->io);
+        $this->assertNull($shell->main());
+        $err = $this->err->messages();
+        $this->assertContains('Could not print command list', $err[0]);
+    }
+
+    /**
+     * Test the command listing
+     *
+     * @return void
+     */
+    public function testMain()
+    {
+        $this->shell->main();
+        $output = implode("\n", $this->out->messages());
+        $this->assertContains('- sample', $output, 'app shell');
+        $this->assertContains('- routes', $output, 'core shell');
+        $this->assertContains('- test_plugin.example', $output, 'Long plugin name');
+        $this->assertContains('- example', $output, 'Short plugin name');
+        $this->assertContains('To run a command', $output, 'more info present');
+        $this->assertContains('To get help', $output, 'more info present');
+    }
+
+    /**
+     * Test help --xml
+     *
+     * @return void
+     */
+    public function testMainAsXml()
+    {
+        $this->shell->params['xml'] = true;
+        $this->shell->main();
+        $output = implode("\n", $this->out->messages());
+
+        $this->assertContains('<shells>', $output);
+
+        $find = '<shell name="sample" call_as="sample" provider="TestApp\Shell\SampleShell" help="sample -h"';
+        $this->assertContains($find, $output);
+
+        $find = '<shell name="orm_cache" call_as="orm_cache" provider="Cake\Shell\OrmCacheShell" help="orm_cache -h"';
+        $this->assertContains($find, $output);
+
+        $find = '<shell name="test_plugin.sample" call_as="test_plugin.sample" provider="TestPlugin\Shell\SampleShell" help="test_plugin.sample -h"';
+        $this->assertContains($find, $output);
+    }
+}