release(); break; case "infos": case "i": if ($runfile->isRunning()) { $action = $runfile->getActionDesc(); if ($action !== null) $action = ": $action"; echo "running$action\n"; } else { echo "not running\n"; $ec = 1; } break; default: fwrite(STDERR, "$argv[2]: unexpected command\n"); $ec = app2::EC_BAD_COMMAND; } exit($ec); } static function run(?Application $app=null): void { $unlock = false; $stop = false; register_shutdown_function(function() use (&$unlock, &$stop) { if ($unlock) { app2::get()->getRunfile()->release(); $unlock = false; } if ($stop) { app2::get()->getRunfile()->wfStop(); $stop = false; } }); app2::install_signal_handler(static::USE_SIGNAL_HANDLER); try { static::_initialize_app(); $useRunfile = static::USE_RUNFILE; $useRunlock = static::USE_RUNLOCK; if ($useRunfile) { $runfile = app2::get()->getRunfile(); self::_manage_runfile($runfile); if ($useRunlock && $runfile->warnIfLocked()) exit(app2::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->haveMessage()) msg::error($e); exit($e->getCode()); } catch (Exception $e) { msg::error($e); exit(app2::EC_EXCEPTION); } } protected static function _initialize_app(): void { app2::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" => app2::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" => [app2::class, "set_profile"], "help" => "spécifier le profil d'exécution", ], ["-P", "--prod", "action" => [app2::class, "set_profile", config::PROD]], ["-T", "--test", "action" => [app2::class, "set_profile", config::TEST]], ["--devel", "action" => [app2::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 = app2::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(); }