Giter Club home page Giter Club logo

php-cli's Introduction

adhocore/cli

Framework agnostic Command Line Interface utilities and helpers for PHP. Build Console App with ease, fun and love.

Latest Version Build Scrutinizer CI Codecov branch StyleCI Software License Tweet Support

  • Command line application made easy
  • Inspired by nodejs commander (thanks tj)
  • Zero dependency.
  • For PHP7, PHP8 and for good

Screen Preview

What's included

Core: Argv parser · Cli application · Shell

IO: Colorizer · Cursor manipulator · Progress bar · Stream writer · Stream reader

Other: Autocompletion

Installation

# PHP8.0 and above v1.0.0
composer require adhocore/cli:^v1.0.0

# PHP 7.x
composer require adhocore/cli:^v0.9.0

Usage

Argv parser

$command = new Ahc\Cli\Input\Command('rmdir', 'Remove dirs');

$command
    ->version('0.0.1-dev')
    // Arguments are separated by space
    // Format: `<name>` for required, `[name]` for optional
    //  `[name:default]` for default value, `[name...]` for variadic (last argument)
    ->arguments('<dir> [dirs...]')
    // `-h --help`, `-V --version`, `-v --verbosity` options are already added by default.
    // Format: `<name>` for required, `[name]` for optional
    ->option('-s --with-subdir', 'Also delete subdirs (`with` means false by default)')
    ->option('-e,--no-empty', 'Delete empty (`no` means true by default)')
    // Specify santitizer/callback as 3rd param, default value as 4th param
    ->option('-d|--depth [nestlevel]', 'How deep to process subdirs', 'intval', 5)
    ->parse(['thisfile.php', '-sev', 'dir', 'dir1', 'dir2', '-vv']) // `$_SERVER['argv']`
;

// Print all values:
print_r($command->values());

/*Array
(
    [help] =>
    [version] => 0.0.1
    [verbosity] => 3
    [dir] => dir
    [dirs] => Array
        (
            [0] => dir1
            [1] => dir2
        )

    [subdir] => true
    [empty] => false
    [depth] => 5
)*/

// To get values for options except the default ones (help, version, verbosity)
print_r($command->values(false));

// Pick a value by name
$command->dir;   // dir
$command->dirs;  // [dir1, dir2]
$command->depth; // 5

Command help

It can be triggered manually with $command->showHelp() or automatic when -h or --help option is passed to $command->parse().

For above example, the output would be: Command Help

Command version

It can be triggered manually with $command->showVersion() or automatic when -V or --version option is passed to $command->parse().

For above example, the output would be:

0.0.1-dev

Console app

Definitely check adhocore/phint - a real world console application made using adhocore/cli.

Here we simulate a git app with limited functionality of add, and checkout. You will see how intuitive, fluent and cheese building a console app is!

Git app

$app = new Ahc\Cli\Application('git', '0.0.1');

$app
    // Register `add` command
    ->command('add', 'Stage changed files', 'a') // alias a
        // Set options and arguments for this command
        ->arguments('<path> [paths...]')
        ->option('-f --force', 'Force add ignored file', 'boolval', false)
        ->option('-N --intent-to-add', 'Add content later but index now', 'boolval', false)
        // Handler for this command: param names should match but order can be anything :)
        ->action(function ($path, $paths, $force, $intentToAdd) {
            array_unshift($paths, $path);

            echo ($intentToAdd ? 'Intent to add ' : 'Add ')
                . implode(', ', $paths)
                . ($force ? ' with force' : '');

            // If you return integer from here, that will be taken as exit error code
        })
        // Done setting up this command for now, tap() to retreat back so we can add another command
        ->tap()
    ->command('checkout', 'Switch branches', 'co') // alias co
        ->arguments('<branch>')
        ->option('-b --new-branch', 'Create a new branch and switch to it', false)
        ->option('-f --force', 'Checkout even if index differs', 'boolval', false)
        ->action(function ($branch, $newBranch, $force) {
            echo 'Checkout to '
                . ($newBranch ? 'new ' . $branch : $branch)
                . ($force ? ' with force' : '');
        })
;

// Parse only parses input but doesnt invoke action
$app->parse(['git', 'add', 'path1', 'path2', 'path3', '-f']);

// Handle will do both parse and invoke action.
$app->handle(['git', 'add', 'path1', 'path2', 'path3', '-f']);
// Will produce: Add path1, path2, path3 with force

$app->handle(['git', 'co', '-b', 'master-2', '-f']);
// Will produce: Checkout to new master-2 with force

Organized app

Instead of inline commands/actions, we define and add our own commands (having interact() and execute()) to the app:

class InitCommand extends Ahc\Cli\Input\Command
{
    public function __construct()
    {
        parent::__construct('init', 'Init something');

        $this
            ->argument('<arrg>', 'The Arrg')
            ->argument('[arg2]', 'The Arg2')
            ->option('-a --apple', 'The Apple')
            ->option('-b --ball', 'The ball')
            // Usage examples:
            ->usage(
                // append details or explanation of given example with ` ## ` so they will be uniformly aligned when shown
                '<bold>  init</end> <comment>--apple applet --ball ballon <arggg></end> ## details 1<eol/>' .
                // $0 will be interpolated to actual command name
                '<bold>  $0</end> <comment>-a applet -b ballon <arggg> [arg2]</end> ## details 2<eol/>'
            );
    }

    // This method is auto called before `self::execute()` and receives `Interactor $io` instance
    public function interact(Ahc\Cli\IO\Interactor $io) : void
    {
        // Collect missing opts/args
        if (!$this->apple) {
            $this->set('apple', $io->prompt('Enter apple'));
        }

        if (!$this->ball) {
            $this->set('ball', $io->prompt('Enter ball'));
        }

        // ...
    }

    // When app->handle() locates `init` command it automatically calls `execute()`
    // with correct $ball and $apple values
    public function execute($ball, $apple)
    {
        $io = $this->app()->io();

        $io->write('Apple ' . $apple, true);
        $io->write('Ball ' . $ball, true);

        // more codes ...

        // If you return integer from here, that will be taken as exit error code
    }
}

class OtherCommand extends Ahc\Cli\Input\Command
{
    public function __construct()
    {
        parent::__construct('other', 'Other something');
    }

    public function execute()
    {
        $io = $this->app()->io();

        $io->write('Other command');

        // more codes ...

        // If you return integer from here, that will be taken as exit error code
    }
}

// Init App with name and version
$app = new Ahc\Cli\Application('App', 'v0.0.1');

// Add commands with optional aliases`
$app->add(new InitCommand, 'i');
$app->add(new OtherCommand, 'o');

// Set logo
$app->logo('Ascii art logo of your app');

$app->handle($_SERVER['argv']); // if argv[1] is `i` or `init` it executes InitCommand

Grouping commands

Grouped commands are listed together in commands list. Explicit grouping a command is optional. By default if a command name has a colon : then the part before it is taken as a group, else * is taken as a group.

Example: command name app:env has a default group app, command name appenv has group *.

// Add grouped commands:
$app->group('Configuration', function ($app) {
    $app->add(new ConfigSetCommand);
    $app->add(new ConfigListCommand);
});

// Alternatively, set group one by one in each commands:
$app->add((new ConfigSetCommand)->inGroup('Config'));
$app->add((new ConfigListCommand)->inGroup('Config'));
...

Exception handler

Set a custom exception handler as callback. The callback receives exception & exit code. The callback may rethrow exception or may exit the program or just log exception and do nothing else.

$app = new Ahc\Cli\Application('App', 'v0.0.1');
$app->add(...);
$app->onException(function (Throwable $e, int $exitCode) {
    // send to sentry
    // write to logs

    // optionally, exit with exit code:
    exit($exitCode);

    // or optionally rethrow, a rethrown exception is propagated to top layer caller.
    throw $e;
})->handle($argv);

App help

It can be triggered manually with $app->showHelp() or automatic when -h or --help option is passed to $app->parse(). Note If you pass something like ['app', cmd', '-h'] to $app->parse() it will automatically and instantly show you help of that cmd and not the $app.

For above example, the output would be: App Help

App version

Same version number is passed to all attached Commands. So you can trigger version on any of the commands.

Shell

Very thin shell wrapper that provides convenience methods around proc_open().

Basic usage

$shell = new Ahc\Cli\Helper\Shell($command = 'php -v', $rawInput = null);

// Waits until proc finishes
$shell->execute($async = false); // default false

echo $shell->getOutput(); // PHP version string (often with zend/opcache info)

Advanced usage

$shell = new Ahc\Cli\Helper\Shell('php /some/long/running/scipt.php');

// With async flag, doesnt wait for proc to finish!
$shell->setOptions($workDir = '/home', $envVars = [])
    ->execute($async = true)
    ->isRunning(); // true

// Force stop anytime (please check php.net/proc_close)
$shell->stop(); // also closes pipes

// Force kill anytime (please check php.net/proc_terminate)
$shell->kill();

Timeout

$shell = new Ahc\Cli\Helper\Shell('php /some/long/running/scipt.php');

// Wait for at most 10.5 seconds for proc to finish!
// If it doesnt complete by then, throws exception
$shell->setOptions($workDir, $envVars, $timeout = 10.5)->execute();

// And if it completes within timeout, you can access the stdout/stderr
echo $shell->getOutput();
echo $shell->getErrorOutput();

Cli Interaction

You can perform user interaction like printing colored output, reading user input programatically and moving the cursors around with provided Ahc\Cli\IO\Interactor.

$interactor = new Ahc\Cli\IO\Interactor;

// For mocking io:
$interactor = new Ahc\Cli\IO\Interactor($inputPath, $outputPath);

Confirm

$confirm = $interactor->confirm('Are you happy?', 'n'); // Default: n (no)
$confirm // is a boolean
    ? $interactor->greenBold('You are happy :)', true)  // Output green bold text
    : $interactor->redBold('You are sad :(', true);     // Output red bold text

Single choice

$fruits = ['a' => 'apple', 'b' => 'banana'];
$choice = $interactor->choice('Select a fruit', $fruits, 'b');
$interactor->greenBold("You selected: {$fruits[$choice]}", true);

Multiple choices

$fruits  = ['a' => 'apple', 'b' => 'banana', 'c' => 'cherry'];
$choices = $interactor->choices('Select fruit(s)', $fruits, ['b', 'c']);
$choices = \array_map(function ($c) use ($fruits) { return $fruits[$c]; }, $choices);
$interactor->greenBold('You selected: ' . implode(', ', $choices), true);

Prompt free input

$any = $interactor->prompt('Anything', rand(1, 100)); // Random default
$interactor->greenBold("Anything is: $any", true);

Prompt with validation

$nameValidator = function ($value) {
    if (\strlen($value) < 5) {
        throw new \InvalidArgumentException('Name should be atleast 5 chars');
    }

    return $value;
};

// No default, Retry 5 more times
$name = $interactor->prompt('Name', null, $nameValidator, 5);
$interactor->greenBold("The name is: $name", true);

Prompt hidden

On windows platform, it may change the fontface which can be fixed.

$passValidator = function ($pass) {
    if (\strlen($pass) < 6) {
        throw new \InvalidArgumentException('Password too short');
    }

    return $pass;
};

$pass = $interactor->promptHidden('Password', $passValidator, 2);

Interactive Preview

IO Components

The interactor is composed of Ahc\Cli\Input\Reader and Ahc\Cli\Output\Writer while the Writer itself is composed of Ahc\Cli\Output\Color. All these components can be used standalone.

Color

Color looks cool!

$color = new Ahc\Cli\Output\Color;

Simple usage

echo $color->warn('This is warning');
echo $color->info('This is info');
echo $color->error('This is error');
echo $color->comment('This is comment');
echo $color->ok('This is ok msg');

Custom style

Ahc\Cli\Output\Color::style('mystyle', [
    'bg' => Ahc\Cli\Output\Color::CYAN,
    'fg' => Ahc\Cli\Output\Color::WHITE,
    'bold' => 1, // You can experiment with 0, 1, 2, 3 ... as well
]);

echo $color->mystyle('My text');

Cursor

Move cursor around, erase line up or down, clear screen.

$cursor = new Ahc\Cli\Output\Cursor;

echo  $cursor->up(1)
    . $cursor->down(2)
    . $cursor->right(3)
    . $cursor->left(4)
    . $cursor->next(0)
    . $cursor->prev(2);
    . $cursor->eraseLine()
    . $cursor->clear()
    . $cursor->clearUp()
    . $cursor->clearDown()
    . $cursor->moveTo(5, 8); // x, y

Progress Bar

Easily add a progress bar to your output:

$progress = new Ahc\Cli\Output\ProgressBar(100);
for ($i = 0; $i <= 100; $i++) {
    $progress->current($i);

    // Simulate something happening
    usleep(80000);
}

You can also manually advance the bar:

$progress = new Ahc\Cli\Output\ProgressBar(100);

// Do something

$progress->advance(); // Adds 1 to the current progress

// Do something

$progress->advance(10); // Adds 10 to the current progress

// Do something

$progress->advance(5, 'Still going.'); // Adds 5, displays a label

You can override the progress bar options to customize it to your liking:

$progress = new Ahc\Cli\Output\ProgressBar(100);
$progress->option('pointer', '>>');
$progress->option('loader', '');

// You can set the progress fluently
$progress->option('pointer', '>>')->option('loader', '');

// You can also use an associative array to set many options in one time
$progress->option([
    'pointer' => '>>',
    'loader'  => ''
]);

// Available options
+---------------+------------------------------------------------------+---------------+
| Option        | Description                                          | Default value |
+===============+======================================================+===============+
| pointer       | The progress bar head symbol                         | >             |
| loader        | The loader symbol                                    | =             |
| color         | The color of progress bar                            | white         |
| labelColor    | The text color of the label                          | white         |
| labelPosition | The position of the label (top, bottom, left, right) | bottom        |
+---------------+------------------------------------------------------+---------------+

Writer

Write anything in style.

$writer = new Ahc\Cli\Output\Writer;

// All writes are forwarded to STDOUT
// But if you specify error, then to STDERR
$writer->errorBold('This is error');

Output formatting

You can call methods composed of any combinations: '<colorName>', 'bold', 'bg', 'fg', 'warn', 'info', 'error', 'ok', 'comment' ... in any order (eg: bgRedFgBlaock, boldRed, greenBold, commentBgPurple and so on ...)

$writer->bold->green->write('It is bold green');
$writer->boldGreen('It is bold green'); // Same as above
$writer->comment('This is grayish comment', true); // True indicates append EOL character.
$writer->bgPurpleBold('This is white on purple background');

Free style

Many colors with one single call: wrap text with tags <method> and </end> For NL/EOL just use <eol> or </eol> or <eol/>.

Great for writing long colorful texts for example command usage info.

$writer->colors('<red>This is red</end><eol><bgGreen>This has bg Green</end>');

Raw output

$writer->raw('Enter name: ');

Tables

Just pass array of assoc arrays. The keys of first array will be taken as heading. Heading is auto inflected to human readable capitalized words (ucwords).

$writer->table([
    ['a' => 'apple', 'b-c' => 'ball', 'c_d' => 'cat'],
    ['a' => 'applet', 'b-c' => 'bee', 'c_d' => 'cute'],
]);

Gives something like:

+--------+------+------+
| A      | B C  | C D  |
+--------+------+------+
| apple  | ball | cat  |
| applet | bee  | cute |
+--------+------+------+

Designing table look and feel

Just pass 2nd param $styles:

$writer->table([
    ['a' => 'apple', 'b-c' => 'ball', 'c_d' => 'cat'],
    ['a' => 'applet', 'b-c' => 'bee', 'c_d' => 'cute'],
], [
    // for => styleName (anything that you would call in $writer instance)
    'head' => 'boldGreen', // For the table heading
    'odd'  => 'bold',      // For the odd rows (1st row is odd, then 3, 5 etc)
    'even' => 'comment',   // For the even rows (2nd row is even, then 4, 6 etc)
]);

// 'head', 'odd', 'even' are all the styles for now
// In future we may support styling a column by its name!

Justify content (Display setting)

If you want to display certain configurations (from your .env file for example) a bit like Laravel does (via the php artisan about command) you can use the justify method.

$writer->justify('Environment');
$writer->justify('PHP Version', PHP_VERSION);
$writer->justify('App Version', '1.0.0');
$writer->justify('Locale', 'en');

Gives something like:

Environment ........................................
PHP Version .................................. 8.1.4
App Version .................................. 1.0.0
Locale .......................................... en

You can use the sep parameter to define the separator to use.

$writer->justify('Environment', '', ['sep' => '-']);
$writer->justify('PHP Version', PHP_VERSION);

Gives something like:

Environment ----------------------------------------
PHP Version .................................. 8.1.4

In addition, the text color, the background color and the thickness of the two texts can be defined via the 3rd argument of this method.

$writer->justify('Cache Enable', 'true', [
    'first' => ['fg' => Ahc\Cli\Output\Color::CYAN], // style of the key
    'second' => ['fg' => Ahc\Cli\Output\Color::GREEN], // style of the value
]);
$writer->justify('Debug Mode', 'false', [
    'first' => ['fg' => Ahc\Cli\Output\Color::CYAN], // style of the key
    'second' => ['fg' => Ahc\Cli\Output\Color::RED], // style of the value
]);

For more details regarding the different color options, see Custom style

Reader

Read and pre process user input.

$reader = new Ahc\Cli\Input\Reader;

// No default, callback fn `ucwords()`
$reader->read(null, 'ucwords');

// Default 'abc', callback `trim()`
$reader->read('abc', 'trim');

// Read at most first 5 chars
// (if ENTER is pressed before 5 chars then further read is aborted)
$reader->read('', 'trim', 5);

// Read but dont echo back the input
$reader->readHidden($default, $callback);

// Read from piped stream (or STDIN) if available without waiting
$reader->readPiped();

// Pass in a callback for if STDIN is empty
// The callback recieves $reader instance and MUST return string
$reader->readPiped(function ($reader) {
    // Wait to read a line!
    return $reader->read();

    // Wait to read multi lines (until Ctrl+D pressed)
    return $reader->readAll();
});

Exceptions

Whenever an exception is caught by Application::handle(), it will show a beautiful stack trace and exit with non 0 status code.

Exception Preview

Autocompletion

Any console applications that are built on top of adhocore/cli can entertain autocomplete of commands and options in zsh shell with oh-my-zsh.

All you have to do is add one line to the end of ~/.oh-my-zsh/custom/plugins/ahccli/ahccli.plugin.zsh:

compdef _ahccli <appname>

Example: compdef _ahccli phint for phint.

That is cumbersome to perform manually, here's a complete command you can copy/paste/run:

One time setup

mkdir -p ~/.oh-my-zsh/custom/plugins/ahccli && cd ~/.oh-my-zsh/custom/plugins/ahccli

[ -f ./ahccli.plugin.zsh ] || curl -sSLo ./ahccli.plugin.zsh https://raw.githubusercontent.com/adhocore/php-cli/master/ahccli.plugin.zsh

chmod 760 ./ahccli.plugin.zsh && cd -
Load ahccli plugin

This is also one time setup.

# Open .zshrc
nano ~/.zshrc

# locate plugins=(... ...) and add ahccli
plugins=(git ... ... ahccli)

# ... then save it (Ctrl + O)

Registering app

# replace appname with real name eg: phint
echo compdef _ahccli appname >> ~/.oh-my-zsh/custom/plugins/ahccli/ahccli.plugin.zsh

Of course you can add multiple apps, just change appname in above command

Then either restart the shell or source the plugin like so:

source ~/.oh-my-zsh/custom/plugins/ahccli/ahccli.plugin.zsh

Trigger autocomplete

appname <tab>            # autocompletes commands               (phint <tab>)
appname subcommand <tab> # autocompletes options for subcommand (phint init <tab>)

Related

Contributors

License

© 2017-2020, Jitendra Adhikari | MIT

Credits

This project is release managed by please.

php-cli's People

Contributors

adhocore avatar alexjeen avatar chantron avatar daemonu avatar dependabot-preview[bot] avatar dimtrovich avatar dongasai avatar mmusselman avatar mrmusselman1 avatar pattisahusiwa avatar shlomohass avatar stylecibot avatar sushilkg avatar tal7aouy avatar usox avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

php-cli's Issues

Support multiline or array option descriptions

$cmd->option('-s|--long-option', ['Line one', 'Next line'], ...);

would be printed like this on help:

  [-s|--long-option]   Line one
                       Next line
  [-l|--some-optiom]   Disable StyleCI
  [-t|--foo-bar]       Disable travis

Great project!

I found this project by packagist, I need it, it's great!
thanks~

Negative argument values and optional variadic arguments / options.

Hi,
First and foremost, thank you for this fantastic project! While there are others out there, I really like this one since it's small, light, simple, and very flexible.

I am having trouble with negative values:

# cmd <offset> --reduce 
$ cmd  -20 --reduce -4 # fails as it parses -20 to -2 -0 and -4 as an option name.

Usually, in some CLI programs, something like this would be evaluated correctly:

$ cmd  "-20" --reduce "-4" # same issue
$ cmd "-20" --reduce=-4 # this one partially works 

It seems that currently, php-cli doesn't support direct negative values unless I'm missing something (please correct me if I'm wrong).

I modified the Normalizer and the Parser to support that if this is truly an issue let me know, and I can create a pull request.

Also, as an artifact, now a syntax as follows is easily implemented:

# cmd <name> [counted...] --variadic [values...] --another <values...>
$ cmd john [12 45 87] --variadic [ 15 20 65 ] --another 98 65 45
# Square brackets act like group boundaries for "in the middle" variadic arguments.
# Still the last variadic argument, without square brackets, functions as normal.

I think it's Cool... and very useful.

Let me know if that's an acceptable improvement

Unable to execute certain commands using `Ahc\Cli\Helper\Shell`

I'm unable to execute the following simplified version of something I'm doing in a project that uses adhocore/php-cli after upgrading from version 0.9.1 to verison v1.2.0. I'm running on CentOS.

$shell = new \Ahc\Cli\Helper\Shell('semanage');
$shell->execute(false);
error_log($shell->getOutput());
error_log($shell->getErrorOutput());
error_log($shell->getExitCode());

In version 0.9.1 the output includes the help text for semanage and the exit code of 0. When I run this in version 1.2.0, I get the exit code of 127.

autocompletion

should support autocompletion for existing commands and options

SC folders to be removed

instead it should be uploaded into imgur.
best is to use new screenshot as these ones are a bit old

Wrong order of arguments when using application

I noticed that when using the cli application and adding two or more arguments for a command, the ordering of the arguments in the help may differ from the setup.

This is what I configured for a certain command:

Bildschirmfoto 2024-01-22 um 14 44 13

And this is what the help for the given command outputs:

Bildschirmfoto 2024-01-22 um 14 44 52

It seems like the output of the help command orders the arguments by name ascending.

Exception Propagation

Is there a method for exception propagation? The handle method currently catches and outputs the stacktrace. I'm looking to capture the exception and send to a centralized issue tracking site. I can capture the $exitCode but the original exception stacktrace and message is what i'm after.

thanks for any help.

Add cursor support for prompts

Hi,

Great library for building CLI applications, thank you! One question regarding prompts. Is it possible to add support to move the cursor to any position in the input? For example, when I press the left cursor, a ^[[D is added. Support for Pos1 and End would be great too.

Thank you

Christian

v1.7.0 is not available on packagist

image

I'm trying to use the latest version of cli in my project, but it's not available on packagist.

image

I went to packagist and realized that indeed, this version is not listed on packagist although the release was published on github. @adhocore , you must have forgotten to update packagist.

Capture d'écran 2024-04-05 161649

Group commands into categories

It would be interesting if the commands could be grouped into categories. a bit like with the laravel console or codeigniter

Like:
--Database
db:create
db:seed

-- Route
route:list
route:generate

Add development tools

It would be nice if you can add coding style and static analyzer? I've checked this repo with PHPStan and found at least 68 errors.

Ahc\Cli\Helper\Shell->getOutput() - No output stream (pipe)

Hi,
I already fixed this issue and I just want to make sure I understand why you chose the NUL file descriptor....

OS : Windows 10
PHP: 8.2
Reproduce:

$shell = new Shell('echo hello');
$shell->execute();
echo $shell->getOutput();
/*
Warning: Undefined array key 1 in D:\server\bsik1\vendor\adhocore\cli\src\Helper\Shell.php on line 239
TypeError stream_get_contents(): Argument #1 ($stream) must be of type resource, null given
(thrown in D:\server\bsik1\vendor\adhocore\cli\src\Helper\Shell.php:239)
*/

I think its because the descriptor for windows is ['file', 'NUL', 'w'].
If I set it to a normal write pipe everything is working as expected :

// Shell.php line 103:
protected function getDescriptors(): array
{
    // $out = $this->isWindows() ? ['file', 'NUL', 'w'] : ['pipe', 'w'];
    $out = $this->isWindows() ? ['pipe', 'w'] : ['pipe', 'w'];
    return [
        self::STDIN_DESCRIPTOR_KEY  => ['pipe', 'r'],
        self::STDOUT_DESCRIPTOR_KEY => $out,
        self::STDERR_DESCRIPTOR_KEY => $out,
    ];
}

so I wonder why you decided to use this descriptor for windows?

Note that on windows running the php-cli tests have many failures...

I already fixed this issue (and tests) - Just reaching out to check before I submit my changes.

Great project BTW 😃

Add support for localized strings

This library output some strings to the console that are hardcoded in English and cannot be localized. It would be nice if these strings could be translated to other languages using for instance something like gettext.
Examples of those strings are:

  • Description of default options ("Show help", "Show version", "Verbosity level") in file Command.php
  • Help messages ("Comand ... version", "Usage:", "Legend...") in Command.php
  • Error messages like 'Invalid value. Please try again!' in Interactor.php

Support for options defined as "--name=value"

Hi, thanks for this great library!
I've noted that the parser does not support the ability to define arguments in this format:

command --option1 --option2="value"

But this works

command --option1 --option2 "value"

I think this whould be a good adition because it's a common way to set option values.
Thanks!

Goodbye

Hello,

I just want to say that it's a pleasure working with you and I'm very very very sorry that you leave the team.
Anyway, maybe you have different career path, I wish you luck on your new journey.

I can't find your email to say goodbye to you in private, so here it is.

Thank you and goodbye 😄

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.