nur-sery/src/wip/app/app.php

288 lines
8.2 KiB
PHP
Raw Normal View History

2024-06-11 12:06:54 +04:00
<?php
2024-06-13 07:28:11 +04:00
namespace nur\sery\wip\app;
#XXX déplacer dans nur\sery\app dès que la dépendance sur nur\cli\Application sera levée
2024-06-11 12:06:54 +04:00
use nur\cli\Application;
2024-06-13 07:28:11 +04:00
use nur\sery\app\LockFile;
use nur\sery\app\RunFile;
2024-06-11 12:06:54 +04:00
use nur\sery\os\path;
2024-06-11 15:56:54 +04:00
use nur\sery\os\sh;
2024-06-13 12:24:15 +04:00
use nur\sery\str;
2024-06-11 12:06:54 +04:00
use nur\sery\ValueException;
class app {
2024-06-13 07:28:11 +04:00
private static function isa_Application($app): bool {
if (!is_string($app)) return false;
return $app === Application::class || is_subclass_of($app, Application::class);
}
2024-06-11 12:06:54 +04:00
/** @param Application|string */
static function with($app): self {
if ($app instanceof Application) {
$projdir = $app::PROJDIR;
$appcode = $app::APPCODE;
$name = $app::NAME;
$title = $app::TITLE;
$datadir = $app::DATADIR;
$etcdir = $app::ETCDIR;
$vardir = $app::VARDIR;
$logdir = $app::LOGDIR;
2024-06-13 07:28:11 +04:00
} elseif (self::isa_Application($app)) {
2024-06-11 12:06:54 +04:00
$projdir = constant("$app::PROJDIR");
$appcode = constant("$app::APPCODE");
$name = constant("$app::NAME");
$title = constant("$app::TITLE");
$datadir = constant("$app::DATADIR");
$etcdir = constant("$app::ETCDIR");
$vardir = constant("$app::VARDIR");
$logdir = constant("$app::LOGDIR");
2024-06-11 15:56:54 +04:00
} elseif (is_array($app)) {
return new static($app);
2024-06-11 12:06:54 +04:00
} else {
throw ValueException::invalid_type($app, Application::class);
}
return new static([
"projdir" => $projdir,
"appcode" => $appcode,
"apptype" => "cli",
"name" => $name,
"title" => $title,
"datadir" => $datadir,
"etcdir" => $etcdir,
"vardir" => $vardir,
"logdir" => $logdir,
]);
}
protected static ?app $app = null;
static function init($app): void {
self::$app = static::with($app);
}
static function get(): self {
return self::$app ??= new self(null);
}
function __construct(?array $params) {
$this->projdir = $projdir = path::abspath($params["projdir"] ?? ".");
$this->appcode = $appcode = $params["appcode"] ?? "app";
$this->apptype = $apptype = $params["apptype"] ?? "cli";
2024-06-13 12:24:15 +04:00
# 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;
2024-06-11 12:06:54 +04:00
$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);
}
protected string $projdir;
function getProjdir(): string {
return $this->projdir;
}
protected string $appcode;
function getAppcode(): string {
return $this->appcode;
}
protected string $apptype;
function getApptype(): string {
return $this->apptype;
}
protected string $name;
function getName(): ?string {
return $this->name;
}
protected ?string $title;
function getTitle(): ?string {
return $this->title;
}
protected string $profile;
function getProfile(): string {
return $this->profile;
}
/**
* @param ?string|false $profile
*/
function withProfile(string $file, $profile): string {
if ($profile !== false) {
if ($profile === null) $profile = $this->getProfile();
[$dir, $filename] = path::split($file);
$basename = path::basename($filename);
$ext = path::ext($file);
$file = path::join($dir, "$basename.$profile$ext");
}
return $file;
}
function findFile(array $dirs, array $names, $profile=null): string {
# d'abord chercher avec le profil
if ($profile !== false) {
foreach ($dirs as $dir) {
foreach ($names as $name) {
$file = path::join($dir, $name);
$file = $this->withProfile($file, $profile);
if (file_exists($file)) return $file;
}
}
}
# puis sans profil
foreach ($dirs as $dir) {
foreach ($names as $name) {
$file = path::join($dir, $name);
if (file_exists($file)) return $file;
}
}
# la valeur par défaut est avec profil
return $this->withProfile(path::join($dirs[0], $names[0]), $profile);
}
function fencedJoin(string $basedir, string $path): string {
$path = path::reljoin($basedir, $path);
if (!path::is_within($path, $basedir)) {
throw ValueException::invalid_value($path, "path");
}
return $path;
}
protected string $cwd;
function getCwd(): string {
return $this->cwd;
}
protected string $datadir;
function getDatadir(): string {
return $this->datadir;
}
protected string $etcdir;
function getEtcdir(): string {
return $this->etcdir;
}
function getEtcfile(string $name, $profile=null): string {
return $this->findFile([$this->etcdir], [$name], $profile);
}
protected string $vardir;
function getVardir(): string {
return $this->vardir;
}
function getVarfile(string $name, $profile=null): string {
2024-06-11 15:56:54 +04:00
$file = $this->withProfile($this->fencedJoin($this->vardir, $name), $profile);
sh::mkdirof($file);
return $file;
2024-06-11 12:06:54 +04:00
}
protected string $logdir;
function getLogdir(): string {
return $this->logdir;
}
2024-06-11 15:56:54 +04:00
function getLogfile(?string $name=null, $profile=null): string {
if ($name === null) $name = "{$this->name}.log";
$file = $this->withProfile($this->fencedJoin($this->logdir, $name), $profile);
sh::mkdirof($file);
return $file;
2024-06-11 12:06:54 +04:00
}
/**
* obtenir le chemin absolu vers un fichier de travail
* - si le chemin est absolu, il est inchangé
* - si le chemin est qualifié (commence par ./ ou ../) ou sans chemin, il est
* exprimé par rapport à $vardir
* - sinon le chemin est exprimé par rapport au répertoire de travail de base
* $datadir
*
* is $ensure_dir, créer le répertoire du fichier s'il n'existe pas déjà
*/
function getWorkfile(?string $file, $profile=null, bool $ensureDir=true): ?string {
if ($file === null) return null;
if (path::is_qualified($file) || !path::have_dir($file)) {
$file = path::reljoin($this->vardir, $file);
} else {
$file = path::reljoin($this->datadir, $file);
}
$file = $this->withProfile($file, $profile);
2024-06-11 15:56:54 +04:00
if ($ensureDir) sh::mkdirof($file);
2024-06-11 12:06:54 +04:00
return $file;
}
/**
* obtenir le chemin absolu vers un fichier spécifié par l'utilisateur.
* - si le chemin commence par /, il est laissé en l'état
* - si le chemin commence par ./ ou ../, il est exprimé par rapport à $cwd
* - sinon le chemin est exprimé par rapport au répertoire de travail $vardir
*/
function getUserfile(?string $file): ?string {
if ($file === null) return null;
if (path::is_qualified($file)) {
return path::reljoin($this->cwd, $file);
} else {
return path::reljoin($this->vardir, $file);
}
}
protected ?RunFile $runfile = null;
function getRunfile(): RunFile {
$name = $this->name;
return $this->runfile ??= new RunFile($this->getWorkfile($name), $name);
}
protected ?LockFile $lockFile = null;
function getLockfile(): LockFile {
return $this->lockFile ??= $this->getRunfile()->getLockFile(null, $this->title);
}
}