241 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			241 lines
		
	
	
		
			7.2 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 {
 | |
|   # préfixes de projets dont on tient compte
 | |
|   const PREFIXES = ["ur/", "nur/", "lib/", "nulib/"];
 | |
| 
 | |
|   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;
 | |
|   }
 | |
| }
 |