Browse Source

Replicate previous usage text

getopt
J. King 5 months ago
parent
commit
2bfecbffdc
  1. 98
      lib/CLI.php
  2. 4
      tests/cases/CLI/TestCLI.php

98
lib/CLI.php

@ -15,26 +15,12 @@ use GetOpt\GetOpt;
use GetOpt\Command; use GetOpt\Command;
use GetOpt\Operand; use GetOpt\Operand;
use GetOpt\Option; use GetOpt\Option;
use GetOpt\ArgumentException;
class CLI { class CLI {
protected function usage($prog): string { protected $cli;
$prog = basename($prog);
return str_replace("arsse.php", $prog, self::USAGE);
}
/** @codeCoverageIgnore */ public function __construct() {
protected function loadConf(): bool {
Arsse::bootstrap();
return true;
}
protected function resolveFile($file, string $mode): string {
// TODO: checking read/write permissions on the provided path may be useful
$stdinOrStdout = in_array($mode, ["r", "r+"]) ? "php://input" : "php://output";
return ($file === "-" ? null : $file) ?? $stdinOrStdout;
}
public function dispatch(array $argv = null): int {
$cli = new GetOpt([], []); $cli = new GetOpt([], []);
$cli->addOptions([ $cli->addOptions([
Option::create("h", "help"), Option::create("h", "help"),
@ -93,8 +79,75 @@ class CLI {
Command::create("conf save-defaults", [$this, "confSaveDefaults"]) Command::create("conf save-defaults", [$this, "confSaveDefaults"])
->addOperand(Operand::create("file", Operand::OPTIONAL)), ->addOperand(Operand::create("file", Operand::OPTIONAL)),
]); ]);
$this->cli = $cli;
}
public function usage(string $prog, bool $help = false): string {
$cli = $this->cli;
$out = "Usage:\n";
foreach ($cli->getCommands() as $cmd) {
$out .= " $prog ".$cmd->getName();
foreach ($cmd->getOperands() as $op) {
$rep = "<".$op->getName().">";
if (!$op->isRequired()) {
$rep = "[$rep]";
}
$out .= " $rep";
}
foreach ($cmd->getOptions() as $op) {
$arg = $op->getArgument();
$rep = "--".$op->getName()."";
if ($op->getMode() === GetOpt::REQUIRED_ARGUMENT) {
$rep = "$rep=".$arg->getName();
}
if ($short = $op->getShort()) {
$srep = "-$short";
$rep = "$srep|$rep";
}
$out .= " [$rep]";
}
$out .= "\n";
}
foreach ($cli->getOptionObjects() as $op) {
$rep = "--".$op->getName()."";
if ($short = $op->getShort()) {
$srep = "-$short";
$rep = "$srep|$rep";
}
$out .= " $prog $rep\n";
}
if ($help) {
$out .= <<<HELP_TEXT
\nThe Arsse command-line interface can be used to perform various administrative
tasks such as starting the newsfeed refresh service, managing users, and
importing or exporting data.
See the manual page for more details:
man arsse\n
HELP_TEXT;
}
return $out;
}
/** @codeCoverageIgnore */
protected function loadConf(): bool {
Arsse::bootstrap();
return true;
}
protected function resolveFile($file, string $mode): string {
// TODO: checking read/write permissions on the provided path may be useful
$stdinOrStdout = in_array($mode, ["r", "r+"]) ? "php://input" : "php://output";
return ($file === "-" ? null : $file) ?? $stdinOrStdout;
}
public function dispatch(array $argv = null): int {
$cli = $this->cli;
$argv = $argv ?? $_SERVER['argv'];
$prog = array_shift($argv);
try { try {
$cli->process(array_slice($argv, 1)); $cli->process($argv);
// ensure the require extensions are loaded // ensure the require extensions are loaded
Arsse::checkExtensions(...Arsse::REQUIRED_EXTENSIONS); Arsse::checkExtensions(...Arsse::REQUIRED_EXTENSIONS);
$cmd = $cli->getCommand(); $cmd = $cli->getCommand();
@ -109,7 +162,7 @@ class CLI {
if ($cli->getOption("version")) { if ($cli->getOption("version")) {
echo Arsse::VERSION.\PHP_EOL; echo Arsse::VERSION.\PHP_EOL;
} else { } else {
echo $cli->getHelpText(); echo $this->usage($prog, (bool) $cli->getOption("help"));
} }
return 0; return 0;
case "daemon": case "daemon":
@ -137,7 +190,7 @@ class CLI {
$file = $this->resolveFile($cli->getOperand("file"), "r"); $file = $this->resolveFile($cli->getOperand("file"), "r");
return (int) !Arsse::$obj->get(OPML::class)->importFile($file, $u, (bool) $cli->getOption("flat"), (bool) $cli->getOption("replace")); return (int) !Arsse::$obj->get(OPML::class)->importFile($file, $u, (bool) $cli->getOption("flat"), (bool) $cli->getOption("replace"));
case "token list": case "token list":
$u = $cli->getOperand("username"); return $this->tokenList($cli->getOperand("username"));
case "token create": case "token create":
echo Arsse::$obj->get(Miniflux::class)->tokenGenerate($cli->getOperand("username"), $cli->getOperand("label")).\PHP_EOL; echo Arsse::$obj->get(Miniflux::class)->tokenGenerate($cli->getOperand("username"), $cli->getOperand("label")).\PHP_EOL;
return 0; return 0;
@ -183,7 +236,12 @@ class CLI {
default: default:
throw new Exception("constantUnknown", $cmd); // @codeCoverageIgnore throw new Exception("constantUnknown", $cmd); // @codeCoverageIgnore
} }
} catch (ArgumentException $e) {
// invalid command was entered
$this->logError(trim($this->usage($prog)));
return 1;
} catch (AbstractException $e) { } catch (AbstractException $e) {
// some other error
$this->logError($e->getMessage()); $this->logError($e->getMessage());
return $e->getCode(); return $e->getCode();
} }

4
tests/cases/CLI/TestCLI.php

@ -52,7 +52,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideHelpText */ /** @dataProvider provideHelpText */
public function testPrintHelp(string $cmd, string $name): void { public function testPrintHelp(string $cmd, string $name): void {
$this->assertConsole($cmd, 0, str_replace("arsse.php", $name, CLI::USAGE)); $this->assertConsole($cmd, 0, trim($this->cli->get()->usage($name, true)));
$this->cli->loadConf->never()->called(); $this->cli->loadConf->never()->called();
} }
@ -169,9 +169,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
$str = implode(PHP_EOL, $list); $str = implode(PHP_EOL, $list);
return [ return [
["arsse.php user list", $list, 0, $str], ["arsse.php user list", $list, 0, $str],
["arsse.php user", $list, 0, $str],
["arsse.php user list", [], 0, ""], ["arsse.php user list", [], 0, ""],
["arsse.php user", [], 0, ""],
]; ];
} }

Loading…
Cancel
Save