From 7fa690d71869da305e25144e3144770f2a204aa1 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Wed, 8 Feb 2023 16:23:30 +0300 Subject: [PATCH 1/2] Added Support for Callbacks to Execute After Each Command --- tests/webfiori/tests/cli/RunnerTest.php | 42 ++++++++++++++++++- webfiori/cli/Runner.php | 56 ++++++++++++++++++++----- 2 files changed, 86 insertions(+), 12 deletions(-) diff --git a/tests/webfiori/tests/cli/RunnerTest.php b/tests/webfiori/tests/cli/RunnerTest.php index 252abee..f4ce515 100644 --- a/tests/webfiori/tests/cli/RunnerTest.php +++ b/tests/webfiori/tests/cli/RunnerTest.php @@ -374,6 +374,9 @@ public function testRunner15() { $runner->register(new Command00()); $runner->register(new HelpCommand()); $runner->register(new WithExceptionCommand()); + $runner->setAfterExecution(function (Runner $r) { + $r->getActiveCommand()->println('Command Exit Status: '.$r->getLastCommandExitStatus()); + }); $runner->setArgsVector([ 'entry.php', '--ansi', @@ -391,11 +394,14 @@ public function testRunner15() { ">>  super-hero: A command to display hero's name.\n", " Supported Arguments:\n", " name: The name of the hero\n", + "Command Exit Status: 0\n", ">> Error: An exception was thrown.\n", "Exception Message: Call to undefined method webfiori\\tests\\cli\\testCommands\\WithExceptionCommand::notExist()\n", + "Code: 0\n", "At: ".ROOT_DIR."tests".DS."webfiori".DS."tests".DS."cli".DS."testCommands".DS."WithExceptionCommand.php\n", "Line: 12\n", - ">> " + "Command Exit Status: -1\n", + ">> ", ], $runner->getOutput()); } /** @@ -434,6 +440,9 @@ public function testRunner18() { $runner = new Runner(); $runner->register(new Command01()); $runner->setInput([]); + $runner->setAfterExecution(function (Runner $r) { + $r->getActiveCommand()->println('Command Exit Status: '.$r->getLastCommandExitStatus()); + }); $this->assertEquals(0, $runner->runCommand(null, [ 'show-v', 'arg-1' => 'Super Cool Arg', @@ -443,7 +452,8 @@ public function testRunner18() { "System version: 1.0.0\n", "Super Cool Arg\n", "First One is Coller\n", - "Hello\n" + "Hello\n", + "Command Exit Status: 0\n" ], $runner->getOutput()); } /** @@ -493,4 +503,32 @@ public function testRunner20() { "Info: No command was specified to run.\n", ], $runner->getOutput()); } + /** + * @test + */ + public function testRunner21() { + $runner = new Runner(); + + $runner->register(new Command00()); + $runner->register(new HelpCommand()); + $runner->register(new WithExceptionCommand()); + $runner->setAfterExecution(function (Runner $r) { + $r->getActiveCommand()->println('Command Exit Status: '.$r->getLastCommandExitStatus()); + }); + + $runner->setArgsVector([ + 'entry.php', + 'with-exception', + ]); + $runner->setInput([]); + $runner->start(); + $this->assertEquals([ + "Error: An exception was thrown.\n", + "Exception Message: Call to undefined method webfiori\\tests\cli\\testCommands\WithExceptionCommand::notExist()\n", + "Code: 0\n", + "At: ".ROOT_DIR."tests\webfiori\\tests\cli\\testCommands\WithExceptionCommand.php\n", + "Line: 12\n", + "Command Exit Status: -1\n" + ], $runner->getOutput()); + } } diff --git a/webfiori/cli/Runner.php b/webfiori/cli/Runner.php index cbb7809..f9312df 100644 --- a/webfiori/cli/Runner.php +++ b/webfiori/cli/Runner.php @@ -27,6 +27,13 @@ class Runner { private $commandExitVal; private $argsV; private $isAnsi; + /** + * An array that holds sub-arrays for callbacks that will be executed + * each time a command finish execution. + * + * @var array + */ + private $afterRunPool; /** * An associative array that contains supported commands. * @@ -70,6 +77,7 @@ public function __construct() { $this->inputStream = new StdIn(); $this->outputStream = new StdOut(); $this->commandExitVal = 0; + $this->afterRunPool = []; $this->addArg('--ansi', [ 'optional' => true, @@ -82,6 +90,24 @@ public function __construct() { $r->checkIsIntr(); }); } + /** + * Add a function to execute after every command. + * + * The method can be used to set multiple callbacks. + * + * @param callable $func The function that will be executed after the + * completion of command execution. The first parameter of the method + * will always be an instance of 'Runner' (e.g. function (Runner $runner){}). + * + * @param array $params Any additional parameters that will be passed to the + * callback. + */ + public function setAfterExecution(callable $func, array $params = []) { + $this->afterRunPool[] = [ + 'func' => $func, + 'params' => $params + ]; + } /** * Adds a global command argument. * @@ -397,11 +423,28 @@ public function runCommand(CLICommand $c = null, array $args = [], bool $ansi = } $this->setArgV($args); $this->setActiveCommand($c); - $this->commandExitVal = $c->excCommand(); + + try { + $this->commandExitVal = $c->excCommand(); + } catch (Throwable $ex) { + $this->printMsg('An exception was thrown.', 'Error:', 'red'); + $this->printMsg($ex->getMessage(), 'Exception Message:', 'yellow'); + $this->printMsg($ex->getCode(), 'Code:', 'yellow'); + $this->printMsg($ex->getFile(), 'At:', 'yellow'); + $this->printMsg($ex->getLine(), 'Line:', 'yellow'); + $this->commandExitVal = $ex->getCode() == 0 ? -1 : $ex->getCode(); + } + + $this->invokeAfterExc(); $this->setActiveCommand(); - return $this->commandExitVal; } + private function invokeAfterExc() { + foreach ($this->afterRunPool as $funcArr) { + call_user_func_array($funcArr['func'], array_merge([$this], $funcArr['params'])); + } + } + /** * Sets the command which is currently in execution stage. * @@ -526,14 +569,7 @@ public function start() : int { } else if ($args[0] == 'exit') { return 0; } else { - try { - $this->runCommand(null, $args, $this->isAnsi); - } catch (Throwable $ex) { - $this->printMsg('An exception was thrown.', 'Error:', 'red'); - $this->printMsg($ex->getMessage(), 'Exception Message:', 'yellow'); - $this->printMsg($ex->getFile(), 'At:', 'yellow'); - $this->printMsg($ex->getLine(), 'Line:', 'yellow'); - } + $this->runCommand(null, $args, $this->isAnsi); } $this->printMsg('', '>>', 'blue'); } From 304b6a8040e821d55c25688f523b0a2e6fe26e03 Mon Sep 17 00:00:00 2001 From: Ibrahim Date: Wed, 8 Feb 2023 16:31:52 +0300 Subject: [PATCH 2/2] Update RunnerTest.php --- tests/webfiori/tests/cli/RunnerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/webfiori/tests/cli/RunnerTest.php b/tests/webfiori/tests/cli/RunnerTest.php index f4ce515..a5fd572 100644 --- a/tests/webfiori/tests/cli/RunnerTest.php +++ b/tests/webfiori/tests/cli/RunnerTest.php @@ -526,7 +526,7 @@ public function testRunner21() { "Error: An exception was thrown.\n", "Exception Message: Call to undefined method webfiori\\tests\cli\\testCommands\WithExceptionCommand::notExist()\n", "Code: 0\n", - "At: ".ROOT_DIR."tests\webfiori\\tests\cli\\testCommands\WithExceptionCommand.php\n", + "At: ".ROOT_DIR."tests".DS."webfiori".DS."tests".DS."cli".DS."testCommands".DS."WithExceptionCommand.php\n", "Line: 12\n", "Command Exit Status: -1\n" ], $runner->getOutput());