simple-cli / simple-cli
一个简单的命令行框架
Requires
- php: ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.4.0
- pdepend/pdepend: dev-fix/traits-collision as 2.11.0
- phan/phan: ^5.3.1
- phpmd/phpmd: ^2.11.1
- phpstan/phpstan: ^1.2.0
- phpunit/phpunit: ^9.5.10
- squizlabs/php_codesniffer: ^3.5.8
- vimeo/psalm: ^4.13.1
This package is auto-updated.
Last update: 2024-08-26 19:08:13 UTC
README
一个面向对象和无需依赖的简单 CLI 框架。
特性
- 自动文档。使用可用的命令、参数和选项自动生成
--help
。 - 使用 PHP 8 属性的清洁语法。
- 检测可能的输入错误并自动建议。
- 基于文档注释以保持代码的超清洁。
- 支持颜色。
- 支持交互式命令和 CLI 输入的自动完成。
- 提供预定义命令:
usage
和version
。 - 提供预定义选项:
--help
、--quiet
和--verbose
。 - 提供用于创建程序和命令引导的 CLI。
- 将您的程序构建为 PHAR 文件。
以下文档是为 simple-cli 2 编写的,它需要 PHP 8 并支持属性和注释。
simple-cli 1 与 PHP >= 7.1 兼容,仅支持注释。
创建命令行程序
您可以将您的命令行程序添加到任何现有的 composer 应用程序中,或者使用 composer init
创建一个新的。
然后添加 simple-cli
composer require simple-cli/simple-cli
假设您的应用程序允许添加或乘以两个参数,并且您想在 CLI 中调用 easy-calc
,那么您需要创建一个扩展 SimpleCli\SimpleCli
的 EasyCalc
类。
因此,首先检查您的 composer.json 中是否有 PSR 自动加载设置
"autoload": { "psr-4": { "MyVendorName\\": "src/MyVendorName/" } },
(您可能需要运行 composer update
或 composer dump-autoload
以使自动加载生效。)
然后创建该类,使其可以被自动加载,所以按照上面的例子,我们可以创建文件 src/MyVendorName/CliApp/EasyCalc.php
<?php namespace MyVendorName\CliApp; use SimpleCli\SimpleCli; class EasyCalc extends SimpleCli { public function getCommands() : array { return []; // Your class needs to implement the getCommands(), we'll see later what to put in here. } }
默认情况下,程序名称将从类名计算得出,这里 EasyCalc
变为 easy-calc
,但您可以在类中添加 protected ?string $name = 'my-custom-name';
来选择任何名称。
现在您可以从控制台运行它
vendor/bin/simple-cli create "MyVendorName\CliApp\EasyCalc"
它将为 Unix 系统创建 bin/easy-calc
,为 Windows OS 创建 bin/easy-calc.bat
。
您可以将它添加到 composer.json 中,这样用户就可以通过 composer 调用它
"bin": [ "bin/easy-calc" ],
现在我们来测试您的 CLI 程序
bin/easy-calc
如你所见,simple-cli 默认提供了两个命令:list
(这是当用户没有选择命令时的默认命令,列出可用的命令)和 version
(将显示您的 composer 包的版本和您可能添加的版本详细信息)。
请注意,如果您不想发布它,您可以自定义要显示的版本,或者禁用任何默认命令
class EasyCalc extends SimpleCli { public function getCommands() : array { return []; } public function getVersion(): string { return '1.0.0'; } }
或者您可以选择禁用任何默认命令
class EasyCalc extends SimpleCli { public function getCommands() : array { return [ 'version' => false, ]; } }
构建为 PHAR
Simple-CLI 允许您将您的程序打包为单个 PHAR 文件。
它将自动打包您 src
文件夹中的所有文件,您的主类所在的不同根文件夹,以及 vendor
文件夹。
因此,为了使其轻量,请从这些文件夹中删除任何不需要的文件,例如使用
composer install --no-dev
然后简单地运行
./bin/simple-cli build-phar
在您的工作目录内。
您也可以指定包的版本
PHAR_PACKAGE_VERSION=2.0.0 ./bin/simple-cli build-phar
因此,使用 GitHub Actions,在推送时自动构建您的项目为 PHAR 可以轻松完成
.github/workflows/phar.yml:
name: Generate phar on: push: branches: [ '**' ] pull_request: branches: [ '**' ] create: tags: - "*" release: types: - created jobs: build: runs-on: ubuntu-latest timeout-minutes: 15 env: COMPOSER_NO_INTERACTION: 1 name: Build PHAR steps: - name: Checkout code uses: actions/checkout@v2 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.0' coverage: none tools: composer:v2 - name: Cache Composer packages id: composer-cache uses: actions/cache@v2 with: path: vendor key: phar-${{ runner.os }}-php${{ matrix.php }}-${{ hashFiles('**/composer.lock') }} - name: Install dependencies run: composer install --prefer-dist --no-progress --no-dev - name: Build run: | chmod +x ./bin/simple-cli ./bin/simple-cli build-phar env: PHAR_PACKAGE_VERSION: ${{ secrets.GITHUB_REF }} - name: Upload my-cli.phar uses: actions/upload-artifact@v2 with: name: my-cli.phar path: my-cli.phar - name: Release my-cli.phar if: github.event_name == 'release' uses: skx/github-action-publish-binaries@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: args: 'my-cli.phar'
将 my-cli
替换为您的程序名称。
添加命令
现在您的 CLI 需要实际的命令。例如,要创建一个 add
命令,您可以创建一个 MyVendorName\CliApp\Command\Add
类
<?php namespace MyVendorName\CliApp\Command; use SimpleCli\Command; use SimpleCli\Options\Help; use SimpleCli\SimpleCli; /** * Sum arguments. */ class Add implements Command { use Help; public function run(SimpleCli $cli): bool { } }
然后在您的CLI中添加这个带有名称的命令
class EasyCalc extends SimpleCli { public function getCommands() : array { return [ 'add' => \MyVendorName\CliApp\Command\Add::class, ]; } }
如果您再次运行 bin/easy-calc
(或 bin/easy-calc list
),现在您将看到可用的命令 add
。您在 /** */
中放置的注释将显示在描述中。
如果您运行 bin/easy-calc add --help
(或 bin/easy-calc add -h
),您将看到基于定义的选项和参数的命令文档。如您所见,只有由特质 SimpleCli\Options\Help
(我们强烈建议在您的命令中始终使用此特质)提供的 --help
选项(或 -h
别名)。
添加参数
现在让我们添加一些参数,以便您的命令实际上可以做一些事情。
<?php namespace MyVendorName\CliApp\Command; use SimpleCli\Attribute\Argument; use SimpleCli\Command; use SimpleCli\Options\Help; use SimpleCli\SimpleCli; /** * Sum arguments. */ class Add implements Command { use Help; #[Argument('The first number')] public float $number1 = 0; #[Argument('The second number')] public float $number2 = 0; public function run(SimpleCli $cli): bool { $cli->write($this->number1 + $this->number2); return true; } }
#[Argument]
属性允许 simple-cli 知道它是一个参数。
参数类型将从属性类型提示中获取,如果您需要比简单的 array
更精确的类型,例如 string[]
,而不是简单地使用 array
,您可以使用 PHPDoc 中的 @var
注释来指定它,例如 /** @var string[] */
将被使用,否则类型将根据默认值推断。因此,public float $number2;
将被视为 float
,而 public $number2 = false;
将被视为 bool
。
如果您运行 bin/easy-calc add --help
,您将看到它们在帮助中显示,包括它们的描述、类型和默认值。
现在是执行您的命令的时候了
bin/easy-calc add 2 3
它输出 5
🚀
请注意,run()
必须返回一个布尔值
- 对于成功的命令(退出代码 0)返回
true
- 对于错误(退出代码 1)返回
false
您还可以使用属性 #[Rest]
允许无限数量的参数。rest arguments 变量将是一个包含所有其他参数的数组。
因此,如果您有 2 个 #[Argument]
和一个 #[Rest]
,那么如果用户使用 5 个参数调用您的命令,第一个参数将传递到第一个 #[Argument]
,第二个参数传递到第二个 #[Argument]
,而其他 3 个参数则作为一个数组传递到 #[Rest]
参数。
当然,您也可以将 #[Rest]
与任何其他参数一起使用,因此对于我们的 add
命令,它可以是
<?php namespace MyVendorName\CliApp\Command; use SimpleCli\Attribute\Rest; use SimpleCli\Command; use SimpleCli\Options\Help; use SimpleCli\SimpleCli; /** * Sum arguments. */ class Add implements Command { use Help; /** @var float[] */ #[Rest('The numbers to sum')] public array $numbers = []; public function run(SimpleCli $cli): bool { $cli->write(array_sum($this->numbers)); return true; } }
现在您可以以任意数量的参数调用
bin/easy-calc build 2 3 1.5
输出:6.5
SimpleCli\Annotation\*
导入,如 use SimpleCli\Annotation\argument;
可用于帮助 IDE 自动完成,但不是必需的。
添加选项
simple-cli 提供 3 个标准选项。您已经了解 --help -h
作为 SimpleCli\Options\Help
特质,您可以在您的命令中简单地使用 use
。
但还有 --quiet -q
作为 SimpleCli\Options\Quiet
,允许用户静音输出。如果您在命令中使用此特质,并且用户传递选项 --quiet
或 -q
,则方法 $cli->write()
和 $cli->writeLine()
(以及所有输出方法)将不再输出任何内容。
您还可以使用 --verbose -v
使用 SimpleCli\Options\Verbose
<?php namespace MyVendorName\CliApp\Command; use SimpleCli\Command; use SimpleCli\Options\Verbose; use SimpleCli\SimpleCli; /** * Sum arguments. */ class Add implements Command { use Verbose; public function run(SimpleCli $cli): bool { // ... if ($this->verbose) { $cli->writeLine('Log some additional info', 'light_cyan'); } // ... } }
您还可以使用 #[Option]
属性创建自己的选项
<?php namespace MyVendorName\CliApp\Command; use SimpleCli\Attribute\Option; use SimpleCli\Command; use SimpleCli\SimpleCli; /** * Sum arguments. */ class Add implements Command { #[Option('Something the command can use.')] public $foo = 'default'; #[Option( name: 'show-foo', description: 'Whether foo should be displayed or not.', )] public $showFoo = false; public function run(SimpleCli $cli): bool { if ($this->showFoo) { $cli->write($this->foo, 'red'); } return true; } }
bin/easy-calc --show-foo --foo=bar
输出:bar
(红色)。
请注意,您可以在属性中传递选项的名称和别名:#[Option(name: ['some-name', 'other-name'], alias: ['s', 'o'])]
这意味着 --some-name
、--other-name
、-s
和 -o
都将存储在同一个选项变量中。
此外,请注意,如果选项是布尔类型(显式类型为 bool
、@var bool
或布尔默认值)并且具有别名,则它们可以合并。如果您有 #[Option(name: 'show-foo', alias: 's')
和 #[Option(name: 'verbose', alias: 'v')
,并且通过 CLI 传递 -vs
,则两个选项都将为 true
。
对于非布尔选项,可以使用 --foo bar
或 --foo=bar
设置值,两者都有效。并且选项可以放在任何位置(在参数之前、之后或之间)。
最后,如果您没有设置名称,仅使用 #[Option]
属性,选项将与其变量具有相同的名称,如果可用,则将首字母用作别名。
注解
可以一行内编写 @option
、@argument
和 @rest
的注解。
class Add implements Command { #[Argument('First argument.')] public $first = 'main'; #[Rest('Other arguments.')] public $others = []; #[Option('Something the command can use.')] public $foo = 'default'; #[Option( name: 'show-foo', alias: 'f', description: 'Whether foo should be displayed or not.', )] public $showFoo = false; // run(...) }
使用此语法,无法进行 @var
类型指定,因此类型将自动使用属性类型提示或从默认值推断。
进度条小部件
use SimpleCli\Command; use SimpleCli\SimpleCli; use SimpleCli\Widget\ProgressBar; class SomeCommand implements Command { public function run(SimpleCli $cli): bool { $bar = new ProgressBar($cli); $bar->start(); $bar->setValue(0.3); $bar->setValue(0.7); $bar->setValue(1); $bar->end(); return true; } }
这将显示 30% 和一个 30% 填充的条,然后替换为 70% 的条,最后为满条。看起来如下:
| 70% [===================================> ]
ProgressBar
将其设置和使用的字符作为公共属性暴露,因此您可以简单地设置以自定义条样式:[源代码](https://github.com/kylekatarnls/simple-cli/blob/master/src/SimpleCli/Widget/ProgressBar.php)
让我们看看一个具体的例子
public function run(SimpleCli $cli): bool { $bar = new ProgressBar($cli); // Assuming we have a 214MB file being downloaded in a parallel process $bar->total = 214 * 1024 * 1024; // Let's customize a bit the style: $bar->width = 20; // inner bar size $dash = str_repeat('─', $bar->width); // Let's draw a swaure around the bar $bar->start = " ┌{$dash}┐\n"; $bar->barStart = '│'; $bar->barEnd = '│'; $bar->after = "\n └{$dash}┘"; $bar->cursor = ''; // remove bar middle cursor // Colorize some characters for bar (left) and empty bar (right) $bar->bar = $cli->colorize('█', 'cyan'); $bar->emptyBar = $cli->colorize('░', 'light_gray'); // as ->after contains a new line, we have // to rewind 1 more line $bar->rewind = "\033[1A\r"; $bar->start(); while ($bar->isInProgress()) { // while value < total $bar->setValue(filesize('partially-downloaded-file.part')); usleep(250000); // Let's refresh every 250ms } $bar->end(); return true; }
表格小部件
use SimpleCli\Command; use SimpleCli\SimpleCli; use SimpleCli\Widget\Table; use SimpleCli\Widget\Cell; class SomeCommand implements Command { public function run(SimpleCli $cli): bool { $data = [ [ new Cell('Artist', Cell::ALIGN_CENTER), new Cell('Song', Cell::ALIGN_CENTER), new Cell('Year', Cell::ALIGN_CENTER), ], [$cli->colorize('Nina Simone', 'cyan'), 'Feeling Good', 1965], ['The Marvelettes', 'Please Mr. Postman', 1961], ]; $table = new Table($data); $cli->writeLine($table->format()); return true; } }
Table
仅接受数据并将它们格式化为文本表格,因此它基本上可以在 SimpleCli
上下文之外使用。
它提供了一个非常简单的方式来自定义模板。您只需要提供一个示例,使用 1
、2
、3
和 4
作为 2x2 表格的内容,然后它将您的示例应用到任何大小的表格上。
$table = new Table([ ['One', 'Two', 'Three'], ['*'], ['Hello', 'World', '!'], ]); $table->template = '╔═══╤═══╗ ║ 1 │ 2 ║ ╟───┼───╢ ║ 3 │ 4 ║ ╚═══╧═══╝';
输出
╔═══════╤═══════╤═══════╗
║ One │ Two │ Three ║
╟───────┼───────┼───────╢
║ * │ │ ║
╟───────┼───────┼───────╢
║ Hello │ World │ ! ║
╚═══════╧═══════╧═══════╝
为了防止代码中的丑陋缩进,您可以使用 !template!
在给定位置开始模板
$table->template = ' !template! ╔═══╤═══╗ ║ 1 │ 2 ║ ╟───┼───╢ ║ 3 │ 4 ║ ╚═══╧═══╝';
相当于上面的模板,因为在 !
之前的所有缩进都将被忽略。
您还可以设置用作填充的字符串
$table->fill = '_-';
最后,您可以设置每列的默认对齐方式
$table->align = [Cell::ALIGN_LEFT, Cell::ALIGN_CENTER, Cell::ALIGN_RIGHT];
您仍然可以使用以下方式覆盖给定单元格的对齐方式
new Cell('Text', Cell::ALIGN_CENTER)
Cell
还允许您跨列
// 2 columns-wide (new Cell('Text'))->cols(2) // 3 columns-wide centered (new Cell('Text', Cell::ALIGN_CENTER))->cols(3)
文本占用的空间将平均分配到各列中。
最后,您可以使用 $cli->colorize()
将颜色添加到模板或单元格内容中。考虑到了颜色特殊字符,因此无论是否有颜色,显示都将保持正确对齐。
API 参考
在上面的例子中,您可以看到您的命令 run(SimpleCli $cli)
方法获得了一个 SimpleCli 实例。 $cli
是您的程序对象,是扩展 SimpleCli
的类的实例,因此在上面的例子中,它是 EasyCalc
的实例,这意味着您可以通过 $cli
访问您在子类中定义的所有方法(或覆盖以自定义您的程序)以及从继承的 SimpleCli
类中可用的所有方法。
getVersionDetails(): string
获取要显示在版本命令中的详细信息。
getVersion(): string
获取处理 CLI 程序的包的 composer 版本。
displayVariable(int $length, string $variable, array $definition, mixed $defaultValue): void
输出标准命令变量(参数或选项)。
autocomplete(string $start): array
获取给定起始处的可能完成项。
read(string $prompt, Closure|callable|array|null $completion): string
提示用户 $prompt 并返回 CLI 输入。
getStandardInput(): string
获取命令通过:echo "foobar" | command 或:command < some-file.txt 接收的初始 stdin 内容。如果没有传递输入,则返回空字符串。
getColors(): array
每个文本颜色名称的代码列表。
getBackgrounds(): array
每个背景颜色名称的代码列表。
isMuted(): bool
如果 CLI 程序被静音(安静),则返回 true。
setMuted(bool $muted): void
设置静音状态。
mute(): void
静音程序(不再输出)。
unmute(): void
取消静音程序(启用输出)。
enableColors(): void
在命令行中启用颜色支持。
disableColors(): void
在命令行中禁用颜色支持。
setEscapeCharacter(string $escapeCharacter): void
在 CLI 字符串中设置用于转义命令的自定义字符串。
setColors(array $colors, array $backgrounds): void
设置颜色调色板。
colorize(string $text, string $color, string $background): string
返回具有给定颜色和背景颜色的 $text。
rewind(int $length): void
将 CLI 光标回退 $length 个字符,如果省略 $length,则使用最后写入的字符串长度。
write(string $text, string $color, string $background): void
以给定颜色和背景颜色输出 $text。
writeLine(string $text, string $color, string $background): void
以给定颜色和背景颜色输出 $text 并添加新行。
rewrite(string $text, string $color, string $background): void
用给定颜色和背景颜色的 $text 替换最后写入的行。
rewriteLine(string $text, string $color, string $background): void
用给定颜色和背景颜色的 $text 替换最后写入的行并重新添加新行。
getName(): string
获取 CLI 程序的名称。
getFile(): string
获取 CLI 中调用的当前程序文件。
getCommands(): array
获取命令列表,排除 SimpleCli 提供的命令。
getAvailableCommands(): array
获取包含 SimpleCli 提供的命令的命令列表。
getCommand(): string
获取选择的命令。
getParameters(): array
获取未经筛选的原始参数(选项和参数)。
getParameterValue(string $parameter, array $parameterDefinition): string|int|float|bool|null
根据定义中的类型转换参数/选项。
getArguments(): array
获取当前筛选参数列表。
getExpectedArguments(): array
获取预期参数的定义。
getRestArguments(): array
获取筛选参数的其余部分。
getExpectedRestArgument(): array
如果提供了 @rest 属性,则获取其余参数的定义。
getOptions(): array
获取当前筛选选项列表。
getExpectedOptions(): array
获取预期选项的定义。
getOptionDefinition(string $name): array
获取指定名称或别名的选项定义及其预期类型/值。
getPackageName(): string
获取处理 CLI 程序的 composer 包名。
setVendorDirectory(string $vendorDirectory): void
设置应包含 composer/installed.json 的包的供应商。
getVendorDirectory(): string
获取应包含 composer/installed.json 的包的供应商。
getInstalledPackages(): array<string|int, array<string, string>>
获取 composer 安装的包列表。
getInstalledPackage(string $name): SimpleCli\Composer\InstalledPackage
获取给定已安装包的数据。
getInstalledPackageVersion(string $name): string
获取给定已安装包的版本。
extractClassNameDescription(string $className): string
获取给定类的 PHP 注释文档块内容。
getAttributeOrAnnotation(string $source, string $annotation, ReflectionProperty $property, string $attributeClass): object|string|null
如果存在,则获取属性或从 PHP 注释文档块中提取注释内容。
extractAnnotation(string $source, string $annotation): string
从 PHP 注释文档块中提取注释内容。