@@ -271,22 +271,132 @@ protected function consolidateConfiguration() {
271271 */
272272 protected function checkPackages () {
273273 if ($ this ->onlySecurity ) {
274- $ packages_to_update = $ this ->runCommand (sprintf ('composer audit --locked %s --format plain 2>&1 | grep ^Package | cut -f2 -d: | sort -u ' , $ this ->getNoDevParameter ()))->getOutput ();
274+ $ package_list = $ this
275+ ->runCommand (sprintf ('composer audit --locked %s --format plain 2>&1 | grep ^Package | cut -f2 -d: | sort -u ' , $ this ->getNoDevParameter ()))
276+ ->getOutput ();
275277 }
276278 else {
277- $ packages_to_update = $ this ->runCommand (sprintf ('composer show --locked --direct --name-only %s 2>/dev/null ' , $ this ->getNoDevParameter ()))
279+ $ package_list = $ this
280+ ->runCommand (sprintf ('composer show --locked --outdated --name-only %s 2>/dev/null ' , $ this ->getNoDevParameter ()))
278281 ->getOutput ();
279282 }
283+ $ package_list_massaged = $ this ->massagePackageList ($ package_list );
284+ $ this ->packagesToUpdate = $ this ->findDirectPackagesFromList ($ package_list_massaged );
285+
286+ $ this ->output ->writeln (implode ("\n" , $ this ->packagesToUpdate ));
287+ }
288+
289+ /**
290+ * Given a list of packages , find its direct packages.
291+ *
292+ * @see UpdaterCommand::findDirectPackage()
293+ *
294+ * @param array $packages_list
295+ * Packages list.
296+ * @return array
297+ * List of direct packages.
298+ */
299+ protected function findDirectPackagesFromList (array $ packages_list ) {
300+ if (empty ($ packages_list )) {
301+ return [];
302+ }
303+
304+ $ direct_packages = $ this ->massagePackageList ($ this
305+ ->runCommand (sprintf ('composer show --locked --direct --name-only %s 2>/dev/null ' , $ this ->getNoDevParameter ()))
306+ ->getOutput ());
307+
308+ $ direct_packages_found = array_intersect ($ packages_list , $ direct_packages );
309+
310+ $ not_direct_packages = array_diff ($ packages_list , $ direct_packages );
311+
312+ foreach ($ not_direct_packages as $ package ) {
313+ $ direct_packages_found [] = $ this ->findDirectPackage ($ package , $ direct_packages );
314+ }
315+
316+ return array_unique ($ direct_packages_found );
317+ }
318+
319+ /**
320+ * Find the direct package for a specific not direct dependency.
321+ *
322+ * If no direct package is found, consider the self package as direct. It is a extreme use
323+ * case where a too deep dependency is not found. For module convenience, it is needed to consider
324+ * package as direct so it can be updated.
325+ *
326+ * @param string $package
327+ * Package.
328+ * @param array $direct_packages
329+ * List of direct packages.
330+ *
331+ * @return string
332+ * The direct package.
333+ */
334+ protected function findDirectPackage (string $ package , array $ direct_packages ) {
335+ $ composer_why_recursive_timeout = 2 ;
336+ $ commands = [
337+ sprintf ("composer why %s --locked | awk '{print $1}' " , $ package ),
338+ sprintf ("timeout %s composer why %s --locked -r | awk '{print $1}' " , $ composer_why_recursive_timeout , $ package ),
339+ ];
340+
341+ foreach ($ commands as $ command ) {
342+ $ direct_package = $ this ->findPackageInPackageListCommand ($ command , $ direct_packages );
343+ if (!empty ($ direct_package )) {
344+ return $ direct_package ;
345+ }
346+ }
347+
348+ return $ package ;
349+ }
350+
351+ /**
352+ * Finds a package from a command that is present in a package list command.
353+ *
354+ * This is used to get direct apckages from not direct packages.
355+ *
356+ * @see UpdaterCommand::findDirectPackage()
357+ *
358+ * @param string $command
359+ * List that return packages list.
360+ * @param array $package_list
361+ * List of packages we want to look for.
362+ *
363+ * @return string|null
364+ * FIrst package from command that is present in package list.
365+ */
366+ protected function findPackageInPackageListCommand (string $ command , array $ package_list ) {
367+ $ package_list_output = array_filter (explode ("\n" , (string ) trim ($ this ->runCommand ($ command )
368+ ->getOutput ())));
369+ foreach ($ package_list_output as $ package ) {
370+ if (in_array ($ package , $ package_list )) {
371+ return $ package ;
372+ }
373+ }
280374
281- $ this ->packagesToUpdate = explode ("\n" , $ packages_to_update );
282- $ this ->packagesToUpdate = array_map (function ($ package ) {
375+ return null ;
376+ }
377+
378+ /**
379+ * Masssages a list of packages.
380+ *
381+ * It converts a package list bash output into a package list array,
382+ * removing any element that is not a package and removing spaces.
383+ *
384+ * @param string $package_list
385+ * List of packages coming from a bash command (s.e.: composer show --names-only).
386+ *
387+ * @return array
388+ * List of packages. Example:
389+ * - metadrop/drupal-updater
390+ * - metadrop/drupal-artifact-builder
391+ */
392+ protected function massagePackageList (string $ package_list ) {
393+ $ package_list = explode ("\n" , $ package_list );
394+ $ package_list = array_map (function ($ package ) {
283395 return trim ($ package );
284- }, $ this -> packagesToUpdate );
285- $ this -> packagesToUpdate = array_filter ($ this -> packagesToUpdate , function ($ package ) {
396+ }, $ package_list );
397+ return array_filter ($ package_list , function ($ package ) {
286398 return preg_match ('/^([A-Za-z0-9_-]*\/[A-Za-z0-9_-]*)/ ' , $ package );
287399 });
288-
289- $ this ->output ->writeln (implode ("\n" , $ this ->packagesToUpdate ));
290400 }
291401
292402 /**
0 commit comments