*/
abstract class CLICommand
{
- protected $argc;
- protected $argv;
- protected $cmds = array();
- protected $args = array();
- protected $typs = array();
-
- function __construct($argc, array $argv)
- {
- $this->argc = $argc;
- $this->argv = $argv;
- $this->cmds = self::getCommands($this);
- $this->typs = self::getArgTyps($this);
-
- if ($argc < 2)
- {
- self::error("No command given, check ${argv[0]} help\n");
- }
- elseif (!isset($this->cmds[$argv[1]]['run']))
- {
- self::error("Unknown command '${argv[1]}', check ${argv[0]} help\n");
- }
- else
- {
- $command = $argv[1];
- }
-
- if (isset($this->cmds[$command]['arg']))
- {
- $this->args = call_user_func(array($this, $this->cmds[$command]['arg']));
- $i = 1;
- $missing = false;
- while (++$i < $argc)
- {
- if ($argv[$i][0] == '-')
- {
- if (strlen($argv[$i]) == 2 && isset($this->args[$argv[$i][1]]))
- {
- $arg = $argv[$i][1];
- if (++$i >= $argc)
- {
- self::error("Missing argument to parameter '$arg' of command '$command', check ${argv[0]} help\n");
- }
- else
- {
- $this->args[$arg]['val'] = $this->checkArgTyp($arg, $i, $argc, $argv);
- }
- }
- else
- {
- self::error("Unknown parameter '${argv[$i]}' to command $command, check ${argv[0]} help\n");
- }
- }
- else
- {
- break;
- }
- }
- if (isset($this->args['']))
- {
- if ($i >= $argc)
- {
- if (isset($this->args['']['require']) && $this->args['']['require'])
- {
- echo "Missing default trailing arguments to command $command, check ${argv[0]} help\n";
- $missing = true;
- }
- }
- else
- {
- $this->args['']['val'] = array();
- while($i < $argc)
- {
- $this->args['']['val'][] = $argv[$i++];
- }
- }
- }
- else if ($i < $argc)
- {
- self::error("Unexpected default arguments to command $command, check ${argv[0]} help\n");
- }
- $missing = '';
- foreach($this->args as $arg => $inf)
- {
- if (strlen($arg) && !isset($inf['val']) && isset($inf['required']) && $inf['required'])
- {
- $missing .= "Missing parameter '-$arg' to command $command.\n";
- }
- }
- if (strlen($missing))
- {
- $missing .= "Check ${argv[0]} help\n";
- self::error($missing);
- }
- }
-
- call_user_func(array($this, $this->cmds[$command]['run']), $this->args);
- }
-
- static function error($msg, $exit_code = 1)
- {
- fprintf(STDERR, $msg);
- exit($exit_code);
- }
-
- function checkArgTyp($arg, $i, $argc, $argv)
- {
- $typ = $this->args[$arg]['typ'];
-
- if (isset($this->typs[$typ]['typ']))
- {
- return call_user_func(array($this, $this->typs[$typ]['typ']), $argv[$i], $this->args[$arg], $arg);
- }
- else
- {
- return $argv[$i];
- }
- }
-
- static function getSubFuncs(CLICommand $cmdclass, $prefix, array $subs)
- {
- $a = array();
- $r = new ReflectionClass($cmdclass);
- $l = strlen($prefix);
-
- foreach($r->getMethods() as $m)
- {
- if (substr($m->name, 0, $l) == $prefix)
- {
- foreach($subs as $sub)
- {
- $what = substr($m->name, $l+strlen($sub)+1);
- $func = $prefix . $sub . '_' . $what;
- $what = str_replace('_', '-', $what);
- if ($r->hasMethod($func))
- {
- if (!isset($a[$what]))
- {
- $a[$what] = array();
- }
- $a[$what][$sub] = /*$m->class . '::' .*/ $func;
- }
- }
- }
- }
- return $a;
- }
-
- static function getCommands(CLICommand $cmdclass)
- {
- return self::getSubFuncs($cmdclass, 'cli_cmd_', array('arg','inf','run'));
- }
-
- static function getArgTyps(CLICommand $cmdclass)
- {
- return self::getSubFuncs($cmdclass, 'cli_arg_', array('typ'));
- }
-
- static function cli_arg_typ_bool($arg, $cfg, $key)
- {
- return (bool)$arg;
- }
-
- static function cli_arg_typ_int($arg, $cfg, $key)
- {
- if ((int)$arg != $arg)
- {
- self::error("Argument to -$key must be an integer.\n");
- }
- return (int)$arg;
- }
-
- static function cli_arg_typ_regex($arg, $cfg, $key)
- {
- if (strlen($arg))
- {
- if (strlen($arg) > 1 && $arg[0] == $arg[strlen($arg)-1] && strpos('/,', $arg) !== false)
- {
- return $arg;
- }
- else
- {
- return '/' . $arg . '/';
- }
- }
- else
- {
- return NULL;
- }
- }
-
- static function cli_arg_typ_select($arg, $cfg, $key)
- {
- if (!in_array($arg, array_keys($cfg['select'])))
- {
- self::error("Parameter value '$arg' not one of '" . join("', '", array_keys($cfg['select'])) . "'.\n");
- }
- return $arg;
- }
-
- static function cli_arg_typ_dir($arg, $cfg, $key)
- {
- $f = realpath($arg);
- if ($f===false || !file_exists($f) || !is_dir($f))
- {
- self::error("Requested path '$arg' does not exist.\n");
- }
- return $f;
- }
-
- static function cli_arg_typ_file($arg, $cfg, $key)
- {
- $f = realpath($arg);
- if ($f===false || !file_exists($f))
- {
- self::error("Requested file '$arg' does not exist.\n");
- }
- return $f;
- }
-
- static function cli_arg_typ_filenew($arg, $cfg, $key)
- {
- $d = dirname($arg);
- $f = realpath($d);
- if ($f === false)
- {
- self::error("Path for file '$arg' does not exist.\n");
- }
- return $f . substr($arg, strlen($d));;
- }
-
- static function cli_arg_typ_filecont($arg, $cfg, $key)
- {
- return file_get_contents(self::cli_arg_typ_file($arg, $cfg, $key));
- }
-
- function cli_get_SP2($l1, $arg_inf)
- {
- return str_repeat(' ', $l1 + 2 + 4 + 8);
- }
-
- function cli_get_SP3($l1, $l2, $arg_inf)
- {
- return str_repeat(' ', $l1 + 2 + 4 + 8 + 2 + $l2 + 2);
- }
-
- static function cli_cmd_inf_help()
- {
- return "This help or help for a selected command.";
- }
-
- private function cli_wordwrap($what, $l, $sp)
- {
- $p = max(79 - $l, 40); // minimum length for paragraph
- $b = substr($what, 0, $l); // strip out initial $l
- $r = substr($what, $l); // remainder
- $r = str_replace("\n", "\n".$sp, $r); // in remainder replace \n's
- return $b . wordwrap($r, $p, "\n".$sp);
- }
-
- private function cli_help_get_args($func, $l, $sp, $required)
- {
- $inf = "";
- foreach(call_user_func($func, $l, $sp) as $arg => $conf)
- {
- if ((isset($conf['required']) && $conf['required']) != $required)
- {
- continue;
- }
- if (strlen($arg))
- {
- $arg = "-$arg ";
- }
- else
- {
- $arg = "... ";
- }
- $sp2 = $this->cli_get_SP2($l, $inf);
- $l2 = strlen($sp2);
- $inf .= $this->cli_wordwrap($sp . $arg . $conf['inf'], $l2, $sp2) . "\n";
- if (isset($conf['select']) && count($conf['select']))
- {
- $ls = 0;
- foreach($conf['select'] as $opt => $what)
- {
- $ls = max($ls, strlen($opt));
- }
- $sp3 = $this->cli_get_SP3($l, $ls, $inf);
- $l3 = strlen($sp3);
- foreach($conf['select'] as $opt => $what)
- {
- $inf .= $this->cli_wordwrap($sp2 . " " . sprintf("%-${ls}s ", $opt) . $what, $l3, $sp3) . "\n";
- }
- }
- }
- if (strlen($inf))
- {
- if ($required)
- {
- return $sp . "Required arguments:\n\n" . $inf;
- }
- else
- {
- return $sp . "Optional arguments:\n\n". $inf;
- }
- }
- }
-
- function cli_cmd_arg_help()
- {
- return array('' => array('typ'=>'any','val'=>NULL,'inf'=>'Optional command to retrieve help for.'));
- }
-
- function cli_cmd_run_help()
- {
- $argv = $this->argv;
- $which = $this->args['']['val'];
- if (isset($which))
- {
- if (count($which) != 1)
- {
- self::error("More than one command given.\n");
- }
- $which = $which[0];
- if (!array_key_exists($which, $this->cmds))
- {
- self::error("Unknown command, cannot retrieve help.\n");
- }
- $l = strlen($which);
- $cmds = array($which => $this->cmds[$which]);
- }
- else
- {
- echo "\n$argv[0] <command> [options]\n\n";
- $l = 0;
- ksort($this->cmds);
- foreach($this->cmds as $name => $funcs)
- {
- $l = max($l, strlen($name));
- }
- $inf = "Commands:";
- $lst = "";
- $ind = strlen($inf) + 1;
- foreach($this->cmds as $name => $funcs)
- {
- $lst .= ' ' . $name;
- }
- echo $this->cli_wordwrap($inf.$lst, $ind, str_repeat(' ', $ind)) . "\n\n";
- $cmds = $this->cmds;
- }
- $sp = str_repeat(' ', $l + 2);
- foreach($cmds as $name => $funcs)
- {
- $inf = $name . substr($sp, strlen($name));
- if (isset($funcs['inf']))
- {
- $inf .= $this->cli_wordwrap(call_user_func(array($this, $funcs['inf'])), $l, $sp) . "\n";
- if (isset($funcs['arg']))
- {
- $inf .= "\n";
- $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, true);
- $inf .= "\n";
- $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, false);
- }
- }
- echo "$inf\n\n";
- }
- exit(0);
- }
-
- static function cli_cmd_inf_help_list()
- {
- return "Lists available commands.";
- }
-
- function cli_cmd_run_help_list()
- {
- ksort($this->cmds);
- $lst = '';
- foreach($this->cmds as $name => $funcs)
- {
- $lst .= $name . ' ';
- }
- echo substr($lst, 0, -1) . "\n";
- }
+ protected $argc;
+ protected $argv;
+ protected $cmds = array();
+ protected $args = array();
+ protected $types = array();
+
+ function __construct($argc, array $argv)
+ {
+ $this->argc = $argc;
+ $this->argv = $argv;
+ $this->cmds = self::getCommands($this);
+ $this->types = self::getArgTyps($this);
+
+ if ($argc < 2) {
+ self::error("No command given, check ${argv[0]} help\n");
+ } elseif (!isset($this->cmds[$argv[1]]['run'])) {
+ self::error("Unknown command '${argv[1]}', check ${argv[0]} help\n");
+ } else {
+ $command = $argv[1];
+ }
+
+ if (isset($this->cmds[$command]['arg'])) {
+ $this->args = call_user_func(array($this, $this->cmds[$command]['arg']));
+ $i = 1;
+ $missing = false;
+ while (++$i < $argc) {
+ if ($argv[$i][0] == '-') {
+ if (strlen($argv[$i]) == 2 && isset($this->args[$argv[$i][1]])) {
+ $arg = $argv[$i][1];
+ if (++$i >= $argc) {
+ self::error("Missing argument to parameter '$arg' of command '$command', check ${argv[0]} help\n");
+ } else {
+ $this->args[$arg]['val'] = $this->checkArgTyp($arg, $i, $argc, $argv);
+ }
+ } else {
+ self::error("Unknown parameter '${argv[$i]}' to command $command, check ${argv[0]} help\n");
+ }
+ } else {
+ break;
+ }
+ }
+ if (isset($this->args[''])) {
+ if ($i >= $argc) {
+ if (isset($this->args['']['require']) && $this->args['']['require']) {
+ self::error("Missing default trailing arguments to command $command, check ${argv[0]} help\n");
+ }
+ } else {
+ $this->args['']['val'] = array();
+ while($i < $argc) {
+ $this->args['']['val'][] = $argv[$i++];
+ }
+ }
+ } else if ($i < $argc) {
+ self::error("Unexpected default arguments to command $command, check ${argv[0]} help\n");
+ }
+
+ foreach($this->args as $arg => $inf) {
+ if (strlen($arg) && !isset($inf['val']) && isset($inf['required']) && $inf['required']) {
+ $missing .= "Missing parameter '-$arg' to command $command, check ${argv[0]} help\n";
+ }
+ }
+ if (strlen($missing))
+ {
+ self::error($missing);
+ }
+ }
+
+ call_user_func(array($this, $this->cmds[$command]['run']), $this->args);
+ }
+
+ static function error ($msg, $exit_code = 1)
+ {
+ fprintf(STDERR, $msg);
+ exit($exit_code);
+ }
+
+ function checkArgType($arg, $i, $argc, $argv)
+ {
+ $typ = $this->args[$arg]['type'];
+
+ if (isset($this->types[$type]['type'])) {
+ return call_user_func(array($this, $this->types[$type]['type']), $argv[$i], $this->args[$arg], $arg);
+ } else {
+ return $argv[$i];
+ }
+ }
+
+ static function getSubFuncs(CLICommand $cmdclass, $prefix, array $subs)
+ {
+ $a = array();
+ $r = new ReflectionClass($cmdclass);
+ $l = strlen($prefix);
+
+ foreach($r->getMethods() as $m)
+ {
+ if (substr($m->name, 0, $l) == $prefix)
+ {
+ foreach($subs as $sub)
+ {
+ $what = substr($m->name, $l+strlen($sub)+1);
+ $func = $prefix . $sub . '_' . $what;
+ $what = str_replace('_', '-', $what);
+ if ($r->hasMethod($func))
+ {
+ if (!isset($a[$what]))
+ {
+ $a[$what] = array();
+ }
+ $a[$what][$sub] = /*$m->class . '::' .*/ $func;
+ }
+ }
+ }
+ }
+ return $a;
+ }
+
+ static function getCommands(CLICommand $cmdclass)
+ {
+ return self::getSubFuncs($cmdclass, 'cli_cmd_', array('arg','inf','run'));
+ }
+
+ static function getArgTyps(CLICommand $cmdclass)
+ {
+ return self::getSubFuncs($cmdclass, 'cli_arg_', array('type'));
+ }
+
+ static function cli_arg_type_bool($arg, $cfg, $key)
+ {
+ return (bool)$arg;
+ }
+
+
+ static function cli_arg_type_int($arg, $cfg, $key)
+ {
+ if ((int)$arg != $arg) {
+ self::error("Argument to -$key must be an integer.\n");
+ }
+
+ return (int)$arg;
+ }
+
+ static function cli_arg_type_regex($arg, $cfg, $key)
+ {
+ if (strlen($arg))
+ {
+ if (strlen($arg) > 1 && $arg[0] == $arg[strlen($arg)-1] && strpos('/,', $arg) !== false)
+ {
+ return $arg;
+ }
+ else
+ {
+ return '/' . $arg . '/';
+ }
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+ static function cli_arg_type_select($arg, $cfg, $key)
+ {
+ if (!in_array($arg, array_keys($cfg['select']))) {
+ self::error("Parameter value '$arg' not one of '" . join("', '", array_keys($cfg['select'])) . "'.\n");
+ }
+ return $arg;
+ }
+
+ static function cli_arg_type_dir($arg, $cfg, $key)
+ {
+ $f = realpath($arg);
+
+ if ($f===false || !file_exists($f) || !is_dir($f)) {
+ self::error("Requested path '$arg' does not exist.\n");
+ }
+ return $f;
+ }
+
+ static function cli_arg_type_file($arg)
+ {
+ $f = new SplFileInfo($arg);
+ $f = $f->getRealPath();
+ if ($f===false || !file_exists($f))
+ {
+ echo "Requested file '$arg' does not exist.\n";
+ exit(1);
+ }
+ return $f;
+ }
+
+ static function cli_arg_type_filenew($arg, $cfg, $key)
+ {
+ $d = dirname($arg);
+ $f = realpath($d);
+
+ if ($f === false) {
+ self::error("Path for file '$arg' does not exist.\n");
+ }
+ return $f . substr($arg, strlen($d));;
+ }
+
+ static function cli_arg_type_filecont($arg, $cfg, $key)
+ {
+ return file_get_contents(self::cli_arg_type_file($arg, $cfg, $key));
+ }
+
+ function cli_get_SP2($l1, $arg_inf)
+ {
+ return str_repeat(' ', $l1 + 2 + 4 + 8);
+ }
+
+ function cli_get_SP3($l1, $l2, $arg_inf)
+ {
+ return str_repeat(' ', $l1 + 2 + 4 + 8 + 2 + $l2 + 2);
+ }
+
+ static function cli_cmd_inf_help()
+ {
+ return "This help or help for a selected command.";
+ }
+
+ private function cli_wordwrap($what, $l, $sp)
+ {
+ $p = max(79 - $l, 40); // minimum length for paragraph
+ $b = substr($what, 0, $l); // strip out initial $l
+ $r = substr($what, $l); // remainder
+ $r = str_replace("\n", "\n".$sp, $r); // in remainder replace \n's
+ return $b . wordwrap($r, $p, "\n".$sp);
+ }
+
+ private function cli_help_get_args($func, $l, $sp, $required)
+ {
+ $inf = "";
+ foreach(call_user_func($func, $l, $sp) as $arg => $conf)
+ {
+ if ((isset($conf['required']) && $conf['required']) != $required)
+ {
+ continue;
+ }
+ if (strlen($arg))
+ {
+ $arg = "-$arg ";
+ }
+ else
+ {
+ $arg = "... ";
+ }
+ $sp2 = $this->cli_get_SP2($l, $inf);
+ $l2 = strlen($sp2);
+ $inf .= $this->cli_wordwrap($sp . $arg . $conf['inf'], $l2, $sp2) . "\n";
+ if (isset($conf['select']) && count($conf['select']))
+ {
+ $ls = 0;
+ foreach($conf['select'] as $opt => $what)
+ {
+ $ls = max($ls, strlen($opt));
+ }
+ $sp3 = $this->cli_get_SP3($l, $ls, $inf);
+ $l3 = strlen($sp3);
+ foreach($conf['select'] as $opt => $what)
+ {
+ $inf .= $this->cli_wordwrap($sp2 . " " . sprintf("%-${ls}s ", $opt) . $what, $l3, $sp3) . "\n";
+ }
+ }
+ }
+ if (strlen($inf))
+ {
+ if ($required)
+ {
+ return $sp . "Required arguments:\n\n" . $inf;
+ }
+ else
+ {
+ return $sp . "Optional arguments:\n\n". $inf;
+ }
+ }
+ }
+
+ function cli_cmd_arg_help()
+ {
+ return array('' => array('type'=>'any','val'=>NULL,'inf'=>'Optional command to retrieve help for.'));
+ }
+
+ function cli_cmd_run_help()
+ {
+ $argv = $this->argv;
+ $which = $this->args['']['val'];
+ if (isset($which))
+ {
+ if (count($which) != 1) {
+ self::error("More than one command given.\n");
+ }
+
+ $which = $which[0];
+ if (!array_key_exists($which, $this->cmds)) {
+ self::error("Unknown command, cannot retrieve help.\n");
+ }
+
+ $l = strlen($which);
+ $cmds = array($which => $this->cmds[$which]);
+ } else {
+ echo "\n$argv[0] <command> [options]\n\n";
+ $l = 0;
+ ksort($this->cmds);
+ foreach($this->cmds as $name => $funcs) {
+ $l = max($l, strlen($name));
+ }
+ $inf = "Commands:";
+ $lst = "";
+ $ind = strlen($inf) + 1;
+ foreach($this->cmds as $name => $funcs)
+ {
+ $lst .= ' ' . $name;
+ }
+ echo $this->cli_wordwrap($inf.$lst, $ind, str_repeat(' ', $ind)) . "\n\n";
+ $cmds = $this->cmds;
+ }
+ $sp = str_repeat(' ', $l + 2);
+ foreach($cmds as $name => $funcs)
+ {
+ $inf = $name . substr($sp, strlen($name));
+ if (isset($funcs['inf']))
+ {
+ $inf .= $this->cli_wordwrap(call_user_func(array($this, $funcs['inf'])), $l, $sp) . "\n";
+ if (isset($funcs['arg']))
+ {
+ $inf .= "\n";
+ $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, true);
+ $inf .= "\n";
+ $inf .= $this->cli_help_get_args(array($this, $funcs['arg']), $l, $sp, false);
+ }
+ }
+ echo "$inf\n\n";
+ }
+ exit(0);
+ }
+
+ static function cli_cmd_inf_help_list()
+ {
+ return "Lists available commands.";
+ }
+
+ function cli_cmd_run_help_list()
+ {
+ ksort($this->cmds);
+ $lst = '';
+ foreach($this->cmds as $name => $funcs) {
+ $lst .= $name . ' ';
+ }
+ echo substr($lst, 0, -1) . "\n";
+ }
}
-?>
\ No newline at end of file
+?>