- First commit
This commit is contained in:
commit
19aa25df1b
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Dave Mc Nicoll
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "mcnd/cli",
|
||||
"description": "A middleware which captures CLI commands and executes them based on a preset definition.",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Dave Mc Nicoll",
|
||||
"email": "info@mcnd.ca"
|
||||
}
|
||||
],
|
||||
"require": {},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mcnd\\CLI\\": "src/"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
namespace Mcnd\CLI;
|
||||
|
||||
use Laminas\Diactoros\Response\TextResponse;
|
||||
use Notes\CLI\CommandFetcher;
|
||||
|
||||
use Psr\Http\Message\ResponseFactoryInterface,
|
||||
Psr\Container\ContainerInterface,
|
||||
Psr\Http\Message\ResponseInterface,
|
||||
Psr\Http\Message\ServerRequestInterface,
|
||||
Psr\Http\Server\MiddlewareInterface,
|
||||
Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class CliMiddleware implements MiddlewareInterface
|
||||
{
|
||||
public \Closure $defaultResponse;
|
||||
|
||||
public ContainerInterface $container;
|
||||
|
||||
public null|CommandFetcher $fetcher;
|
||||
|
||||
public CommandStack $commands;
|
||||
|
||||
protected array $receivedCommandArgv;
|
||||
|
||||
protected array $parsedCommandArgv;
|
||||
|
||||
protected array $parsedOptions = [];
|
||||
|
||||
public function __construct(ContainerInterface $container, callable $defaultResponseInterface = null, null|CommandFetcher $fetcher = null, null|CommandStack $stack = null) {
|
||||
$this->defaultResponse = $defaultResponseInterface;
|
||||
$this->container = $container;
|
||||
$this->fetcher = $fetcher;
|
||||
$this->commands = $stack ?? new CommandStack();
|
||||
}
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
|
||||
{
|
||||
if (php_sapi_name() === 'cli' OR defined('STDIN')) {
|
||||
if ($this->fetcher) {
|
||||
$this->getCommandsFromAttributes();
|
||||
}
|
||||
|
||||
$cliRequest = new CliRequest($request);
|
||||
|
||||
# $cliRequest->setOptions($commands->getOptions());
|
||||
|
||||
if ( $command = $this->commands->matchCommand($cliRequest->command, $cliRequest->options) ) {
|
||||
if ($command->callback) {
|
||||
if (is_string($command->callback)) {
|
||||
list($class, $method) = explode('::', $command->callback);
|
||||
|
||||
return $this->container->make($class)->{$method}($request->withAttribute('cli.command', $command)->withAttribute('cli.request', $cliRequest), []);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $this->printCommand($command);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return call_user_func($this->defaultResponse);
|
||||
}
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
public function getCommandsFromAttributes() : self
|
||||
{
|
||||
$this->commands->merge($this->fetcher->compile());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function printCommand(Command $command) : ResponseInterface
|
||||
{
|
||||
$text = [
|
||||
$command->description, "",
|
||||
"Usage:",
|
||||
" command [options] [arguments]", "",
|
||||
"Options:",
|
||||
" OPTIONS HERE", "",
|
||||
"Available commands:",
|
||||
" COMMANDS HERE", "",
|
||||
];
|
||||
|
||||
return new TextResponse( implode(PHP_EOL, $text) );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace Mcnd\CLI;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class CliRequest
|
||||
{
|
||||
public array $command = [];
|
||||
|
||||
public array $options = [];
|
||||
|
||||
protected string $shortOptions;
|
||||
|
||||
protected array $longOptions;
|
||||
|
||||
public function __construct(
|
||||
public ServerRequestInterface $request
|
||||
) {
|
||||
$this->parseCommandLine();
|
||||
}
|
||||
|
||||
public function matchOptions(string ... $options) : bool
|
||||
{
|
||||
foreach($options as $opt) {
|
||||
if ( $this->matchOption($opt) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function matchOption(string $option) : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function parseCommandLine() : void
|
||||
{
|
||||
$executionString = $this->argv();
|
||||
|
||||
# Removing execution's path
|
||||
array_shift($executionString);
|
||||
|
||||
foreach($executionString as $cmd) {
|
||||
$this->command[] = $cmd;
|
||||
}
|
||||
|
||||
dump($executionString);
|
||||
|
||||
$this->command = $executionString;
|
||||
}
|
||||
|
||||
protected function argv() : array
|
||||
{
|
||||
return $this->request->getServerParams()['argv'];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace Mcnd\CLI;
|
||||
|
||||
class Command
|
||||
{
|
||||
public function __construct(
|
||||
public readonly string $name,
|
||||
public string $description,
|
||||
public array $options = [],
|
||||
public null|Command $parent = null,
|
||||
public \Closure|string|null $callback = null,
|
||||
public bool $isRoot = false,
|
||||
) {}
|
||||
|
||||
public function pushOption(Option|array $option) : void
|
||||
{
|
||||
$this->options[] = array_merge($this->options, $option);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Mcnd\CLI;
|
||||
|
||||
class CommandStack
|
||||
{
|
||||
public array $commands = [];
|
||||
|
||||
public function __construct()
|
||||
{}
|
||||
|
||||
public function merge(CommandStack $stack) : void
|
||||
{
|
||||
$this->commands = array_merge($this->commands, $stack->commands);
|
||||
}
|
||||
|
||||
public function append(Command $command) : void
|
||||
{
|
||||
$this->commands[] = $command;
|
||||
}
|
||||
|
||||
public function matchCommand(array $commands, array $options) : null|Command
|
||||
{
|
||||
$cmd = implode(' ', $commands);
|
||||
|
||||
foreach($this->commands as $command) {
|
||||
if ($command->name === $cmd) {
|
||||
return $command;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Mcnd\CLI;
|
||||
|
||||
class Option
|
||||
{
|
||||
public const ARGUMENT_NONE = 0;
|
||||
|
||||
public const ARGUMENT_OPTIONAL = 1;
|
||||
|
||||
public const ARGUMENT_REQUIRED = 2;
|
||||
|
||||
public function __construct(
|
||||
public array|string $toggle,
|
||||
public string $description = "",
|
||||
public int $argument = self::ARGUMENT_NONE,
|
||||
public mixed $default = null,
|
||||
public mixed $awaiting = null,
|
||||
) {}
|
||||
|
||||
}
|
Loading…
Reference in New Issue