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;
 | 
						|
  }
 | 
						|
}
 |