From 17406f2b769eb615605d9a84585adf67ebec2fb0 Mon Sep 17 00:00:00 2001 From: David Jonas Date: Sat, 5 Nov 2022 23:28:58 -0700 Subject: [PATCH 1/3] Separate out direct dependencies --- composer-lock-diff | 69 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/composer-lock-diff b/composer-lock-diff index 2d4a213..2818ee6 100755 --- a/composer-lock-diff +++ b/composer-lock-diff @@ -47,12 +47,12 @@ function diff($key, $data_from, $data_to) { $pkgs = array(); foreach($data_from->$key as $pkg) { - $pkgs[$pkg->name] = array(version($pkg), 'REMOVED', ''); + $pkgs[$pkg->name] = array(version($pkg), 'REMOVED', '', array('direct' => property_exists($pkg, 'direct'))); } foreach($data_to->$key as $pkg) { if (! array_key_exists($pkg->name, $pkgs)) { - $pkgs[$pkg->name] = array('NEW', version($pkg), ''); + $pkgs[$pkg->name] = array('NEW', version($pkg), '', array('direct' => property_exists($pkg, 'direct'))); continue; } @@ -61,6 +61,9 @@ function diff($key, $data_from, $data_to) { } else { $pkgs[$pkg->name][1] = version($pkg); $pkgs[$pkg->name][2] = makeCompareUrl($pkg, $pkgs); + if ($pkgs[$pkg->name][3]['direct'] === false) { // Don't overwrite direct if it was already set to true + $pkgs[$pkg->name][3]['direct'] = property_exists($pkg, 'direct'); + } } } @@ -101,7 +104,7 @@ function tableize($header, $data, $opts = array()) { $widths = array(maxLength(array_merge(array($header), array_keys($data)))); - $count = count(reset($data)); + $count = 3; // it will always be 3. The fourth item is a properties array for($i = 0; $i < $count; $i++) { $widths[] = max(strlen($titles[$i + 1]), maxLength(array_map(function($k) use ($data, $i) { return $data[$k][$i]; }, array_keys($data)))); } @@ -113,8 +116,18 @@ function tableize($header, $data, $opts = array()) { $lines[] = tabelizeLine($titles, $widths); $lines[] = separatorLine($widths, $opts['joint']); + $lines[] = fillLine(array("Direct"), '~', $widths); + + foreach($data as $key => $v) { + if (! $v[3]['direct']) continue; + $lines[] = tabelizeLine(array_merge(array($key), array_slice($v, 0, $count)), $widths); + } + + $lines[] = fillLine(array("Indirect"), '~', $widths); + foreach($data as $key => $v) { - $lines[] = tabelizeLine(array_merge(array($key), $v), $widths); + if ($v[3]['direct']) continue; + $lines[] = tabelizeLine(array_merge(array($key), array_slice($v, 0, $count)), $widths); } if ($opts['capped']) { @@ -132,6 +145,19 @@ function maxLength(array $array) { return max(array_map('strlen', $array)); } +function fillLine($data, $fill_char, $widths) { + $count = count($data); + for ($i = 0; $i < count($widths); $i++) { + if ($i < $count) { + $data[$i] = $fill_char . " " . $data[$i] . " " . str_repeat($fill_char, $widths[$i] - (strlen($data[$i]) + 3)); + } else { + $data[$i] = str_repeat($fill_char, $widths[$i]); + } + } + + return tabelizeLine($data, $widths); +} + function tabelizeLine($data, $widths) { $fields = array(); $count = max(array(count($data), count($widths))); @@ -209,11 +235,20 @@ function loadFile($fileish, $base_path, $default_fileish) { } // Is it a file in the local filesystem? - if (file_exists($fileish)) { - return array(mustDecodeJson(file_get_contents($fileish), $fileish), false); + if (! file_exists($fileish)) { + return array(false, "Candidate '$fileish' does not look loadable from the fs or php stream wrappers"); + } + + $data = mustDecodeJson(file_get_contents($fileish), $fileish); + + // Try to load composer.json and mark deps. + if (substr($fileish, -4) == "lock") { + $composer_json_fileish = substr($fileish, 0, -4) . 'json'; + $composer_json = mustDecodeJson(file_get_contents($composer_json_fileish), $composer_json_fileish); + markDirectDependencies($data, $composer_json); } - return array(false, "Candidate '$fileish' does not look loadable from the fs or php stream wrappers"); + return array($data, false); } function isUrl($string) { @@ -231,6 +266,26 @@ function mustDecodeJson($json, $context) { return $data; } +function markDirectDependencies($lock, $json) { + foreach (array('', '-dev') as $ext) { + foreach ($json->{'require'.$ext} as $pkg => $_) { + $packages = 'packages'.$ext; + + $index = false; + for($i = 0; $i < count($lock->{$packages}); $i++) { + if ($lock->{$packages}[$i]->name == $pkg) { + $index = $i; + break; + } + } + + if ($index !== false) { + $lock->{$packages}[$i]->direct = true; + } + } + } +} + function makeCompareUrl($pkg, $diff) { $func = 'formatCompare' . ucfirst(getSourceRepoType((string) @$pkg->source->url)); return call_user_func($func, @$pkg->source->url, $diff[$pkg->name][0], $diff[$pkg->name][1]); From 5fa7c7bc9b8017c6c36b9e05fad0b5dec4842f7f Mon Sep 17 00:00:00 2001 From: Christian Weiske Date: Thu, 28 Nov 2024 12:27:44 +0100 Subject: [PATCH 2/3] Separate tables for changes in direct and indirect dependencies Builds upon https://github.com/davidrjonas/composer-lock-diff/pull/41 Resolves: https://github.com/davidrjonas/composer-lock-diff/issues/37 Example: $ composer-lock-diff --no-links +------------------------------------+-------------+-----------------------+ | Production Changes | From | To | +------------------------------------+-------------+-----------------------+ | andersundsehr/aus-driver-amazon-s3 | 1.12.1 | 1.13.1 | | felixnagel/generic-gallery | 4.3.0 | 5.2.0 | | fluidtypo3/flux | 9.7.2 | 9.7.4 | +------------------------------------+-------------+-----------------------+ +-------------------+---------+---------+ | Dev Changes | From | To | +-------------------+---------+---------+ | mogic/mogic-phpcs | d81fefd | 0eb8337 | +-------------------+---------+---------+ +------------------------------------+---------+---------+ | Indirect Production Changes | From | To | +------------------------------------+---------+---------+ | aws/aws-crt-php | v1.0.2 | v1.2.7 | | aws/aws-sdk-php | 3.255.7 | 3.331.0 | | beberlei/assert | v3.3.2 | v3.3.3 | | clue/stream-filter | v1.6.0 | v1.7.0 | +------------------------------------+---------+---------+ +----------------------+---------+---------+ | Indirect Dev Changes | From | To | +----------------------+---------+---------+ | phpstan/phpstan | 1.12.10 | 1.12.11 | +----------------------+---------+---------+ --- composer-lock-diff | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/composer-lock-diff b/composer-lock-diff index 2818ee6..1332cb6 100755 --- a/composer-lock-diff +++ b/composer-lock-diff @@ -34,12 +34,21 @@ if ($opts['md']) { } $table_titles = array( - 'changes' => 'Production Changes', - 'changes-dev' => 'Dev Changes', + true => array( + 'changes' => 'Production Changes', + 'changes-dev' => 'Dev Changes', + ), + false => array( + 'changes' => 'Indirect Production Changes', + 'changes-dev' => 'Indirect Dev Changes', + ) ); -foreach($changes as $k => $diff) { - print tableize($table_titles[$k], $diff, $table_opts); +foreach(array(true, false) as $direct) { + foreach($changes as $k => $diff) { + $diff = filterDirect($diff, $direct); + print tableize($table_titles[$direct][$k], $diff, $table_opts); + } } function diff($key, $data_from, $data_to) { @@ -70,6 +79,18 @@ function diff($key, $data_from, $data_to) { return $pkgs; } +function filterDirect($diff, $direct) +{ + if (empty($diff)) return $diff; + + $filtered = array(); + foreach($diff as $key => $v) { + if ($v[3]['direct'] != $direct) continue; + $filtered[$key] = $v; + } + return $filtered; +} + function version($pkg) { if((substr($pkg->version,0,4) == 'dev-' || '-dev' === substr($pkg->version, -4)) && isset($pkg->source) && isset($pkg->source->reference)) { @@ -104,7 +125,7 @@ function tableize($header, $data, $opts = array()) { $widths = array(maxLength(array_merge(array($header), array_keys($data)))); - $count = 3; // it will always be 3. The fourth item is a properties array + $count = count(reset($data)) - 1; for($i = 0; $i < $count; $i++) { $widths[] = max(strlen($titles[$i + 1]), maxLength(array_map(function($k) use ($data, $i) { return $data[$k][$i]; }, array_keys($data)))); } @@ -116,17 +137,7 @@ function tableize($header, $data, $opts = array()) { $lines[] = tabelizeLine($titles, $widths); $lines[] = separatorLine($widths, $opts['joint']); - $lines[] = fillLine(array("Direct"), '~', $widths); - foreach($data as $key => $v) { - if (! $v[3]['direct']) continue; - $lines[] = tabelizeLine(array_merge(array($key), array_slice($v, 0, $count)), $widths); - } - - $lines[] = fillLine(array("Indirect"), '~', $widths); - - foreach($data as $key => $v) { - if ($v[3]['direct']) continue; $lines[] = tabelizeLine(array_merge(array($key), array_slice($v, 0, $count)), $widths); } @@ -542,4 +553,3 @@ EOF; exit(0); } # vim: ff=unix ts=4 ss=4 sr et - From 4a5187916efdd49fe90eaa164479a0b61339a016 Mon Sep 17 00:00:00 2001 From: Christian Weiske Date: Thu, 5 Dec 2024 09:56:49 +0100 Subject: [PATCH 3/3] Do not crash when there is are require-dev changes --- composer-lock-diff | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer-lock-diff b/composer-lock-diff index 1332cb6..74817d7 100755 --- a/composer-lock-diff +++ b/composer-lock-diff @@ -279,6 +279,9 @@ function mustDecodeJson($json, $context) { function markDirectDependencies($lock, $json) { foreach (array('', '-dev') as $ext) { + if (!isset($json->{'require'.$ext})) { + continue; + } foreach ($json->{'require'.$ext} as $pkg => $_) { $packages = 'packages'.$ext;