modifs.mineures sans commentaires
This commit is contained in:
parent
43952bb4a9
commit
c35ca7e5d4
|
@ -124,27 +124,27 @@ abstract class Application {
|
|||
$unlock = false;
|
||||
$stop = false;
|
||||
register_shutdown_function(function () use (&$unlock, &$stop) {
|
||||
$self = app::get();
|
||||
if ($unlock) $self->getLockfile()->release();
|
||||
if ($stop) $self->getRunfile()->stop();
|
||||
$runfile = app::get()->getRunfile();
|
||||
if ($unlock) $runfile->release();
|
||||
if ($stop) $runfile->wfStop();
|
||||
});
|
||||
try {
|
||||
static::_app_init();
|
||||
if (static::USE_RUNFILE) {
|
||||
$self = app::get();
|
||||
$runfile = app::get()->getRunfile();
|
||||
global $argc, $argv;
|
||||
if ($argc === 2 && $argv[1] === "--Application-Runlock-release") {
|
||||
$self->getLockfile()->release();
|
||||
$runfile->release();
|
||||
exit(0);
|
||||
}
|
||||
$useRunlock = static::USE_RUNLOCK;
|
||||
if ($useRunlock && $self->getLockfile()->warnIfLocked()) {
|
||||
if ($useRunlock && $runfile->warnIfLocked()) {
|
||||
exit(1);
|
||||
}
|
||||
$self->getRunfile()->start();
|
||||
$runfile->wfStart();
|
||||
$stop = true;
|
||||
if ($useRunlock) {
|
||||
$self->getLockfile()->lock();
|
||||
$runfile->lock();
|
||||
$unlock = true;
|
||||
}
|
||||
}
|
||||
|
|
32
src/A.php
32
src/A.php
|
@ -63,4 +63,36 @@ class A {
|
|||
static final function mpselect(?array &$dest, ?array $merge, ?array $pkeys): void {
|
||||
$dest = cl::mpselect($dest, $merge, $pkeys);
|
||||
}
|
||||
|
||||
static final function append_nn(?array &$dest, $value, $key=null) {
|
||||
if ($value !== null) {
|
||||
if ($key === null) $dest[] = $value;
|
||||
else $dest[$key] = $value;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
static final function append_nz(?array &$dest, $value, $key=null) {
|
||||
if ($value !== null && $value !== false) {
|
||||
if ($key === null) $dest[] = $value;
|
||||
else $dest[$key] = $value;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
static final function prepend_nn(?array &$dest, $value) {
|
||||
if ($value !== null) {
|
||||
if ($dest === null) $dest = [];
|
||||
array_unshift($dest, $value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
static final function prepend_nz(?array &$dest, $value) {
|
||||
if ($value !== null && $value !== false) {
|
||||
if ($dest === null) $dest = [];
|
||||
array_unshift($dest, $value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace nur\sery\app;
|
|||
use nur\sery\cl;
|
||||
use nur\sery\file\SharedFile;
|
||||
use nur\sery\os\path;
|
||||
use nur\sery\output\msg;
|
||||
use nur\sery\php\time\DateTime;
|
||||
use nur\sery\str;
|
||||
|
||||
|
@ -43,9 +44,15 @@ class RunFile {
|
|||
"pg_pid" => null,
|
||||
"pid" => posix_getpid(),
|
||||
"serial" => 0,
|
||||
# lock
|
||||
"locked" => false,
|
||||
"date_lock" => null,
|
||||
"date_release" => null,
|
||||
# run
|
||||
"date_start" => $dateStart,
|
||||
"date_stop" => null,
|
||||
"exitcode" => null,
|
||||
# action
|
||||
"action" => null,
|
||||
"action_date_start" => null,
|
||||
"action_current_step" => null,
|
||||
|
@ -60,6 +67,93 @@ class RunFile {
|
|||
return $data;
|
||||
}
|
||||
|
||||
protected function willWrite(): array {
|
||||
$file = $this->file;
|
||||
$file->lockWrite();
|
||||
$data = $file->unserialize(null, false, true);
|
||||
if (!is_array($data)) {
|
||||
$data = $this->initData();
|
||||
$file->ftruncate();
|
||||
$file->serialize($data, false, true);
|
||||
}
|
||||
$file->ftruncate();
|
||||
return [$file, $data];
|
||||
}
|
||||
|
||||
protected function serialize(SharedFile $file, array $data, ?array $merge=null): void {
|
||||
$file->serialize(self::merge($data, $merge), true, true);
|
||||
}
|
||||
|
||||
protected function update(callable $func): void {
|
||||
[$file, $data] = $this->willWrite();
|
||||
$merge = call_user_func($func, $data);
|
||||
$this->serialize($file, $data, $merge);
|
||||
}
|
||||
|
||||
function haveWorked(int $serial, ?int &$currentSerial=null): bool {
|
||||
$data = $this->read();
|
||||
$currentSerial = $data["serial"];
|
||||
return $serial !== $currentSerial;
|
||||
}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# verrouillage par défaut
|
||||
|
||||
function isLocked(?array &$data=null): bool {
|
||||
$data = $this->read();
|
||||
return $data["locked"];
|
||||
}
|
||||
|
||||
function warnIfLocked(?array $data=null): bool {
|
||||
if ($data === null) $data = $this->read();
|
||||
if ($data["locked"]) {
|
||||
msg::warning("$data[name]: possède le verrou depuis $data[date_lock]");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function lock(): bool {
|
||||
$this->update(function ($data) use (&$locked) {
|
||||
if ($data["locked"]) {
|
||||
$locked = false;
|
||||
return null;
|
||||
} else {
|
||||
$locked = true;
|
||||
return [
|
||||
"locked" => true,
|
||||
"date_lock" => new DateTime(),
|
||||
"date_release" => null,
|
||||
];
|
||||
}
|
||||
});
|
||||
return $locked;
|
||||
}
|
||||
|
||||
function release(): void {
|
||||
$this->update(function ($data) {
|
||||
return [
|
||||
"locked" => false,
|
||||
"date_release" => new DateTime(),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# cycle de vie de l'application
|
||||
|
||||
/**
|
||||
* indiquer que l'application démarre. l'état est entièrement réinitialisé,
|
||||
* sauf le PID du leader qui est laissé en l'état
|
||||
*/
|
||||
function wfStart(): void {
|
||||
$this->update(function (array $data) {
|
||||
return cl::merge($this->initData(), [
|
||||
"pg_pid" => $data["pg_pid"],
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/** tester si l'application a déjà été démarrée */
|
||||
function wasStarted(): bool {
|
||||
$data = $this->read();
|
||||
|
@ -97,6 +191,13 @@ class RunFile {
|
|||
return true;
|
||||
}
|
||||
|
||||
/** indiquer que l'application s'arrête */
|
||||
function wfStop(): void {
|
||||
$this->update(function (array $data) {
|
||||
return ["date_stop" => new DateTime()];
|
||||
});
|
||||
}
|
||||
|
||||
/** tester si l'application est déjà été stoppée */
|
||||
function wasStopped(): bool {
|
||||
$data = $this->read();
|
||||
|
@ -109,46 +210,20 @@ class RunFile {
|
|||
return $data["date_start"] !== null && $data["date_stop"] !== null;
|
||||
}
|
||||
|
||||
function haveWorked(int $serial, ?int &$currentSerial=null): bool {
|
||||
$data = $this->read();
|
||||
$currentSerial = $data["serial"];
|
||||
return $serial !== $currentSerial;
|
||||
}
|
||||
|
||||
protected function willWrite(): array {
|
||||
$file = $this->file;
|
||||
$file->lockWrite();
|
||||
$data = $file->unserialize(null, false, true);
|
||||
if (!is_array($data)) {
|
||||
$data = $this->initData();
|
||||
$file->ftruncate();
|
||||
$file->serialize($data, false, true);
|
||||
}
|
||||
$file->ftruncate();
|
||||
return [$file, $data];
|
||||
}
|
||||
|
||||
protected function serialize(SharedFile $file, array $data, ?array $merge=null): void {
|
||||
$file->serialize(self::merge($data, $merge), true, true);
|
||||
}
|
||||
|
||||
protected function update(callable $func): void {
|
||||
[$file, $data] = $this->willWrite();
|
||||
$merge = call_user_func($func, $data);
|
||||
$this->serialize($file, $data, $merge);
|
||||
}
|
||||
|
||||
/** indiquer que l'application démarre */
|
||||
function start(): void {
|
||||
$this->update(function (array $data) {
|
||||
# garder l'identifiant de process
|
||||
$pgPid = $data["pg_pid"] ?? null;
|
||||
return cl::merge($this->initData(), [
|
||||
"pg_pid" => $pgPid,
|
||||
]);
|
||||
/** après l'arrêt de l'application, mettre à jour le code de retour */
|
||||
function wfStopped(int $exitcode): void {
|
||||
$this->update(function (array $data) use ($exitcode) {
|
||||
return [
|
||||
"pg_pid" => null,
|
||||
"date_stop" => $data["date_stop"] ?? new DateTime(),
|
||||
"exitcode" => $exitcode,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# gestion des actions
|
||||
|
||||
/** indiquer le début d'une action */
|
||||
function action(?string $title, ?int $maxSteps=null): void {
|
||||
$this->update(function (array $data) use ($title, $maxSteps) {
|
||||
|
@ -171,23 +246,8 @@ class RunFile {
|
|||
});
|
||||
}
|
||||
|
||||
/** indiquer que l'application s'arrête */
|
||||
function stop(): void {
|
||||
$this->update(function (array $data) {
|
||||
return ["date_stop" => new DateTime()];
|
||||
});
|
||||
}
|
||||
|
||||
/** après l'arrêt de l'application, mettre à jour le code de retour */
|
||||
function stopped(int $exitcode): void {
|
||||
$this->update(function (array $data) use ($exitcode) {
|
||||
return [
|
||||
"pg_pid" => null,
|
||||
"date_stop" => $data["date_stop"] ?? new DateTime(),
|
||||
"exitcode" => $exitcode,
|
||||
];
|
||||
});
|
||||
}
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# Divers
|
||||
|
||||
function getLockFile(?string $name=null, ?string $title=null): LockFile {
|
||||
$ext = self::LOCK_EXT;
|
||||
|
@ -197,7 +257,10 @@ class RunFile {
|
|||
return new LockFile($file, $name, $title);
|
||||
}
|
||||
|
||||
/** démarrer un groupe de process */
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# Gestionnaire de tâches (tm_*)
|
||||
|
||||
/** démarrer un groupe de process dont le process courant est le leader */
|
||||
function tm_startPg(): void {
|
||||
$this->update(function (array $data) {
|
||||
posix_setsid();
|
||||
|
|
|
@ -17,13 +17,15 @@ class launcher {
|
|||
return $exitcode;
|
||||
}
|
||||
|
||||
static function _start(array $args, Runfile $runfile): void {
|
||||
static function _start(array $args, Runfile $runfile): bool {
|
||||
if ($runfile->isLocked()) 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 les tuer toutes en même temps
|
||||
|
@ -34,10 +36,12 @@ class launcher {
|
|||
$cmd = new Cmd($args);
|
||||
#XXX fichier de log?
|
||||
#XXX charger /g/init.env
|
||||
$cmd->addSource("/g/init.env");
|
||||
$cmd->addRedir("null");
|
||||
$cmd->fork_exec($exitcode);
|
||||
return true;
|
||||
} finally {
|
||||
$runfile->stopped($exitcode);
|
||||
$runfile->wfStopped($exitcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +76,7 @@ class launcher {
|
|||
return;
|
||||
}
|
||||
}
|
||||
$runfile->stopped(-778);
|
||||
$runfile->wfStopped(-778);
|
||||
msg::asuccess();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
<?php
|
||||
namespace nur\sery\os\proc;
|
||||
|
||||
use nur\A;
|
||||
use nur\base;
|
||||
use nur\sery\A;
|
||||
use nur\sery\cv;
|
||||
use nur\sery\os\sh;
|
||||
use nur\shell;
|
||||
|
||||
abstract class AbstractCmd implements ICmd {
|
||||
private bool $needsStdin;
|
||||
|
||||
private bool $needsTty;
|
||||
|
||||
protected ?array $sources;
|
||||
|
||||
protected ?array $vars;
|
||||
|
||||
protected array $cmds;
|
||||
|
@ -18,6 +19,7 @@ abstract class AbstractCmd implements ICmd {
|
|||
function __construct() {
|
||||
$this->needsStdin = true;
|
||||
$this->needsTty = true;
|
||||
$this->sources = null;
|
||||
$this->vars = null;
|
||||
$this->cmds = [];
|
||||
}
|
||||
|
@ -74,13 +76,27 @@ abstract class AbstractCmd implements ICmd {
|
|||
$this->needsTty = $needsTty;
|
||||
}
|
||||
|
||||
function addSource(?string $source, bool $onlyIfExists=true): void {
|
||||
if ($source === null) return;
|
||||
if (!$onlyIfExists || file_exists($source)) {
|
||||
$source = implode(" ", ["source", sh::quote($source)]);
|
||||
$this->sources[] = $source;
|
||||
}
|
||||
}
|
||||
|
||||
function getSources(?string $sep=null): ?string {
|
||||
if ($this->sources === null) return null;
|
||||
if ($sep === null) $sep = "\n";
|
||||
return implode($sep, $this->sources);
|
||||
}
|
||||
|
||||
function addLiteralVars($vars, ?string $sep=null): void {
|
||||
if (base::z($vars)) return;
|
||||
if (cv::z($vars)) return;
|
||||
if (is_array($vars)) {
|
||||
if ($sep === null) $sep = "\n";
|
||||
$vars = implode($sep, $vars);
|
||||
}
|
||||
A::append($this->vars, strval($vars));
|
||||
$this->vars[] = strval($vars);
|
||||
}
|
||||
|
||||
function addVars(?array $vars): void {
|
||||
|
@ -88,8 +104,8 @@ abstract class AbstractCmd implements ICmd {
|
|||
foreach ($vars as $name => $value) {
|
||||
$var = [];
|
||||
if (!is_array($value)) $var[] = "export ";
|
||||
A::merge($var, [$name, "=", shell::quote($value)]);
|
||||
A::append($this->vars, implode("", $var));
|
||||
A::merge($var, [$name, "=", sh::quote($value)]);
|
||||
$this->vars[] = implode("", $var);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,7 +122,7 @@ abstract class AbstractCmd implements ICmd {
|
|||
if ($cmd instanceof ICmd) {
|
||||
$cmd->addPrefix($prefix);
|
||||
} elseif (is_array($prefix)) {
|
||||
$prefix = shell::join($prefix);
|
||||
$prefix = sh::join($prefix);
|
||||
$cmd = "$prefix $cmd";
|
||||
} else {
|
||||
$cmd = "$prefix $cmd";
|
||||
|
@ -167,8 +183,8 @@ abstract class AbstractCmd implements ICmd {
|
|||
}
|
||||
|
||||
function system(string &$output=null, int &$retcode=null): bool {
|
||||
$last_line = system($this->getCmd(), $retcode);
|
||||
if ($last_line !== false) $output = $last_line;
|
||||
$lastLine = system($this->getCmd(), $retcode);
|
||||
if ($lastLine !== false) $output = $lastLine;
|
||||
return $retcode == 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
namespace nur\sery\os\proc;
|
||||
|
||||
use nur\A;
|
||||
use nur\shell;
|
||||
use nur\sery\A;
|
||||
use nur\sery\os\sh;
|
||||
|
||||
/**
|
||||
* Class AbstractCmdList: une séquence de commandes séparées par ;, && ou ||
|
||||
|
@ -24,7 +24,7 @@ abstract class AbstractCmdList extends AbstractCmd {
|
|||
function add($cmd, ?string $input=null, ?string $output=null): self {
|
||||
if ($cmd !== null) {
|
||||
if (!($cmd instanceof ICmd)) {
|
||||
shell::fix_cmd($cmd, null, $input, $output);
|
||||
sh::verifix_cmd($cmd, null, $input, $output);
|
||||
}
|
||||
$this->cmds[] = $cmd;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ abstract class AbstractCmdList extends AbstractCmd {
|
|||
if ($sep === null) $sep = "\n";
|
||||
|
||||
$actualCmd = [];
|
||||
A::append_nn($actualCmd, $this->getSources($sep));
|
||||
A::append_nn($actualCmd, $this->getVars($sep));
|
||||
|
||||
$parts = [];
|
||||
|
@ -44,9 +45,8 @@ abstract class AbstractCmdList extends AbstractCmd {
|
|||
}
|
||||
$parts[] = $cmd;
|
||||
}
|
||||
$psep = $this->sep;
|
||||
if ($psep === null) $psep = $sep;
|
||||
A::append($actualCmd, implode($psep, $parts));
|
||||
$psep = $this->sep ?? $sep;
|
||||
$actualCmd[] = implode($psep, $parts);
|
||||
|
||||
return implode($sep, $actualCmd);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
namespace nur\sery\os\proc;
|
||||
|
||||
use nur\A;
|
||||
use nur\shell;
|
||||
use nur\sery\A;
|
||||
use nur\sery\os\sh;
|
||||
|
||||
/**
|
||||
* Class CmdPipe: une suite de commandes qui doivent s'exécuter avec les sorties
|
||||
|
@ -32,7 +32,7 @@ class CmdPipe extends AbstractCmd {
|
|||
function add($cmd): self {
|
||||
if ($cmd !== null) {
|
||||
if (!($cmd instanceof ICmd)) {
|
||||
shell::fix_cmd($cmd);
|
||||
sh::verifix_cmd($cmd);
|
||||
}
|
||||
$this->cmds[] = $cmd;
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ class CmdPipe extends AbstractCmd {
|
|||
if ($sep === null) $sep = "\n";
|
||||
|
||||
$actualCmd = [];
|
||||
A::append_nn($actualCmd, $this->getSources($sep));
|
||||
A::append_nn($actualCmd, $this->getVars($sep));
|
||||
|
||||
$parts = [];
|
||||
|
@ -73,7 +74,7 @@ class CmdPipe extends AbstractCmd {
|
|||
if ($output !== null) $parts[] = ">".escapeshellarg($output);
|
||||
$cmd = implode(" ", $parts);
|
||||
}
|
||||
A::append($actualCmd, $cmd);
|
||||
$actualCmd[] = $cmd;
|
||||
|
||||
return implode($sep, $actualCmd);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use nur\sery\app\LockFile;
|
|||
use nur\sery\app\RunFile;
|
||||
use nur\sery\os\path;
|
||||
use nur\sery\os\sh;
|
||||
use nur\sery\str;
|
||||
use nur\sery\ValueException;
|
||||
|
||||
class app {
|
||||
|
@ -67,7 +68,11 @@ class app {
|
|||
$this->projdir = $projdir = path::abspath($params["projdir"] ?? ".");
|
||||
$this->appcode = $appcode = $params["appcode"] ?? "app";
|
||||
$this->apptype = $apptype = $params["apptype"] ?? "cli";
|
||||
$this->name = $params["name"] ?? $appcode;
|
||||
# si $name est une classe, enlever le package et normaliser
|
||||
$name = $params["name"] ?? $appcode;
|
||||
$name = preg_replace('/.*\\\\/', "", $name);
|
||||
$name = str::without_suffix("-app", str::camel2us($name));
|
||||
$this->name = $name;
|
||||
$this->title = $params["title"] ?? null;
|
||||
$appcode = strtoupper($appcode);
|
||||
# profile
|
||||
|
|
Loading…
Reference in New Issue