tao-test/app/tao/scripts/class.Runner.php

513 lines
17 KiB
PHP
Raw Normal View History

2022-08-29 20:14:13 +02:00
<?php
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2002-2008 (original work) Public Research Centre Henri Tudor & University of Luxembourg (under the project TAO & TAO2);
* 2008-2010 (update and modification) Deutsche Institut für Internationale Pädagogische Forschung (under the project TAO-TRANSFER);
* 2009-2012 (update and modification) Public Research Centre Henri Tudor (under the project TAO-SUSTAIN & TAO-DEV);
*
*/
/**
* Short description of class tao_scripts_Runner
*
* @abstract
* @access public
* @author firstname and lastname of author, <author@example.org>
* @package tao
*/
abstract class tao_scripts_Runner
{
// Adding container and logger.
use \oat\oatbox\log\ContainerLoggerTrait;
/**
* Runner related dependencies will be reached under this offset.
* (use different indexes for every single child!!!)
*/
const CONTAINER_INDEX = 'taoScriptsRunner';
// --- ASSOCIATIONS ---
// --- ATTRIBUTES ---
private $isCli;
private $logOny;
/**
* Short description of attribute parameters
*
* @access protected
* @var array
*/
protected $parameters = [];
/**
* Short description of attribute inputFormat
*
* @access protected
* @var array
*/
protected $inputFormat = [];
// --- OPERATIONS ---
/**
* Short description of method __construct
*
* @access public
* @author firstname and lastname of author, <author@example.org>
* @param \Pimple\Container|array $inputFormat
* @param array $options
* @return mixed
*/
public function __construct($inputFormat = [], $options = [])
{
// Using the container if it's necessary with automatic dependency returning.
$inputFormat = $this->initContainer($inputFormat, static::CONTAINER_INDEX);
if (PHP_SAPI == 'cli' && !isset($options['argv'])) {
$this->argv = $_SERVER['argv'];
$this->isCli = true;
} else {
$this->argv = isset($options['argv']) ? $options['argv'] : [];
$this->isCli = false;
}
if (isset($options['output_mode']) && $options['output_mode'] == 'log_only') {
$this->logOny = true;
}
$this->out("* Running " . (isset($this->argv[0]) ? $this->argv[0] : __CLASS__), $options);
$this->inputFormat = $inputFormat;
//check if help is needed
$helpParams = ['-h', 'help', '-help', '--help'];
$help = array_intersect($helpParams, $this->argv);
if (!empty($help)) {
$this->help();
exit(0);
}
//validate the input parameters
if (!$this->validateInput()) {
$this->help();
$this->err("Scripts stopped!", true);
}
//script run loop
$this->preRun();
$this->run();
$this->postRun();
$this->out('Execution of Script ' . (isset($this->argv[0]) ? $this->argv[0] : __CLASS__) . ' completed', $options);
}
/**
* Short description of method validateInput
*
* @access private
* @author firstname and lastname of author, <author@example.org>
* @return boolean
*/
private function validateInput()
{
$returnValue = (bool) false;
$returnValue = true;
/**
* Parse the arguments from the command lines
* and set them into the parameter variable.
* All the current formats are allowed:
* <code>
* php script.php -arg1 value1 -arg2 value2
* php script.php --arg1 value1 --arg2 value2
* php script.php -arg1=value1 -arg2=value2
* php script.php --arg1=value1 --arg2=value2
* php script.php value1 value2 //the key will be numeric
* </code>
*/
$i = 1;
while ($i < count($this->argv)) {
$arg = trim($this->argv[$i]);
if (!empty($arg)) {
// command -(-)arg1=value1
if (preg_match("/^[\-]{1,2}\w+=(.*)+$/", $arg)) {
$sequence = explode('=', preg_replace("/^[\-]{1,}/", '', $arg));
if (count($sequence) >= 2) {
$this->parameters[$sequence[0]] = $sequence[1];
}
}
// command -(-)arg1 value1 value2
elseif (preg_match("/^[\-]{1,2}\w+$/", $arg)) {
$key = preg_replace("/^[\-]{1,}/", '', $arg);
$this->parameters[$key] = '';
while (isset($this->argv[$i + 1]) && substr(trim($this->argv[$i + 1]), 0, 1) != '-') {
$this->parameters[$key] .= trim($this->argv[++$i]) . ' ';
}
$this->parameters[$key] = substr($this->parameters[$key], 0, -1);
}
// command value1 value2
else {
$this->parameters[$i] = $arg;
}
}
$i++;
}
//replaces shortcuts by their original names
if (isset($this->inputFormat['parameters'])) {
foreach ($this->inputFormat['parameters'] as $parameter) {
if (isset($parameter['shortcut'])) {
$short = $parameter['shortcut'];
$long = $parameter['name'];
if (array_key_exists($short, $this->parameters) && !array_key_exists($long, $this->parameters)) {
$this->parameters[$long] = $this->parameters[$short];
unset($this->parameters[$short]);
}
}
}
}
//one we have the parameters, we can validate it
if (isset($this->inputFormat['min'])) {
$min = (int) $this->inputFormat['min'];
$found = count($this->parameters);
if ($found < $min) {
$this->err("Invalid parameter count: $found parameters found ($min expected)");
$returnValue = false;
}
}
if (isset($this->inputFormat['required']) && is_array($this->inputFormat['required']) && count($this->inputFormat['required'])) {
$requireds = [];
if (!is_array($this->inputFormat['required'][0])) {
$requireds = [$this->inputFormat['required']];
} else {
$requireds = $this->inputFormat['required'];
}
$found = false;
foreach ($requireds as $required) {
$matched = 0;
foreach ($required as $parameter) {
if (array_key_exists($parameter, $this->parameters)) {
$matched++;
}
}
if ($matched == count($required)) {
$found = true;
break;
}
}
if (!$found) {
$this->err("Unable to find required arguments");
$returnValue = false;
}
}
if ($returnValue && isset($this->inputFormat['parameters'])) {
foreach ($this->inputFormat['parameters'] as $parameter) {
if (isset($this->parameters[$parameter['name']])) {
$input = $this->parameters[$parameter['name']];
switch ($parameter['type']) {
case 'file':
if (
!is_file($input) ||
!file_exists($input) ||
!is_readable($input)
) {
$this->err("Unable to access to the file: $input");
$returnValue = false;
}
break;
case 'dir':
if (
!is_dir($input) ||
!is_readable($input)
) {
$this->err("Unable to access to the directory: $input");
$returnValue = false;
}
break;
case 'path':
if (!is_dir(dirname($input))) {
$this->err("Wrong path given: $input");
$returnValue = false;
}
break;
case 'int':
case 'float':
case 'double':
if (!is_numeric($input)) {
$this->err("$input is not a valid " . $parameter['type']);
$returnValue = false;
}
break;
case 'string':
if (!is_string($input)) {
$this->err("$input is not a valid " . $parameter['type']);
$returnValue = false;
}
break;
case 'boolean':
if (!is_bool($input) && strtolower($input) != 'true' && strtolower($input) != 'false' && !empty($input)) {
$this->err("$input is not a valid " . $parameter['type']);
$returnValue = false;
} else {
if (is_bool($input)) {
$this->parameters[$parameter['name']] = $input = settype($input, 'boolean');
} elseif (!empty($input)) {
$this->parameters[$parameter['name']] = ((strtolower($input) == 'true') ? true : false);
} else {
$this->parameters[$parameter['name']] = true;
}
}
break;
}
}
}
}
return (bool) $returnValue;
}
/**
* Short description of method preRun
*
* @access protected
* @author firstname and lastname of author, <author@example.org>
* @return mixed
*/
protected function preRun()
{
}
/**
* Short description of method run
*
* @abstract
* @access protected
* @author firstname and lastname of author, <author@example.org>
* @return mixed
*/
abstract protected function run();
/**
* Short description of method postRun
*
* @access protected
* @author firstname and lastname of author, <author@example.org>
* @return mixed
*/
protected function postRun()
{
}
/**
*
* @access
* @author "Lionel Lecaque, <lionel@taotesting.com>"
* @param unknown $message
* @param unknown $options
* @return Ambigous <string, unknown>
*/
private function renderCliOutput($message, $options = [])
{
$returnValue = '';
if (isset($options['prefix'])) {
$returnValue = $options['prefix'];
}
$colorized = false;
isset($options['color']) ? $color = $options['color'] : $color = 'grey';
$color = trim(tao_helpers_Cli::getFgColor($color));
if (!empty($color) && substr(strtoupper(PHP_OS), 0, 3) != 'WIN') {
$colorized = true;
$returnValue .= "\033[{$color}m" ;
}
isset($options['background']) ? $bg = $options['background'] : $bg = '';
$bg = trim(tao_helpers_Cli::getBgColor($bg));
if (!empty($bg)) {
$colorized = true;
$returnValue .= "\033[{$bg}m";
}
$returnValue .= $message;
if (!isset($options['inline'])) {
$returnValue .= "\n";
}
if ($colorized) {
$returnValue .= "\033[0m";
}
return $returnValue;
}
/**
*
* @access private
* @author "Lionel Lecaque, <lionel@taotesting.com>"
* @param string $message
* @param array $options
* @return string
*/
private function renderHtmlOutput($message, $options = [])
{
$returnValue = '';
if (isset($options['prefix'])) {
$returnValue = $options['prefix'];
}
isset($options['color']) ? $color = $options['color'] : $color = 'grey';
if (!empty($color)) {
$colorized = true;
$returnValue .= '<div class="' . $color . '">';
}
$returnValue .= $message;
if (!isset($options['inline'])) {
$returnValue .= "<br/>";
}
if ($colorized) {
$returnValue .= "</div>";
}
return $returnValue;
}
/**
* Short description of method out
*
* @access public
* @author firstname and lastname of author, <author@example.org>
* @param string message
* @param array options
*/
public function out($message, $options = [])
{
$returnValue = $this->isCli ? $this->renderCliOutput($message, $options) : $this->renderHtmlOutput($message, $options);
if ($this->logOny) {
//do nothing
} else {
echo $returnValue ;
}
common_Logger::i($message, ['SCRIPTS_RUNNER']);
}
/**
* Short description of method err
*
* @access protected
* @author firstname and lastname of author, <author@example.org>
* @param string message
* @param boolean stopExec
*/
protected function err($message, $stopExec = false)
{
common_Logger::e($message);
echo $this->out($message, ['color' => 'light_red']);
if ($stopExec == true) {
$this->handleError(new Exception($message, 1));
}
}
/**
* Handles a fatal error situation.
*
* @param Exception $e
*
* @throws Exception
*/
protected function handleError(Exception $e)
{
if ($this->isCli) {
$errorCode = $e->getCode();
exit((empty($errorCode)) ? 1 : $errorCode); //exit the program with an error
} else {
throw new Exception($e->getMessage());
}
}
/**
* Short description of method help
*
* @access protected
* @author firstname and lastname of author, <author@example.org>
* @return mixed
*/
protected function help()
{
$usage = "Usage:php {$this->argv[0]} [arguments]\n";
$usage .= "\nArguments list:\n";
foreach ($this->inputFormat['parameters'] as $parameter) {
$line = '';
if (isset($parameter['required'])) {
if ($parameter['required'] == true) {
$line .= "Required";
} else {
$line .= "Optional";
}
} else {
//$usage .= "\t";
}
$line = str_pad($line, 15) . ' ';
$line .= "--{$parameter['name']}";
if (isset($parameter['shortcut'])) {
$line .= "|-{$parameter['shortcut']}";
}
$line = str_pad($line, 39) . ' ';
$line .= "{$parameter['description']}";
$usage .= $line . "\n";
}
$this->out($usage, ['color' => 'light_blue']);
}
/**
* Short description of method outVerbose
*
* @access public
* @author firstname and lastname of author, <author@example.org>
* @param string message
* @param array options
* @return mixed
*/
public function outVerbose($message, $options = [])
{
common_Logger::i($message);
if (isset($this->parameters['verbose']) && $this->parameters['verbose'] === true) {
$this->out($message, $options);
}
}
} /* end of abstract class tao_scripts_Runner */