Skip to content

Commit

Permalink
New helper functions (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
SmetDenis committed Apr 24, 2022
1 parent 9a91137 commit 6cc2760
Show file tree
Hide file tree
Showing 12 changed files with 206 additions and 20 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -137,7 +137,7 @@ The simplest CLI action: [./demo/Commands/Simple.php](demo/Commands/Simple.php)
$this->_('Hello world!');

// Exit code. 0 - success, 1 - error.
return Codes::OK;
return self::SUCCESS;
}
}
```
Expand Down
60 changes: 60 additions & 0 deletions demo/Commands/ExamplesHelpers.php
@@ -0,0 +1,60 @@
<?php

/**
* JBZoo Toolbox - Cli
*
* This file is part of the JBZoo Toolbox project.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package Cli
* @license MIT
* @copyright Copyright (C) JBZoo.com, All rights reserved.
* @link https://github.com/JBZoo/Cli
*/

declare(strict_types=1);

namespace DemoApp\Commands;

use JBZoo\Cli\CliCommand;
use JBZoo\Cli\CliRender;
use JBZoo\Cli\Codes;

use function JBZoo\Cli\cli;

/**
* Class ExamplesHelpers
*/
class ExamplesHelpers extends CliCommand
{
protected function configure(): void
{
$this
->setName('examples:helpers')
->setDescription('Examples of new CLI helpers');

parent::configure();
}

/**
* @inheritDoc
*/
protected function executeAction(): int
{
$yourName = $this->ask("What's your name?", 'idk');
cli("Your name is \"{$yourName}\"");

$yourSecret = $this->askPassword("New password?");
cli("Your secret is \"{$yourSecret}\"");

$selectedColor = $this->askOption('Choose your favorite color', ['Red', 'Blue', 'Yellow'], 1);
$colorAlias = strtolower($selectedColor);
cli("Selected color is \"<{$colorAlias}>{$selectedColor}</{$colorAlias}>\"");

$isConfirmed = $this->confirmation('Are you ready to execute the script?');
cli("Is confirmed: " . ($isConfirmed ? 'Yes' : 'No'));

return self::SUCCESS;
}
}
3 changes: 1 addition & 2 deletions demo/Commands/ExamplesOptionsStrictTypes.php
Expand Up @@ -197,7 +197,6 @@ protected function executeAction(): int


// Default success exist code is "0". Max value is 255.
// See JBZoo\Cli\Codes class for more info
return Codes::OK;
return self::SUCCESS;
}
}
3 changes: 1 addition & 2 deletions demo/Commands/ExamplesOutput.php
Expand Up @@ -119,7 +119,6 @@ protected function executeAction(): int


// Default success exist code is "0". Max value is 255.
// See JBZoo\Cli\Codes class for more info
return Codes::OK;
return self::SUCCESS;
}
}
4 changes: 2 additions & 2 deletions demo/Commands/ExamplesProgressBar.php
Expand Up @@ -90,8 +90,8 @@ protected function executeAction(): int
}, 'Handling list of exceptions at once', true);
}


// Default success exist code is "0". Max value is 255.
// See JBZoo\Cli\Codes class for more info
return Codes::OK;
return self::SUCCESS;
}
}
4 changes: 2 additions & 2 deletions demo/Commands/ExamplesStyles.php
Expand Up @@ -92,8 +92,8 @@ protected function executeAction(): int
'\<e\>' => '<e>Alias for \<error\></e>',
], '*'));


// Default success exist code is "0". Max value is 255.
// See JBZoo\Cli\Codes class for more info
return Codes::OK;
return self::SUCCESS;
}
}
2 changes: 1 addition & 1 deletion demo/Commands/Simple.php
Expand Up @@ -42,6 +42,6 @@ protected function executeAction(): int
$this->_('Hello world!');

// Exit code. 0 - success, 1 - error.
return Codes::OK;
return self::SUCCESS;
}
}
40 changes: 35 additions & 5 deletions src/Cli.php
Expand Up @@ -63,13 +63,26 @@ class Cli
*/
private $outputHasErrors = false;

/**
* @var float
*/
private $prevTime;

/**
* @var int
*/
private $prevMemory;

/**
* @param InputInterface $input
* @param OutputInterface $output
*/
public function __construct(InputInterface $input, OutputInterface $output)
{
$this->prevMemory = \memory_get_usage(false);
$this->startTimer = \microtime(true);
$this->prevTime = $this->startTimer;

$this->input = $input;
$this->output = self::addOutputStyles($output);

Expand All @@ -88,6 +101,14 @@ public function __construct(InputInterface $input, OutputInterface $output)
self::$instance = $this;
}

/**
* @return float
*/
public function getStartTime(): float
{
return $this->startTimer;
}

/**
* @return $this
*/
Expand Down Expand Up @@ -186,11 +207,19 @@ public static function addOutputStyles(OutputInterface $output): OutputInterface
*/
public function getProfileInfo(): array
{
return [
\number_format(\microtime(true) - $this->startTimer, 3),
FS::format(\memory_get_usage(false)),
FS::format(\memory_get_peak_usage(false)),
$currentTime = \microtime(true);
$currentMemory = \memory_get_usage(false);

$currDiff = $currentMemory - $this->prevMemory;
$result = [
\number_format($currentTime - $this->prevTime, 3),
($currDiff < 0 ? '-' : '+') . FS::format(\abs($currDiff))
];

$this->prevTime = $currentTime;
$this->prevMemory = $currentMemory;

return $result;
}

/**
Expand Down Expand Up @@ -240,7 +269,8 @@ public function _($messages = '', string $verboseLevel = OutLvl::DEFAULT): void

if ($this->input->getOption('profile')) {
[$totalTime, $curMemory] = $this->getProfileInfo();
$profilePrefix .= "<green>[</green>{$curMemory}<green>/</green>{$totalTime}s<green>]</green> ";
$curMemory = \str_pad($curMemory, 10, ' ', \STR_PAD_LEFT);
$profilePrefix .= "<green>[</green>+{$totalTime}s<green>/</green>{$curMemory}<green>]</green> ";
}

$vNormal = OutputInterface::VERBOSITY_NORMAL;
Expand Down
96 changes: 95 additions & 1 deletion src/CliCommand.php
Expand Up @@ -18,11 +18,16 @@
namespace JBZoo\Cli;

use JBZoo\Utils\Arr;
use JBZoo\Utils\FS;
use JBZoo\Utils\Str;
use JBZoo\Utils\Vars;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;

use function JBZoo\Utils\bool;
use function JBZoo\Utils\float;
Expand Down Expand Up @@ -273,7 +278,9 @@ private function showProfiler(): void
return;
}

[$totalTime, $curMemory, $maxMemory] = $this->helper->getProfileInfo();
$totalTime = \number_format(\microtime(true) - $this->helper->getStartTime(), 3);
$curMemory = FS::format(\memory_get_usage(false));
$maxMemory = FS::format(\memory_get_peak_usage(true));

$this->_(\implode('; ', [
"Memory Usage/Peak: <green>{$curMemory}</green>/<green>{$maxMemory}</green>",
Expand Down Expand Up @@ -329,4 +336,91 @@ private function showLegacyOutput(?string $echoContent): void
$this->_($echoContent, OutLvl::LEGACY);
}
}

/**
* @param string $question
* @param string $default
* @param bool $isHidden
* @return string
*/
protected function ask(string $question, string $default = '', bool $isHidden = false): string
{
$question = \rtrim($question, ':');
$questionText = "<yellow-r>Question:</yellow-r> {$question}";
if (!$isHidden) {
$questionText .= ($default ? " (Default: <i>{$default}</i>)" : '');
}

/** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
$helper = $this->getHelper('question');
$questionObj = new Question($questionText . ': ', $default);
if ($isHidden) {
$questionObj->setHidden(true);
$questionObj->setHiddenFallback(false);
}

return (string)$helper->ask($this->helper->getInput(), $this->helper->getOutput(), $questionObj);
}

/**
* @param string $question
* @param bool $randomDefault
* @return string
*/
protected function askPassword(string $question, bool $randomDefault = true): string
{
$default = '';
if ($randomDefault) {
$question .= ' (Default: <i>Random</i>)';
$default = Str::random(10, false);
}

return $this->ask($question, $default, true);
}

/**
* @param string $question
* @param bool $default
* @return bool
*/
protected function confirmation(string $question = 'Are you sure?', bool $default = false): bool
{
$question = '<yellow-r>Question:</yellow-r> ' . \trim($question);

/** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
$helper = $this->getHelper('question');
$defaultValue = $default ? 'Y' : 'n';

$questionObj = new ConfirmationQuestion(
"{$question} (<c>Y/n</c>; Default: <i>{$defaultValue}</i>): ",
$default
);

return (bool)$helper->ask($this->helper->getInput(), $this->helper->getOutput(), $questionObj);
}

/**
* @param string $question
* @param string[] $options
* @param string|int|null $default
* @return string
*/
protected function askOption(string $question, array $options, $default = null): string
{
$question = '<yellow-r>Question:</yellow-r> ' . \trim($question);

$defaultValue = '';
if (null !== $default) {
$defaultValue = $options[$default] ?? $default ?: '';
if ('' !== $defaultValue) {
$defaultValue = " (Default: <i>{$defaultValue}</i>)";
}
}

$helper = $this->getHelper('question');
$questionObj = new ChoiceQuestion($question . $defaultValue . ': ', $options, $default);
$questionObj->setErrorMessage('The option "%s" is undefined. See the avaialable options');

return (string)$helper->ask($this->helper->getInput(), $this->helper->getOutput(), $questionObj);
}
}
1 change: 1 addition & 0 deletions src/ProgressBars/ProgressBar.php
Expand Up @@ -263,6 +263,7 @@ public function execute(): bool
}

self::showListOfExceptions($exceptionMessages);
$this->helper->_('');

return true;
}
Expand Down
8 changes: 4 additions & 4 deletions tests/Cli/CliOutputTest.php
Expand Up @@ -142,10 +142,10 @@ public function testProfile()
{
$output = Helper::executeReal('test:output', ['profile' => null])[1];

isContain('s] Normal 1', $output);
isContain('s] Normal 2', $output);
isContain('s] Quiet -q', $output);
isContain('s] Memory Usage/Peak:', $output);
isContain('B] Normal 1', $output);
isContain('B] Normal 2', $output);
isContain('B] Quiet -q', $output);
isContain('B] Memory Usage/Peak:', $output);
isContain('Execution Time:', $output);
}

Expand Down
3 changes: 3 additions & 0 deletions tests/Cli/CliProgressTest.php
Expand Up @@ -248,18 +248,21 @@ public function testNested()
' * (1): out_child_0_1',
' * (2): out_child_0_2',
' * (3): out_child_0_3',
'',
' * (0): out_parent_0',
'Working on "nested_child_1". Number of steps: 4.',
' * (0): out_child_1_0',
' * (1): out_child_1_1',
' * (2): out_child_1_2',
' * (3): out_child_1_3',
'',
' * (1): out_parent_1',
'Working on "nested_child_2". Number of steps: 4.',
' * (0): out_child_2_0',
' * (1): out_child_2_1',
' * (2): out_child_2_2',
' * (3): out_child_2_3',
'',
' * (2): out_parent_2',
]), $stdOut);
}
Expand Down

0 comments on commit 6cc2760

Please sign in to comment.