2020use Composer \Script \Event ;
2121use Composer \Script \ScriptEvents ;
2222use Composer \Util \Filesystem ;
23+ use Symfony \Component \Console \Formatter \OutputFormatterStyle ;
2324
2425/**
2526 * Plugin class.
@@ -60,6 +61,11 @@ class Plugin implements PluginInterface, EventSubscriberInterface
6061 'params ' => [],
6162 ];
6263
64+ /**
65+ * @var array package name => configs as listed in `composer.json`
66+ */
67+ protected $ originalFiles = [];
68+
6369 protected $ aliases = [];
6470
6571 protected $ extensions = [];
@@ -112,6 +118,7 @@ public function onPostAutoloadDump(Event $event)
112118 $ this ->io ->writeError ('<info>Assembling config files</info> ' );
113119 $ this ->initAutoload ();
114120 $ this ->scanPackages ();
121+ $ this ->showDepsTree ();
115122
116123 $ builder = new Builder ($ this ->files );
117124 $ builder ->setAddition (['aliases ' => $ this ->aliases ]);
@@ -144,6 +151,7 @@ protected function processPackage(CompletePackageInterface $package)
144151 {
145152 $ extra = $ package ->getExtra ();
146153 $ files = isset ($ extra [self ::EXTRA_OPTION_NAME ]) ? $ extra [self ::EXTRA_OPTION_NAME ] : null ;
154+ $ this ->originalFiles [$ package ->getPrettyName ()] = $ files ;
147155
148156 if ($ package ->getType () !== self ::YII2_PACKAGE_TYPE && is_null ($ files )) {
149157 return ;
@@ -311,7 +319,8 @@ public function getPackages()
311319 protected $ plainList = [];
312320
313321 /**
314- * Ordered list of package. Order @see findPackages.
322+ * Ordered list of package in form: package => depth
323+ * For order description @see findPackages.
315324 */
316325 protected $ orderedList = [];
317326
@@ -331,13 +340,8 @@ public function findPackages()
331340 $ this ->orderedList = [];
332341 $ this ->iteratePackage ($ root , true );
333342
334- if ($ this ->io ->isVerbose ()) {
335- $ indent = ' - ' ;
336- $ packages = $ indent . implode ("\n$ indent " , $ this ->orderedList );
337- $ this ->io ->writeError ($ packages );
338- }
339343 $ res = [];
340- foreach ($ this ->orderedList as $ name ) {
344+ foreach (array_keys ( $ this ->orderedList ) as $ name ) {
341345 $ res [] = $ this ->plainList [$ name ];
342346 }
343347
@@ -349,7 +353,7 @@ public function findPackages()
349353 * @param PackageInterface $package to iterate
350354 * @param bool $includingDev process development dependencies, defaults to not process
351355 */
352- public function iteratePackage (PackageInterface $ package , $ includingDev = false )
356+ protected function iteratePackage (PackageInterface $ package , $ includingDev = false )
353357 {
354358 $ name = $ package ->getPrettyName ();
355359
@@ -361,21 +365,27 @@ public function iteratePackage(PackageInterface $package, $includingDev = false)
361365 $ processed [$ name ] = 1 ;
362366 }
363367
368+ /// package depth in dependency hierarchy
369+ static $ depth = 0 ;
370+ $ depth ++;
371+
364372 $ this ->iterateDependencies ($ package );
365373 if ($ includingDev ) {
366374 $ this ->iterateDependencies ($ package , true );
367375 }
368376 if (!isset ($ this ->orderedList [$ name ])) {
369- $ this ->orderedList [$ name ] = $ name ;
377+ $ this ->orderedList [$ name ] = $ depth ;
370378 }
379+
380+ $ depth --;
371381 }
372382
373383 /**
374384 * Iterates dependencies of the given package.
375385 * @param PackageInterface $package
376386 * @param bool $dev which dependencies to iterate: true - dev, default - general
377387 */
378- public function iterateDependencies (PackageInterface $ package , $ dev = false )
388+ protected function iterateDependencies (PackageInterface $ package , $ dev = false )
379389 {
380390 $ path = $ this ->preparePath ($ package , 'composer.json ' );
381391 if (file_exists ($ path )) {
@@ -386,12 +396,43 @@ public function iterateDependencies(PackageInterface $package, $dev = false)
386396 $ deps = $ dev ? $ package ->getDevRequires () : $ package ->getRequires ();
387397 }
388398 foreach (array_keys ($ deps ) as $ target ) {
389- if (isset ($ this ->plainList [$ target ]) && ! isset ($ this ->orderedList [$ target ])) {
399+ if (isset ($ this ->plainList [$ target ]) && empty ($ this ->orderedList [$ target ])) {
390400 $ this ->iteratePackage ($ this ->plainList [$ target ]);
391401 }
392402 }
393403 }
394404
405+ protected function showDepsTree ()
406+ {
407+ if (!$ this ->io ->isVerbose ()) {
408+ return ;
409+ }
410+
411+ $ this ->initStyles ();
412+ foreach (array_reverse ($ this ->orderedList ) as $ name => $ depth ) {
413+ $ deps = $ this ->originalFiles [$ name ];
414+ $ color = $ this ->colors [$ depth ];
415+ $ indent = str_repeat (' ' , $ depth - 1 );
416+ $ package = $ this ->plainList [$ name ];
417+ $ showdeps = $ deps ? '[ ' . implode (', ' , array_keys ($ deps )) . '] ' : '' ;
418+ $ this ->io ->write (sprintf ('%s - <%s>%s</%s> %s %s ' , $ indent , $ color , $ name , $ color , $ package ->getFullPrettyVersion (), $ showdeps ));
419+ }
420+ }
421+
422+ protected $ colors = ['red ' , 'green ' , 'yellow ' , 'cyan ' , 'magenta ' , 'blue ' ];
423+
424+ protected function initStyles ()
425+ {
426+ $ ref = new \ReflectionProperty (get_class ($ this ->io ), 'output ' );
427+ $ ref ->setAccessible (true );
428+ $ output = $ ref ->getValue ($ this ->io );
429+
430+ foreach ($ this ->colors as $ color ) {
431+ $ style = new OutputFormatterStyle ($ color );
432+ $ output ->getFormatter ()->setStyle ($ color , $ style );
433+ }
434+ }
435+
395436 /**
396437 * Get absolute path to package base dir.
397438 * @return string
0 commit comments