$value] devient ["--my-arg", "$value"] * - ["myOpt" => true] devient ["--my-opt"] * - ["myOpt" => false] est momis * - les valeurs séquentielles sont prises telles quelles */ static function verifix_args(array $args): array { if (!cl::is_list($args)) { $fixedArgs = []; $index = 0; foreach ($args as $arg => $value) { if ($arg === $index) { $index++; $fixedArgs[] = $value; continue; } elseif ($value === false) { continue; } $arg = str::us2camel($arg); $arg = str::camel2us($arg, false, "-"); $arg = str_replace("_", "-", $arg); $fixedArgs[] = "--$arg"; if ($value !== true) $fixedArgs[] = "$value"; } $args = $fixedArgs; } # corriger le chemin de l'application pour qu'il soit absolu et normalisé $args[0] = path::abspath($args[0]); return $args; } static function launch(string $appClass, array $args): int { $app = app2::get(); $vendorBindir = $app->getVendorbindir(); $launch_php = "$vendorBindir/_launch.php"; if (!file_exists($launch_php)) { $launch_php = __DIR__."/../../lib/_launch.php"; } $tmpfile = new TmpfileWriter(); $tmpfile->keep()->serialize($app->getParams()); $args = self::verifix_args($args); $cmd = new Cmd([ $launch_php, "--internal-use", $tmpfile->getFile(), $appClass, "--", ...$args, ]); $cmd->addRedir("both", "/tmp/nulib_app_launcher-launch.log"); $cmd->passthru($exitcode); # attendre un peu que la commande aie le temps de s'initialiser sleep(1); $tmpfile->close(); return $exitcode; } static function _start(array $args, Runfile $runfile): bool { if ($runfile->warnIfLocked()) return false; $pid = pcntl_fork(); if ($pid == -1) { # parent, impossible de forker throw new StateException("unable to fork"); } elseif ($pid) { # parent, fork ok return true; } else { ## child, fork ok # Créer un groupe de process, pour pouvoir tuer tous les enfants en même temps $runfile->tm_startPg(); $logfile = $runfile->getLogfile() ?? "/tmp/nulib_app_launcher-_start.log"; $pid = posix_getpid(); $exitcode = -776; try { # puis lancer la commande $cmd = new Cmd($args); $cmd->addSource("/g/init.env"); $cmd->addRedir("both", $logfile, true); msg::debug("$pid: launching\n".$cmd->getCmd()); $cmd->fork_exec($exitcode); msg::debug("$pid: exitcode=$exitcode"); return true; } finally { $runfile->wfStopped($exitcode); } } } static function _stop(Runfile $runfile): void { $data = $runfile->read(); $pid = $data["pg_pid"]; if ($pid === null) { msg::warning("$data[name]: groupe de process inconnu"); return; } msg::action("kill $pid"); if (!posix_kill(-$pid, SIGKILL)) { switch (posix_get_last_error()) { case PCNTL_ESRCH: msg::afailure("process inexistant"); break; case PCNTL_EPERM: msg::afailure("process non accessible"); break; case PCNTL_EINVAL: msg::afailure("signal invalide"); break; } return; } $timeout = 10; while ($runfile->tm_isUndead($pid)) { sleep(1); if (--$timeout == 0) { msg::afailure("impossible d'arrêter la tâche"); return; } } $runfile->wfStopped(-778); msg::asuccess(); } }