diff --git a/php/src/UserException.php b/php/src/UserException.php index 7578093..e41dc2c 100644 --- a/php/src/UserException.php +++ b/php/src/UserException.php @@ -28,7 +28,7 @@ class UserException extends RuntimeException { } function setTechMessage($techMessage): self { - $techMessage ??= c::resolve($techMessage); + if ($techMessage !== null) $techMessage = c::resolve($techMessage); $this->techMessage = $techMessage; return $this; } diff --git a/php/src/app/app.php b/php/src/app/app.php index dc01e45..c3fcdd4 100644 --- a/php/src/app/app.php +++ b/php/src/app/app.php @@ -119,7 +119,7 @@ class app { static function is_production_mode(): bool { return self::get()->isProductionMode(); } - + static function is_prod(): bool { return self::get_profile() === ref_profiles::PROD; } @@ -146,7 +146,7 @@ class app { static final function set_fact(string $fact, $value=true): void { self::get()->setFact($fact, $value); } - + static function is_debug(): bool { return self::get()->isDebug(); } @@ -410,7 +410,7 @@ class app { function fencedJoin(string $basedir, ?string ...$paths): string { $path = path::reljoin($basedir, ...$paths); if (!path::is_within($path, $basedir)) { - throw exceptions::invalid_type($path, $kind, "path"); + throw exceptions::invalid_value($path, "path"); } return $path; } diff --git a/php/src/app/args/Aodef.php b/php/src/app/args/Aodef.php index fd0c726..921a197 100644 --- a/php/src/app/args/Aodef.php +++ b/php/src/app/args/Aodef.php @@ -347,7 +347,7 @@ class Aodef { $haveNull = true; break; } else { - throw _exceptions::invalid_value("$desc: $arg", $kind, "ce n'est pas un argument valide"); + throw _exceptions::invalid_value("$desc: $arg"); } } @@ -366,7 +366,7 @@ class Aodef { $haveNull = true; break; } else { - throw _exceptions::invalid_value("$desc: $arg", $kind, "ce n'est pas un argument valide"); + throw _exceptions::invalid_value("$desc: $arg"); } } if (!$haveOpt) $haveNull = true; @@ -519,7 +519,7 @@ class Aodef { case "--set-args": $this->actionSetArgs($dest, $value); break; case "--set-command": $this->actionSetCommand($dest, $value); break; case "--show-help": $parser->actionPrintHelp($arg); break; - default: throw _exceptions::invalid_value($this->action, $kind, "action non supportée"); + default: throw _exceptions::invalid_value($this->action, null, "action non supportée"); } } diff --git a/php/src/app/args/Aogroup.php b/php/src/app/args/Aogroup.php index 06e2df2..d293a75 100644 --- a/php/src/app/args/Aogroup.php +++ b/php/src/app/args/Aogroup.php @@ -10,7 +10,7 @@ class Aogroup extends Aolist { function __construct(array $defs, bool $setup=false) { $marker = A::pop($defs, 0); if ($marker !== "group") { - throw _exceptions::missing_value(null, $kind, "ce n'est pas un groupe valide"); + throw _exceptions::missing_value(null, null, "ce n'est pas un groupe valide"); } # réordonner les clés numériques $defs = array_merge($defs); diff --git a/php/src/app/cli/Application.php b/php/src/app/cli/Application.php index 02f0901..85c8d13 100644 --- a/php/src/app/cli/Application.php +++ b/php/src/app/cli/Application.php @@ -10,10 +10,13 @@ use nulib\app\config; use nulib\app\RunFile; use nulib\ExitError; use nulib\ext\yaml; -use nulib\output\console; +use nulib\output\con; use nulib\output\log; use nulib\output\msg; -use nulib\output\std\StdMessenger; +use nulib\output\say; +use nulib\output\std\ConsoleMessenger; +use nulib\output\std\LogMessenger; +use nulib\output\std\ProxyMessenger; use nulib\ref\ref_profiles; /** @@ -192,7 +195,7 @@ EOT); protected static function _initialize_app(): void { app::init(static::class); app::set_fact(app::FACT_CLI_APP); - msg::set_messenger(new StdMessenger([ + msg::set_messenger(new ConsoleMessenger([ "min_level" => msg::DEBUG, ])); } @@ -200,18 +203,20 @@ EOT); protected static function _configure_app(Application $app): void { config::configure(config::CONFIGURE_INITIAL_ONLY); - $msgs = null; - $msgs["console"] = new StdMessenger([ + $con = con::set_messenger(new ConsoleMessenger([ "min_level" => msg::NORMAL, - ]); + ])); + say::set_messenger($con); + msg::set_messenger($con); if (static::USE_LOGFILE) { - $msgs["log"] = new StdMessenger([ + $log = log::set_messenger(new LogMessenger([ "output" => app::get()->getLogfile(), "min_level" => msg::MINOR, - "add_date" => true, - ]); + ])); + } else { + $log = log::set_messenger(new ProxyMessenger()); } - msg::init($msgs); + msg::set_messenger($log); $app->parseArgs(); config::configure(); @@ -268,26 +273,36 @@ EOT); "title" => "NIVEAU D'INFORMATION", "show" => false, ["group", - ["--verbosity", + ["-V", "--verbosity", "args" => "verbosity", "argsdesc" => "silent|quiet|verbose|debug", - "action" => [console::class, "set_verbosity"], - "help" => "spécifier le niveau d'informations affiché", + "action" => [con::class, "set_verbosity"], + "help" => "Spécifier le niveau d'informations affiché sur la console", ], - ["-q", "--quiet", "action" => [console::class, "set_verbosity", "quiet"]], - ["-v", "--verbose", "action" => [console::class, "set_verbosity", "verbose"]], - ["-D", "--debug", "action" => [console::class, "set_verbosity", "debug"]], - ], - ["-L", "--logfile", - "args" => "output", - "action" => [log::class, "set_output"], - "help" => "Logger les messages de l'application dans le fichier spécifié", + ["-q", "--quiet", "action" => [con::class, "set_verbosity", "quiet"]], + ["-v", "--verbose", "action" => [con::class, "set_verbosity", "verbose"]], + ["-D", "--debug", "action" => [con::class, "set_verbosity", "debug"]], ], ["group", ["--color", - "action" => [console::class, "set_color", true], + "action" => [con::class, "set_color", true], "help" => "Afficher (resp. ne pas afficher) la sortie en couleur par défaut", ], - ["--no-color", "action" => [console::class, "set_color", false]], + ["--no-color", "action" => [con::class, "set_color", false]], + ], + ["group", + ["-L", "--logfile", + "args" => "output", + "action" => [log::class, "set_output"], + "help" => "Logger les messages de l'application dans le fichier spécifié", + ], + ["--lV", "--lverbosity", + "args" => "verbosity", "argsdesc" => "silent|quiet|verbose|debug", + "action" => [log::class, "set_verbosity"], + "help" => "Spécifier le niveau des informations ajoutées dans les logs", + ], + ["--lq", "--lquiet", "action" => [log::class, "set_verbosity", "quiet"]], + ["--lv", "--lverbose", "action" => [log::class, "set_verbosity", "verbose"]], + ["--lD", "--ldebug", "action" => [log::class, "set_verbosity", "debug"]], ], ]; diff --git a/php/src/app/config.php b/php/src/app/config.php index 8c1581b..6fd270a 100644 --- a/php/src/app/config.php +++ b/php/src/app/config.php @@ -28,7 +28,7 @@ class config { static function configure(?array $params=null): void { self::$config->configure($params); } - + static final function add($config, string ...$profiles): void { self::$config->addConfig($config, $profiles); } static final function load_config($file): void { $ext = path::ext($file); @@ -37,7 +37,7 @@ class config { } elseif ($ext === ".json") { $config = new JsonConfig($file); } else { - throw exceptions::invalid_type($file, $kind, "config file"); + throw exceptions::invalid_value($file, "config file"); } self::add($config); } diff --git a/php/src/app/config/ConfigManager.php b/php/src/app/config/ConfigManager.php index ee3f63a..abcef01 100644 --- a/php/src/app/config/ConfigManager.php +++ b/php/src/app/config/ConfigManager.php @@ -59,11 +59,11 @@ class ConfigManager { protected function cacheHas(string $pkey, string $profile) { return array_key_exists("$profile.$pkey", $this->cache); } - + protected function cacheGet(string $pkey, string $profile) { return cl::get($this->cache, "$profile.$pkey"); } - + protected function cacheSet(string $pkey, $value, string $profile): void { $this->cache["$profile.$pkey"] = $value; } diff --git a/php/src/cl.php b/php/src/cl.php index b15ed55..2e57a87 100644 --- a/php/src/cl.php +++ b/php/src/cl.php @@ -848,7 +848,7 @@ class cl { static final function any_not_same(?array $array, $value): bool { return self::any_if($array, cv::Fnot_same($value)); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - + static final function filter_if(?array $array, callable $cond): ?array { if ($array === null) return null; $filtered = []; diff --git a/php/src/cv.php b/php/src/cv.php index f1ffc85..89b81ac 100644 --- a/php/src/cv.php +++ b/php/src/cv.php @@ -29,7 +29,7 @@ class cv { static final function t($value): bool { return $value || $value === "0"; } - + /** tester si $value est fausse (cela n'inclue pas la chaine "0") */ static final function f($value): bool { return !$value && $value !== "0"; @@ -198,11 +198,11 @@ class cv { * * lever une exception si $value n'est d'aucun de ces types */ - static final function check_key($value, ?string $prefix=null, bool $throw_exception=true): array { + static final function check_key($value, ?string $kind=null, bool $throwException=true): array { $index = is_int($value)? $value : null; $key = is_string($value)? $value : null; - if ($index === null && $key === null && $throw_exception) { - throw exceptions::invalid_type($value, $kind, "key", $prefix); + if ($index === null && $key === null && $throwException) { + throw exceptions::invalid_type($value, $kind, "key"); } else { return [$index, $key]; } @@ -214,12 +214,12 @@ class cv { * * @throws ValueException si $value n'est d'aucun de ces types */ - static final function check_bsa($value, ?string $prefix=null, bool $throw_exception=true): array { + static final function check_bsa($value, ?string $kind=null, bool $throwException=true): array { $bool = is_bool($value)? $value : null; $scalar = !is_bool($value) && is_scalar($value)? $value : null; $array = is_array($value)? $value : null; - if ($bool === null && $scalar === null && $array === null && $throw_exception) { - throw exceptions::invalid_type($value, $kind, ["bool", "scalar", "array"], $prefix); + if ($bool === null && $scalar === null && $array === null && $throwException) { + throw exceptions::invalid_type($value, $kind, ["bool", "scalar", "array"]); } else { return [$bool, $scalar, $array]; } diff --git a/php/src/db/_private/_base.php b/php/src/db/_private/_base.php index c554174..8325bae 100644 --- a/php/src/db/_private/_base.php +++ b/php/src/db/_private/_base.php @@ -8,7 +8,7 @@ abstract class _base extends _common { if (is_array($sql)) { $prefix = $sql[0] ?? null; if ($prefix === null) { - throw exceptions::invalid_type($sql, "cette requête sql"); + throw exceptions::invalid_value($sql, "cette requête sql"); } elseif (_create::isa($prefix)) { $sql = _create::parse($sql, $bindings); $meta = ["isa" => "create", "type" => "ddl"]; @@ -28,7 +28,7 @@ abstract class _base extends _common { $sql = _generic::parse($sql, $bindings); $meta = ["isa" => "generic", "type" => null]; } else { - throw exceptions::invalid_type($sql, "cette requête sql"); + throw exceptions::invalid_value($sql, "cette requête sql"); } } else { if (!is_string($sql)) $sql = strval($sql); diff --git a/php/src/file.php b/php/src/file.php index a8175d4..4c84f58 100644 --- a/php/src/file.php +++ b/php/src/file.php @@ -57,7 +57,7 @@ class file { } return $file; } - + static function writer($output, ?string $mode="w+b", ?callable $func=null): FileWriter { $file = new FileWriter(self::fix_dash($output), $mode); if ($func !== null) { diff --git a/php/src/file/csv/csv_flavours.php b/php/src/file/csv/csv_flavours.php index 2a782e6..bb00150 100644 --- a/php/src/file/csv/csv_flavours.php +++ b/php/src/file/csv/csv_flavours.php @@ -17,13 +17,13 @@ class csv_flavours { "dumb," => ref_csv::DUMB_OO_FLAVOUR, "dumb" => ref_csv::DUMB_FLAVOUR, ]; - + const ENCODINGS = [ ref_csv::OO_FLAVOUR => ref_csv::OO_ENCODING, ref_csv::XL_FLAVOUR => ref_csv::XL_ENCODING, ref_csv::DUMB_FLAVOUR => ref_csv::DUMB_ENCODING, ]; - + static final function verifix(?string $flavour): ?string { if ($flavour === null) return null; $lflavour = strtolower($flavour); @@ -41,7 +41,7 @@ class csv_flavours { elseif ($flavour == ref_csv::XL_FLAVOUR) return ref_csv::MSEXCEL; else return $flavour; } - + static final function get_params(string $flavour): array { return [$flavour[0], $flavour[1], $flavour[2]]; } diff --git a/php/src/output/TODO.md b/php/src/output/TODO.md index 28ae6ac..0164f84 100644 --- a/php/src/output/TODO.md +++ b/php/src/output/TODO.md @@ -1,8 +1,13 @@ # nulib\output -* dans msg::action($m, function() {}), *bloquer* la marque pour empêcher d'aller - plus bas que prévu. comme ça s'il y a plusieurs success ou failure dans la - fonction, c'est affiché correctement. +* log:: permet d'ajouter autant d'instance de LogMessenger que nécessaire + * on pourrait qualifier un logger avec par exemple la classe qui l'appelle + ou le nom d'un sous-système. + * pour un log structuré, un attribut donnerai le qualificatif, ce qui ne + serait pris en compte que par le logger approprié (e.g un logger qui est + responsable de nulib/io logguera les message de nulib/io/ClassA mais pas + les messages de nulib/args/ClassB + * un trait permet d'ajouter un logger à une classe * [ ] possibilité de paramétrer le nom du fichier destination pour faire une rotation des logs @@ -13,11 +18,6 @@ * [ ] dans `StdMessenger::resetParams()`, `[output]` peut être une instance de StdOutput pour mettre à jour $out ET $err, ou un tableau de deux éléments pour mettre à jour séparément $out et $err -* [ ] vérifier que la date affichée pour un TITLE est celle à laquelle l'appel - a été fait, même si le premier événement en dessous arrive bien plus tard -* [ ] pareil pour action: sauf si c'est une seule ligne, la date de action est - la date du premier appel, alors que la date de $result est celui du result si - c'est affiché sur une autre ligne * réorganiser pour que msg:: attaque un proxy dans lequel est configuré un ensemble standard de sorties: say, log, debuglog * `--aD, --av, --aq, --asilent` pour les valeurs d'ajustement qui sont un diff --git a/php/src/output/_TMessenger.php b/php/src/output/_TMessenger.php new file mode 100644 index 0000000..26de8a5 --- /dev/null +++ b/php/src/output/_TMessenger.php @@ -0,0 +1,62 @@ +addMessenger($msg); + else self::$msg = new ProxyMessenger(self::$msg); + return $msg; + } + + static function get(): IMessenger { + return self::$msg ??= new NullMessenger(); + } + + static function set_verbosity(string $verbosity): void { + $msg = self::get(); + switch ($verbosity) { + case "Q": + case "silent": + $msg->resetParams([ + "min_level" => self::NONE, + ]); + break; + case "q": + case "quiet": + $msg->resetParams([ + "min_level" => self::MAJOR, + ]); + break; + case "n": + case "normal": + $msg->resetParams([ + "min_level" => self::NORMAL, + ]); + break; + case "v": + case "verbose": + $msg->resetParams([ + "min_level" => self::MINOR, + ]); + break; + case "D": + case "debug": + app::set_debug(); + $msg->resetParams([ + "min_level" => self::DEBUG, + ]); + break; + default: + throw exceptions::forbidden_value($verbosity, "verbosity", ["silent", "quiet", "normal", "verbose", "debug"]); + } + } +} diff --git a/php/src/output/_messenger.php b/php/src/output/_messenger.php index 702c4b7..bf5d4ca 100644 --- a/php/src/output/_messenger.php +++ b/php/src/output/_messenger.php @@ -1,44 +1,16 @@ clone($params); } - static final function __callStatic($name, $args) { - $name = str::us2camel($name); - call_user_func_array([static::get(), $name], $args); - } - ############################################################################# const DEBUG = IMessenger::DEBUG; diff --git a/php/src/output/con.php b/php/src/output/con.php new file mode 100644 index 0000000..b9127ef --- /dev/null +++ b/php/src/output/con.php @@ -0,0 +1,27 @@ +resetParams([ + "color" => $color, + ]); + } +} diff --git a/php/src/output/console.php b/php/src/output/console.php deleted file mode 100644 index 205f105..0000000 --- a/php/src/output/console.php +++ /dev/null @@ -1,75 +0,0 @@ -resetParams([ - "min_level" => msg::NONE, - ]); - break; - case "q": - case "quiet": - $console->resetParams([ - "min_level" => msg::MAJOR, - ]); - break; - case "n": - case "normal": - $console->resetParams([ - "min_level" => msg::NORMAL, - ]); - break; - case "v": - case "verbose": - $console->resetParams([ - "min_level" => msg::MINOR, - ]); - break; - case "D": - case "debug": - app::set_debug(); - $console->resetParams([ - "min_level" => msg::DEBUG, - ]); - break; - default: - throw exceptions::forbidden_value($verbosity, $kind, ["silent", "quiet", "normal", "verbose", "debug"]); - } - } - - static function set_color(bool $color=true): void { - console::reset_params([ - "color" => $color, - ]); - } -} diff --git a/php/src/output/log.php b/php/src/output/log.php index 2e1d3ec..967de5c 100644 --- a/php/src/output/log.php +++ b/php/src/output/log.php @@ -1,38 +1,41 @@ isEmpty()) { + $msg->addMessenger(new LogMessenger([ + "min_level" => msg::MINOR, + ])); + } + return $msg; } static function set_output(string $logfile): void { - self::create_or_reset_params([ + self::ensure_log()->resetParams([ "output" => $logfile, - ], StdMessenger::class, [ - "add_date" => true, - "min_level" => self::MINOR, ]); } } diff --git a/php/src/output/msg.php b/php/src/output/msg.php index d180d18..9bd4eee 100644 --- a/php/src/output/msg.php +++ b/php/src/output/msg.php @@ -1,67 +1,18 @@ resetParams($params); - return self::$out; - } - - static function write(...$values): void { self::$out->write(...$values); } - static function print(...$values): void { self::$out->print(...$values); } - - static function iwrite(int $indentLevel, ...$values): void { self::$out->iwrite($indentLevel, ...$values); } - static function iprint(int $indentLevel, ...$values): void { self::$out->iprint($indentLevel, ...$values); } -} -out::reset(); diff --git a/php/src/output/say.php b/php/src/output/say.php index 9d8b6d0..f5d5583 100644 --- a/php/src/output/say.php +++ b/php/src/output/say.php @@ -1,28 +1,17 @@ $max_level) { + throw new Exception("$level: level not allowed here"); + } + return $level; + } + + /** @var StdOutput la sortie standard */ + protected StdOutput $out; + + /** @var int level par défaut dans lequel les messages sont affichés */ + protected int $defaultLevel; + + /** @var int level minimum que doivent avoir les messages pour être affichés */ + protected int $minLevel; + + /** @var bool faut-il ajouter la date à chaque ligne? */ + protected bool $addDate; + + /** @var string format de la date */ + protected string $dateFormat; + + /** @var bool faut-il afficher les ids (p=id t=id a=id) */ + protected bool $showIds; + + /** @var ?string identifiant de ce messenger, à ajouter à chaque ligne */ + protected ?string $id; + + protected int $lastTitleId = 1; + + protected int $lastActionId = 1; + + protected function getLinePrefix(): ?string { + $linePrefix = null; + if ($this->addDate) { + $date = date_create()->format($this->dateFormat); + $linePrefix .= "$date "; + } + if ($this->showIds) { + if ($this->id !== null) $linePrefix .= "p=$this->id "; + $titleId = $this->_getTitleId(); + if ($titleId !== null) $linePrefix .= "t=$titleId "; + $actionId = $this->_getActionId(); + if ($actionId !== null) $linePrefix .= "a=$actionId "; + } + return $linePrefix; + } + + protected function decrLevel(int $level, int $amount=-1): int { + $level += $amount; + if ($level < self::MIN_LEVEL) $level = self::MIN_LEVEL; + return $level; + } + + protected function checkLevel(?int &$level): bool { + if ($level === null) $level = $this->defaultLevel; + elseif ($level < 0) $level = $this->decrLevel($this->defaultLevel, $level); + return $level >= $this->minLevel; + } + + protected function _printTitle( + ?string $linePrefix, int $level, + string $type, $content, + int $indentLevel, StdOutput $out + ): void { + $prefixes = self::GENERIC_PREFIXES[$level][$type]; + if ($prefixes[0]) $out->print(); + $content = cl::with($content); + if ($out->isColor()) { + $before = $prefixes[2]; + $prefix = $prefixes[3]; + $prefix2 = $prefix !== null? "$prefix ": null; + $suffix = $prefixes[4]; + $suffix2 = $suffix !== null? " $suffix": null; + $after = $prefixes[5]; + + $lines = $out->getLines(false, ...$content); + $maxlen = 0; + foreach ($lines as &$content) { + $line = $out->filterColors($content); + $len = mb_strlen($line); + if ($len > $maxlen) $maxlen = $len; + $content = [$content, $len]; + }; unset($content); + if ($before !== null) { + if ($linePrefix !== null) $out->write($linePrefix); + $out->iprint($indentLevel, $prefix, substr($before, 1), str_repeat($before[0], $maxlen), $suffix); + } + foreach ($lines as [$content, $len]) { + if ($linePrefix !== null) $out->write($linePrefix); + $padding = $len < $maxlen? str_repeat(" ", $maxlen - $len): null; + $out->iprint($indentLevel, $prefix2, $content, $padding, $suffix2); + } + if ($after !== null) { + if ($linePrefix !== null) $out->write($linePrefix); + $out->iprint($indentLevel, $prefix, substr($after, 1), str_repeat($after[0], $maxlen), $suffix); + } + } else { + $prefix = $prefixes[1]; + if ($prefix !== null) $prefix .= " "; + $prefix2 = str_repeat(" ", mb_strlen($prefix)); + $lines = $out->getLines(false, ...$content); + foreach ($lines as $content) { + if ($linePrefix !== null) $out->write($linePrefix); + $out->iprint($indentLevel, $prefix, $content); + $prefix = $prefix2; + } + } + } + + protected abstract function flushActions(bool $endAction=false, ?int $overrideLevel=null): void; + + protected function _printAction( + ?string $linePrefix, int $level, + bool $printContent, $content, + bool $printResult, ?bool $rsuccess, $rcontent, + int $indentLevel, StdOutput $out + ): void { + $color = $out->isColor(); + if ($rsuccess === true) $type = "success"; + elseif ($rsuccess === false) $type = "failure"; + else $type = "done"; + $rprefixes = self::RESULT_PREFIXES[$type]; + if ($color) { + $rprefix = $rprefixes[1]; + $rprefix2 = null; + if ($rprefix !== null) { + $rprefix .= " "; + $rprefix2 = $out->filterColors($out->filterContent($rprefix)); + $rprefix2 = str_repeat(" ", mb_strlen($rprefix2)); + } + } else { + $rprefix = $rprefixes[0]; + if ($rprefix !== null) $rprefix .= " "; + $rprefix2 = str_repeat(" ", mb_strlen($rprefix)); + } + if ($printContent && $printResult) { + A::ensure_array($content); + if ($rcontent) { + $content[] = ": "; + $content[] = $rcontent; + } + $lines = $out->getLines(false, ...$content); + foreach ($lines as $content) { + if ($linePrefix !== null) $out->write($linePrefix); + $out->iprint($indentLevel, $rprefix, $content); + $rprefix = $rprefix2; + } + } elseif ($printContent) { + $prefixes = self::GENERIC_PREFIXES[$level]["step"]; + if ($color) { + $prefix = $prefixes[1]; + if ($prefix !== null) $prefix .= " "; + $prefix2 = $out->filterColors($out->filterContent($prefix)); + $prefix2 = str_repeat(" ", mb_strlen($prefix2)); + $suffix = $prefixes[2]; + } else { + $prefix = $prefixes[0]; + if ($prefix !== null) $prefix .= " "; + $prefix2 = str_repeat(" ", mb_strlen($prefix)); + $suffix = null; + } + A::ensure_array($content); + $content[] = ":"; + $lines = $out->getLines(false, ...$content); + foreach ($lines as $content) { + if ($linePrefix !== null) $out->write($linePrefix); + $out->iprint($indentLevel, $prefix, $content, $suffix); + $prefix = $prefix2; + } + } elseif ($printResult) { + if (!$rcontent) { + if ($type === "success") $rcontent = $color? "succès": ""; + elseif ($type === "failure") $rcontent = $color? "échec": ""; + elseif ($type === "done") $rcontent = "fait"; + } + $rprefix = " $rprefix"; + $rprefix2 = " $rprefix2"; + $lines = $out->getLines(false, $rcontent); + foreach ($lines as $rcontent) { + if ($linePrefix !== null) $out->write($linePrefix); + $out->iprint($indentLevel, $rprefix, $rcontent); + $rprefix = $rprefix2; + } + } + } + + protected function _printGeneric( + ?string $linePrefix, int $level, + string $type, $content, + int $indentLevel, StdOutput $out + ): void { + $prefixes = self::GENERIC_PREFIXES[$level][$type]; + $content = cl::with($content); + if ($out->isColor()) { + $prefix = $prefixes[1]; + $prefix2 = null; + if ($prefix !== null) { + $prefix .= " "; + $prefix2 = $out->filterColors($out->filterContent($prefix)); + $prefix2 = str_repeat(" ", mb_strlen($prefix2)); + } + $suffix = $prefixes[2]; + $lines = $out->getLines(false, ...$content); + foreach ($lines as $content) { + if ($linePrefix !== null) $out->write($linePrefix); + $out->iprint($indentLevel, $prefix, $content, $suffix); + $prefix = $prefix2; + } + } else { + $prefix = $prefixes[0]; + if ($prefix !== null) $prefix .= " "; + $prefix2 = str_repeat(" ", mb_strlen($prefix)); + $lines = $out->getLines(false, ...$content); + foreach ($lines as $content) { + if ($linePrefix !== null) $out->write($linePrefix); + $out->iprint($indentLevel, $prefix, $content); + $prefix = $prefix2; + } + } + } + + protected function _printGenericOrException( + ?int $level, + string $type, $content, + int $indentLevel, StdOutput $out + ): void { + $linePrefix = $this->getLinePrefix(); + # si $content contient des exceptions, les afficher avec un level moindre + $exceptions = null; + if (is_array($content)) { + $valueContent = null; + foreach ($content as $value) { + if ($value instanceof Throwable || $value instanceof ExceptionShadow) { + $exceptions[] = $value; + } else { + $valueContent[] = $value; + } + } + if ($valueContent === null) $content = null; + elseif (count($valueContent) == 1) $content = $valueContent[0]; + else $content = $valueContent; + } elseif ($content instanceof Throwable || $content instanceof ExceptionShadow) { + $exceptions[] = $content; + $content = null; + } + + $flushActions = true; + $showContent = $this->checkLevel($level); + if ($content !== null && $showContent) { + $this->flushActions(); $flushActions = false; + $this->_printGeneric($linePrefix, $level, $type, $content, $indentLevel, $out); + } + if ($exceptions !== null) { + $level1 = $this->decrLevel($level); + $showTraceback = $this->checkLevel($level1); + foreach ($exceptions as $exception) { + # tout d'abord message + $message = exceptions::get_message($exception); + if ($showContent) { + if ($flushActions) { $this->flushActions(); $flushActions = false; } + $this->_printGeneric($linePrefix, $level, $type, $message, $indentLevel, $out); + } + # puis summary et traceback + if ($showTraceback) { + if ($flushActions) { $this->flushActions(); $flushActions = false; } + $summary = exceptions::get_summary($exception, false); + $this->_printGeneric($linePrefix, $level1, $type, $summary, $indentLevel, $out); + $traceback = exceptions::get_traceback($exception); + $this->_printGeneric($linePrefix, $level1, $type, $traceback, $indentLevel, $out); + } + } + } + } +} diff --git a/php/src/output/std/ConsoleMessenger.php b/php/src/output/std/ConsoleMessenger.php new file mode 100644 index 0000000..fd3d716 --- /dev/null +++ b/php/src/output/std/ConsoleMessenger.php @@ -0,0 +1,432 @@ + $color, + "indent" => $indent, + ]; + if ($output !== null) { + $this->err = $this->out = new StdOutput($output, $params); + } else { + $this->out = new StdOutput(STDOUT, $params); + $this->err = new StdOutput(STDERR, $params); + } + $this->defaultLevel = $defaultLevel; + $this->minLevel = $minLevel; + $this->addDate = $addDate; + $this->dateFormat = $dateFormat; + $this->id = $id; + $this->showIds = $showIds; + $this->inSection = false; + $this->section = null; + $this->titles = []; + $this->actions = []; + } + + function resetParams(?array $params=null): void { + $output = $params["output"] ?? null; + $color = $params["color"] ?? null; + $indent = $params["indent"] ?? null; + + $defaultLevel = $params["default_level"] ?? null; + if ($defaultLevel !== null) $defaultLevel = self::verifix_level($defaultLevel); + + $debug = $params["debug"] ?? null; + $minLevel = $params["min_level"] ?? null; + if ($debug !== null) $minLevel ??= self::DEBUG; + $minLevel ??= $params["verbosity"] ?? null; # alias + if ($minLevel !== null) $minLevel = self::verifix_level($minLevel, self::NONE); + + $addDate = $params["add_date"] ?? null; + $dateFormat = $params["date_format"] ?? null; + $id = $params["id"] ?? null; + + $params = [ + "output" => $output, + "color" => $color, + "indent" => $indent, + ]; + if ($this->out === $this->err) { + $this->out->resetParams($params); + } else { + # NB: si initialement [output] était null, et qu'on spécifie une valeur + # [output], alors les deux instances $out et $err sont mis à jour + # séparément avec la même valeur de output + # de plus, on ne peut plus revenir à la situation initiale avec une + # destination différente pour $out et $err + $this->out->resetParams($params); + $this->err->resetParams($params); + } + if ($defaultLevel !== null) $this->defaultLevel = $defaultLevel; + if ($minLevel !== null) $this->minLevel = $minLevel; + if ($addDate !== null) $this->addDate = boolval($addDate); + if ($dateFormat !== null) $this->dateFormat = $dateFormat; + if ($id !== null) $this->id = $id; + } + + function clone(?array $params=null): IMessenger { + $clone = clone $this; + if ($params !== null) $clone->resetParams($params); + #XXX faut-il marquer la section et les titres du clone à "print" => false? + # ou en faire des références au parent? + # dans tous les cas, on considère qu'il n'y a pas d'actions en cours, et on + # ne doit pas dépiler avec end() plus que l'état que l'on a eu lors du clone + return $clone; + } + + /** @var StdOutput la sortie d'erreur */ + protected StdOutput $err; + + /** @var bool est-on dans une section? */ + protected bool $inSection; + + /** @var array section qui est en attente d'affichage */ + protected ?array $section; + + function section($content, ?callable $func=null, ?int $level=null): void { + $this->_endSection(); + $this->inSection = true; + if (!$this->checkLevel($level)) return; + $this->section = [ + "line_prefix" => $this->getLinePrefix(), + "level" => $level, + "content" => $content, + "print_content" => true, + ]; + if ($func !== null) { + try { + $func($this); + } finally { + $this->_endSection(); + } + } + } + + protected function printSection() { + $section =& $this->section; + if ($section !== null && $section["print_content"]) { + $this->_printTitle( + $section["line_prefix"], $section["level"], + "section", $section["content"], + 0, $this->err); + $section["print_content"] = false; + } + } + + function _endSection(): void { + while ($this->actions) $this->adone(); + while ($this->titles) $this->_endTitle(); + $this->inSection = false; + $this->section = null; + } + + protected function getIndentLevel(bool $withActions=true): int { + $indentLevel = count($this->titles) - 1; + if ($indentLevel < 0) $indentLevel = 0; + if ($withActions) { + foreach ($this->actions as $action) { + if ($action["level"] < $this->minLevel) continue; + $indentLevel++; + } + } + return $indentLevel; + } + + protected array $titles; + + function _getTitleMark(): int { + return count($this->titles); + } + + function _getTitleId(): ?int { + return end($this->titles)["id"] ?? null; + } + + function title($content, ?callable $func=null, ?int $level=null): void { + if (!$this->checkLevel($level)) return; + $titleLevel = $this->_getTitleMark(); + // faire en deux temps pour linePrefix soit à jour + $this->titles[] = ["id" => $this->lastTitleId++]; + A::merge($this->titles[array_key_last($this->titles)], [ + "title_level" => $titleLevel, + "max_title_level" => null, + "line_prefix" => $this->getLinePrefix(), + "level" => $level, + "content" => $content, + "print_content" => true, + "descs" => [], + "print_descs" => false, + ]); + if ($func !== null) { + try { + $title =& $this->titles[array_key_last($this->titles)]; + $title["max_title_level"] = $titleLevel + 1; + $func($this); + } finally { + $title["max_title_level"] = null; + $this->_endTitle($titleLevel); + } + } + } + + function desc($content, ?int $level=null): void { + if (!$this->checkLevel($level)) return; + $desc = [ + "line_prefix" => $this->getLinePrefix(), + "level" => $level, + "content" => $content, + ]; + $key = array_key_last($this->titles); + if ($key !== null) { + $title =& $this->titles[$key]; + $title["descs"][] = $desc; + $title["print_descs"] = true; + } else { + # pas de titre en cours + $this->_printGeneric( + $desc["line_prefix"], $desc["level"], + "desc", $desc["content"], + 0, $this->err); + } + } + + protected function flushTitles(): void { + $this->printSection(); + $err = $this->err; + $indentLevel = 0; + foreach ($this->titles as &$title) { + if ($title["print_content"]) { + $this->_printTitle( + $title["line_prefix"], $title["level"], + "title", $title["content"], + $indentLevel, $err); + $title["print_content"] = false; + } + if ($title["print_descs"]) { + foreach ($title["descs"] as $desc) { + $this->_printGeneric( + $desc["line_prefix"], $desc["level"], + "desc", $desc["content"], + $indentLevel, $err); + } + $title["descs"] = []; + $title["print_descs"] = false; + } + $indentLevel++; + }; unset($title); + } + + function _endTitle(?int $until=null): void { + $title = $this->titles[array_key_last($this->titles)]; + $until ??= $title["max_title_level"]; + $until ??= $this->_getTitleMark() - 1; + while (count($this->titles) > $until) { + array_pop($this->titles); + } + } + + protected array $actions; + + function _getActionMark(): int { + return count($this->actions); + } + + function _getActionId(): ?int { + return end($this->actions)["id"] ?? null; + } + + protected function flushActions(bool $endAction=false, ?int $overrideLevel=null): void { + $this->flushTitles(); + $err = $this->err; + $indentLevel = $this->getIndentLevel(false); + $lastIndex = array_key_last($this->actions); + $index = 0; + foreach ($this->actions as &$action) { + $mergeResult = $index++ == $lastIndex && $endAction; + $linePrefix = $action["line_prefix"]; + $level = $overrideLevel?? $action["level"]; + $content = $action["content"]; + $printContent = $action["print_content"]; + $rsuccess = $action["result_success"]; + $rcontent = $action["result_content"]; + if ($level < $this->minLevel) continue; + if ($mergeResult) { + if (time() - $action["timestamp"] <= 2) { + $this->_printAction( + $linePrefix, $level, + $printContent, $content, + true, $rsuccess, $rcontent, + $indentLevel, $err); + } else { + # si l'action a pris plus de 2 secondes, ne pas fusionner pour que + # l'on voit le temps que ça a pris + $this->_printAction( + $linePrefix, $level, + $printContent, $content, + false, null, null, + $indentLevel, $err); + # recalculer une nouvelle ligne de préfixe pour le résultat + $linePrefix = $this->getLinePrefix(); + $this->_printAction( + $linePrefix, $level, + false, null, + true, $rsuccess, $rcontent, + $indentLevel, $err); + + } + } elseif ($printContent) { + $this->_printAction( + $linePrefix, $level, + $printContent, $content, + false, $rsuccess, $rcontent, + $indentLevel, $err); + $action["print_content"] = false; + } + $indentLevel++; + }; unset($action); + if ($endAction) $this->_endAction(); + } + + function action($content, ?callable $func=null, ?int $level=null): void { + $this->checkLevel($level); + $actionLevel = $this->_getActionMark(); + // faire en deux temps pour linePrefix soit à jour + $this->actions[] = ["id" => $this->lastActionId++]; + A::merge($this->actions[array_key_last($this->actions)], [ + "action_level" => $actionLevel, + "max_action_level" => null, + "timestamp" => time(), + "line_prefix" => $this->getLinePrefix(), + "level" => $level, + "content" => $content, + "print_content" => true, + "result_success" => null, + "result_content" => null, + ]); + if ($func !== null) { + try { + $action =& $this->actions[array_key_last($this->actions)]; + $action["max_action_level"] = $actionLevel + 1; + $result = $func($this); + if ($this->_getActionMark() > $actionLevel) { + $this->aresult($result); + } + } catch (Exception $e) { + $this->afailure($e); + throw $e; + } finally { + $action["max_action_level"] = null; + $this->_endAction($actionLevel); + } + } + } + + function step($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "step", $content, + $this->getIndentLevel(), $this->err); + } + + function asuccess($content=null, ?int $overrideLevel=null): void { + if (!$this->actions) $this->action(null); + $action =& $this->actions[array_key_last($this->actions)]; + $action["result_success"] = true; + $action["result_content"] = $content; + $this->flushActions(true, $overrideLevel); + } + + function afailure($content=null, ?int $overrideLevel=null): void { + if (!$this->actions) $this->action(null); + $action =& $this->actions[array_key_last($this->actions)]; + $action["result_success"] = false; + $action["result_content"] = $content; + $this->flushActions(true, $overrideLevel); + } + + function adone($content=null, ?int $overrideLevel=null): void { + if (!$this->actions) $this->action(null); + $action =& $this->actions[array_key_last($this->actions)]; + $action["result_success"] = null; + $action["result_content"] = $content; + $this->flushActions(true, $overrideLevel); + } + + function aresult($result=null, ?int $overrideLevel=null): void { + if (!$this->actions) $this->action(null); + if ($result === true) $this->asuccess(null, $overrideLevel); + elseif ($result === false) $this->afailure(null, $overrideLevel); + elseif ($result instanceof Exception) $this->afailure($result, $overrideLevel); + else $this->adone($result, $overrideLevel); + } + + function _endAction(?int $until=null): void { + $action = $this->actions[array_key_last($this->actions)]; + $until ??= $action["max_action_level"]; + $until ??= $this->_getActionMark() - 1; + while (count($this->actions) > $until) { + array_pop($this->actions); + } + } + + function print($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "print", $content, + $this->getIndentLevel(), $this->out); + } + + function info($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "info", $content, + $this->getIndentLevel(), $this->err); + } + + function note($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "note", $content, + $this->getIndentLevel(), $this->err); + } + + function warning($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "warning", $content, + $this->getIndentLevel(), $this->err); + } + + function error($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "error", $content, + $this->getIndentLevel(), $this->err); + } + + function end(bool $all=false): void { + if ($all) $this->_endSection(); + elseif ($this->actions) $this->_endAction(); + elseif ($this->titles) $this->_endTitle(); + else $this->_endSection(); + } +} diff --git a/php/src/output/std/LogMessenger.php b/php/src/output/std/LogMessenger.php new file mode 100644 index 0000000..bc7d978 --- /dev/null +++ b/php/src/output/std/LogMessenger.php @@ -0,0 +1,306 @@ +out = new StdOutput($output ?? STDERR, [ + "color" => $color, + "indent" => $indent, + ]); + $this->defaultLevel = $defaultLevel; + $this->minLevel = $minLevel; + $this->addDate = $addDate; + $this->dateFormat = $dateFormat; + $this->id = $id; + $this->showIds = $showIds; + $this->titles = []; + $this->actions = []; + } + + function resetParams(?array $params=null): void { + $output = $params["output"] ?? null; + $color = $params["color"] ?? null; + $indent = $params["indent"] ?? null; + + $defaultLevel = $params["default_level"] ?? null; + if ($defaultLevel !== null) $defaultLevel = self::verifix_level($defaultLevel); + + $debug = $params["debug"] ?? null; + $minLevel = $params["min_level"] ?? null; + if ($debug !== null) $minLevel ??= self::DEBUG; + $minLevel ??= $params["verbosity"] ?? null; # alias + if ($minLevel !== null) $minLevel = self::verifix_level($minLevel, self::NONE); + + $addDate = $params["add_date"] ?? null; + $dateFormat = $params["date_format"] ?? null; + $id = $params["id"] ?? null; + + $this->out->resetParams([ + "output" => $output, + "color" => $color, + "indent" => $indent, + ]); + if ($defaultLevel !== null) $this->defaultLevel = $defaultLevel; + if ($minLevel !== null) $this->minLevel = $minLevel; + if ($addDate !== null) $this->addDate = boolval($addDate); + if ($dateFormat !== null) $this->dateFormat = $dateFormat; + if ($id !== null) $this->id = $id; + } + + function clone(?array $params=null): IMessenger { + $clone = clone $this; + if ($params !== null) $clone->resetParams($params); + return $clone; + } + + function section($content, ?callable $func=null, ?int $level=null): void { + $this->_endSection(); + if (!$this->checkLevel($level)) return; + $this->_printTitle( + $this->getLinePrefix(), $level, + "section", $content, + 0, $this->out); + if ($func !== null) { + try { + $func($this); + } finally { + $this->_endSection(); + } + } + } + + function _endSection(): void { + $this->end(true); + } + + protected array $titles; + + function _getTitleMark(): int { + return count($this->titles); + } + + function _getTitleId(): ?int { + return end($this->titles)["id"] ?? null; + } + + function title($content, ?callable $func=null, ?int $level=null): void { + if (!$this->checkLevel($level)) return; + $titleLevel = $this->_getTitleMark(); + $this->titles[] = [ + "id" => $this->lastTitleId++, + "title_level" => $titleLevel, + "max_title_level" => null, + ]; + $this->_printTitle( + $this->getLinePrefix(), $level, + "title", $content, + $titleLevel, $this->out); + if ($func !== null) { + try { + $title =& $this->titles[array_key_last($this->titles)]; + $title["max_title_level"] = $titleLevel + 1; + $func($this); + } finally { + $title["max_title_level"] = null; + $this->_endTitle($titleLevel); + } + } + } + + function desc($content, ?int $level=null): void { + if (!$this->checkLevel($level)) return; + $titleLevel = end($this->titles)["title_level"] ?? 0; + $this->_printGeneric( + $this->getLinePrefix(), $level, + "desc", $content, + $titleLevel, $this->out); + + } + + function _endTitle(?int $until=null): void { + $title = $this->titles[array_key_last($this->titles)]; + $until ??= $title["max_title_level"]; + $until ??= $this->_getTitleMark() - 1; + while (count($this->titles) > $until) { + array_pop($this->titles); + } + } + + protected array $actions; + + function _getActionMark(): int { + return count($this->actions); + } + + function _getActionId(): ?int { + return end($this->actions)["id"] ?? null; + } + + function action($content, ?callable $func=null, ?int $level=null): void { + $this->checkLevel($level); + $actionLevel = $this->_getActionMark(); + $this->actions[] = [ + "id" => $this->lastActionId++, + "action_level" => $actionLevel, + "max_action_level" => null, + "level" => $level + ]; + $this->_printAction( + $this->getLinePrefix(), $level, + true, $content, + false, null, null, + $actionLevel, $this->out); + if ($func !== null) { + try { + $action =& $this->actions[array_key_last($this->actions)]; + $action["max_action_level"] = $actionLevel + 1; + $result = $func($this); + if ($this->_getActionMark() > $actionLevel) { + $this->aresult($result); + } + } catch (Exception $e) { + $this->afailure($e); + throw $e; + } finally { + $action["max_action_level"] = null; + $this->_endAction($actionLevel); + } + } + } + + protected function flushActions(bool $endAction=false, ?int $overrideLevel=null): void { + } + + function step($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "step", $content, + $this->getIndentLevel(), $this->out); + } + + function asuccess($content=null, ?int $overrideLevel=null): void { + if ($this->_getActionMark() == 0) $this->action(null); + $action = end($this->actions); + $level = $overrideLevel ?? $action["level"]; + $this->_printAction( + $this->getLinePrefix(), $level, + false, null, + true, true, $content, + $action["action_level"], $this->out); + $this->_endAction(); + } + + function afailure($content=null, ?int $overrideLevel=null): void { + if ($this->_getActionMark() == 0) $this->action(null); + $action = end($this->actions); + $level = $overrideLevel ?? $action["level"]; + $this->_printAction( + $this->getLinePrefix(), $level, + false, null, + true, false, $content, + $action["action_level"], $this->out); + $this->_endAction(); + } + + function adone($content=null, ?int $overrideLevel=null): void { + if ($this->_getActionMark() == 0) $this->action(null); + $action = end($this->actions); + $level = $overrideLevel ?? $action["level"]; + $this->_printAction( + $this->getLinePrefix(), $level, + false, null, + true, null, $content, + $action["action_level"], $this->out); + $this->_endAction(); + } + + function aresult($result=null, ?int $overrideLevel=null): void { + if ($this->_getActionMark() == 0) $this->action(null); + if ($result === true) $this->asuccess(null, $overrideLevel); + elseif ($result === false) $this->afailure(null, $overrideLevel); + elseif ($result instanceof Exception) $this->afailure($result, $overrideLevel); + else $this->adone($result, $overrideLevel); + } + + function _endAction(?int $until=null): void { + $action = $this->actions[array_key_last($this->actions)]; + $until ??= $action["max_action_level"]; + $until ??= $this->_getActionMark() - 1; + while (count($this->actions) > $until) { + array_pop($this->actions); + } + } + + protected function getIndentLevel(bool $withActions=true): int { + $indentLevel = count($this->titles) - 1; + if ($indentLevel < 0) $indentLevel = 0; + if ($withActions) $indentLevel += count($this->actions); + return $indentLevel; + } + + function print($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "print", $content, + $this->getIndentLevel(), $this->out); + } + + function info($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "info", $content, + $this->getIndentLevel(), $this->out); + } + + function note($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "note", $content, + $this->getIndentLevel(), $this->out); + } + + function warning($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "warning", $content, + $this->getIndentLevel(), $this->out); + } + + function error($content, ?int $level=null): void { + $this->_printGenericOrException( + $level, "error", $content, + $this->getIndentLevel(), $this->out); + } + + function end(bool $all=false): void { + if ($all) { + while ($this->actions) $this->adone(); + while ($this->titles) $this->_endTitle(); + } elseif ($this->actions) { + $this->_endAction(); + } elseif ($this->titles) { + $this->_endTitle(); + } + } +} diff --git a/php/src/output/std/NullMessenger.php b/php/src/output/std/NullMessenger.php new file mode 100644 index 0000000..ca4f816 --- /dev/null +++ b/php/src/output/std/NullMessenger.php @@ -0,0 +1,58 @@ +msgs = []; foreach ($msgs as $msg) { if ($msg !== null) $this->msgs[] = $msg; } } /** @var IMessenger[] */ - protected $msgs; + protected ?array $msgs = []; + + function isEmpty(): bool { + return !$this->msgs; + } + + function addMessenger(IMessenger $msg): self { + $this->msgs[] = $msg; + return $this; + } + + function resetParams(?array $params=null): void { + foreach ($this->msgs as $msg) { + $msg->resetParams($params); + } + } - function resetParams(?array $params=null): void { foreach ($this->msgs as $msg) { $msg->resetParams($params); } } function clone(?array $params=null): self { $clone = clone $this; foreach ($clone->msgs as &$msg) { @@ -30,6 +42,7 @@ class ProxyMessenger implements IMessenger { }; unset($msg); return $clone; } + function section($content, ?callable $func=null, ?int $level=null): void { $useFunc = false; foreach ($this->msgs as $msg) { @@ -47,6 +60,7 @@ class ProxyMessenger implements IMessenger { } } } + function title($content, ?callable $func=null, ?int $level=null): void { $useFunc = false; $untils = []; @@ -71,7 +85,13 @@ class ProxyMessenger implements IMessenger { } } } - function desc($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->desc($content, $level); } } + + function desc($content, ?int $level=null): void { + foreach ($this->msgs as $msg) { + $msg->desc($content, $level); + } + } + function action($content, ?callable $func=null, ?int $level=null): void { $useFunc = false; $untils = []; @@ -107,15 +127,70 @@ class ProxyMessenger implements IMessenger { } } } - function step($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->step($content, $level); } } - function asuccess($content=null, ?int $overrideLevel=null): void { foreach ($this->msgs as $msg) { $msg->asuccess($content, $overrideLevel); } } - function afailure($content=null, ?int $overrideLevel=null): void { foreach ($this->msgs as $msg) { $msg->afailure($content, $overrideLevel); } } - function adone($content=null, ?int $overrideLevel=null): void { foreach ($this->msgs as $msg) { $msg->adone($content, $overrideLevel); } } - function aresult($result=null, ?int $overrideLevel=null): void { foreach ($this->msgs as $msg) { $msg->aresult($result, $overrideLevel); } } - function print($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->print($content, $level); } } - function info($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->info($content, $level); } } - function note($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->note($content, $level); } } - function warning($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->warning($content, $level); } } - function error($content, ?int $level=null): void { foreach ($this->msgs as $msg) { $msg->error($content, $level); } } - function end(bool $all=false): void { foreach ($this->msgs as $msg) { $msg->end($all); } } + + function step($content, ?int $level=null): void { + foreach ($this->msgs as $msg) { + $msg->step($content, $level); + } + } + + function asuccess($content=null, ?int $overrideLevel=null): void { + foreach ($this->msgs as $msg) { + $msg->asuccess($content, $overrideLevel); + } + } + + function afailure($content=null, ?int $overrideLevel=null): void { + foreach ($this->msgs as $msg) { + $msg->afailure($content, $overrideLevel); + } + } + + function adone($content=null, ?int $overrideLevel=null): void { + foreach ($this->msgs as $msg) { + $msg->adone($content, $overrideLevel); + } + } + + function aresult($result=null, ?int $overrideLevel=null): void { + foreach ($this->msgs as $msg) { + $msg->aresult($result, $overrideLevel); + } + } + + function print($content, ?int $level=null): void { + foreach ($this->msgs as $msg) { + $msg->print($content, $level); + } + } + + function info($content, ?int $level=null): void { + foreach ($this->msgs as $msg) { + $msg->info($content, $level); + } + } + + function note($content, ?int $level=null): void { + foreach ($this->msgs as $msg) { + $msg->note($content, $level); + } + } + + function warning($content, ?int $level=null): void { + foreach ($this->msgs as $msg) { + $msg->warning($content, $level); + } + } + + function error($content, ?int $level=null): void { + foreach ($this->msgs as $msg) { + $msg->error($content, $level); + } + } + + function end(bool $all=false): void { + foreach ($this->msgs as $msg) { + $msg->end($all); + } + } } diff --git a/php/src/output/std/StdMessenger.php b/php/src/output/std/StdMessenger.php deleted file mode 100644 index 4ac8d83..0000000 --- a/php/src/output/std/StdMessenger.php +++ /dev/null @@ -1,724 +0,0 @@ - self::DEBUG, - "minor" => self::MINOR, "verbose" => self::MINOR, - "normal" => self::NORMAL, - "major" => self::MAJOR, "quiet" => self::MAJOR, - "none" => self::NONE, "silent" => self::NONE, - ]; - - protected static function verifix_level($level, int $max_level=self::MAX_LEVEL): int { - if (!in_array($level, self::VALID_LEVELS, true)) { - $level = cl::get(self::LEVEL_MAP, $level, $level); - } - if (!in_array($level, self::VALID_LEVELS, true)) { - throw new Exception("$level: invalid level"); - } - if ($level > $max_level) { - throw new Exception("$level: level not allowed here"); - } - return $level; - } - - const GENERIC_PREFIXES = [ - self::MAJOR => [ - "section" => [true, "SECTION!", "===", "=", "=", "==="], - "title" => [false, "TITLE!", null, "T", "", "==="], - "desc" => ["DESC!", ">", ""], - "error" => ["CRIT.ERROR!", "E!", ""], - "warning" => ["CRIT.WARNING!", "W!", ""], - "note" => ["ATTENTION!", "N!", ""], - "info" => ["IMPORTANT!", "N!", ""], - "step" => ["*", ".", ""], - "print" => [null, null, null], - ], - self::NORMAL => [ - "section" => [true, "SECTION:", "---", "-", "-", "---"], - "title" => [false, "TITLE:", null, "T", "", "---"], - "desc" => ["DESC:", ">", ""], - "error" => ["ERROR:", "E", ""], - "warning" => ["WARNING:", "W", ""], - "note" => ["NOTE:", "N", ""], - "info" => ["INFO:", "I", ""], - "step" => ["*", ".", ""], - "print" => [null, null, null], - ], - self::MINOR => [ - "section" => [true, "section", null, ">>", "<<", null], - "title" => [false, "title", null, "t", "", null], - "desc" => ["desc", ">", ""], - "error" => ["error", "E", ""], - "warning" => ["warning", "W", ""], - "note" => ["note", "N", ""], - "info" => ["info", "I", ""], - "step" => ["*", ".", ""], - "print" => [null, null, null], - ], - self::DEBUG => [ - "section" => [true, "section", null, ">>", "<<", null], - "title" => [false, "title", null, "t", "", null], - "desc" => ["desc", ">", ""], - "error" => ["debugE", "e", ""], - "warning" => ["debugW", "w", ""], - "note" => ["debugN", "i", ""], - "info" => ["debug", "D", ""], - "step" => ["*", ".", ""], - "print" => [null, null, null], - ], - ]; - - const RESULT_PREFIXES = [ - "failure" => ["(FAILURE)", ""], - "success" => ["(SUCCESS)", ""], - "done" => [null, null], - ]; - - function __construct(?array $params=null) { - $output = cl::get($params, "output"); - $color = cl::get($params, "color"); - $indent = cl::get($params, "indent", static::INDENT); - - $defaultLevel = cl::get($params, "default_level"); - if ($defaultLevel === null) $defaultLevel = self::NORMAL; - $defaultLevel = self::verifix_level($defaultLevel); - - $debug = boolval(cl::get($params, "debug")); - $minLevel = cl::get($params, "min_level"); - if ($minLevel === null && $debug) $minLevel = self::DEBUG; - if ($minLevel === null) $minLevel = cl::get($params, "verbosity"); # alias - if ($minLevel === null) $minLevel = self::NORMAL; - $minLevel = self::verifix_level($minLevel, self::NONE); - - $addDate = boolval(cl::get($params, "add_date")); - $dateFormat = cl::get($params, "date_format", static::DATE_FORMAT); - $id = cl::get($params, "id"); - - $params = [ - "color" => $color, - "indent" => $indent, - ]; - if ($output !== null) { - $this->err = $this->out = new StdOutput($output, $params); - } else { - $this->out = new StdOutput(STDOUT, $params); - $this->err = new StdOutput(STDERR, $params); - } - $this->defaultLevel = $defaultLevel; - $this->minLevel = $minLevel; - $this->addDate = $addDate; - $this->dateFormat = $dateFormat; - $this->id = $id; - $this->inSection = false; - $this->titles = []; - $this->actions = []; - } - - function resetParams(?array $params=null): void { - $output = cl::get($params, "output"); - $color = cl::get($params, "color"); - $indent = cl::get($params, "indent"); - - $defaultLevel = cl::get($params, "default_level"); - if ($defaultLevel !== null) $defaultLevel = self::verifix_level($defaultLevel); - - $debug = cl::get($params, "debug"); - $minLevel = cl::get($params, "min_level"); - if ($minLevel === null && $debug !== null) $minLevel = $debug? self::DEBUG: self::NORMAL; - if ($minLevel === null) $minLevel = cl::get($params, "verbosity"); # alias - if ($minLevel !== null) $minLevel = self::verifix_level($minLevel, self::NONE); - - $addDate = cl::get($params, "add_date"); - $dateFormat = cl::get($params, "date_format"); - $id = cl::get($params, "id"); - - $params = [ - "output" => $output, - "color" => $color, - "indent" => $indent, - ]; - if ($this->out === $this->err) { - $this->out->resetParams($params); - } else { - # NB: si initialement [output] était null, et qu'on spécifie une valeur - # [output], alors les deux instances $out et $err sont mis à jour - # séparément avec la même valeur de output - # de plus, on ne peut plus revenir à la situation initiale avec une - # destination différente pour $out et $err - $this->out->resetParams($params); - $this->err->resetParams($params); - } - if ($defaultLevel !== null) $this->defaultLevel = $defaultLevel; - if ($minLevel !== null) $this->minLevel = $minLevel; - if ($addDate !== null) $this->addDate = boolval($addDate); - if ($dateFormat !== null) $this->dateFormat = $dateFormat; - if ($id !== null) $this->id = $id; - } - - function clone(?array $params=null): IMessenger { - $clone = clone $this; - if ($params !== null) $clone->resetParams($params); - #XXX faut-il marquer la section et les titres du clone à "print" => false? - # ou en faire des références au parent? - # dans tous les cas, on considère qu'il n'y a pas d'actions en cours, et on - # ne doit pas dépiler avec end() plus que l'état que l'on a eu lors du clone - return $clone; - } - - /** @var StdOutput la sortie standard */ - protected $out; - - /** @var StdOutput la sortie d'erreur */ - protected $err; - - /** @var int level par défaut dans lequel les messages sont affichés */ - protected $defaultLevel; - - /** @var int level minimum que doivent avoir les messages pour être affichés */ - protected $minLevel; - - /** @var bool faut-il ajouter la date à chaque ligne? */ - protected $addDate; - - /** @var string format de la date */ - protected $dateFormat; - - /** @var ?string identifiant de ce messenger, à ajouter à chaque ligne */ - protected $id; - - protected function getLinePrefix(): ?string { - $linePrefix = null; - if ($this->addDate) { - $date = date_create()->format($this->dateFormat); - $linePrefix .= "$date "; - } - if ($this->id !== null) { - $linePrefix .= "$this->id "; - } - return $linePrefix; - } - - protected function decrLevel(int $level, int $amount=-1): int { - $level += $amount; - if ($level < self::MIN_LEVEL) $level = self::MIN_LEVEL; - return $level; - } - - protected function checkLevel(?int &$level): bool { - if ($level === null) $level = $this->defaultLevel; - elseif ($level < 0) $level = $this->decrLevel($this->defaultLevel, $level); - return $level >= $this->minLevel; - } - - protected function getIndentLevel(bool $withActions=true): int { - $indentLevel = count($this->titles) - 1; - if ($indentLevel < 0) $indentLevel = 0; - if ($withActions) { - foreach ($this->actions as $action) { - if ($action["level"] < $this->minLevel) continue; - $indentLevel++; - } - } - return $indentLevel; - } - - protected function _printTitle( - ?string $linePrefix, int $level, - string $type, $content, - int $indentLevel, StdOutput $out - ): void { - $prefixes = self::GENERIC_PREFIXES[$level][$type]; - if ($prefixes[0]) $out->print(); - $content = cl::with($content); - if ($out->isColor()) { - $before = $prefixes[2]; - $prefix = $prefixes[3]; - $prefix2 = $prefix !== null? "$prefix ": null; - $suffix = $prefixes[4]; - $suffix2 = $suffix !== null? " $suffix": null; - $after = $prefixes[5]; - - $lines = $out->getLines(false, ...$content); - $maxlen = 0; - foreach ($lines as &$content) { - $line = $out->filterColors($content); - $len = mb_strlen($line); - if ($len > $maxlen) $maxlen = $len; - $content = [$content, $len]; - }; unset($content); - if ($before !== null) { - if ($linePrefix !== null) $out->write($linePrefix); - $out->iprint($indentLevel, $prefix, substr($before, 1), str_repeat($before[0], $maxlen), $suffix); - } - foreach ($lines as [$content, $len]) { - if ($linePrefix !== null) $out->write($linePrefix); - $padding = $len < $maxlen? str_repeat(" ", $maxlen - $len): null; - $out->iprint($indentLevel, $prefix2, $content, $padding, $suffix2); - } - if ($after !== null) { - if ($linePrefix !== null) $out->write($linePrefix); - $out->iprint($indentLevel, $prefix, substr($after, 1), str_repeat($after[0], $maxlen), $suffix); - } - } else { - $prefix = $prefixes[1]; - if ($prefix !== null) $prefix .= " "; - $prefix2 = str_repeat(" ", mb_strlen($prefix)); - $lines = $out->getLines(false, ...$content); - foreach ($lines as $content) { - if ($linePrefix !== null) $out->write($linePrefix); - $out->iprint($indentLevel, $prefix, $content); - $prefix = $prefix2; - } - } - } - - protected function _printAction( - ?string $linePrefix, int $level, - bool $printContent, $content, - bool $printResult, ?bool $rsuccess, $rcontent, - int $indentLevel, StdOutput $out - ): void { - $color = $out->isColor(); - if ($rsuccess === true) $type = "success"; - elseif ($rsuccess === false) $type = "failure"; - else $type = "done"; - $rprefixes = self::RESULT_PREFIXES[$type]; - if ($color) { - $rprefix = $rprefixes[1]; - $rprefix2 = null; - if ($rprefix !== null) { - $rprefix .= " "; - $rprefix2 = $out->filterColors($out->filterContent($rprefix)); - $rprefix2 = str_repeat(" ", mb_strlen($rprefix2)); - } - } else { - $rprefix = $rprefixes[0]; - if ($rprefix !== null) $rprefix .= " "; - $rprefix2 = str_repeat(" ", mb_strlen($rprefix)); - } - if ($printContent && $printResult) { - A::ensure_array($content); - if ($rcontent) { - $content[] = ": "; - $content[] = $rcontent; - } - $lines = $out->getLines(false, ...$content); - foreach ($lines as $content) { - if ($linePrefix !== null) $out->write($linePrefix); - $out->iprint($indentLevel, $rprefix, $content); - $rprefix = $rprefix2; - } - } elseif ($printContent) { - $prefixes = self::GENERIC_PREFIXES[$level]["step"]; - if ($color) { - $prefix = $prefixes[1]; - if ($prefix !== null) $prefix .= " "; - $prefix2 = $out->filterColors($out->filterContent($prefix)); - $prefix2 = str_repeat(" ", mb_strlen($prefix2)); - $suffix = $prefixes[2]; - } else { - $prefix = $prefixes[0]; - if ($prefix !== null) $prefix .= " "; - $prefix2 = str_repeat(" ", mb_strlen($prefix)); - $suffix = null; - } - A::ensure_array($content); - $content[] = ":"; - $lines = $out->getLines(false, ...$content); - foreach ($lines as $content) { - if ($linePrefix !== null) $out->write($linePrefix); - $out->iprint($indentLevel, $prefix, $content, $suffix); - $prefix = $prefix2; - } - } elseif ($printResult) { - if (!$rcontent) { - if ($type === "success") $rcontent = $color? "succès": ""; - elseif ($type === "failure") $rcontent = $color? "échec": ""; - elseif ($type === "done") $rcontent = "fait"; - } - $rprefix = " $rprefix"; - $rprefix2 = " $rprefix2"; - $lines = $out->getLines(false, $rcontent); - foreach ($lines as $rcontent) { - if ($linePrefix !== null) $out->write($linePrefix); - $out->iprint($indentLevel, $rprefix, $rcontent); - $rprefix = $rprefix2; - } - } - } - - protected function _printGeneric( - ?string $linePrefix, int $level, - string $type, $content, - int $indentLevel, StdOutput $out - ): void { - $prefixes = self::GENERIC_PREFIXES[$level][$type]; - $content = cl::with($content); - if ($out->isColor()) { - $prefix = $prefixes[1]; - $prefix2 = null; - if ($prefix !== null) { - $prefix .= " "; - $prefix2 = $out->filterColors($out->filterContent($prefix)); - $prefix2 = str_repeat(" ", mb_strlen($prefix2)); - } - $suffix = $prefixes[2]; - $lines = $out->getLines(false, ...$content); - foreach ($lines as $content) { - if ($linePrefix !== null) $out->write($linePrefix); - $out->iprint($indentLevel, $prefix, $content, $suffix); - $prefix = $prefix2; - } - } else { - $prefix = $prefixes[0]; - if ($prefix !== null) $prefix .= " "; - $prefix2 = str_repeat(" ", mb_strlen($prefix)); - $lines = $out->getLines(false, ...$content); - foreach ($lines as $content) { - if ($linePrefix !== null) $out->write($linePrefix); - $out->iprint($indentLevel, $prefix, $content); - $prefix = $prefix2; - } - } - } - - protected function _printGenericOrException( - ?int $level, - string $type, $content, - int $indentLevel, StdOutput $out - ): void { - $linePrefix = $this->getLinePrefix(); - # si $content contient des exceptions, les afficher avec un level moindre - $exceptions = null; - if (is_array($content)) { - $valueContent = null; - foreach ($content as $value) { - if ($value instanceof Throwable || $value instanceof ExceptionShadow) { - $exceptions[] = $value; - } else { - $valueContent[] = $value; - } - } - if ($valueContent === null) $content = null; - elseif (count($valueContent) == 1) $content = $valueContent[0]; - else $content = $valueContent; - } elseif ($content instanceof Throwable || $content instanceof ExceptionShadow) { - $exceptions[] = $content; - $content = null; - } - - $printActions = true; - $showContent = $this->checkLevel($level); - if ($content !== null && $showContent) { - $this->printActions(); $printActions = false; - $this->_printGeneric($linePrefix, $level, $type, $content, $indentLevel, $out); - } - if ($exceptions !== null) { - $level1 = $this->decrLevel($level); - $showTraceback = $this->checkLevel($level1); - foreach ($exceptions as $exception) { - # tout d'abord message - $message = exceptions::get_message($exception); - if ($showContent) { - if ($printActions) { $this->printActions(); $printActions = false; } - $this->_printGeneric($linePrefix, $level, $type, $message, $indentLevel, $out); - } - # puis summary et traceback - if ($showTraceback) { - if ($printActions) { $this->printActions(); $printActions = false; } - $summary = exceptions::get_summary($exception, false); - $this->_printGeneric($linePrefix, $level1, $type, $summary, $indentLevel, $out); - $traceback = exceptions::get_traceback($exception); - $this->_printGeneric($linePrefix, $level1, $type, $traceback, $indentLevel, $out); - } - } - } - } - - /** @var bool est-on dans une section? */ - protected $inSection; - - /** @var array section qui est en attente d'affichage */ - protected $section; - - function section($content, ?callable $func=null, ?int $level=null): void { - $this->_endSection(); - $this->inSection = true; - if (!$this->checkLevel($level)) return; - $this->section = [ - "line_prefix" => $this->getLinePrefix(), - "level" => $level, - "content" => $content, - "print_content" => true, - ]; - if ($func !== null) { - try { - $func($this); - } finally { - $this->_endSection(); - } - } - } - - protected function printSection() { - $section =& $this->section; - if ($section !== null && $section["print_content"]) { - $this->_printTitle( - $section["line_prefix"], $section["level"], - "section", $section["content"], - 0, $this->err); - $section["print_content"] = false; - } - } - - function _endSection(): void { - $this->inSection = false; - $this->section = null; - } - - /** @var array */ - protected $titles; - - /** @var array */ - protected $title; - - function _getTitleMark(): int { - return count($this->titles); - } - - function title($content, ?callable $func=null, ?int $level=null): void { - if (!$this->checkLevel($level)) return; - $until = $this->_getTitleMark(); - $this->titles[] = [ - "line_prefix" => $this->getLinePrefix(), - "level" => $level, - "content" => $content, - "print_content" => true, - "descs" => [], - "print_descs" => false, - ]; - $this->title =& $this->titles[$until]; - if ($func !== null) { - try { - $func($this); - } finally { - $this->_endTitle($until); - } - } - } - - function desc($content, ?int $level=null): void { - if (!$this->checkLevel($level)) return; - $title =& $this->title; - $title["descs"][] = [ - "line_prefix" => $this->getLinePrefix(), - "level" => $level, - "content" => $content, - ]; - $title["print_descs"] = true; - } - - protected function printTitles(): void { - $this->printSection(); - $err = $this->err; - $indentLevel = 0; - foreach ($this->titles as &$title) { - if ($title["print_content"]) { - $this->_printTitle( - $title["line_prefix"], $title["level"], - "title", $title["content"], - $indentLevel, $err); - $title["print_content"] = false; - } - if ($title["print_descs"]) { - foreach ($title["descs"] as $desc) { - $this->_printGeneric( - $desc["line_prefix"], $desc["level"], - "desc", $desc["content"], - $indentLevel, $err); - } - $title["descs"] = []; - $title["print_descs"] = false; - } - $indentLevel++; - }; unset($title); - } - - function _endTitle(?int $until=null): void { - if ($until === null) $until = $this->_getTitleMark() - 1; - while (count($this->titles) > $until) { - array_pop($this->titles); - } - if ($this->titles) { - $this->title =& $this->titles[count($this->titles) - 1]; - } else { - $this->titles = []; - unset($this->title); - } - } - - /** @var array */ - protected $actions; - - /** @var array */ - protected $action; - - function _getActionMark(): int { - return count($this->actions); - } - - function action($content, ?callable $func=null, ?int $level=null): void { - $this->checkLevel($level); - $until = $this->_getActionMark(); - $this->actions[] = [ - "line_prefix" => $this->getLinePrefix(), - "level" => $level, - "content" => $content, - "print_content" => true, - "result_success" => null, - "result_content" => null, - ]; - $this->action =& $this->actions[$until]; - if ($func !== null) { - try { - $result = $func($this); - if ($this->_getActionMark() > $until) { - $this->aresult($result); - } - } catch (Exception $e) { - $this->afailure($e); - throw $e; - } finally { - $this->_endAction($until); - } - } - } - - function printActions(bool $endAction=false, ?int $overrideLevel=null): void { - $this->printTitles(); - $err = $this->err; - $indentLevel = $this->getIndentLevel(false); - $lastIndex = count($this->actions) - 1; - $index = 0; - foreach ($this->actions as &$action) { - $mergeResult = $index++ == $lastIndex && $endAction; - $linePrefix = $action["line_prefix"]; - $level = $overrideLevel?? $action["level"]; - $content = $action["content"]; - $printContent = $action["print_content"]; - $rsuccess = $action["result_success"]; - $rcontent = $action["result_content"]; - if ($level < $this->minLevel) continue; - if ($mergeResult) { - $this->_printAction( - $linePrefix, $level, - $printContent, $content, - true, $rsuccess, $rcontent, - $indentLevel, $err); - } elseif ($printContent) { - $this->_printAction( - $linePrefix, $level, - $printContent, $content, - false, $rsuccess, $rcontent, - $indentLevel, $err); - $action["print_content"] = false; - } - $indentLevel++; - }; unset($action); - if ($endAction) $this->_endAction(); - } - - function step($content, ?int $level=null): void { - $this->_printGenericOrException($level, "step", $content, $this->getIndentLevel(), $this->err); - } - - function asuccess($content=null, ?int $overrideLevel=null): void { - if (!$this->actions) $this->action(null); - $this->action["result_success"] = true; - $this->action["result_content"] = $content; - $this->printActions(true, $overrideLevel); - } - - function afailure($content=null, ?int $overrideLevel=null): void { - if (!$this->actions) $this->action(null); - $this->action["result_success"] = false; - $this->action["result_content"] = $content; - $this->printActions(true, $overrideLevel); - } - - function adone($content=null, ?int $overrideLevel=null): void { - if (!$this->actions) $this->action(null); - $this->action["result_success"] = null; - $this->action["result_content"] = $content; - $this->printActions(true, $overrideLevel); - } - - function aresult($result=null, ?int $overrideLevel=null): void { - if (!$this->actions) $this->action(null); - if ($result === true) $this->asuccess(null, $overrideLevel); - elseif ($result === false) $this->afailure(null, $overrideLevel); - elseif ($result instanceof Exception) $this->afailure($result, $overrideLevel); - else $this->adone($result, $overrideLevel); - } - - function _endAction(?int $until=null): void { - if ($until === null) $until = $this->_getActionMark() - 1; - while (count($this->actions) > $until) { - array_pop($this->actions); - } - if ($this->actions) { - $this->action =& $this->actions[count($this->actions) - 1]; - } else { - $this->actions = []; - unset($this->action); - } - } - - function print($content, ?int $level=null): void { - $this->_printGenericOrException($level, "print", $content, $this->getIndentLevel(), $this->out); - } - - function info($content, ?int $level=null): void { - $this->_printGenericOrException($level, "info", $content, $this->getIndentLevel(), $this->err); - } - - function note($content, ?int $level=null): void { - $this->_printGenericOrException($level, "note", $content, $this->getIndentLevel(), $this->err); - } - - function warning($content, ?int $level=null): void { - $this->_printGenericOrException($level, "warning", $content, $this->getIndentLevel(), $this->err); - } - - function error($content, ?int $level=null): void { - $this->_printGenericOrException($level, "error", $content, $this->getIndentLevel(), $this->err); - } - - function end(bool $all=false): void { - if ($all) { - while ($this->actions) $this->adone(); - while ($this->titles) $this->_endTitle(); - $this->_endSection(); - } elseif ($this->actions) { - $this->_endAction(); - } elseif ($this->titles) { - $this->_endTitle(); - } else { - $this->_endSection(); - } - } -} diff --git a/php/src/output/std/StdOutput.php b/php/src/output/std/StdOutput.php index c30c466..945b9b3 100644 --- a/php/src/output/std/StdOutput.php +++ b/php/src/output/std/StdOutput.php @@ -79,12 +79,12 @@ class StdOutput { } function resetParams(?array $params=null): void { - $output = cl::get($params, "output"); + $output = $params["output"] ?? null; $maskErrors = null; - $color = cl::get($params, "color"); - $filterTags = cl::get($params, "filter_tags"); - $indent = cl::get($params, "indent"); - $flush = cl::get($params, "flush"); + $color = $params["color"] ?? null; + $filterTags = $params["filter_tags"] ?? null; + $indent = $params["indent"] ?? null; + $flush = $params["flush"] ?? null; if ($output instanceof Stream) $output = $output->getResource(); if ($output !== null) { @@ -105,14 +105,14 @@ class StdOutput { else $message = "$output: open error"; throw new Exception($message); } - if ($flush === null) $flush = true; + $flush ??= true; } else { $outf = $output; } $this->outf = $outf; $this->maskErrors = $maskErrors; - if ($color === null) $color = stream_isatty($outf); - if ($flush === null) $flush = false; + $color ??= stream_isatty($outf); + $flush ??= false; } if ($color !== null) $this->color = boolval($color); if ($filterTags !== null) $this->filterTags = boolval($filterTags); @@ -124,23 +124,23 @@ class StdOutput { protected $outf; /** @var bool faut-il masquer les erreurs d'écriture? */ - protected $maskErrors; + protected ?bool $maskErrors; /** @var bool faut-il autoriser la sortie en couleur? */ - protected $color; + protected bool $color = false; function isColor(): bool { return $this->color; } /** @var bool faut-il enlever les tags dans la sortie? */ - protected $filterTags; + protected bool $filterTags = true; /** @var string indentation unitaire */ - protected $indent; + protected string $indent = " "; /** @var bool faut-il flush le fichier après l'écriture de chaque ligne */ - protected $flush; + protected bool $flush = true; function isatty(): bool { return stream_isatty($this->outf); @@ -167,6 +167,7 @@ class StdOutput { $text .= "m"; return $text; } + function filterContent(string $text): string { # couleur au début $text = preg_replace_callback('/]*)>/', [self::class, "replace_colors"], $text); @@ -178,6 +179,7 @@ class StdOutput { } return $text; } + function filterColors(string $text): string { return preg_replace('/\x1B\[.*?m/', "", $text); } diff --git a/php/src/output/std/_IMessenger.php b/php/src/output/std/_IMessenger.php index 9b54b59..ed1c70f 100644 --- a/php/src/output/std/_IMessenger.php +++ b/php/src/output/std/_IMessenger.php @@ -7,13 +7,84 @@ use nulib\output\IMessenger; * Interface _IMessenger: méthodes privées de IMessenger */ interface _IMessenger extends IMessenger { + const INDENT = " "; + + const DATE_FORMAT = 'Y-m-d\TH:i:s.u'; + + const VALID_LEVELS = [self::DEBUG, self::MINOR, self::NORMAL, self::MAJOR, self::NONE]; + + const LEVEL_MAP = [ + "debug" => self::DEBUG, + "minor" => self::MINOR, "verbose" => self::MINOR, + "normal" => self::NORMAL, + "major" => self::MAJOR, "quiet" => self::MAJOR, + "none" => self::NONE, "silent" => self::NONE, + ]; + + const GENERIC_PREFIXES = [ + self::MAJOR => [ + "section" => [true, "SECTION!", "===", "=", "=", "==="], + "title" => [false, "TITLE!", null, "T", "", "==="], + "desc" => ["DESC!", ">", ""], + "error" => ["CRIT.ERROR!", "E!", ""], + "warning" => ["CRIT.WARNING!", "W!", ""], + "note" => ["ATTENTION!", "N!", ""], + "info" => ["IMPORTANT!", "N!", ""], + "step" => ["*", ".", ""], + "print" => [null, null, null], + ], + self::NORMAL => [ + "section" => [true, "SECTION:", "---", "-", "-", "---"], + "title" => [false, "TITLE:", null, "T", "", "---"], + "desc" => ["DESC:", ">", ""], + "error" => ["ERROR:", "E", ""], + "warning" => ["WARNING:", "W", ""], + "note" => ["NOTE:", "N", ""], + "info" => ["INFO:", "I", ""], + "step" => ["*", ".", ""], + "print" => [null, null, null], + ], + self::MINOR => [ + "section" => [true, "section", null, ">>", "<<", null], + "title" => [false, "title", null, "t", "", null], + "desc" => ["desc", ">", ""], + "error" => ["error", "E", ""], + "warning" => ["warning", "W", ""], + "note" => ["note", "N", ""], + "info" => ["info", "I", ""], + "step" => ["*", ".", ""], + "print" => [null, null, null], + ], + self::DEBUG => [ + "section" => [true, "section", null, ">>", "<<", null], + "title" => [false, "title", null, "t", "", null], + "desc" => ["desc", ">", ""], + "error" => ["debugE", "e", ""], + "warning" => ["debugW", "w", ""], + "note" => ["debugN", "i", ""], + "info" => ["debug", "D", ""], + "step" => ["*", ".", ""], + "print" => [null, null, null], + ], + ]; + + const RESULT_PREFIXES = [ + "failure" => ["(FAILURE)", ""], + "success" => ["(SUCCESS)", ""], + "done" => [null, null], + ]; + function _endSection(): void; function _getTitleMark(): int; + function _getTitleId(): ?int; + function _endTitle(?int $until=null): void; function _getActionMark(): int; + function _getActionId(): ?int; + function _endAction(?int $until=null): void; } diff --git a/php/src/output/web.php b/php/src/output/web.php new file mode 100644 index 0000000..c3b6e4b --- /dev/null +++ b/php/src/output/web.php @@ -0,0 +1,15 @@ +getTimestamp() - $start->getTimestamp(); return (new self($seconds, $resolution))->formatAt(); } - + static function format_since(DateTimeInterface $start, ?DateTimeInterface $now=null, ?int $resolution=null): string { $now ??= new DateTime(); $seconds = $now->getTimestamp() - $start->getTimestamp(); return (new self($seconds, $resolution))->formatSince(); } - + static function format_delay(DateTimeInterface $start, ?DateTimeInterface $now=null, ?int $resolution=null): string { $now ??= new DateTime(); $seconds = $now->getTimestamp() - $start->getTimestamp(); diff --git a/php/src/str.php b/php/src/str.php index c330b37..0614ad1 100644 --- a/php/src/str.php +++ b/php/src/str.php @@ -110,7 +110,7 @@ class str { if ($s === null) return null; else return ucfirst($s); } - + static final function upperw(?string $s, ?string $delimiters=null): ?string { if ($s === null) return null; if ($delimiters !== null) return ucwords($s, $delimiters); @@ -438,7 +438,7 @@ class str { } elseif (preg_match(self::CAMEL_PATTERN2, $camel, $ms, PREG_OFFSET_CAPTURE)) { # préfixe en minuscule } else { - throw exceptions::invalid_type($camel, $kind, "camel string"); + throw exceptions::invalid_value($camel, "camel string"); } $parts[] = strtolower($ms[1][0]); $index = intval($ms[1][1]) + strlen($ms[1][0]); diff --git a/php/src/txt.php b/php/src/txt.php index 2c5ef53..68a2794 100644 --- a/php/src/txt.php +++ b/php/src/txt.php @@ -105,7 +105,7 @@ class txt { if ($s === null) return null; return mb_strtoupper(mb_substr($s, 0, 1)).mb_substr($s, 1); } - + static final function upperw(?string $s, ?string $delimiters=null): ?string { if ($s === null) return null; if ($delimiters === null) $delimiters = " _-\t\r\n\f\v"; diff --git a/php/tbin/.gitignore b/php/tbin/.gitignore index c44eb09..4e0bb30 100644 --- a/php/tbin/.gitignore +++ b/php/tbin/.gitignore @@ -1,2 +1,3 @@ /*.db /*.cache +/*.log diff --git a/php/tbin/test-console.php b/php/tbin/test-console.php deleted file mode 100755 index bc50074..0000000 --- a/php/tbin/test-console.php +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/php -title("title0"); -$msg->title("title1"); -$msg->print("print under title1"); -$msg->end(); -$msg->print("print under title0"); -$msg->end(); - -$msg->desc("action avec step"); -$msg->action("action avec step"); -$msg->step("step"); -$msg->asuccess("action success"); - -$msg->action("action avec step"); -$msg->step("step"); -$msg->afailure("action failure"); - -$msg->action("action avec step"); -$msg->step("step"); -$msg->adone("action neutral"); - -$msg->desc("actions sans step"); -$msg->action("action sans step"); -$msg->asuccess("action success"); - -$msg->action("action sans step"); -$msg->afailure("action failure"); - -$msg->action("action sans step"); -$msg->adone("action neutral"); - -$msg->desc("actions imbriquées"); -$msg->action("action0"); -$msg->action("action1"); -$msg->action("action2"); -$msg->asuccess("action2 success"); -$msg->asuccess("action1 success"); -$msg->asuccess("action0 success"); - -$msg->desc("action avec step, sans messages"); -$msg->action("action avec step, sans messages, success"); -$msg->step("step"); -$msg->asuccess(); - -$msg->action("action avec step, sans messages, failure"); -$msg->step("step"); -$msg->afailure(); - -$msg->action("action avec step, sans messages, done"); -$msg->step("step"); -$msg->adone(); - -$msg->desc("action sans step, sans messages"); -$msg->action("action sans step, sans messages, success"); -$msg->asuccess(); - -$msg->action("action sans step, sans messages, failure"); -$msg->afailure(); - -$msg->action("action sans step, sans messages, done"); -$msg->adone(); - -$msg->desc("actions imbriquées, sans messages"); -$msg->action("action0"); -$msg->action("action1"); -$msg->action("action2"); -$msg->asuccess(); -$msg->asuccess(); -$msg->asuccess(); - -$msg->info("info"); -$msg->note("note"); -$msg->warning("warning"); -$msg->error("error"); - -$msg->section("section", function ($msg) { - $msg->title("title", function ($msg) { - $msg->desc("desc"); - $msg->print("print"); - - $msg->desc("action avec step"); - $msg->action("action avec step", function ($msg) { - $msg->step("step"); - $msg->asuccess("action success"); - }); - - $msg->action("action avec step", function ($msg) { - $msg->step("step"); - $msg->afailure("action failure"); - }); - - $msg->action("action avec step", function ($msg) { - $msg->step("step"); - $msg->adone("action done"); - }); - - $msg->desc("actions sans step"); - $msg->action("action sans step", function ($msg) { - $msg->asuccess("action success"); - }); - - $msg->action("action sans step", function ($msg) { - $msg->afailure("action failure"); - }); - - $msg->action("action sans step", function ($msg) { - $msg->adone("action done"); - }); - - $msg->desc("actions imbriquées"); - $msg->action("action0", function ($msg) { - $msg->action("action1", function ($msg) { - $msg->action("action2", function ($msg) { - $msg->asuccess("action2 success"); - }); - $msg->asuccess("action1 success"); - }); - $msg->asuccess("action0 success"); - }); - - $msg->desc("action avec step, sans messages"); - $msg->action("action avec step, sans messages, success", function ($msg) { - $msg->step("step"); - $msg->asuccess(); - }); - - $msg->action("action avec step, sans messages, failure", function ($msg) { - $msg->step("step"); - $msg->afailure(); - }); - - $msg->action("action avec step, sans messages, done", function ($msg) { - $msg->step("step"); - $msg->adone(); - }); - - $msg->desc("action sans step, sans messages"); - $msg->action("action sans step, sans messages, success", function ($msg) { - $msg->asuccess(); - }); - - $msg->action("action sans step, sans messages, failure", function ($msg) { - $msg->afailure(); - }); - - $msg->action("action sans step, sans messages, done", function ($msg) { - $msg->adone(); - }); - - $msg->desc("actions imbriquées, sans messages"); - $msg->action("action0", function ($msg) { - $msg->action("action1", function ($msg) { - $msg->action("action2", function ($msg) { - $msg->asuccess(); - }); - $msg->asuccess(); - }); - $msg->asuccess(); - }); - - $msg->desc("action avec step, avec code de retour"); - $msg->action("action avec step, avec code de retour true", function ($msg) { - $msg->step("step"); - return true; - }); - - $msg->action("action avec step, avec code de retour false", function ($msg) { - $msg->step("step"); - return false; - }); - - $msg->action("action avec step, avec code de retour autre", function ($msg) { - $msg->step("step"); - return "autre"; - }); - - $msg->action("action avec step, avec code de retour null", function ($msg) { - $msg->step("step"); - }); - - $msg->desc("action sans step, avec code de retour"); - $msg->action("action sans step, avec code de retour true", function ($msg) { - return true; - }); - - $msg->action("action sans step, avec code de retour false", function ($msg) { - return false; - }); - - $msg->action("action sans step, avec code de retour autre", function ($msg) { - return "autre"; - }); - - # ici, il n'y aura pas de message du tout - $msg->action("action sans step, avec code de retour null", function ($msg) { - }); - - $msg->info("info"); - $msg->note("note"); - $msg->warning("warning"); - $msg->error("error"); - }); -}); - -$msg->section("multi-line\nsection", function ($msg) { - $msg->title("multi-line\ntitle"); - $msg->title("another\ntitle"); - - $msg->print("multi-line\nprint"); - $msg->info("multi-line\ninfo"); - $msg->action("multi-line\naction"); - $msg->asuccess(); - $msg->action("multi-line\naction"); - $msg->step("multi-line\nstep"); - $msg->afailure(); - $msg->action("multi-line\naction"); - $msg->step("multi-line\nstep"); - $msg->asuccess("multi-line\nsuccess"); - $msg->action("multi-line\naction"); - $msg->step("multi-line\nstep"); - $msg->adone("multi-line\ndone"); - - $msg->end(); - $msg->end(); -}); - -$msg->section("Exceptions", function ($msg) { - $e = new Exception("message"); - $u1 = new UserException("userMessage"); - $u2 = new UserException("userMessage", "techMessage"); - $msg->title("avec message", function ($msg) use ($e, $u1, $u2) { - $msg->info(["exception", $e]); - $msg->info(["userException1", $u1]); - $msg->info(["userException2", $u2]); - }); - $msg->title("sans message", function ($msg) use ($e, $u1, $u2) { - $msg->info($e); - $msg->info($u1); - $msg->info($u2); - }); -}); diff --git a/php/tbin/test-mysql.php b/php/tbin/test-mysql.php index e2eb555..043d924 100644 --- a/php/tbin/test-mysql.php +++ b/php/tbin/test-mysql.php @@ -7,9 +7,9 @@ use nulib\db\CapacitorChannel; use nulib\db\mysql\Mysql; use nulib\db\mysql\MysqlStorage; use nulib\output\msg; -use nulib\output\std\StdMessenger; +use nulib\output\std\ConsoleMessenger; -msg::set_messenger_class(StdMessenger::class); +msg::set_messenger_class(ConsoleMessenger::class); $db = new Mysql([ "type" => "mysql", diff --git a/php/tbin/test-output-forever.php b/php/tbin/test-output-forever.php index 42d014d..6bee7b2 100755 --- a/php/tbin/test-output-forever.php +++ b/php/tbin/test-output-forever.php @@ -3,10 +3,10 @@ require(__DIR__.'/../vendor/autoload.php'); use nulib\UserException; -use nulib\output\std\StdMessenger; +use nulib\output\std\ConsoleMessenger; use nulib\output\msg; -msg::set_messenger(new StdMessenger(), new StdMessenger([ +msg::set_messenger(new ConsoleMessenger(), new ConsoleMessenger([ "output" => "output-forever.log", ])); diff --git a/php/tbin/test-output.php b/php/tbin/test-output.php new file mode 100755 index 0000000..78aa8d0 --- /dev/null +++ b/php/tbin/test-output.php @@ -0,0 +1,458 @@ +#!/usr/bin/php +title("title"); + sleep(5); + $msg->info("info"); + sleep(5); + $msg->info("info"); + $msg->end(); + + echo date("Y-m-d\\TH:i:s.u")."\n"; + $msg->action("action"); + sleep(5); + $msg->info("info"); + sleep(5); + $msg->info("info"); + $msg->adone(); + + echo date("Y-m-d\\TH:i:s.u")."\n"; + $msg->action("action"); + sleep(5); + $msg->asuccess(); + + echo date("Y-m-d\\TH:i:s.u")."\n"; + $msg->action("action"); + $msg->asuccess("plouf1"); + + echo date("Y-m-d\\TH:i:s.u")."\n"; + $msg->action("action"); + sleep(5); + $msg->asuccess("plouf2"); +} + +if ($titles) { + $msg->title("title0"); + $msg->desc("desc0"); + $msg->title("title1"); + $msg->desc("desc1"); + $msg->print("print under title1"); + $msg->end(); + $msg->print("print under title0"); + $msg->end(); + $msg->print("print out of title"); +} + +if ($maxTitleLevel) { + $msg->info("test maxTitleLevel"); + $msg->title("1first", function(IMessenger $msg) { + $msg->info("1one"); + $msg->end(); + $msg->info("1two"); + $msg->end(); + $msg->info("1three"); + }); + $msg->info("0one"); + $msg->end(); + $msg->info("0two"); + $msg->end(); + $msg->info("0three"); + + $msg->title("2first", function(IMessenger $msg) { + $msg->title("3second", function(IMessenger $msg) { + $msg->title("4third", function(IMessenger $msg) { + $msg->info("4one"); + $msg->end(); + $msg->info("4two"); + $msg->end(); + $msg->info("4three"); + }); + $msg->info("3four"); + $msg->end(); + $msg->info("3five"); + $msg->end(); + $msg->info("3six"); + }); + $msg->info("2seven"); + $msg->end(); + $msg->info("2eight"); + $msg->end(); + $msg->info("2nine"); + }); + $msg->info("1one"); + $msg->end(); + $msg->info("1two"); + $msg->end(); + $msg->info("1three"); +} + +if ($actions) { + $msg->desc("action avec step"); + $msg->action("action avec step"); + $msg->step("step"); + $msg->asuccess("action success"); + + $msg->action("action avec step"); + $msg->step("step"); + $msg->afailure("action failure"); + + $msg->action("action avec step"); + $msg->step("step"); + $msg->adone("action neutral"); + + $msg->desc("actions sans step"); + $msg->action("action sans step"); + $msg->asuccess("action success"); + + $msg->action("action sans step"); + $msg->afailure("action failure"); + + $msg->action("action sans step"); + $msg->adone("action neutral"); + + $msg->desc("actions imbriquées"); + $msg->action("action0"); + $msg->action("action1"); + $msg->action("action2"); + $msg->asuccess("action2 success"); + $msg->asuccess("action1 success"); + $msg->asuccess("action0 success"); + + $msg->desc("action avec step, sans messages"); + $msg->action("action avec step, sans messages, success"); + $msg->step("step"); + $msg->asuccess(); + + $msg->action("action avec step, sans messages, failure"); + $msg->step("step"); + $msg->afailure(); + + $msg->action("action avec step, sans messages, done"); + $msg->step("step"); + $msg->adone(); + + $msg->desc("action sans step, sans messages"); + $msg->action("action sans step, sans messages, success"); + $msg->asuccess(); + + $msg->action("action sans step, sans messages, failure"); + $msg->afailure(); + + $msg->action("action sans step, sans messages, done"); + $msg->adone(); + + $msg->desc("actions imbriquées, sans messages"); + $msg->action("action0"); + $msg->action("action1"); + $msg->action("action2"); + $msg->asuccess(); + $msg->asuccess(); + $msg->asuccess(); +} + +if ($maxActionLevel) { + $msg->info("test maxActionLevel"); + $msg->action("first1", function (IMessenger $msg) { + $msg->info("one"); + $msg->end(); + $msg->info("two"); + $msg->end(); + $msg->info("three"); + }); + $msg->action("first2", function (IMessenger $msg) { + $msg->info("one"); + $msg->adone(); + $msg->info("two"); + $msg->adone(); + $msg->info("three"); + }); + $msg->action("first3", function (IMessenger $msg) { + $msg->action("second", function (IMessenger $msg) { + $msg->action("third", function (IMessenger $msg) { + $msg->info("one"); + $msg->end(); + $msg->info("two"); + $msg->end(); + $msg->info("three"); + }); + $msg->info("four"); + $msg->end(); + $msg->info("five"); + $msg->end(); + $msg->info("six"); + }); + $msg->info("seven"); + $msg->end(); + $msg->info("eight"); + $msg->end(); + $msg->info("nine"); + }); + $msg->info("ten"); + $msg->end(); + $msg->info("eleven"); + $msg->end(); + $msg->info("twelve"); + + $msg->action("first4", function (IMessenger $msg) { + $msg->action("second", function (IMessenger $msg) { + $msg->action("third", function (IMessenger $msg) { + $msg->info("one"); + $msg->adone(); + $msg->info("two"); + $msg->adone(); + $msg->info("three"); + }); + $msg->info("four"); + $msg->adone(); + $msg->info("five"); + $msg->adone(); + $msg->info("six"); + }); + $msg->info("seven"); + $msg->adone(); + $msg->info("eight"); + $msg->adone(); + $msg->info("nine"); + }); + $msg->info("ten"); + $msg->adone(); + $msg->info("eleven"); + $msg->adone(); + $msg->info("twelve"); +} + +if ($levels) { + $msg->info("info"); + $msg->note("note"); + $msg->warning("warning"); + $msg->error("error"); +} + +if ($complete) { + $msg->section("section", function (IMessenger $msg) { + $msg->title("title", function (IMessenger $msg) { + $msg->desc("desc"); + $msg->print("print"); + + $msg->desc("action avec step"); + $msg->action("action avec step", function (IMessenger $msg) { + $msg->step("step"); + $msg->asuccess("action success"); + }); + + $msg->action("action avec step", function (IMessenger $msg) { + $msg->step("step"); + $msg->afailure("action failure"); + }); + + $msg->action("action avec step", function (IMessenger $msg) { + $msg->step("step"); + $msg->adone("action done"); + }); + + $msg->desc("actions sans step"); + $msg->action("action sans step", function (IMessenger $msg) { + $msg->asuccess("action success"); + }); + + $msg->action("action sans step", function (IMessenger $msg) { + $msg->afailure("action failure"); + }); + + $msg->action("action sans step", function (IMessenger $msg) { + $msg->adone("action done"); + }); + + $msg->desc("actions imbriquées"); + $msg->action("action0", function (IMessenger $msg) { + $msg->action("action1", function (IMessenger $msg) { + $msg->action("action2", function (IMessenger $msg) { + $msg->asuccess("action2 success"); + }); + $msg->asuccess("action1 success"); + }); + $msg->asuccess("action0 success"); + }); + + $msg->desc("action avec step, sans messages"); + $msg->action("action avec step, sans messages, success", function (IMessenger $msg) { + $msg->step("step"); + $msg->asuccess(); + }); + + $msg->action("action avec step, sans messages, failure", function (IMessenger $msg) { + $msg->step("step"); + $msg->afailure(); + }); + + $msg->action("action avec step, sans messages, done", function (IMessenger $msg) { + $msg->step("step"); + $msg->adone(); + }); + + $msg->desc("action sans step, sans messages"); + $msg->action("action sans step, sans messages, success", function (IMessenger $msg) { + $msg->asuccess(); + }); + + $msg->action("action sans step, sans messages, failure", function (IMessenger $msg) { + $msg->afailure(); + }); + + $msg->action("action sans step, sans messages, done", function (IMessenger $msg) { + $msg->adone(); + }); + + $msg->desc("actions imbriquées, sans messages"); + $msg->action("action0", function (IMessenger $msg) { + $msg->action("action1", function (IMessenger $msg) { + $msg->action("action2", function (IMessenger $msg) { + $msg->asuccess(); + }); + $msg->asuccess(); + }); + $msg->asuccess(); + }); + + $msg->desc("action avec step, avec code de retour"); + $msg->action("action avec step, avec code de retour true", function (IMessenger $msg) { + $msg->step("step"); + return true; + }); + + $msg->action("action avec step, avec code de retour false", function (IMessenger $msg) { + $msg->step("step"); + return false; + }); + + $msg->action("action avec step, avec code de retour autre", function (IMessenger $msg) { + $msg->step("step"); + return "autre"; + }); + + $msg->action("action avec step, avec code de retour null", function (IMessenger $msg) { + $msg->step("step"); + }); + + $msg->desc("action sans step, avec code de retour"); + $msg->action("action sans step, avec code de retour true", function (IMessenger $msg) { + return true; + }); + + $msg->action("action sans step, avec code de retour false", function (IMessenger $msg) { + return false; + }); + + $msg->action("action sans step, avec code de retour autre", function (IMessenger $msg) { + return "autre"; + }); + + # ici, il n'y aura pas de message du tout + $msg->action("action sans step, avec code de retour null", function (IMessenger $msg) { + }); + + $msg->info("info"); + $msg->note("note"); + $msg->warning("warning"); + $msg->error("error"); + }); + }); +} + +if ($multilines) { + $msg->section("multi-line\nsection", function (IMessenger $msg) { + $msg->title("multi-line\ntitle"); + $msg->title("another\ntitle"); + + $msg->print("multi-line\nprint"); + $msg->info("multi-line\ninfo"); + $msg->action("multi-line\naction"); + $msg->asuccess(); + $msg->action("multi-line\naction"); + $msg->step("multi-line\nstep"); + $msg->afailure(); + $msg->action("multi-line\naction"); + $msg->step("multi-line\nstep"); + $msg->asuccess("multi-line\nsuccess"); + $msg->action("multi-line\naction"); + $msg->step("multi-line\nstep"); + $msg->adone("multi-line\ndone"); + + $msg->end(); + $msg->end(); + }); +} + +if ($exceptions) { + $msg->section("Exceptions", function (IMessenger $msg) { + $e = new Exception("message"); + $u1 = new UserException("userMessage"); + $u2 = (new UserException("userMessage"))->setTechMessage("techMessage"); + $msg->title("avec message", function (IMessenger $msg) use ($e, $u1, $u2) { + $msg->info(["exception", $e]); + $msg->info(["userException1", $u1]); + $msg->info(["userException2", $u2]); + }); + $msg->title("sans message", function (IMessenger $msg) use ($e, $u1, $u2) { + $msg->info($e); + $msg->info($u1); + $msg->info($u2); + }); + }); +} diff --git a/php/tests/cache/_TestCase.php b/php/tests/cache/_TestCase.php index f05875c..a8bfa11 100644 --- a/php/tests/cache/_TestCase.php +++ b/php/tests/cache/_TestCase.php @@ -3,7 +3,7 @@ namespace nulib\cache; use nulib\db\sqlite\SqliteStorage; use nulib\output\msg; -use nulib\output\std\StdMessenger; +use nulib\output\std\ConsoleMessenger; use nulib\tests\TestCase; class _TestCase extends TestCase { @@ -11,7 +11,7 @@ class _TestCase extends TestCase { static function setUpBeforeClass(): void { parent::setUpBeforeClass(); - msg::set_messenger_class(StdMessenger::class); + msg::set_messenger_class(ConsoleMessenger::class); self::$storage = new SqliteStorage(__DIR__."/cache.db"); cache::set_storage(self::$storage); } diff --git a/php/tests/cache/cacheTest.php b/php/tests/cache/cacheTest.php index 7c31f37..b8d8c55 100644 --- a/php/tests/cache/cacheTest.php +++ b/php/tests/cache/cacheTest.php @@ -26,7 +26,7 @@ class cacheTest extends _TestCase { } self::assertSame($expectedCount, $count); } - + function _testGet(string $dataId, int $expectedCount, callable $gencompute) { msg::section($dataId); cache::nc(true, true); diff --git a/php/tests/db/sqlite/ChannelMigrationTest.php b/php/tests/db/sqlite/ChannelMigrationTest.php index fa48e7c..30a80f4 100644 --- a/php/tests/db/sqlite/ChannelMigrationTest.php +++ b/php/tests/db/sqlite/ChannelMigrationTest.php @@ -7,14 +7,14 @@ use nulib\db\sqlite\impl\MyChannelV2; use nulib\db\sqlite\impl\MyChannelV3; use nulib\db\sqlite\impl\MyIndexChannel; use nulib\output\msg; -use nulib\output\std\StdMessenger; +use nulib\output\std\ConsoleMessenger; use nulib\php\time\DateTime; use nulib\tests\TestCase; class ChannelMigrationTest extends TestCase { static function setUpBeforeClass(): void { parent::setUpBeforeClass(); - msg::set_messenger_class(StdMessenger::class); + msg::set_messenger_class(ConsoleMessenger::class); } protected function addData(MyChannel $channel, array $data): void { diff --git a/php/tests/php/funcTest.php b/php/tests/php/funcTest.php index 371cc35..b942beb 100644 --- a/php/tests/php/funcTest.php +++ b/php/tests/php/funcTest.php @@ -1016,7 +1016,7 @@ namespace nulib\php { $i1 = $func->invoke([1, 2]); self::assertInstanceOf(C1::class, $i1); self::assertSame(1, $i1->base); } - + private static function invoke_asserts(): array { $inv_ok = function($func) { return func::with($func)->invoke();