Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Runner, fold implementation into CmdRunner #13

Merged
merged 1 commit into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 0 additions & 196 deletions src/main/php/xp/command/AbstractRunner.class.php

This file was deleted.

173 changes: 165 additions & 8 deletions src/main/php/xp/command/CmdRunner.class.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<?php namespace xp\command;

use lang\reflect\{Modifiers, Package, TargetInvocationException};
use lang\reflection\Type;
use lang\{ClassLoader, ClassNotFoundException, System, Throwable, XPClass};
use rdbms\ConnectionManager;
use util\cmd\{Commands, Config, ParamString};
use io\streams\{ConsoleInputStream, ConsoleOutputStream, InputStream, OutputStream, StringReader, StringWriter};
use lang\reflect\{Package, Modifiers};
use lang\reflection\{InvocationFailed, Type};
use lang\{ClassLoader, ClassNotFoundException, Throwable, Reflection};
use util\cmd\{Arg, Args, Commands, Config, Console, ParamString};
use util\{Properties, PropertyAccess, PropertyManager};
use xp\runtime\Help;

Expand Down Expand Up @@ -38,9 +38,52 @@
* @test util.cmd.unittest.CmdRunnerTest
* @see util.cmd.Command
*/
class CmdRunner extends AbstractRunner {
class CmdRunner {
const DEFAULT_CONFIG_PATH= 'etc';

static function __static() { }
private static $in;
private static $out;
private static $err;
private $verbose= false;

static function __static() {
self::$in= Console::$in;
self::$out= Console::$out;
self::$err= Console::$err;
}

/**
* Reassigns standard input stream
*
* @param io.streams.InputStream in
* @return io.streams.InputStream the given input stream
*/
public function setIn(InputStream $in) {
self::$in= new StringReader($in);
return $in;
}

/**
* Reassigns standard output stream
*
* @param io.streams.OutputStream out
* @return io.streams.OutputStream the given output stream
*/
public function setOut(OutputStream $out) {
self::$out= new StringWriter($out);
return $out;
}

/**
* Reassigns standard error stream
*
* @param io.streams.OutputStream error
* @return io.streams.OutputStream the given output stream
*/
public function setErr(OutputStream $err) {
self::$err= new StringWriter($err);
return $err;
}

/**
* Shows usage
Expand Down Expand Up @@ -143,6 +186,110 @@ protected function listCommands() {
Help::render(self::$err, $markdown, []);
}

/**
* Runs class
*
* @param string $command
* @param util.cmd.ParamString $params
* @param util.cmd.Config $config
* @return int
*/
protected function runCommand($command, $params, $config) {
try {
$type= Reflection::type(Commands::named($command));
} catch (Throwable $e) {
self::$err->writeLine('*** ', $this->verbose ? $e : $e->getMessage());
return 1;
}

// Usage
if ($params->exists('help', '?')) {
$this->commandUsage($type);
return 0;
}

if ($method= $type->method('newInstance')) {
$instance= $method->invoke(null, [$config]);
} else {
$instance= $type->newInstance($config);
}

$instance->in= self::$in;
$instance->out= self::$out;
$instance->err= self::$err;

// Arguments
foreach ($type->methods() as $method) {
if ($args= $method->annotation(Args::class)) {
if ($select= $args->argument('select')) {
$pass= [];
foreach (preg_split('/, ?/', $select) as $def) {
if (is_numeric($def) || '-' === $def[0]) {
$pass[]= $params->value((int)$def);
} else {
sscanf($def, '[%d..%d]', $begin, $end);
$begin ?? $begin= 0;
$end ?? $end= $params->count - 1;

while ($begin <= $end) {
$pass[]= $params->value($begin++);
}
}
}
} else {
$begin= 0;
$end= $params->count;
$pass= array_slice($params->list, 0, $end);
}

try {
$method->invoke($instance, [$pass]);
} catch (InvocationFailed $e) {
self::$err->writeLine("*** Error for arguments {$begin}..{$end}: ", $this->verbose ? $e : $e->getMessage());
return 2;
}
} else if ($arg= $method->annotation(Arg::class)) {
if (null !== ($position= $arg->argument('position'))) {
$select= (int)$position;
$name= '#'.($position + 1);
$short= null;
} else {
$select= $name= $arg->argument('name') ?? strtolower(preg_replace('/^set/', '', $method->name()));
$short= $arg->argument('short');
}

$first= $method->parameter(0);
if (null === $first) {
if (!$params->exists($select, $short)) continue;
$args= [];
} else if (!$params->exists($select, $short)) {
if (!$first->optional()) {
self::$err->writeLine("*** Argument {$name} does not exist!");
return 2;
}

$args= [];
} else {
$args= [$params->value($select, $short)];
}

try {
$method->invoke($instance, $args);
} catch (InvocationFailed $e) {
self::$err->writeLine("*** Error for argument {$name}: ", $this->verbose ? $e->getCause() : $e->getCause()->compoundMessage());
return 2;
}
}
}

try {
return (int)$instance->run();
} catch (Throwable $t) {
self::$err->writeLine('*** ', $t->toString());
return 70; // EX_SOFTWARE according to sysexits.h
}
}

/**
* Main method
*
Expand Down Expand Up @@ -193,7 +340,17 @@ public function run(ParamString $params, Config $config= null) {
}

unset($params->list[-1]);
$classparams= new ParamString(array_slice($params->list, $offset+ 1));
$classparams= new ParamString(array_slice($params->list, $offset + 1));
return $this->runCommand($params->value($offset), $classparams, $config);
}

/**
* Main method
*
* @param string[] args
* @return int
*/
public static function main(array $args) {
return (new self())->run(new ParamString($args));
}
}
Loading
Loading