From f5ee0314d32ada4b206754d44c5b0c708c8939d2 Mon Sep 17 00:00:00 2001 From: Julien Rosset Date: Sun, 25 Oct 2020 15:45:37 +0100 Subject: [PATCH] Add exit codes support in help message --- Tests/test.php | 5 +- src/CommandLine/CommandLine.php | 163 ++++++++++++++++++++++++++++++-- 2 files changed, 160 insertions(+), 8 deletions(-) diff --git a/Tests/test.php b/Tests/test.php index 28df663..f385de0 100644 --- a/Tests/test.php +++ b/Tests/test.php @@ -10,11 +10,14 @@ use CommandLine\CommandLine; $cmdline = new CommandLine('Test', 'Programme de test', 'php test.php'); $cmdline->addDefaultArguments(); -$cmdline->addOption(new Flag('array_form', false, 'Sous la forme d\'un tableau ?'."\n".'Ou pas')); +$cmdline->addOption(new Flag('array_form', false, 'Sous la forme d\'un tableau ?' . "\n" . 'Ou pas')); $cmdline->addOption((new Value('days', 'Nombre jour', new IntegerParser(0, 365)))->setDefault(3)); $cmdline->addOption((new Value('years', 'Nombre d\'années', new IntegerParser(0)))->setDefault(5)); $cmdline->addValue((new \CommandLine\Argument\Value\Value('path', 'Chemin sauvegarde images', new PathParser(), true))); +$cmdline->addExitCode(0, 'OK'); +$cmdline->addExitCode(255, 'Unexpected error' . "\n" . 'Unknown error'); + $args = $cmdline->parse(); $cmdline->treatDefaultArguments($args, false); diff --git a/src/CommandLine/CommandLine.php b/src/CommandLine/CommandLine.php index 7a313ad..9af0957 100644 --- a/src/CommandLine/CommandLine.php +++ b/src/CommandLine/CommandLine.php @@ -83,6 +83,11 @@ class CommandLine { */ protected $_arguments_values = array(); + /** + * @var string[] Liste des codes de retour avec leur descriptif + */ + protected $_exitCodes = array(); + /** * Crée un ligne de commande * @@ -527,6 +532,103 @@ class CommandLine { } } + /** + * La liste des codes de retour avec leur descriptif + * + * @return string[] La liste des codes de retour avec leur descriptifs + */ + public function getExitCodes () { + return $this->_exitCodes; + } + /** + * La description de l'un de code de retour + * + * @param int $code Le code de retour + * + * @return string|null La description correspondante ou Null si le code n'existe pas ou n'a pas de description + * + * @throws InvalidArgumentException Si le code de retour n'est pas un entier + */ + public function getExitCodeDescription ($code) { + if (filter_var($code, FILTER_VALIDATE_INT) === false) { + throw new InvalidArgumentException('Le code de retour "' . $code . '" n\'est pas un entier'); + } + return $this->_exitCodes[(int)$code]; + } + /** + * Remplace la liste des codes de retour avec leur descriptif + * + * @param string[] $exitCodes La nouvelle liste des codes de retour + * + * @return $this + * + * @throws InvalidArgumentException Si la clé du tableaux (les codes) ne sont pas des entiers ou + * que la valeur (description) n'est pas convertible en chaine de caractères + */ + public function setExitCodes ($exitCodes = array()) { + $this->_exitCodes = array(); + return $this->addExitCodes($exitCodes); + } + /** + * Ajoute une liste de codes de retour avec leur descriptif + * + * @param string[] $exitCodes La liste des codes de retour à ajouter + * + * @return $this + * + * @throws InvalidArgumentException Si la clé du tableaux (les codes) ne sont pas des entiers ou + * que la valeur (description) n'est pas convertible en chaine de caractères + */ + public function addExitCodes ($exitCodes) { + foreach ($exitCodes as $code => $description) { + $this->addExitCode($code, $description); + } + + return $this; + } + /** + * Ajoute un code de retour avec son descriptif + * + * @param int $code Le code de retour + * @param string|null $description La description + * + * @return $this + * + * @throws InvalidArgumentException Si le code n'est pas un entier ou + * que la description n'est pas convertible en chaine de caractères + */ + public function addExitCode ($code, $description = null) { + if (filter_var($code, FILTER_VALIDATE_INT) === false) { + throw new InvalidArgumentException('Le code de retour "' . $code . '" n\'est pas un entier'); + } + + if ( + is_array($description) + || (is_object($description) && !method_exists($description, '__toString')) + || (!is_object($description) && settype($description, 'string') === false) + ) { + throw new InvalidArgumentException('La description "' . $code . '" n\'est pas convertible en chaine de caractères'); + } + + $this->_exitCodes[(int)$code] = (string)$description; + return $this; + } + /** + * Est-ce que le code de retour demandé existe ? + * + * @param int $code Le code de retour + * + * @return bool True si le code de retour existe + * + * @throws InvalidArgumentException Si le code de retour n'est pas un entier + */ + public function existsExitCode ($code) { + if (filter_var($code, FILTER_VALIDATE_INT) === false) { + throw new InvalidArgumentException('Le code de retour "' . $code . '" n\'est pas un entier'); + } + return array_key_exists((int)$code, $this->_exitCodes); + } + /** * Ajoute les options communes à la plupart des programmes * @@ -629,6 +731,12 @@ class CommandLine { $help = array_merge($help, self::_getOptionsListing($this->getOptions())); $help[] = ''; + if (count($this->getExitCodes()) > 0) { + $help[] = 'Exit codes :'; + $help = array_merge($help, self::_getExitCodesListing($this->getExitCodes())); + $help[] = ''; + } + return implode("\n", $help); } @@ -708,10 +816,10 @@ class CommandLine { $spaces = array(); $spaces[] = str_pad('', $pads->name, ' '); $spaces[] = str_pad('', $pads->occurMin + 4 + $pads->occurMax, ' '); - if($pads->valueDescription > 0) { + if ($pads->valueDescription > 0) { $spaces[] = str_pad('', $pads->valueDescription, ' '); } - if($pads->default > 0) { + if ($pads->default > 0) { $spaces[] = str_pad('', $pads->default, ' '); } $spaces[] = ''; @@ -732,7 +840,7 @@ class CommandLine { $occur .= str_pad(is_null($max) ? 'N' : $max, $pads->occurMax, ' ', STR_PAD_RIGHT); $entry[] = $occur; - if($pads->valueDescription > 0) { + if ($pads->valueDescription > 0) { $entry[] = str_pad( $value instanceof IArgumentValueDescription ? $value->getValueDescription() : '', $pads->valueDescription, @@ -793,10 +901,10 @@ class CommandLine { $spaces = array(); $spaces[] = str_pad('', $pads->tagShort + 1 + $pads->tagLong + 2, ' '); - if($pads->valueDescription > 0) { + if ($pads->valueDescription > 0) { $spaces[] = str_pad('', $pads->valueDescription, ' '); } - if($pads->default > 0) { + if ($pads->default > 0) { $spaces[] = str_pad('', $pads->default, ' '); } $spaces[] = ''; @@ -817,7 +925,7 @@ class CommandLine { $label .= $option->allowMultiple() ? ' *' : ($option->isStoppingParse() ? ' X' : ' '); $entry[] = $label; - if($pads->valueDescription) { + if ($pads->valueDescription) { $entry[] = str_pad( $option instanceof IArgumentValueDescription ? $option->getValueDescription() : '', $pads->valueDescription, @@ -826,7 +934,7 @@ class CommandLine { ); } - if($pads->default > 0) { + if ($pads->default > 0) { $entry[] = str_pad($option->getDefault(), $pads->default, ' ', STR_PAD_RIGHT); } @@ -841,6 +949,47 @@ class CommandLine { return $entries; } + /** + * Génère l'aide d'une liste de codes de retour + * + * @param string[] $exitCodes La liste des codes de retour et leur description + * + * @return string[] L'aide de chaque code de retour + */ + protected static function _getExitCodesListing ($exitCodes) { + /* + * Calcul des différents padding + */ + // Initialisation + $pads = new stdClass; + $pads->codes = 0; + + // Lecture des codes de retour + foreach ($exitCodes as $code => $_) { + $pads->codes = max($pads->codes, strlen($code)); + } + + $spaces[] = str_pad('', $pads->tagShort + 1 + $pads->tagLong + 2, ' '); + + /* + * Génération des descriptifs + */ + $entries = array(); + foreach ($exitCodes as $code => $description) { + $entry = array(); + + $entry[] = str_pad($code, $pads->codes, ' ', STR_PAD_RIGHT); + $entry[] = preg_replace( + '@\r?\n@', + '$0' . self::TAB . str_repeat(' ', $pads->codes) . self::TAB, + $description + ); + + $entries[] = self::TAB . implode(self::TAB, $entry); + } + + return $entries; + } /** * Traite les arguments du script