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();