modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2024-06-13 17:19:58 +04:00
parent 16376a473a
commit a09f3a0a2b
7 changed files with 218 additions and 111 deletions

View File

@ -1,13 +1,26 @@
#!/usr/bin/php #!/usr/bin/php
<?php <?php
require $_composer_autoload_path?? __DIR__.'/../vendor/autoload.php'; $internalUse = $argv[1] ?? null;
if ($internalUse !== "--internal-use") exit("Wrong args");
$paramsfile = $argv[2] ?? null;
if (!file_exists($paramsfile)) exit("bad params file");
$argc -= 2;
$argv = array_merge(
array_slice($argv, 0, 1),
array_slice($argv, 3),
);
$app_params = unserialize(file_get_contents($paramsfile));
require $app_params["vendor"]["autoload"];
use nur\cli\Application; use nur\cli\Application;
use nur\sery\wip\app\app; use nur\sery\wip\app\app;
use nur\sery\app\launcher; use nur\sery\app\launcher;
use nur\yaml; use nur\yaml;
Application::run(new class extends Application { class _LaunchApp extends Application {
const NAME = "_launch";
const ACTION_INFOS = 0, ACTION_START = 1, ACTION_STOP = 2; const ACTION_INFOS = 0, ACTION_START = 1, ACTION_STOP = 2;
const ARGS = [ const ARGS = [
@ -44,8 +57,7 @@ Application::run(new class extends Application {
self::die("Cette application ne supporte pas l'usage de runfile"); self::die("Cette application ne supporte pas l'usage de runfile");
} }
$app = app::with($appClass); $runfile = app::with($appClass, self::$internal_use_app_params)->getRunfile();
$runfile = $app->getRunfile();
switch ($this->action) { switch ($this->action) {
case self::ACTION_START: case self::ACTION_START:
launcher::_start($args, $runfile); launcher::_start($args, $runfile);
@ -58,4 +70,6 @@ Application::run(new class extends Application {
break; break;
} }
} }
}); }
_LaunchApp::internal_use_set_app_params($app_params);
_LaunchApp::run();

View File

@ -19,9 +19,20 @@ use nur\sery\output\std\StdMessenger;
* Class Application: application de base * Class Application: application de base
*/ */
abstract class Application { abstract class Application {
protected static ?array $internal_use_app_params = null;
static function internal_use_set_app_params($params) {
self::$internal_use_app_params = $params;
}
/** @var string répertoire du projet (celui qui contient composer.json */ /** @var string répertoire du projet (celui qui contient composer.json */
const PROJDIR = null; const PROJDIR = null;
/**
* @var array répertoires vendor exprimés relativement à PROJDIR
*/
const VENDOR = null;
/** /**
* @var string code du projet, utilisé pour dériver le noms de certains des * @var string code du projet, utilisé pour dériver le noms de certains des
* paramètres extraits de l'environnement, e.g XXX_DATADIR si le projet a pour * paramètres extraits de l'environnement, e.g XXX_DATADIR si le projet a pour
@ -85,7 +96,7 @@ abstract class Application {
if ($projdir == "/") break; if ($projdir == "/") break;
} }
app::init(static::class); app::init(static::class, self::$internal_use_app_params);
nmsg::set_messenger(new StdMessenger([ nmsg::set_messenger(new StdMessenger([
"min_level" => nmsg::DEBUG, "min_level" => nmsg::DEBUG,
])); ]));
@ -124,9 +135,8 @@ abstract class Application {
$unlock = false; $unlock = false;
$stop = false; $stop = false;
register_shutdown_function(function () use (&$unlock, &$stop) { register_shutdown_function(function () use (&$unlock, &$stop) {
$runfile = app::get()->getRunfile(); if ($unlock) app::get()->getRunfile()->release();
if ($unlock) $runfile->release(); if ($stop) app::get()->getRunfile()->wfStop();
if ($stop) $runfile->wfStop();
}); });
try { try {
static::_app_init(); static::_app_init();

View File

@ -175,14 +175,14 @@ class RunFile {
if ($data["date_stop"] !== null) return false; if ($data["date_stop"] !== null) return false;
if (!posix_kill($data["pid"], 0)) { if (!posix_kill($data["pid"], 0)) {
switch (posix_get_last_error()) { switch (posix_get_last_error()) {
case PCNTL_ESRCH: case 1: #PCNTL_EPERM:
# process inexistant
return false;
case PCNTL_EPERM:
# process auquel on n'a pas accès?! est-ce un autre process qui a # process auquel on n'a pas accès?! est-ce un autre process qui a
# réutilisé le PID? # réutilisé le PID?
return false; return false;
case PCNTL_EINVAL: case 3: #PCNTL_ESRCH:
# process inexistant
return false;
case 22: #PCNTL_EINVAL:
# ne devrait pas se produire # ne devrait pas se produire
return false; return false;
} }
@ -281,14 +281,14 @@ class RunFile {
$pid ??= $data["pid"]; $pid ??= $data["pid"];
if (!posix_kill($pid, 0)) { if (!posix_kill($pid, 0)) {
switch (posix_get_last_error()) { switch (posix_get_last_error()) {
case PCNTL_ESRCH: case 1: #PCNTL_EPERM:
# process inexistant
return true;
case PCNTL_EPERM:
# process auquel on n'a pas accès?! est-ce un autre process qui a # process auquel on n'a pas accès?! est-ce un autre process qui a
# réutilisé le PID? # réutilisé le PID?
return false; return false;
case PCNTL_EINVAL: case 3: #PCNTL_ESRCH:
# process inexistant
return true;
case 22: #PCNTL_EINVAL:
# ne devrait pas se produire # ne devrait pas se produire
return false; return false;
} }

View File

@ -1,21 +1,32 @@
<?php <?php
namespace nur\sery\app; namespace nur\sery\app;
use nur\sery\file\TmpfileWriter;
use nur\sery\os\proc\Cmd; use nur\sery\os\proc\Cmd;
use nur\sery\output\msg; use nur\sery\output\msg;
use nur\sery\StateException; use nur\sery\StateException;
use nur\sery\wip\app\app;
class launcher { class launcher {
static function launch(string $appClass, ...$args): int { static function launch(string $appClass, ...$args): int {
global $_composer_bin_dir; $app = app::get();
if (isset($_composer_bin_dir)) { $vendorBindir = $app->getVendorbindir();
$launch_php = "$_composer_bin_dir/_launch.php"; $launch_php = "$vendorBindir/_launch.php";
} else { if (!file_exists($launch_php)) {
$launch_php = __DIR__."/../../lib/_launch.php"; $launch_php = __DIR__."/../../lib/_launch.php";
} }
$cmd = new Cmd([$launch_php, $appClass, ...$args]); $tmpfile = new TmpfileWriter();
//$cmd->addRedir("null"); $tmpfile->serialize($app->getParams());
$cmd = new Cmd([
$launch_php,
"--internal-use", $tmpfile->getFile(),
$appClass, ...$args,
]);
$cmd->addRedir("null");
$cmd->passthru($exitcode); $cmd->passthru($exitcode);
$tmpfile->close();
return $exitcode; return $exitcode;
} }
@ -37,7 +48,6 @@ class launcher {
# puis lancer la commande # puis lancer la commande
$cmd = new Cmd($args); $cmd = new Cmd($args);
#XXX fichier de log? #XXX fichier de log?
#XXX charger /g/init.env
$cmd->addSource("/g/init.env"); $cmd->addSource("/g/init.env");
$cmd->addRedir("null"); $cmd->addRedir("null");
$cmd->fork_exec($exitcode); $cmd->fork_exec($exitcode);

View File

@ -79,7 +79,7 @@ abstract class AbstractCmd implements ICmd {
function addSource(?string $source, bool $onlyIfExists=true): void { function addSource(?string $source, bool $onlyIfExists=true): void {
if ($source === null) return; if ($source === null) return;
if (!$onlyIfExists || file_exists($source)) { if (!$onlyIfExists || file_exists($source)) {
$source = implode(" ", ["source", sh::quote($source)]); $source = implode(" ", [".", sh::quote($source)]);
$this->sources[] = $source; $this->sources[] = $source;
} }
} }
@ -200,7 +200,9 @@ abstract class AbstractCmd implements ICmd {
* composition de plusieurs commandes * composition de plusieurs commandes
*/ */
protected function useExec(): bool { protected function useExec(): bool {
return $this->vars === null && count($this->cmds) == 1; return $this->sources === null
&& $this->vars === null
&& count($this->cmds) == 1;
} }
function fork_exec(int &$retcode=null): bool { function fork_exec(int &$retcode=null): bool {

View File

@ -2,6 +2,7 @@
namespace nur\sery\os; namespace nur\sery\os;
use nur\sery\cl; use nur\sery\cl;
use nur\sery\StateException;
use RuntimeException; use RuntimeException;
class sh { class sh {
@ -144,19 +145,19 @@ class sh {
$pid = pcntl_fork(); $pid = pcntl_fork();
if ($pid == -1) { if ($pid == -1) {
// parent, impossible de forker // parent, impossible de forker
throw new RuntimeException("unable to fork"); throw new StateException("unable to fork");
} elseif ($pid) { } elseif ($pid) {
// parent, fork ok // parent, fork ok
pcntl_waitpid($pid, $status); pcntl_waitpid($pid, $status);
if (pcntl_wifexited($status)) { if (pcntl_wifexited($status)) $retcode = pcntl_wexitstatus($status);
$retcode = pcntl_wexitstatus($status); else $retcode = 127;
} else {
$retcode = 127;
}
return $retcode == 0; return $retcode == 0;
} }
// child, fork ok // child, fork ok
pcntl_exec("/bin/sh", ["-c", $cmd]); $shell = "/bin/bash";
if (!file_exists($shell)) $shell = "/bin/sh";
$shell = "/bin/sh";
pcntl_exec($shell, ["-c", $cmd]);
return false; return false;
} }

View File

@ -5,112 +5,172 @@ namespace nur\sery\wip\app;
use nur\cli\Application; use nur\cli\Application;
use nur\sery\app\LockFile; use nur\sery\app\LockFile;
use nur\sery\app\RunFile; use nur\sery\app\RunFile;
use nur\sery\cl;
use nur\sery\os\path; use nur\sery\os\path;
use nur\sery\os\sh; use nur\sery\os\sh;
use nur\sery\str; use nur\sery\str;
use nur\sery\ValueException; use nur\sery\ValueException;
class app { class app {
/**
* @var array répertoires vendor exprimés relativement à PROJDIR
*/
const DEFAULT_VENDOR = [
"bindir" => "vendor/bin",
"autoload" => "vendor/autoload.php",
];
private static function isa_Application($app): bool { private static function isa_Application($app): bool {
if (!is_string($app)) return false; if (!is_string($app)) return false;
return $app === Application::class || is_subclass_of($app, Application::class); return $app === Application::class || is_subclass_of($app, Application::class);
} }
private static function verifix_name(string &$name): void {
# si $name est une classe, enlever le package et normaliser
$name = preg_replace('/.*\\\\/', "", $name);
$name = str::without_suffix("-app", str::camel2us($name, false, "-"));
}
/** @param Application|string */ /** @param Application|string */
static function with($app): self { static function with($app, ?array $internal_use_params=null): self {
if ($app instanceof Application) { if ($app instanceof Application) {
$projdir = $app::PROJDIR; $params = [
$appcode = $app::APPCODE; "projdir" => $app::PROJDIR,
$name = $app::NAME; "vendor" => $app::VENDOR,
$title = $app::TITLE; "appcode" => $app::APPCODE,
$datadir = $app::DATADIR; "apptype" => "cli",
$etcdir = $app::ETCDIR; "name" => $app::NAME,
$vardir = $app::VARDIR; "title" => $app::TITLE,
$logdir = $app::LOGDIR; "datadir" => $app::DATADIR,
"etcdir" => $app::ETCDIR,
"vardir" => $app::VARDIR,
"logdir" => $app::LOGDIR,
];
} elseif (self::isa_Application($app)) { } elseif (self::isa_Application($app)) {
$projdir = constant("$app::PROJDIR"); $params = [
$appcode = constant("$app::APPCODE"); "projdir" => constant("$app::PROJDIR"),
$name = constant("$app::NAME"); "vendor" => constant("$app::VENDOR"),
$title = constant("$app::TITLE"); "appcode" => constant("$app::APPCODE"),
$datadir = constant("$app::DATADIR"); "apptype" => "cli",
$etcdir = constant("$app::ETCDIR"); "name" => constant("$app::NAME"),
$vardir = constant("$app::VARDIR"); "title" => constant("$app::TITLE"),
$logdir = constant("$app::LOGDIR"); "datadir" => constant("$app::DATADIR"),
"etcdir" => constant("$app::ETCDIR"),
"vardir" => constant("$app::VARDIR"),
"logdir" => constant("$app::LOGDIR"),
];
} elseif (is_array($app)) { } elseif (is_array($app)) {
return new static($app); $params = $app;
} else { } else {
throw ValueException::invalid_type($app, Application::class); throw ValueException::invalid_type($app, Application::class);
} }
return new static([ if ($internal_use_params !== null) {
"projdir" => $projdir, $params = array_merge($internal_use_params, cl::selectm($params, [
"appcode" => $appcode, "name",
"apptype" => "cli", "title",
"name" => $name, ], [
"title" => $title, "apptype" => "cli",
"datadir" => $datadir, ]));
"etcdir" => $etcdir, self::verifix_name($params["name"]);
"vardir" => $vardir, }
"logdir" => $logdir, return new static($params, $internal_use_params !== null);
]);
} }
protected static ?app $app = null; protected static ?app $app = null;
static function init($app): void { static function init($app, ?array $internal_use_params=null): void {
self::$app = static::with($app); self::$app = static::with($app, $internal_use_params);
} }
static function get(): self { static function get(): self {
return self::$app ??= new self(null); return self::$app ??= new self(null);
} }
function __construct(?array $params) { function __construct(?array $params, bool $internalUse_asis=false) {
$this->projdir = $projdir = path::abspath($params["projdir"] ?? "."); if ($internalUse_asis) {
$this->appcode = $appcode = $params["appcode"] ?? "app"; [
$this->apptype = $apptype = $params["apptype"] ?? "cli"; "projdir" => $this->projdir,
$name = $params["name"] ?? null; "vendor" => $this->vendor,
if ($name === null) { "appcode" => $this->appcode,
$name = $appcode; "apptype" => $this->apptype,
"name" => $this->name,
"title" => $this->title,
"profile" => $this->profile,
"cwd" => $this->cwd,
"datadir" => $this->datadir,
"etcdir" => $this->etcdir,
"vardir" => $this->vardir,
"logdir" => $this->logdir,
] = $params;
} else { } else {
# si $name est une classe, enlever le package et normaliser $this->projdir = $projdir = path::abspath($params["projdir"] ?? ".");
$name = $params["name"] ?? $appcode; $vendor = $params["vendor"] ?? self::DEFAULT_VENDOR;
$name = preg_replace('/.*\\\\/', "", $name); $vendor["bindir"] = path::reljoin($projdir, $vendor["bindir"]);
$name = str::without_suffix("-app", str::camel2us($name, false, "-")); $vendor["autoload"] = path::reljoin($projdir, $vendor["autoload"]);
$this->vendor = $vendor;
$this->appcode = $appcode = $params["appcode"] ?? "app";
$this->apptype = $apptype = $params["apptype"] ?? "cli";
$name = $params["name"] ?? null;
if ($name === null) {
$name = $appcode;
} else {
# si $name est une classe, enlever le package et normaliser
$name = preg_replace('/.*\\\\/', "", $name);
$name = str::without_suffix("-app", str::camel2us($name, false, "-"));
}
$this->name = $name;
$this->title = $params["title"] ?? null;
$appcode = strtoupper($appcode);
# profile
$profile = getenv("${appcode}_PROFILE");
if ($profile === false) $profile = getenv("APP_PROFILE");
if ($profile === false) $profile = $params["profile"] ?? null;
if ($profile === null) {
if (file_exists("$projdir/.default-profile-devel")) $profile = "devel";
else $profile = "prod";
}
$this->profile = $profile;
# cwd
$this->cwd = getcwd();
# datadir
$datadir = getenv("${appcode}_DATADIR");
if ($datadir === false) $datadir = $params["datadir"] ?? null;
if ($datadir === null) $datadir = "devel/$apptype";
$this->datadir = $datadir = path::reljoin($projdir, $datadir);
# etcdir
$etcdir = getenv("${appcode}_ETCDIR");
if ($etcdir === false) $etcdir = $params["etcdir"] ?? null;
if ($etcdir === null) $etcdir = "etc";
$this->etcdir = $etcdir = path::reljoin($datadir, $etcdir);
# vardir
$vardir = getenv("${appcode}_VARDIR");
if ($vardir === false) $vardir = $params["vardir"] ?? null;
if ($vardir === null) $vardir = "var";
$this->vardir = $vardir = path::reljoin($datadir, $vardir);
# logdir
$logdir = getenv("${appcode}_LOGDIR");
if ($logdir === false) $logdir = $params["logdir"] ?? null;
if ($logdir === null) $logdir = "log";
$this->logdir = $logdir = path::reljoin($datadir, $logdir);
} }
$this->name = $name; }
$this->title = $params["title"] ?? null;
$appcode = strtoupper($appcode); /** recréer le tableau des paramètres */
# profile function getParams(): array {
$profile = getenv("${appcode}_PROFILE"); return [
if ($profile === false) $profile = getenv("APP_PROFILE"); "projdir" => $this->projdir,
if ($profile === false) $profile = $params["profile"] ?? null; "vendor" => $this->vendor,
if ($profile === null) { "appcode" => $this->appcode,
if (file_exists("$projdir/.default-profile-devel")) $profile = "devel"; "apptype" => $this->apptype,
else $profile = "prod"; "name" => $this->name,
} "title" => $this->title,
$this->profile = $profile; "profile" => $this->profile,
# cwd "cwd" => $this->cwd,
$this->cwd = getcwd(); "datadir" => $this->datadir,
# datadir "etcdir" => $this->etcdir,
$datadir = getenv("${appcode}_DATADIR"); "vardir" => $this->vardir,
if ($datadir === false) $datadir = $params["datadir"] ?? null; "logdir" => $this->logdir,
if ($datadir === null) $datadir = "devel/$apptype"; ];
$this->datadir = $datadir = path::reljoin($projdir, $datadir);
# etcdir
$etcdir = getenv("${appcode}_ETCDIR");
if ($etcdir === false) $etcdir = $params["etcdir"] ?? null;
if ($etcdir === null) $etcdir = "etc";
$this->etcdir = $etcdir = path::reljoin($datadir, $etcdir);
# vardir
$vardir = getenv("${appcode}_VARDIR");
if ($vardir === false) $vardir = $params["vardir"] ?? null;
if ($vardir === null) $vardir = "var";
$this->vardir = $vardir = path::reljoin($datadir, $vardir);
# logdir
$logdir = getenv("${appcode}_LOGDIR");
if ($logdir === false) $logdir = $params["logdir"] ?? null;
if ($logdir === null) $logdir = "log";
$this->logdir = $logdir = path::reljoin($datadir, $logdir);
} }
protected string $projdir; protected string $projdir;
@ -119,6 +179,16 @@ class app {
return $this->projdir; return $this->projdir;
} }
protected array $vendor;
function getVendorBindir(): string {
return $this->vendor["bindir"];
}
function getVendorAutoload(): string {
return $this->vendor["autoload"];
}
protected string $appcode; protected string $appcode;
function getAppcode(): string { function getAppcode(): string {