Move CLI stuff in EesyPHP namespace

This commit is contained in:
Benjamin Renard 2023-01-30 00:11:26 +01:00
parent 5e8a2b6d1c
commit c8659ea46f
6 changed files with 230 additions and 172 deletions

View file

@ -1,8 +1,7 @@
#!/usr/bin/php #!/usr/bin/php
<?php <?php
use EesyPHP\Cli;
require realpath(dirname(__FILE__).'/..')."/includes/core.php"; require realpath(dirname(__FILE__).'/..')."/includes/core.php";
if (is_callable('handle_cli_args')) Cli :: handle_args();
handle_cli_args();
else
Log :: fatal("An error occured initializing CLI : handle_cli_args() function not found.");

View file

@ -1,32 +1,10 @@
<?php <?php
use EesyPHP\Check; use EesyPHP\Check;
use EesyPHP\Cli;
use EesyPHP\I18n; use EesyPHP\I18n;
use EesyPHP\Log; use EesyPHP\Log;
$cli_commands=array();
function add_cli_command($command, $handler, $short_desc, $usage_args=false, $long_desc=false,
$override=false) {
global $cli_commands;
if (array_key_exists($command, $cli_commands) && !$override) {
Log :: error(_("The CLI command '%s' already exists."), $command);
return False;
}
if (!is_callable($handler)) {
Log :: error(_("The CLI command '%s' handler is not callable !"), $command);
return False;
}
$cli_commands[$command] = array (
'handler' => $handler,
'short_desc' => $short_desc,
'usage_args' => $usage_args,
'long_desc' => $long_desc,
);
return True;
}
/* /*
************************************************************************************************* *************************************************************************************************
* /!\ Code after this message will only be execute on CLI context /!\ * /!\ Code after this message will only be execute on CLI context /!\
@ -35,126 +13,11 @@ function add_cli_command($command, $handler, $short_desc, $usage_args=false, $lo
if (php_sapi_name() != "cli") if (php_sapi_name() != "cli")
return true; return true;
// Store current CLI command
$cli_command = null;
/** /**
* CLI Helpers * CLI Helpers
**/ **/
function usage($error=false) {
global $cli_commands, $cli_command, $argv;
// If more than 1 arguments passed, format error message using sprintf
if (func_num_args() > 1) {
$error = call_user_func_array(
'sprintf',
array_merge(array($error), array_slice(func_get_args(), 1))
);
}
if ($error)
echo "$error\n\n";
printf(_("Usage: %s [-h] [-qd] command\n"), basename($argv[0]));
echo _(" -h Show this message\n");
echo _(" -q / -d Quiet/Debug mode\n");
echo _(" --trace Trace mode (the most verbose)\n");
echo _(" command Command to run\n");
echo "\n";
echo _("Available commands:\n");
foreach ($cli_commands as $command => $info) {
if ($cli_command && $command != $cli_command)
continue;
echo (
" ".str_replace(
"\n", "\n ",
wordwrap("$command : "._($info['short_desc'])))
."\n\n");
echo (
" ".basename($argv[0])." $command ".
($info['usage_args']?_($info['usage_args']):'').
"\n");
if ($info['long_desc']) {
if (is_array($info['long_desc'])) {
$lines = array();
foreach ($info['long_desc'] as $line)
$lines[] = _($line);
$info['long_desc'] = implode("\n", $lines);
}
else
$info['long_desc'] = _($info['long_desc']);
echo "\n ".str_replace("\n", "\n ", wordwrap($info['long_desc']))."\n";
}
echo "\n";
}
exit(($error?1:0));
}
function handle_cli_args() {
global $log_level, $cli_commands, $cli_command, $argv;
$log_level = 'INFO';
$cli_command = false;
$command_args = array();
for ($i=1; $i < count($argv); $i++) {
if (array_key_exists($argv[$i], $cli_commands)) {
if (!$cli_command)
$cli_command = $argv[$i];
else
usage(_("Only one command could be executed !"));
}
else {
switch($argv[$i]) {
case '-h':
case '--help':
usage();
break;
case '-d':
case '--debug':
$log_level = 'DEBUG';
break;
case '-q':
case '--quiet':
$log_level = 'WARNING';
break;
case '--trace':
$log_level = 'TRACE';
break;
default:
if ($cli_command)
$command_args[] = $argv[$i];
else
usage(
_(
"Invalid parameter \"%s\".\nNote: Command's parameter/argument must be place ".
"after the command."
), $argv[$i]
);
}
}
}
if (!$cli_command)
usage();
Log :: debug(
"Run %s command %s with argument(s) '%s'.",
basename($argv[0]), $cli_command, implode("', '", $command_args)
);
try {
$result = call_user_func($cli_commands[$cli_command]['handler'], $command_args);
exit($result?0:1);
}
catch(Exception $e) {
Log :: exception($e, _("An exception occured running command %s"), $cli_command);
exit(1);
}
}
function print_item_info($item) { function print_item_info($item) {
printf(_("Item #%s:\n"), $item['id']); printf(_("Item #%s:\n"), $item['id']);
printf("\t"._("ID: %s")."\n", $item['id']); printf("\t"._("ID: %s")."\n", $item['id']);
@ -188,7 +51,7 @@ function cli_list($command_args) {
case '--orderby': case '--orderby':
$i++; $i++;
if(!in_array($command_args[$i], $orderbys)) if(!in_array($command_args[$i], $orderbys))
usage('Invalid --orderby clause'); Cli :: usage('Invalid --orderby clause');
$params['order'] = $command_args[$i]; $params['order'] = $command_args[$i];
break; break;
case '-r': case '-r':
@ -199,7 +62,7 @@ function cli_list($command_args) {
case '--status': case '--status':
$i++; $i++;
if(!check_status($command_args[$i])) if(!check_status($command_args[$i]))
usage('Invalid -s/--status clause'); Cli :: usage('Invalid -s/--status clause');
$params['status'] = $command_args[$i]; $params['status'] = $command_args[$i];
break; break;
default: default:
@ -246,7 +109,7 @@ function cli_list($command_args) {
echo "\n".sprintf(_("%d item(s)"), $items['count'])."\n"; echo "\n".sprintf(_("%d item(s)"), $items['count'])."\n";
return True; return True;
} }
add_cli_command( Cli :: add_command(
'list', 'list',
'cli_list', 'cli_list',
I18n :: ___("List/search items"), I18n :: ___("List/search items"),
@ -262,7 +125,7 @@ add_cli_command(
function cli_show($command_args) { function cli_show($command_args) {
if (count($command_args) != 1 || !Check :: id($command_args[0])) if (count($command_args) != 1 || !Check :: id($command_args[0]))
usage(_('You must provide a valid ID.')); Cli :: usage(_('You must provide a valid ID.'));
$item_id = $command_args[0]; $item_id = $command_args[0];
$item = get_item($item_id); $item = get_item($item_id);
@ -273,7 +136,7 @@ function cli_show($command_args) {
print_item_info($item); print_item_info($item);
return True; return True;
} }
add_cli_command( Cli :: add_command(
'show', 'show',
'cli_show', 'cli_show',
I18n :: ___("Show item"), I18n :: ___("Show item"),
@ -282,7 +145,7 @@ add_cli_command(
function cli_delete($command_args) { function cli_delete($command_args) {
if (count($command_args) != 1) if (count($command_args) != 1)
usage(_('You must provide item ID.')); Cli :: usage(_('You must provide item ID.'));
// Check URI // Check URI
if (!Check :: id($command_args[0])) if (!Check :: id($command_args[0]))
@ -311,7 +174,7 @@ function cli_delete($command_args) {
return True; return True;
} }
add_cli_command( Cli :: add_command(
'delete', 'delete',
'cli_delete', 'cli_delete',
I18n :: ___("Delete item"), I18n :: ___("Delete item"),
@ -324,7 +187,7 @@ function cli_export($command_args) {
fclose($fd); fclose($fd);
Log :: info("Items export to '".(count($command_args) >= 1?$command_args[0]:'STDOUT')."'."); Log :: info("Items export to '".(count($command_args) >= 1?$command_args[0]:'STDOUT')."'.");
} }
add_cli_command( Cli :: add_command(
'export', 'export',
'cli_export', 'cli_export',
I18n :: ___("Export items (as CSV)"), I18n :: ___("Export items (as CSV)"),
@ -340,7 +203,7 @@ function cli_restore($command_args) {
(count($command_args) >= 1?$command_args[0]:'STDIN') (count($command_args) >= 1?$command_args[0]:'STDIN')
); );
} }
add_cli_command( Cli :: add_command(
'restore', 'restore',
'cli_restore', 'cli_restore',
I18n :: ___("Restore items (from CSV)"), I18n :: ___("Restore items (from CSV)"),
@ -359,7 +222,7 @@ function cli_cron($command_args) {
case '--max-age': case '--max-age':
$i++; $i++;
if(!Check :: id($command_args[$i])) if(!Check :: id($command_args[$i]))
usage('Invalid -m|--max-age clause'); Cli :: usage('Invalid -m|--max-age clause');
$item_max_age = $command_args[$i]; $item_max_age = $command_args[$i];
break; break;
case '-j': case '-j':
@ -367,7 +230,7 @@ function cli_cron($command_args) {
$just_try = true; $just_try = true;
break; break;
default: default:
usage('Invalid parameter '.$command_args[$i]); Cli :: usage('Invalid parameter '.$command_args[$i]);
} }
} }
@ -408,11 +271,11 @@ function cli_cron($command_args) {
} }
exit($error?1:0); exit($error?1:0);
} }
add_cli_command( Cli :: add_command(
'cron', 'cron',
'cli_cron', 'cli_cron',
I18n :: ___("Cron to handle item expiration"), I18n :: ___("Cron to handle item expiration"),
false, null,
array ( array (
I18n :: ___("-j/--just-try Just-try mode : do not really removed expired item(s)"), I18n :: ___("-j/--just-try Just-try mode : do not really removed expired item(s)"),
I18n :: ___("-m/--max-age Item expiration limit (in days, optional)"), I18n :: ___("-m/--max-age Item expiration limit (in days, optional)"),

View file

@ -4,7 +4,7 @@ parameters:
- src - src
- includes - includes
- public_html - public_html
- bin - bin/eesyphp
excludePaths: excludePaths:
- includes/config.local.php - includes/config.local.php
ignoreErrors: ignoreErrors:

185
src/Cli.php Normal file
View file

@ -0,0 +1,185 @@
<?php
namespace EesyPHP;
use EesyPHP\Log;
use Exception;
class Cli {
/**
* Registered commands
* @var array<string,array>
*/
protected static $commands = array();
/**
* Current CLI command
* @var string|null
*/
protected static $command = null;
/**
* Add CLI command
* @param string $command The command name
* @param callable $handler The command handler
* @param string $short_desc Short command description
* @param string|null $usage_args Argument usage short message
* @param string|array<string>|null $long_desc Long command description
* @return bool
*/
public static function add_command($command, $handler, $short_desc, $usage_args=null, $long_desc=null,
$override=false) {
if (array_key_exists($command, self :: $commands) && !$override) {
Log :: error(_("The CLI command '%s' already exists."), $command);
return False;
}
if (!is_callable($handler)) {
Log :: error(_("The CLI command '%s' handler is not callable !"), $command);
return False;
}
self :: $commands[$command] = array (
'handler' => $handler,
'short_desc' => $short_desc,
'usage_args' => $usage_args,
'long_desc' => $long_desc,
);
return True;
}
/**
* Show usage message
* @param string|false $error Error message to show (optional)
* @param array $extra_args Extra arguments to use to compute error message using sprintf
* @return void
*/
public static function usage($error=false, ...$extra_args) {
global $argv;
// If extra arguments passed, format error message using sprintf
if ($extra_args) {
$error = call_user_func_array(
'sprintf',
array_merge(array($error), $extra_args)
);
}
if ($error)
echo "$error\n\n";
printf(_("Usage: %s [-h] [-qd] command\n"), basename($argv[0]));
echo _(" -h Show this message\n");
echo _(" -q / -d Quiet/Debug mode\n");
echo _(" --trace Trace mode (the most verbose)\n");
echo _(" command Command to run\n");
echo "\n";
echo _("Available commands:\n");
foreach (self :: $commands as $command => $info) {
if (self :: $command && $command != self :: $command)
continue;
echo (
" ".str_replace(
"\n", "\n ",
wordwrap("$command : "._($info['short_desc'])))
."\n\n");
echo (
" ".basename($argv[0])." $command ".
($info['usage_args']?_($info['usage_args']):'').
"\n");
if ($info['long_desc']) {
if (is_array($info['long_desc'])) {
$lines = array();
foreach ($info['long_desc'] as $line)
$lines[] = _($line);
$info['long_desc'] = implode("\n", $lines);
}
else
$info['long_desc'] = _($info['long_desc']);
echo "\n ".str_replace("\n", "\n ", wordwrap($info['long_desc']))."\n";
}
echo "\n";
}
exit(($error?1:0));
}
/**
* Handle command line arguments
* @param array|null $args Command line argurment to handle (optional, default: $argv)
* @return void
*/
public static function handle_args($args=null) {
global $argv;
$args = is_array($args)?$args:array_slice($argv, 1);
$log_level_set = false;
self :: $command = null;
$command_args = array();
for ($i=0; $i < count($args); $i++) {
if (array_key_exists($args[$i], self :: $commands)) {
if (!self :: $command)
self :: $command = $args[$i];
else
self :: usage(_("Only one command could be executed !"));
}
else {
switch($args[$i]) {
case '-h':
case '--help':
self :: usage();
break;
case '-d':
case '--debug':
Log :: set_level('DEBUG');
$log_level_set = true;
break;
case '-q':
case '--quiet':
Log :: set_level('WARNING');
$log_level_set = true;
break;
case '--trace':
Log :: set_level('TRACE');
$log_level_set = true;
break;
default:
if (self :: $command)
$command_args[] = $args[$i];
else
self :: usage(
_(
"Invalid parameter \"%s\".\nNote: Command's parameter/argument must be place ".
"after the command."
), $args[$i]
);
}
}
}
if (!$log_level_set)
Log :: set_level('INFO');
if (!self :: $command)
self :: usage();
Log :: debug(
"Run %s command %s with argument(s) '%s'.",
basename($args[0]), self :: $command, implode("', '", $command_args)
);
try {
$result = call_user_func(self :: $commands[self :: $command]['handler'], $command_args);
exit($result?0:1);
}
catch(Exception $e) {
Log :: exception($e, _("An exception occured running command %s"), self :: $command);
exit(1);
}
}
}

View file

@ -2,6 +2,7 @@
namespace EesyPHP; namespace EesyPHP;
use EesyPHP\Cli;
use EesyPHP\Log; use EesyPHP\Log;
use Locale; use Locale;
@ -114,7 +115,7 @@ class I18n {
} }
if (php_sapi_name() == 'cli') { if (php_sapi_name() == 'cli') {
add_cli_command( Cli :: add_command(
'extract_messages', 'extract_messages',
array('\\EesyPHP\\I18n', 'cli_extract_messages'), array('\\EesyPHP\\I18n', 'cli_extract_messages'),
self :: ___("Extract messages that need to be translated"), self :: ___("Extract messages that need to be translated"),
@ -122,7 +123,7 @@ class I18n {
self :: ___("This command could be used to generate/update lang/messages.pot file.") self :: ___("This command could be used to generate/update lang/messages.pot file.")
); );
add_cli_command( Cli :: add_command(
'update_messages', 'update_messages',
array('\\EesyPHP\\I18n', 'cli_update_messages'), array('\\EesyPHP\\I18n', 'cli_update_messages'),
self :: ___("Update messages in translation PO lang files"), self :: ___("Update messages in translation PO lang files"),
@ -130,7 +131,7 @@ class I18n {
self :: ___("This command could be used to init/update PO files in lang/*/LC_MESSAGES directories.") self :: ___("This command could be used to init/update PO files in lang/*/LC_MESSAGES directories.")
); );
add_cli_command( Cli :: add_command(
'compile_messages', 'compile_messages',
array('\\EesyPHP\\I18n', 'cli_compile_messages'), array('\\EesyPHP\\I18n', 'cli_compile_messages'),
self :: ___( self :: ___(

View file

@ -66,19 +66,8 @@ class Log {
public static function init($filepath, $level=null, $php_errors_levels=null) { public static function init($filepath, $level=null, $php_errors_levels=null) {
self :: $filepath = $filepath; self :: $filepath = $filepath;
// Set default log level (if not defined or invalid) // Set log level
if (is_null($level)) { self :: set_level($level);
self :: $level = self :: $default_level;
}
elseif (!array_key_exists($level, self :: $levels)) {
self :: $level = self :: $default_level;
self :: warning(
"Invalid log level value found in configuration (%s). ".
"Set as default (%s).", $level, self :: $default_level);
}
else {
self :: $level = $level;
}
// Log PHP errors // Log PHP errors
if (!is_null($php_errors_levels)) if (!is_null($php_errors_levels))
@ -258,6 +247,27 @@ class Log {
return True; return True;
} }
/**
* Set current log level
* @param string $level The new log level to set
* @return void
*/
public static function set_level($level=null) {
// Set default log level (if not defined or invalid)
if (is_null($level)) {
self :: $level = self :: $default_level;
}
elseif (!array_key_exists($level, self :: $levels)) {
self :: $level = self :: $default_level;
self :: warning(
"Invalid log level value found in configuration (%s). ".
"Set as default (%s).", $level, self :: $default_level);
}
else {
self :: $level = $level;
}
}
/* /*
******************************************************************************* *******************************************************************************
* Handle exception logging * Handle exception logging