modifs.mineures sans commentaires
This commit is contained in:
		
							parent
							
								
									b0a677c6b6
								
							
						
					
					
						commit
						605db70cc5
					
				
							
								
								
									
										72
									
								
								src/cli/Application.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/cli/Application.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\cli;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use nulib\ExitException;
 | 
			
		||||
use nur\sery\output\msg;
 | 
			
		||||
use nur\sery\output\std\StdMessenger;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class Application: une application en ligne de commande
 | 
			
		||||
 */
 | 
			
		||||
abstract class Application {
 | 
			
		||||
  protected static function _app_init(): void {
 | 
			
		||||
    msg::set_messenger_class(StdMessenger::class);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected static function _app_configure(Application $app): void {
 | 
			
		||||
    $app->parseArgs();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected static function _app_main(Application $app): void {
 | 
			
		||||
    $retcode = $app->main();
 | 
			
		||||
    if (is_int($retcode)) exit($retcode);
 | 
			
		||||
    elseif (is_bool($retcode)) exit($retcode? 0: 1);
 | 
			
		||||
    elseif ($retcode !== null) exit(strval($retcode));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static function run(?Application $app=null): void {
 | 
			
		||||
    try {
 | 
			
		||||
      static::_app_init();
 | 
			
		||||
      if ($app === null) $app = new static();
 | 
			
		||||
      static::_app_configure($app);
 | 
			
		||||
      static::_app_main($app);
 | 
			
		||||
    } catch (ExitException $e) {
 | 
			
		||||
      msg::error($e->getUserMessage());
 | 
			
		||||
      exit($e->getCode());
 | 
			
		||||
    } catch (Exception $e) {
 | 
			
		||||
      msg::error($e);
 | 
			
		||||
      exit(1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * sortir de l'application avec un code d'erreur, qui est 0 par défaut (i.e
 | 
			
		||||
   * pas d'erreur)
 | 
			
		||||
   *
 | 
			
		||||
   * équivalent à lancer l'exception {@link ExitException}
 | 
			
		||||
   */
 | 
			
		||||
  protected static final function exit(int $exitcode=0, $message=null) {
 | 
			
		||||
    throw new ExitException($exitcode, $message);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * sortir de l'application avec un code d'erreur, qui vaut 1 par défaut (i.e
 | 
			
		||||
   * une erreur s'est produite)
 | 
			
		||||
   *
 | 
			
		||||
   * équivalent à lancer l'exception {@link ExitException}
 | 
			
		||||
   */
 | 
			
		||||
  protected static final function die($message=null, int $exitcode=1) {
 | 
			
		||||
    throw new ExitException($exitcode, $message);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const ARGS = [];
 | 
			
		||||
 | 
			
		||||
  /** @throws ArgsException */
 | 
			
		||||
  function parseArgs(array $args=null): void {
 | 
			
		||||
    $parser = new ArgsParser(static::ARGS);
 | 
			
		||||
    $parser->parse($this, $args);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  abstract function main();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								src/cli/ArgsException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/cli/ArgsException.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\cli;
 | 
			
		||||
 | 
			
		||||
use nulib\UserException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ArgsException: exception lancée quand il y a une erreur dans l'analyse
 | 
			
		||||
 * des arguments de la ligne de commande
 | 
			
		||||
 */
 | 
			
		||||
class ArgsException extends UserException {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1546
									
								
								src/cli/ArgsParser.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1546
									
								
								src/cli/ArgsParser.php
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										82
									
								
								src/cli/DynamicCommand.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/cli/DynamicCommand.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\cli;
 | 
			
		||||
 | 
			
		||||
use nur\sery\php\func;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class DynamicCommand: implémentation par défaut de {@link IDynamicCommand}
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
class DynamicCommand implements IDynamicCommand {
 | 
			
		||||
  /**
 | 
			
		||||
   * retourner la liste des commandes sous la forme d'un tableau associatif avec
 | 
			
		||||
   * des éléments { $command => $cdef }
 | 
			
		||||
   */
 | 
			
		||||
  protected function COMMANDS(): array {
 | 
			
		||||
    return static::COMMANDS;
 | 
			
		||||
  } const COMMANDS = null;
 | 
			
		||||
 | 
			
		||||
  private $commands;
 | 
			
		||||
  private $dcommands;
 | 
			
		||||
  private $aliases;
 | 
			
		||||
 | 
			
		||||
  protected function buildCommands(): void {
 | 
			
		||||
    if ($this->commands !== null) return;
 | 
			
		||||
    $commands = [];
 | 
			
		||||
    $dcommands = [];
 | 
			
		||||
    $aliases = [];
 | 
			
		||||
    $index = 0;
 | 
			
		||||
    foreach ($this->COMMANDS() as $key => $cdef) {
 | 
			
		||||
      if ($key === $index) {
 | 
			
		||||
        $index++;
 | 
			
		||||
        [$cnames, $assoc] = A::split_assoc($cdef);
 | 
			
		||||
        $cname = $cnames[0];
 | 
			
		||||
        if ($cname === null) {
 | 
			
		||||
          # commande complètement dynamique
 | 
			
		||||
          $dcommands[] = $cnames[2];
 | 
			
		||||
          if ($cnames[1] === null) continue;
 | 
			
		||||
          $cdef = [null, $cnames[1]];
 | 
			
		||||
          $cname = $cnames[1][0];
 | 
			
		||||
          $cnames = [];
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        $cname = $key;
 | 
			
		||||
        $cnames = [$cname];
 | 
			
		||||
        [$seq, $assoc] = A::split_assoc($cdef);
 | 
			
		||||
        A::merge($cnames, $seq);
 | 
			
		||||
        A::merge_assoc($cdef, $cnames, $assoc, true);
 | 
			
		||||
      }
 | 
			
		||||
      $commands[$cname] = $cdef;
 | 
			
		||||
      foreach ($cnames as $key) {
 | 
			
		||||
        $aliases[$key] = $cname;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    $this->commands = $commands;
 | 
			
		||||
    $this->dcommands = $dcommands;
 | 
			
		||||
    $this->aliases = $aliases;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getCommands(): ?array {
 | 
			
		||||
    $this->buildCommands();
 | 
			
		||||
    return array_keys($this->commands);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getCommandDefs(string $command, bool $virtual): ?array {
 | 
			
		||||
    $this->buildCommands();
 | 
			
		||||
    $command = A::get($this->aliases, $command, $command);
 | 
			
		||||
    $cdef = A::get($this->commands, $command);
 | 
			
		||||
    if ($cdef !== null) {
 | 
			
		||||
      if ($cdef[0] === null) {
 | 
			
		||||
        if ($virtual) $cdef = $cdef[1];
 | 
			
		||||
        else return null;
 | 
			
		||||
      }
 | 
			
		||||
      return $cdef !== null? [$cdef]: null;
 | 
			
		||||
    }
 | 
			
		||||
    # tester les commandes complètement dynamiques
 | 
			
		||||
    foreach ($this->dcommands as $func) {
 | 
			
		||||
      $cdef = func::call($func, $command);
 | 
			
		||||
      if ($cdef !== null) return [$cdef];
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								src/cli/DynamicCommandMethod.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/cli/DynamicCommandMethod.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\cli;
 | 
			
		||||
 | 
			
		||||
use nur\sery\php\func;
 | 
			
		||||
 | 
			
		||||
class DynamicCommandMethod implements IDynamicCommand {
 | 
			
		||||
  function __construct($func) {
 | 
			
		||||
    $this->func = $func;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @var object */
 | 
			
		||||
  private $dest;
 | 
			
		||||
 | 
			
		||||
  function setDest($dest): void {
 | 
			
		||||
    if (!is_object($dest)) $dest = null;
 | 
			
		||||
    $this->dest = $dest;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getCommands(): ?array {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private $func;
 | 
			
		||||
 | 
			
		||||
  function getCommandDefs(string $command, bool $virtual): ?array {
 | 
			
		||||
    $func = $this->func;
 | 
			
		||||
    $func_args = [$command];
 | 
			
		||||
    func::check_func($func, $this->dest, $func_args);
 | 
			
		||||
    return func::call($func, ...$func_args);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								src/cli/IDynamicCommand.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/cli/IDynamicCommand.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\cli;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class IDynamicCommand: gestionnaire de commandes dynamiques
 | 
			
		||||
 */
 | 
			
		||||
interface IDynamicCommand {
 | 
			
		||||
  /**
 | 
			
		||||
   * retourner la liste des commandes valides, ou null si cette liste ne peut
 | 
			
		||||
   * pas être construite
 | 
			
		||||
   */
 | 
			
		||||
  function getCommands(): ?array;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * retourner les définitions pour la commande spécifiée, ou null si elle n'est
 | 
			
		||||
   * pas valide
 | 
			
		||||
   */
 | 
			
		||||
  function getCommandDefs(string $command, bool $virtual): ?array;
 | 
			
		||||
}
 | 
			
		||||
@ -2,6 +2,6 @@
 | 
			
		||||
 | 
			
		||||
Ce package contient des services permettant d'interagir avec le système d'exploitation
 | 
			
		||||
 | 
			
		||||
exemple: sh, args, file, IOException, etc.
 | 
			
		||||
exemple: args, etc.
 | 
			
		||||
 | 
			
		||||
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary
 | 
			
		||||
							
								
								
									
										85
									
								
								src/ref/cli/ref_args.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/ref/cli/ref_args.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,85 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace nur\sery\ref\cli;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ref_args: référence du format des arguments pour une application
 | 
			
		||||
 */
 | 
			
		||||
class ref_args {
 | 
			
		||||
  const DEFS_SCHEMA = [
 | 
			
		||||
    "set_defaults" => [null, null, "tableau contenant des paramètres et des options par défaut"],
 | 
			
		||||
    "merge_arrays" => [null, null, "liste de tableaux à merger à celui-ci avant de calculer la liste effective des options"],
 | 
			
		||||
    "merge" => [null, null, "tableau à merger à celui-ci avant de calculer la liste effective des options",
 | 
			
		||||
      # si merge_arrays et merge sont spécifiés tous les deux, "merge" est mergé après "merge_arrays"
 | 
			
		||||
    ],
 | 
			
		||||
    "prefix" => [null, null, "texte à afficher avant l'aide générée automatiquement"],
 | 
			
		||||
    "name" => [null, null, "nom du programme, utilisé pour l'affichage de l'aide"],
 | 
			
		||||
    "purpose" => [null, null, "courte description de l'objet de ce programme"],
 | 
			
		||||
    "usage" => [null, null, "exposé textuel des arguments valides du programme",
 | 
			
		||||
      # ce peut être une chaine e.g '[options] SRC DESC'
 | 
			
		||||
      # ou un tableau auquel cas autant de lignes que nécessaire sont affichées
 | 
			
		||||
    ],
 | 
			
		||||
    "description" => [null, null, "description longue de l'objet du programme, affiché après usage"],
 | 
			
		||||
    "suffix" => [null, null, "texte à afficher après l'aide générée automatiquement"],
 | 
			
		||||
    "dynamic_command" => [null, null, "fonction indiquant si une commande est valide",
 | 
			
		||||
      # la signature de la fonction est function(string $command):?array
 | 
			
		||||
      # elle doit retourner un tableau au format DEFS_SCHEMA qui définit la
 | 
			
		||||
      # commande spécifiée, ou null si ce n'est pas une commande valide
 | 
			
		||||
    ],
 | 
			
		||||
    "sections" => [null, null, "liste de sections permettant de grouper les arguments"],
 | 
			
		||||
    "commandname" => [null, null, "propriété ou clé qui obtient la commande courante",
 | 
			
		||||
      # la valeur par défaut est "command" si ni commandproperty ni commandkey ne sont définis
 | 
			
		||||
    ],
 | 
			
		||||
    "commandproperty" => [null, null, "comme commandname mais force l'utilisation d'une propriété"],
 | 
			
		||||
    "commandkey" => [null, null, "comme commandname mais force l'utilisation d'une clé"],
 | 
			
		||||
    "argsname" => [null, null, "propriété ou clé qui obtient les arguments restants",
 | 
			
		||||
      # la valeur par défaut est "args" si ni argsproperty ni argskey ne sont définis
 | 
			
		||||
    ],
 | 
			
		||||
    "argsproperty" => [null, null, "comme argsname mais force l'utilisation d'une propriété"],
 | 
			
		||||
    "argskey" => [null, null, "comme argsname mais force l'utilisation d'une clé"],
 | 
			
		||||
    "autohelp" => ["?bool", null, "faut-il ajouter automatiquement le support de l'option --help"],
 | 
			
		||||
    "autoremains" => ["?bool", null, "faut-il ajouter automatiquement la prise en compte des arguments restants"],
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const SECTION_SCHEMA = [
 | 
			
		||||
    "show" => ["bool", true, "faut-il afficher cette section?"],
 | 
			
		||||
    "title" => [null, null, "titre de la section"],
 | 
			
		||||
    "prefix" => [null, null, "texte à afficher avant l'aide générée automatiquement"],
 | 
			
		||||
    "suffix" => [null, null, "texte à afficher après l'aide générée automatiquement"],
 | 
			
		||||
 | 
			
		||||
    # ces valeurs sont calculées
 | 
			
		||||
    "defs" => [null, null, "(interne) liste des définitions de cette section"],
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const DEF_SCHEMA = [
 | 
			
		||||
    "set_defaults" => [null, null, "tableau contenant des paramètres par défaut"],
 | 
			
		||||
    "merge_arrays" => [null, null, "liste de tableaux à merger à celui-ci"],
 | 
			
		||||
    "merge" => [null, null, "tableau à merger à celui-ci",
 | 
			
		||||
      # si merge_arrays et merge sont spécifiés tous les deux, "merge" est mergé après "merge_arrays"
 | 
			
		||||
    ],
 | 
			
		||||
    "kind" => [null, null, "type de définition: 'option' ou 'command'"],
 | 
			
		||||
    "arg" => [null, null, "type de l'argument attendu par l'option"],
 | 
			
		||||
    "args" => [null, null, "type des arguments attendus par l'option",
 | 
			
		||||
      # si args est spécifié, arg est ignoré
 | 
			
		||||
    ],
 | 
			
		||||
    "argsdesc" => [null, null, "description textuelle des arguments, utilisé pour l'affichage de l'aide"],
 | 
			
		||||
    "type" => [null, null, "types dans lesquels convertir les arguments avant de les fournir à l'utilisateur"],
 | 
			
		||||
    "action" => [null, null, "fonction à appeler quand cette option est utilisée",
 | 
			
		||||
      # la signature de la fonction est ($value, $name, $arg, $dest, $def)
 | 
			
		||||
    ],
 | 
			
		||||
    "name" => [null, null, "propriété ou clé à initialiser en réponse à l'utilisation de cette option",
 | 
			
		||||
      # le nom à spécifier est au format under_score, qui est transformée en camelCase si la destination est un objet
 | 
			
		||||
    ],
 | 
			
		||||
    "property" => [null, null, "comme name mais force l'utilisation d'une propriété"],
 | 
			
		||||
    "key" => [null, null, "comme name mais force l'utilisation d'une clé"],
 | 
			
		||||
    "inverse" => ["bool", false, "décrémenter la destination au lieu de l'incrémenter pour une option sans argument"],
 | 
			
		||||
    "value" => ["mixed", null, "valeur à forcer au lieu d'incrémenter la destination"],
 | 
			
		||||
    "ensure_array" => [null, null, "forcer la destination à être un tableau"],
 | 
			
		||||
    "help" => [null, null, "description de cette option, utilisé pour l'affichage de l'aide"],
 | 
			
		||||
    "cmd_args" => [null, null, "définition des sous-options pour une commande"],
 | 
			
		||||
 | 
			
		||||
    # ces valeurs sont calculées
 | 
			
		||||
    "cmd_defs" => [null, null, "(interne) liste des définitions correspondant au paramètre options"],
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const ARGS_ALLOWED_VALUES = ["value", "path", "dir", "file", "host"];
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user