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
 | |
|             array_splice($deps, $di, 1);
 | |
|             array_splice($deps, $pi, 0, [$dep]);
 | |
|             $modified = true;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       if (!$modified) $pi++;
 | |
|     }
 | |
|     return $deps;
 | |
|   }
 | |
| }
 |