diff --git a/composer-lock-diff b/composer-lock-diff index 2d4a213..74817d7 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) { @@ -47,12 +56,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,12 +70,27 @@ 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'); + } } } 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)) { @@ -101,7 +125,7 @@ function tableize($header, $data, $opts = array()) { $widths = array(maxLength(array_merge(array($header), array_keys($data)))); - $count = count(reset($data)); + $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)))); } @@ -114,7 +138,7 @@ function tableize($header, $data, $opts = array()) { $lines[] = separatorLine($widths, $opts['joint']); foreach($data as $key => $v) { - $lines[] = tabelizeLine(array_merge(array($key), $v), $widths); + $lines[] = tabelizeLine(array_merge(array($key), array_slice($v, 0, $count)), $widths); } if ($opts['capped']) { @@ -132,6 +156,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 +246,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"); } - 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($data, false); } function isUrl($string) { @@ -231,6 +277,29 @@ function mustDecodeJson($json, $context) { return $data; } +function markDirectDependencies($lock, $json) { + foreach (array('', '-dev') as $ext) { + if (!isset($json->{'require'.$ext})) { + continue; + } + 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]); @@ -487,4 +556,3 @@ EOF; exit(0); } # vim: ff=unix ts=4 ss=4 sr et -