238 lines
7.1 KiB
PHP
238 lines
7.1 KiB
PHP
|
<?php
|
||
|
namespace nur\tools\compctl;
|
||
|
|
||
|
use nur\A;
|
||
|
use nur\b\ValueException;
|
||
|
use nur\data\types\md_utils;
|
||
|
use nur\data\types\Metadata;
|
||
|
use nur\path;
|
||
|
use nur\str;
|
||
|
use nur\yaml;
|
||
|
|
||
|
class ConfigFile {
|
||
|
const DEFAULT_DEP = "dev-master";
|
||
|
const DEFAULT_DEPS = [
|
||
|
"wip" => "dev-wip",
|
||
|
"develop" => "dev-develop",
|
||
|
];
|
||
|
const DEFAULT_ALLOW_LINK = false;
|
||
|
const DEFAULT_ALLOW_LINKS = [
|
||
|
"wip" => true,
|
||
|
"develop" => true,
|
||
|
];
|
||
|
const DEFAULT_CONFIG = [
|
||
|
# cette définition tient compte des valeurs DEFAULT_* ci-dessus
|
||
|
"defaults" => [
|
||
|
"wip" => "dev-wip",
|
||
|
"develop" => "dev-develop",
|
||
|
"master" => [
|
||
|
"version" => "dev-master",
|
||
|
"allow_link" => false,
|
||
|
],
|
||
|
],
|
||
|
];
|
||
|
const PROJNAMES = [
|
||
|
# noms de projets particuliers
|
||
|
"nulib/php" => "nulib",
|
||
|
];
|
||
|
|
||
|
const DEP_SCHEMA = [
|
||
|
"libname" => ["string", null, "nom de la librairie"],
|
||
|
"version" => ["?string", null, "version de la librairie"],
|
||
|
"projname" => ["?string", null, "nom du répertoire du projet sur le système de fichier"],
|
||
|
"type" => ["?string", null, "type de dépendance"],
|
||
|
"url" => ["?string", null, "url de la dépendance"],
|
||
|
"allow_link" => ["?bool", null, "peut-on lier vers le projet sur disque?"],
|
||
|
"link" => ["?bool", null, "faut-il ajouter l'url dans [repositories]"],
|
||
|
"branch" => ["?string", null, "branche de la dépendance dans le projet"],
|
||
|
];
|
||
|
|
||
|
function __construct(string $configFile, ?string $projdir=null, bool $ensureExists=true) {
|
||
|
if ($projdir === null) $projdir = dirname($configFile);
|
||
|
if ($ensureExists && !file_exists($configFile)) {
|
||
|
$message = path::ppath($projdir).": aucune configuration n'a été trouvée";
|
||
|
throw new ValueException($message);
|
||
|
}
|
||
|
$this->configFile = $configFile;
|
||
|
$this->projdir = $projdir;
|
||
|
}
|
||
|
|
||
|
/** @var string */
|
||
|
protected $configFile;
|
||
|
|
||
|
/** @var string */
|
||
|
protected $projdir;
|
||
|
|
||
|
/** @var array */
|
||
|
protected $data;
|
||
|
|
||
|
protected function load(): array {
|
||
|
if ($this->data === null) {
|
||
|
$this->data = yaml::load($this->configFile);
|
||
|
}
|
||
|
return $this->data;
|
||
|
}
|
||
|
|
||
|
function getv(string $pkey="", $default=null) {
|
||
|
$this->load();
|
||
|
return A::pget($this->data, $pkey, $default);
|
||
|
}
|
||
|
|
||
|
function geta(string $pkey="", array $default=[]): array {
|
||
|
return A::with($this->getv($pkey, $default));
|
||
|
}
|
||
|
|
||
|
function getBranchDeps(): array {
|
||
|
return $this->geta("defaults");
|
||
|
}
|
||
|
|
||
|
function getRequires(): array {
|
||
|
return $this->geta("require");
|
||
|
}
|
||
|
|
||
|
function getBranches(): array {
|
||
|
return $this->geta("branch");
|
||
|
}
|
||
|
|
||
|
private static $dep_md;
|
||
|
private static function dep_md(): Metadata {
|
||
|
return md_utils::ensure_md(self::$dep_md, self::DEP_SCHEMA);
|
||
|
}
|
||
|
|
||
|
/** @var array */
|
||
|
protected $duns;
|
||
|
|
||
|
function getDeps(string $branch): array {
|
||
|
$dun = A::get($this->duns, $branch);
|
||
|
if ($dun !== null) return $dun;
|
||
|
|
||
|
$branches = $this->getBranches();
|
||
|
$source = $branch;
|
||
|
$valid = array_key_exists($source, $branches);
|
||
|
if (!$valid && ($pos = strpos($branch, "/")) !== false) {
|
||
|
# pas de définition pour cette branche, essayer avec la branche de base
|
||
|
# si la branche est de la forme base/xxx
|
||
|
$source = substr($branch, 0, $pos);
|
||
|
$valid = array_key_exists($source, $branches);
|
||
|
}
|
||
|
if (!$valid && array_key_exists("master", $branches)) {
|
||
|
# la branche master est utilisée par défaut si elle existe
|
||
|
$source = "master";
|
||
|
$valid = true;
|
||
|
}
|
||
|
if (!$valid) {
|
||
|
$dun = [null, null, null];
|
||
|
|
||
|
} else {
|
||
|
$projdir = $this->projdir;
|
||
|
|
||
|
$branchDeps = $this->getBranchDeps() + self::DEFAULT_DEPS;
|
||
|
$defaultDep = null;
|
||
|
foreach ($branchDeps as $dbranch => $ddep) {
|
||
|
if ($branch == $dbranch) {
|
||
|
$defaultDep = $ddep;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if ($defaultDep === null) {
|
||
|
foreach ($branchDeps as $dbranch => $ddep) {
|
||
|
if (str::starts_with("$dbranch/", $branch)) {
|
||
|
$defaultDep = $ddep;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ($defaultDep === null) $defaultDep = self::DEFAULT_DEP;
|
||
|
self::dep_md()->ensureSchema($defaultDep, "");
|
||
|
|
||
|
$defaultAllowLink = null;
|
||
|
foreach (self::DEFAULT_ALLOW_LINKS as $albranch => $alvalue) {
|
||
|
if ($branch == $albranch || str::starts_with("$albranch/", $branch)) {
|
||
|
$defaultAllowLink = $alvalue;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if ($defaultAllowLink === null) $defaultAllowLink = self::DEFAULT_ALLOW_LINK;
|
||
|
|
||
|
# tout d'abord, lister les dépendances
|
||
|
$bdeps = [];
|
||
|
foreach ($this->getRequires() as $libname => $dep) {
|
||
|
if (strpos($libname, "/") === false) continue;
|
||
|
if ($dep === false) continue;
|
||
|
if ($dep !== null) {
|
||
|
self::dep_md()->ensureSchema($dep, $libname);
|
||
|
}
|
||
|
$bdeps[$libname] = $dep;
|
||
|
}
|
||
|
foreach ($this->geta("branch.$source") as $libname => $dep) {
|
||
|
if ($dep === false) {
|
||
|
# une définition par défaut peut être supprimée avec la valeur false
|
||
|
A::del($bdeps, $libname);
|
||
|
continue;
|
||
|
}
|
||
|
if ($dep !== null) {
|
||
|
self::dep_md()->ensureSchema($dep, $libname);
|
||
|
if (!array_key_exists($libname, $bdeps)) $bdeps[$libname] = $dep;
|
||
|
elseif ($bdeps[$libname] === null) $bdeps[$libname] = $dep;
|
||
|
else A::merge_nn($bdeps[$libname], $dep);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$deps = [];
|
||
|
$isUrls = [];
|
||
|
$notFoundUrls = [];
|
||
|
foreach ($bdeps as $libname => $dep) {
|
||
|
if ($dep === null) {
|
||
|
$dep = $defaultDep;
|
||
|
$dep["libname"] = $libname;
|
||
|
}
|
||
|
self::dep_md()->ensureSchema($dep, $libname);
|
||
|
$version = $dep["version"];
|
||
|
if ($version === null) $version = $defaultDep["version"];
|
||
|
$projname = $dep["projname"];
|
||
|
if ($projname === null) $projname = A::get(self::PROJNAMES, $libname);
|
||
|
if ($projname === null) {
|
||
|
$projname = str_replace("/", "-", $libname);
|
||
|
}
|
||
|
$type = $dep["type"];
|
||
|
if ($type === null) $type = "path";
|
||
|
$url = $dep["url"];
|
||
|
if ($url === null) $url = "../$projname";
|
||
|
$allowLink = $dep["allow_link"];
|
||
|
if ($allowLink === null) $allowLink = $defaultDep["allow_link"];
|
||
|
if ($allowLink === null) $allowLink = $defaultAllowLink;
|
||
|
$link = $dep["link"];
|
||
|
if ($link === null) {
|
||
|
$isDev = str::starts_with("dev-", $version)
|
||
|
|| str::ends_with("-dev", $version);
|
||
|
$link = $allowLink && $isDev;
|
||
|
}
|
||
|
if ($link && (
|
||
|
$type !== "path" ||
|
||
|
!path::is_dir("$projdir/$url", true)
|
||
|
)) {
|
||
|
$notFoundUrls[] = $url;
|
||
|
$link = false;
|
||
|
}
|
||
|
$vbranch = $version;
|
||
|
if (!str::del_prefix($vbranch, "dev-")
|
||
|
&& !str::del_suffix($vbranch, "-dev")) {
|
||
|
$vbranch = null;
|
||
|
}
|
||
|
A::merge($dep, [
|
||
|
"projname" => $projname,
|
||
|
"type" => $type,
|
||
|
"url" => $url,
|
||
|
"allow_link" => $allowLink,
|
||
|
"link" => $link,
|
||
|
"branch" => $vbranch,
|
||
|
]);
|
||
|
$deps[$libname] = $dep;
|
||
|
$isUrls[$url] = true;
|
||
|
}
|
||
|
$dun = [$deps, $isUrls, $notFoundUrls];
|
||
|
}
|
||
|
return $this->duns[$branch] = $dun;
|
||
|
}
|
||
|
}
|