From d419548c02541f1f585f49fdf688a7fcd5982111 Mon Sep 17 00:00:00 2001 From: inhere Date: Sat, 24 Apr 2021 02:18:42 +0800 Subject: [PATCH] up: now, support run an plugin file --- app/Console/Application.php | 109 +-------- app/Console/Command/EnvCommand.php | 1 - app/Console/Controller/PluginController.php | 76 ++++++ app/Console/Listener/NotFoundListener.php | 86 +++++++ app/Console/Plugin/AbstractPlugin.php | 38 +++ app/Console/Plugin/PluginManager.php | 257 ++++++++++++++++++++ app/Kite.php | 9 + app/Plugin/AbstractPlugin.php | 15 -- resource/Changelog.md | 8 +- 9 files changed, 485 insertions(+), 114 deletions(-) create mode 100644 app/Console/Controller/PluginController.php create mode 100644 app/Console/Listener/NotFoundListener.php create mode 100644 app/Console/Plugin/AbstractPlugin.php create mode 100644 app/Console/Plugin/PluginManager.php delete mode 100644 app/Plugin/AbstractPlugin.php diff --git a/app/Console/Application.php b/app/Console/Application.php index 07d6cae..7e9d45a 100644 --- a/app/Console/Application.php +++ b/app/Console/Application.php @@ -10,9 +10,9 @@ namespace Inhere\Kite\Console; use Inhere\Console\ConsoleEvent; -use Inhere\Kite\Common\CmdRunner; +use Inhere\Kite\Console\Listener\NotFoundListener; +use Inhere\Kite\Console\Plugin\PluginManager; use Inhere\Kite\Kite; -use Inhere\Kite\Plugin\AbstractPlugin; use Toolkit\Stdlib\Arr\ArrayHelper; use function file_exists; use const BASE_PATH; @@ -25,26 +25,9 @@ class Application extends \Inhere\Console\Application { /** - * loaded plugin objects - * - * @var AbstractPlugin[] + * @var PluginManager */ - private $plugins = []; - - /** - * @var array - */ - private $pluginDirs = []; - - /** - * @var array - */ - private $pluginFiles = []; - - /** - * @var array - */ - private $pluginClasses = []; + private $plugManager; protected function prepareRun(): void { @@ -61,9 +44,7 @@ protected function init(): void $this->loadAppConfig(); - $this->initAppEnv(); - - $this->on(ConsoleEvent::ON_NOT_FOUND, $this->onNotFound()); + $this->initAppRun(); } private function loadAppConfig(): void @@ -100,86 +81,20 @@ private function loadAppConfig(): void $this->setConfig($config); } - protected function initAppEnv(): void - { - $this->pluginDirs = $this->getParam('pluginDirs', []); - } - - protected function onNotFound(): callable - { - return static function (string $cmd, Application $app) { - $aliases = $app->getParam('aliases', []); - - // - is an command alias. - if ($aliases && isset($aliases[$cmd])) { - $realCmd = $aliases[$cmd]; - - $app->notice("input command is alias name, will redirect to the real command '$realCmd'"); - $app->dispatch($realCmd); - return true; - } - - // check custom scripts - $scripts = $app->getParam('scripts', []); - if (!$scripts || !isset($scripts[$cmd])) { - // - run plugin - if ($app->isPlugin($cmd)) { - - } - - // - call system command. - if ($cmd[0] === '\\') { - $cmd = substr($cmd, 1); - } - - $cmdLine = $app->getInput()->getFullScript(); - $app->notice("input command is not found, will call system command: $cmdLine"); - - // call system command - CmdRunner::new($cmdLine)->do(true); - return true; - } - - // - run custom scripts. - /** @see \Inhere\Kite\Console\Command\RunCommand::execute() */ - $app->note("command not found, redirect to run script: $cmd"); - - $args = $app->getInput()->getArgs(); - $args = array_merge([$cmd], $args); - - $app->getInput()->setArgs($args, true); - $app->dispatch('run'); - - return true; - }; - } - - /** - * @param string $name - * - * @return bool - */ - public function isPlugin(string $name): bool + protected function initAppRun(): void { - if (\strpos($name, ' ') !== false) { - return false; - } + $plugDirs = $this->getParam('pluginDirs', []); - foreach ($this->pluginDirs as $dir) { - $filename = $dir . '/' . $name . '.php'; - if (\is_file($filename)) { - - } - } + $this->plugManager = new PluginManager($plugDirs); - return false; + $this->on(ConsoleEvent::ON_NOT_FOUND, new NotFoundListener()); } /** - * @param string $name + * @return PluginManager */ - public function runPlugin(string $name): bool + public function getPlugManager(): PluginManager { - return true; + return $this->plugManager; } } diff --git a/app/Console/Command/EnvCommand.php b/app/Console/Command/EnvCommand.php index 0027f30..0764db5 100644 --- a/app/Console/Command/EnvCommand.php +++ b/app/Console/Command/EnvCommand.php @@ -13,7 +13,6 @@ use Inhere\Console\IO\Input; use Inhere\Console\IO\Output; use function is_scalar; -use function strpos; /** * Class DemoCommand diff --git a/app/Console/Controller/PluginController.php b/app/Console/Controller/PluginController.php new file mode 100644 index 0000000..9295db5 --- /dev/null +++ b/app/Console/Controller/PluginController.php @@ -0,0 +1,76 @@ +bindArgument('name', 0); + $name = $input->getRequiredArg('name'); + + $kpm = Kite::plugManager(); + $kpm->run($name, $this->app); + + $output->success('completed'); + } + + /** + * list all plugins dir and file information + * + * @options + * --only-files Only list all plugin names + * + * @param Input $input + * @param Output $output + */ + public function listCommand(Input $input, Output $output): void + { + $kpm = Kite::plugManager(); + $opts = ['ucFirst' => false]; + + if (!$input->getBoolOpt('only-files')) { + $dirs = $kpm->getPluginDirs(); + $output->aList($dirs, 'plugin dirs', $opts); + } + + $files = $kpm->loadPluginFiles()->getPluginFiles(); + $output->aList($files, 'Plugin Files', $opts); + } +} diff --git a/app/Console/Listener/NotFoundListener.php b/app/Console/Listener/NotFoundListener.php new file mode 100644 index 0000000..75c7bdd --- /dev/null +++ b/app/Console/Listener/NotFoundListener.php @@ -0,0 +1,86 @@ +getParam('aliases', []); + + // - is an command alias. + if ($aliases && isset($aliases[$cmd])) { + $realCmd = $aliases[$cmd]; + + $app->notice("input command is alias name, will redirect to the real command '$realCmd'"); + $app->dispatch($realCmd); + return true; + } + + // check custom scripts + $scripts = $app->getParam('scripts', []); + if (!$scripts || !isset($scripts[$cmd])) { + // - run plugin + if ($app->getPlugManager()->isPlugin($cmd)) { + $app->notice("input is an plugin name, will run plugin: $cmd"); + $app->getPlugManager()->run($cmd, $app); + return true; + } + + // - call system command. + $this->callSystemCmd($cmd, $app); + return true; + } + + // - run custom scripts. + $this->runCustomScript($cmd, $app); + return true; + } + + /** + * @param string $cmd + * @param Application $app + */ + private function callSystemCmd(string $cmd, Application $app): void + { + if ($cmd[0] === '\\') { + $cmd = substr($cmd, 1); + } + + $cmdLine = $app->getInput()->getFullScript(); + $app->notice("input command is not found, will call system command: $cmdLine"); + + // call system command + CmdRunner::new($cmdLine)->do(true); + } + + /** + * @param string $cmd + * @param Application $app + */ + private function runCustomScript(string $cmd, Application $app): void + { + /** @see \Inhere\Kite\Console\Command\RunCommand::execute() */ + $app->note("command not found, redirect to run script: $cmd"); + + $args = $app->getInput()->getArgs(); + $args = array_merge([$cmd], $args); + + $app->getInput()->setArgs($args, true); + $app->dispatch('run'); + } +} diff --git a/app/Console/Plugin/AbstractPlugin.php b/app/Console/Plugin/AbstractPlugin.php new file mode 100644 index 0000000..e48195f --- /dev/null +++ b/app/Console/Plugin/AbstractPlugin.php @@ -0,0 +1,38 @@ + 'inhere', + // 'version' => '', + // 'desc' => '', + ]; + } + + /** + * @param Application $app + */ + public function run(Application $app): void + { + $this->exec($app); + } + + /** + * @param Application $app + */ + abstract public function exec(Application $app): void; +} diff --git a/app/Console/Plugin/PluginManager.php b/app/Console/Plugin/PluginManager.php new file mode 100644 index 0000000..9f4efa7 --- /dev/null +++ b/app/Console/Plugin/PluginManager.php @@ -0,0 +1,257 @@ +pluginDirs = $pluginDirs; + } + + /** + * @param string $name plugin name or file path + * @param Application $app + */ + public function run(string $name, Application $app): void + { + $plugin = $this->getPlugin($name); + if (!$plugin) { + throw new RuntimeException('the plugin is not exists. plugin: ' . $name); + } + + $plugin->run($app); + } + + /** + * @param string $name + * + * @return AbstractPlugin|null + */ + public function getPlugin(string $name): ?AbstractPlugin + { + return $this->plugins[$name] ?? $this->loadPlugin($name); + } + + /** + * check plugin, and load plugin + * + * @param string $name plugin name or file path + * + * @return bool + */ + public function isPlugin(string $name): bool + { + $name = trim($name); + $name = trim($name, '/'); + + if (!$name || strpos($name, ' ') !== false) { + return false; + } + + return $this->loadPlugin($name) ? true : false; + } + + /** + * check and load plugin + * + * @param string $name plugin name or file path + * + * @return bool + */ + protected function loadPlugin(string $name): ?AbstractPlugin + { + // not found + if (!isset($this->pluginFiles[$name]) && !$this->loadPluginFile($name)) { + return null; + } + + $filename = $this->pluginFiles[$name]; + $this->requireFile($filename); + + $className = strpos($name, '/') > 0 ? basename($name) : $name; + if (Str::has($className, '.php')) { + $className = substr($className, 0, -4); + } + + $className = Str::camelCase($className, true); + if (!class_exists($className, false)) { + throw new RuntimeException('the plugin file is not an class, plugin: ' . $name); + } + + $pluginObj = new $className; + if (!($pluginObj instanceof AbstractPlugin)) { + throw new RuntimeException('plugin class must extends: ' . AbstractPlugin::class); + } + + $this->plugins[$name] = $pluginObj; + return $pluginObj; + } + + /** + * @param string $name + */ + protected function loadPluginFile(string $name): bool + { + // is an exists php file + if (Str::has($name, '.php') && is_file($name)) { + // $path = $name; + // $name = substr($name, 0, -4); + + $this->pluginFiles[$name] = $name; + return true; + } + + // find in all plugin dirs + $founded = false; + foreach ($this->pluginDirs as $dir) { + $filename = $dir . '/' . $name . '.php'; + if (is_file($filename)) { + $founded = true; + + $this->pluginFiles[$name] = $filename; + break; + } + } + + return $founded; + } + + /** + * load all plugin files + */ + public function loadPluginFiles(): self + { + if ($this->loaded) { + return $this; + } + + $this->loaded = true; + if (!$this->pluginDirs) { + return $this; + } + + $fileFilter = $this->getFileFilter(); + foreach ($this->pluginDirs as $pluginDir) { + $strLen = strlen($pluginDir); + $iterator = Helper::directoryIterator($pluginDir, $fileFilter); + + foreach ($iterator as $fi) { + $filepath = $fi->getPathname(); + $pluginName = substr($filepath, $strLen, -4); + + $this->pluginFiles[$pluginName] = $filepath; + } + } + + return $this; + } + + /** + * @return Closure + */ + protected function getFileFilter(): callable + { + return static function (SplFileInfo $f) { + $name = $f->getFilename(); + + // Skip hidden files and directories. + if (strpos($name, '.') === 0) { + return false; + } + + // go on read sub-dir + if ($f->isDir()) { + return true; + } + + // php file + return $f->isFile() && substr($name, -4) === '.php'; + }; + } + + /** + * @param string $phpFile + */ + private function requireFile(string $phpFile): void + { + /** @noinspection PhpIncludeInspection */ + require_once $phpFile; + } + + /** + * @return array + */ + public function getPluginDirs(): array + { + return $this->pluginDirs; + } + + /** + * @return array + */ + public function getPluginFiles(): array + { + return $this->pluginFiles; + } +} diff --git a/app/Kite.php b/app/Kite.php index 7058825..349c97e 100644 --- a/app/Kite.php +++ b/app/Kite.php @@ -10,6 +10,7 @@ namespace Inhere\Kite; use Inhere\Kite\Console\Application; +use Inhere\Kite\Console\Plugin\PluginManager; use Inhere\Kite\Http\Application as WebApplication; use Inhere\Route\Router; @@ -62,6 +63,14 @@ public static function webRouter(): Router return self::$webApp->getRouter(); } + /** + * @return PluginManager + */ + public static function plugManager(): PluginManager + { + return self::$cliApp->getPlugManager(); + } + /** * @param Application $cliApp */ diff --git a/app/Plugin/AbstractPlugin.php b/app/Plugin/AbstractPlugin.php deleted file mode 100644 index add3eb5..0000000 --- a/app/Plugin/AbstractPlugin.php +++ /dev/null @@ -1,15 +0,0 @@ -