eesyphp/includes/cli.php
2021-07-28 17:13:10 +02:00

435 lines
12 KiB
PHP

<?php
$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) {
logging('ERROR', sprintf(_("The CLI command '%s' already exists.", $command)));
return False;
}
if (!is_callable($handler)) {
logging('ERROR', sprintf(_("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 /!\
**************************************************************************************************************
*/
if (php_sapi_name() != "cli")
return true;
// Store current CLI command
$cli_command = null;
/**
* CLI Helpers
**/
function usage($error=false) {
global $cli_commands, $cli_command, $argv;
if ($error)
echo "$error\n\n";
printf(_("Usage: %s [-h] [-qd] command\n"), $argv[0]);
echo _(" -h Show this message\n");
echo _(" -q / -d Quiet/Debug mode\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 " $command: "._($info['short_desc'])."\n";
echo " ".$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;
default:
if ($cli_command)
$command_args[] = $argv[$i];
else
usage(
sprintf(_("Invalid parameter \"%s\".\nNote: Command's parameter/argument must be place after the command."), $argv[$i])
);
}
}
}
if (!$cli_command)
usage();
logging('DEBUG', 'Run '.basename($argv[0])." command $cli_command with argument(s) '".implode("', '", $command_args)."'");
try {
$result = call_user_func($cli_commands[$cli_command]['handler'], $command_args);
exit($result?0:1);
}
catch(Exception $e) {
log_exception(sprintf(_("An exception occured running command %s"), $cli_command));
exit(1);
}
}
function print_item_info($item) {
printf(_("Item #%s:\n"), $item['id']);
printf("\t"._("ID: %s")."\n", $item['id']);
printf("\t"._("Name: '%s'")."\n", $item['name']);
printf("\t"._("Date: %s")."\n", format_time($item['date']));
printf("\t"._("Description: %s")."\n", ($item['description']?"'".$item['description']."'":_("Not set")));
printf("\t"._("Status: %s")."\n", $item['status']);
return true;
}
/**
* Common CLI commands
**/
$orderbys = array('id', 'name', 'date', 'status', 'description');
function cli_list($command_args) {
global $orderbys;
$params = array(
'order' => $orderbys[0],
'order_direction' => 'ASC',
'all' => true,
);
$patterns = array();
for($i=0; $i < count($command_args); $i++) {
switch($command_args[$i]) {
case '-o':
case '--orderby':
$i++;
if(!in_array($command_args[$i], $orderbys))
usage('Invalid --orderby clause');
$params['order'] = $command_args[$i];
break;
case '-r':
case '--reverse':
$params['order_direction'] = 'DESC';
break;
case '-s':
case '--status':
$i++;
if(!check_status($command_args[$i]))
usage('Invalid -s/--status clause');
$params['status'] = $command_args[$i];
break;
default:
$patterns[] = $command_args[$i];
}
}
if (!empty($patterns))
$params['pattern'] = implode(' ', $patterns);
$items = search_items($params);
if (!is_array($items)) {
logging("ERROR", "Invalid DB info return.\n");
return False;
}
if ($items['count'] == 0){
echo _("No item.\n");
return True;
}
$tbl = new Console_Table();
$tbl->setHeaders(
array(
'ID',
'Name',
'Date',
'Status',
'Description',
)
);
foreach($items['items'] as $info) {
$tbl->addRow(
array(
$info['id'],
$info['name'],
format_time($info['date']),
$info['status'],
($info['description']?$info['description']:''),
)
);
}
echo $tbl->getTable();
echo "\n".sprintf(_("%d item(s)"), $items['count'])."\n";
return True;
}
add_cli_command(
'list',
'cli_list',
___("List/search items"),
___("[patterns]"),
array(
___("-o|--orderby Ordering list criterion. Possible values:"),
" - ".implode("\n - ", $orderbys),
___("-r|--reverse Reverse order"),
___("-s|--status Filter on status. Possible values:"),
" - ".implode("\n - ", array_keys($status_list)),
)
);
function cli_show($command_args) {
if (count($command_args) != 1 || !check_id($command_args[0]))
usage(_('You must provide a valid ID.'));
$item_id = $command_args[0];
$item = get_item($item_id);
if (!$item)
logging('FATAL', sprintf(_("Item #%s not found."), $item_id));
print_item_info($item);
return True;
}
add_cli_command(
'show',
'cli_show',
___("Show item"),
___("[ID]")
);
function cli_delete($command_args) {
if (count($command_args) != 1)
usage(_('You must provide item ID.'));
// Check URI
if (!check_id($command_args[0]))
logging('FATAL', _("Invalid item ID"));
// Check exist
$item_id = $command_args[0];
$item = get_item($item_id);
if (!$item)
logging('FATAL', sprintf(_("Item #%s not found."), $item_id));
print_item_info($item);
// Sure ?
echo _("Are you sure you want to delete this item? Type 'yes' to continue: ");
$handle = fopen ("php://stdin","r");
$line = fgets($handle);
if(trim($line) != 'yes'){
logging('WARNING', _("User cancel"));
exit;
}
echo "\n";
if (!delete_item($item['id']))
logging('FATAL', sprintf(_("An error occured deleting item #%d."), $item_id));
return True;
}
add_cli_command(
'delete',
'cli_delete',
___("Delete item"),
___("[item ID]")
);
function cli_export($command_args) {
$fd = fopen((count($command_args) >= 1?$command_args[0]:'php://output'), 'w');
export_items($fd);
fclose($fd);
logging('INFO', "Items export to '".(count($command_args) >= 1?$command_args[0]:'STDOUT')."'.");
}
add_cli_command(
'export',
'cli_export',
___("Export items (as CSV)"),
___("[output file path]")
);
function cli_restore($command_args) {
$fd = fopen((count($command_args) >= 1?$command_args[0]:'php://stdin'), 'r');
restore_items($fd);
fclose($fd);
logging('INFO', "Items restored from '".(count($command_args) >= 1?$command_args[0]:'STDIN')."'.");
}
add_cli_command(
'restore',
'cli_restore',
___("Restore items (from CSV)"),
___("[input file path]")
);
function cli_cron($command_args) {
global $item_max_age;
if (!isset($item_max_age))
$item_max_age = 30;
$just_try = false;
for($i=0; $i < count($command_args); $i++) {
switch($command_args[$i]) {
case '-m':
case '--max-age':
$i++;
if(!check_id($command_args[$i]))
usage('Invalid -m|--max-age clause');
$item_max_age = $command_args[$i];
break;
case '-j':
case '--just-try':
$just_try = true;
break;
default:
usage('Invalid parameter '.$command_args[$i]);
}
}
if (!is_int($item_max_age) || $item_max_age <= 0)
logging('FATAL', 'Invalid $item_max_age value set in configuration: it\'s must be a positive integer.');
logging('DEBUG', "cli_cron(): item max age = $item_max_age day(s)");
$limit = time() - ($item_max_age * 86400);
logging('DEBUG', "Handle items expiration with creation date limit ".format_time($limit).".");
$items = search_items(array('all' => true));
$error = false;
foreach($items['items'] as $item) {
if ($item['date'] < $limit) {
if ($just_try) {
logging('DEBUG', 'Just-try mode: do not really delete item #'.$item['id'].' ('.$item['name'].', creation date: '.format_time($item['date']).')');
}
else if (delete_item($item['id'])) {
logging('INFO', 'item #'.$item['id'].' ('.$item['name'].') deleted (creation date: '.format_time($item['date']).')');
remove_item_attachments($item['id']);
}
else {
logging('ERROR', 'Fail to delete item "'.$item['id'].'" ('.$item['name'].', creation date: '.format_time($item['date']).')');
$error = true;
}
}
else {
logging('DEBUG', 'item "'.$item['id'].'" ('.$item['name'].') still valid (creation date: '.format_time($item['date']).')');
}
}
exit($error?1:0);
}
add_cli_command(
'cron',
'cli_cron',
___("Cron to handle item expiration"),
false,
array (
___("-j/--just-try Just-try mode : do not really removed expired item(s)"),
___("-m/--max-age Item expiration limit (in days, optional)"),
)
);
function cli_extract_messages($command_args) {
global $root_dir_path, $root_lang_dir, $smarty_templates_dir;
// List PHP files to parse
$php_files = run_external_command(
array('find', escapeshellarg($root_dir_path), '-name', "'*.php'"),
null, // no STDIN data
false // do not escape command args (already done)
);
if (!is_array($php_files) || $php_files[0] != 0) {
logging('FATAL', _("Fail to list PHP files."));
}
// Extract messages from PHP files using xgettext
$result = run_external_command(
array(
"xgettext",
"--from-code utf-8",
"--language=PHP",
"-o", "$root_lang_dir/php-messages.pot", // Output
"--omit-header", // No POT header
"--keyword=___", // Handle custom ___() translation function
"--files=-" // Read files to parse from STDIN
),
$php_files[1] // Pass PHP files list via STDIN
);
if (!is_array($result) || $result[0] != 0)
logging('FATAL', _("Fail to extract messages from PHP files using xgettext."));
// Extract messages from templates files using tsmarty2c.php
$result = run_external_command(
array (
"$root_dir_path/vendor/bin/tsmarty2c.php",
"-o", "$root_lang_dir/templates-messages.pot",
$smarty_templates_dir,
)
);
if (!is_array($result) || $result[0] != 0)
logging('FATAL', _("Fail to extract messages from template files using tsmarty2c.php script."));
// Merge previous results in ldapsaisie.pot file using msgcat
$result = run_external_command(array(
'msgcat',
"$root_lang_dir/php-messages.pot",
"$root_lang_dir/templates-messages.pot",
"-o", "$root_lang_dir/messages.pot",
));
if (!is_array($result) || $result[0] != 0)
logging('FATAL', _("Fail to merge messages using msgcat."));
}
add_cli_command(
'extract_messages',
'cli_extract_messages',
___("Extract messages that need to be translated"),
null,
___("This command could be used to generate/update lang/messages.pot file.")
);