getDesc(); if ($runfile->isRunning()) { $actionDesc = $runfile->getActionDesc(); if ($actionDesc !== null) $actionDesc = "\n$actionDesc"; echo "$desc$actionDesc\n"; } else { echo "$desc\n"; $ec = 1; } break; case "dump": case "d": yaml::dump($runfile->read()); break; case "reset": case "z": if (!$runfile->isRunning()) $runfile->reset(); else $ec = self::_error("cannot reset while running"); break; case "release": case "rl": $runfile->release(); break; case "start": case "s": array_splice($argv, 1, 1); $argc--; return; case "kill": case "k": if ($runfile->isRunning()) $runfile->wfKill(); else $ec = self::_error("not running"); break; default: $ec = self::_error("$argv[1]: unexpected command", app::EC_BAD_COMMAND); } exit($ec); } static function run(?Application $app=null): void { $unlock = false; $stop = false; $shutdown = function () use (&$unlock, &$stop) { if ($unlock) { app::get()->getRunfile()->release(); $unlock = false; } if ($stop) { app::get()->getRunfile()->wfStop(); $stop = false; } }; register_shutdown_function($shutdown); app::install_signal_handler(static::INSTALL_SIGNAL_HANDLER); try { static::_initialize_app(); $useRunfile = static::USE_RUNFILE; $useRunlock = static::USE_RUNLOCK; if ($useRunfile) { $runfile = app::get()->getRunfile(); global $argc, $argv; self::_manage_runfile($argc, $argv, $runfile); if ($useRunlock && $runfile->warnIfLocked()) exit(app::EC_LOCKED); $runfile->wfStart(); $stop = true; if ($useRunlock) { $runfile->lock(); $unlock = true; } } if ($app === null) $app = new static(); static::_configure_app($app); static::_start_app($app); } catch (ExitError $e) { if ($e->haveUserMessage()) msg::error($e->getUserMessage()); exit($e->getCode()); } catch (Exception $e) { msg::error($e); exit(app::EC_UNEXPECTED); } } protected static function _initialize_app(): void { app::init(static::class); msg::set_messenger(new StdMessenger([ "min_level" => msg::DEBUG, ])); } protected static function _configure_app(Application $app): void { config::configure(config::CONFIGURE_INITIAL_ONLY); $msgs = null; $msgs["console"] = new StdMessenger([ "min_level" => msg::NORMAL, ]); if (static::USE_LOGFILE) { $msgs["log"] = new StdMessenger([ "output" => app::get()->getLogfile(), "min_level" => msg::MINOR, "add_date" => true, ]); } msg::init($msgs); $app->parseArgs(); config::configure(); } protected static function _start_app(Application $app): void { $retcode = $app->main(); if (is_int($retcode)) exit($retcode); elseif (is_bool($retcode)) exit($retcode? 0: 1); elseif ($retcode !== null) exit(strval($retcode)); } /** * sortir de l'application avec un code d'erreur, qui est 0 par défaut (i.e * pas d'erreur) * * équivalent à lancer l'exception {@link ExitError} */ protected static final function exit(int $exitcode=0, $message=null) { throw new ExitError($exitcode, $message); } /** * sortir de l'application avec un code d'erreur, qui vaut 1 par défaut (i.e * une erreur s'est produite) * * équivalent à lancer l'exception {@link ExitError} */ protected static final function die($message=null, int $exitcode=1) { throw new ExitError($exitcode, $message); } const PROFILE_SECTION = [ "title" => "PROFILS D'EXECUTION", ["group", ["-p", "--profile", "--app-profile", "args" => 1, "argsdesc" => "PROFILE", "action" => [app::class, "set_profile"], "help" => "spécifier le profil d'exécution", ], ["-P", "--prod", "action" => [app::class, "set_profile", config::PROD]], ["-T", "--test", "action" => [app::class, "set_profile", config::TEST]], ["--devel", "action" => [app::class, "set_profile", config::DEVEL]], ], ]; const VERBOSITY_SECTION = [ "title" => "NIVEAU D'INFORMATION", "show" => false, ["group", ["--verbosity", "args" => 1, "argsdesc" => "silent|quiet|verbose|debug", "action" => [null, "set_application_verbosity"], "help" => "spécifier le niveau d'informations affiché", ], ["-q", "--quiet", "action" => [null, "set_application_verbosity", "quiet"]], ["-v", "--verbose", "action" => [null, "set_application_verbosity", "verbose"]], ["-D", "--debug", "action" => [null, "set_application_verbosity", "debug"]], ], ["-L", "--logfile", "args" => "file", "argsdesc" => "OUTPUT", "action" => [null, "set_application_log_output"], "help" => "Logger les messages de l'application dans le fichier spécifié", ], ["group", ["--color", "action" => [null, "set_application_color", true], "help" => "Afficher (resp. ne pas afficher) la sortie en couleur par défaut", ], ["--no-color", "action" => [null, "set_application_color", false]], ], ]; static function set_application_verbosity(string $verbosity): void { $console = console::get(); switch ($verbosity) { case "Q": case "silent": $console->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": config::set_debug(); $console->resetParams([ "min_level" => msg::DEBUG, ]); break; default: throw ValueException::invalid_value($verbosity, "verbosity"); } } static function set_application_log_output(string $logfile): void { log::create_or_reset_params([ "output" => $logfile, ], StdMessenger::class, [ "add_date" => true, "min_level" => log::MINOR, ]); } static function set_application_color(bool $color): void { console::reset_params([ "color" => $color, ]); } const ARGS = [ "sections" => [ self::PROFILE_SECTION, self::VERBOSITY_SECTION, ], ]; /** @throws ArgsException */ function parseArgs(array $args=null): void { $parser = new ArgsParser(static::ARGS); $parser->parse($this, $args); } const PROFILE_COLORS = [ "prod" => "@r", "test" => "@g", "devel" => "@w", ]; const DEFAULT_PROFILE_COLOR = "y"; /** retourner le profil courant en couleur */ static function get_profile(?string $profile=null): string { if ($profile === null) $profile = app::get_profile(); foreach (static::PROFILE_COLORS as $text => $color) { if (strpos($profile, $text) !== false) { return $color? "$profile": $profile; } } $color = static::DEFAULT_PROFILE_COLOR; return $color? "$profile": $profile; } abstract function main(); static function runfile(): RunFile { return app::with(static::class)->getRunfile(); } }