116 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
namespace nur\tools\compctl;
 | 
						|
 | 
						|
use Exception;
 | 
						|
use nur\A;
 | 
						|
 | 
						|
class ComposerWalker {
 | 
						|
  protected static function get_project_dir($name, string $projects_dir) {
 | 
						|
    $project_dir = A::get(ConfigFile::PROJNAMES, $name);
 | 
						|
    if ($project_dir === null) {
 | 
						|
      $project_dir = preg_replace('/\//', "-", $name, 1);
 | 
						|
    }
 | 
						|
    return "$projects_dir/$project_dir";
 | 
						|
  }
 | 
						|
 | 
						|
  static function parse_project(string $dir, array &$projects, ?array &$new_projects=null, bool $throw=false): ?array {
 | 
						|
    try {
 | 
						|
      $composer = new ComposerFile("$dir/composer.json");
 | 
						|
    } catch (Exception $e) {
 | 
						|
      if ($throw) throw $e;
 | 
						|
      else return null;
 | 
						|
    }
 | 
						|
 | 
						|
    $pname = $composer->getv("name");
 | 
						|
    if (array_key_exists($pname, $projects) && $projects[$pname] !== null) {
 | 
						|
      # projet déjà analysé
 | 
						|
      return $projects[$pname];
 | 
						|
    }
 | 
						|
 | 
						|
    $project = [
 | 
						|
      "composer" => $composer,
 | 
						|
      "name" => $pname,
 | 
						|
      "requires" => [],
 | 
						|
      "branches" => [],
 | 
						|
      "dir" => realpath($dir),
 | 
						|
    ];
 | 
						|
    $requires = $composer->geta("require");
 | 
						|
    if ($requires !== null) {
 | 
						|
      foreach ($requires as $dep => $version) {
 | 
						|
        # ignorer les projets qui n'ont pas le préfixe requis
 | 
						|
        $include_project = false;
 | 
						|
        foreach (ConfigFile::PREFIXES as $prefix) {
 | 
						|
          if (substr($dep, 0, strlen($prefix)) === $prefix) {
 | 
						|
            $include_project = true;
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        if (!$include_project) continue;
 | 
						|
        # sinon, ajouter le projet aux dépendances
 | 
						|
        $project["requires"][] = $dep;
 | 
						|
        if (!array_key_exists($dep, $projects)) {
 | 
						|
          $projects[$dep] = null;
 | 
						|
          $new_projects[$dep] = true;
 | 
						|
        }
 | 
						|
        if (substr($version, 0, 4) === "dev-") {
 | 
						|
          $project["branches"][$dep] = substr($version, 4);
 | 
						|
        } else {
 | 
						|
          $project["branches"][$dep] = $version;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    $projects[$pname] = $project;
 | 
						|
    return $project;
 | 
						|
  }
 | 
						|
 | 
						|
  static function build_projects(array $project_dirs, ?string &$projects_dir): array {
 | 
						|
    $projects = [];
 | 
						|
    foreach ($project_dirs as $project_dir) {
 | 
						|
      if ($projects_dir === null) $projects_dir = dirname($project_dir);
 | 
						|
      # analyser le projet initial
 | 
						|
      $new_projects = [];
 | 
						|
      if (self::parse_project($project_dir, $projects, $new_projects) === null) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      # puis analyser récursivement tous les projets dépendants
 | 
						|
      while (true) {
 | 
						|
        $have_new = false;
 | 
						|
        foreach ($new_projects as $name => &$new) {
 | 
						|
          if ($new) {
 | 
						|
            $new = false;
 | 
						|
            $have_new = true;
 | 
						|
            $project_dir = self::get_project_dir($name, $projects_dir);
 | 
						|
            self::parse_project($project_dir, $projects, $new_projects);
 | 
						|
          }
 | 
						|
        }; unset($new);
 | 
						|
        if (!$have_new) break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return $projects;
 | 
						|
  }
 | 
						|
 | 
						|
  static function order_deps(?array $deps, array $projects): array {
 | 
						|
    if ($deps === null) $deps = array_keys($projects);
 | 
						|
    $pi = 0;
 | 
						|
    $max = count($deps);
 | 
						|
    while ($pi < $max) {
 | 
						|
      $modified = false;
 | 
						|
      $project = $projects[$deps[$pi]];
 | 
						|
      if ($project !== null) {
 | 
						|
        # dépendance dont on a trouvé la correspondance sur disque
 | 
						|
        foreach ($project["requires"] as $dep) {
 | 
						|
          $di = array_search($dep, $deps);
 | 
						|
          if ($di > $pi) {
 | 
						|
            # si la dépendance se situe après le projet, la placer avant
 | 
						|
            $deps = array_splice($deps, $di, 1);
 | 
						|
            $deps = array_splice($deps, $pi, 0, [$dep]);
 | 
						|
            $modified = true;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (!$modified) $pi++;
 | 
						|
    }
 | 
						|
    return $deps;
 | 
						|
  }
 | 
						|
}
 |