#!/usr/local/bin/php * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * PHP version 5 * * @author Martin Schütte * @copyright 2010 Martin Schütte * @license BSD License (2 Clause) * @version 1.0 */ /** * Extracts values from XML data. * * Takes output from SimpleXML and returns two arrays: * one for classes and one for methods. * Ignores classes without a package, i.e. the unit tests. * * @param SimpleXMLElement $xml The XML Object from SimpleXML * * @return array */ function read_data($xml) { $class_list = array(); $method_list = array(); // iterate packages foreach ($xml->package as $pkg) { // skip file summaries $attr = $pkg->attributes(); $pkg_name = $attr["name"]; // skip classes without a package if ($pkg_name == "+global") continue; // iterate classes foreach ($pkg->class as $class) { $class->addAttribute('package', $pkg_name); $attr = $class->attributes(); $class_name = $attr["name"]; // flatten array $properties = array(); foreach ($attr as $key => $value) { $properties[$key] = strval($value); } $class_list[] = $properties; // iterate methods foreach ($class->method as $method) { $method->addAttribute('package', $pkg_name); $method->addAttribute('class', $class_name); $attr = $method->attributes(); // flatten array $properties = array(); foreach ($attr as $key => $value) { $properties[$key] = strval($value); } $method_list[] = $properties; } } } return array($class_list, $method_list); } /** * Comparison functions to sort class/method list by name */ function cmp_name($a, $b) { return strcmp($a["name"], $b["name"]); } /** * Comparison functions to sort method list by class */ function cmp_class($a, $b) { return strcmp($a["class"], $b["class"]); } /** * Comparison functions to sort class list by WMC */ function cmp_wmc($a, $b) { return intval($b["wmc"]) - intval($a["wmc"]); } /** * Comparison functions to sort method list by cyclomatic complexity */ function cmp_ccn($a, $b) { return intval($b["ccn"]) - intval($a["ccn"]); } /** * Comparison functions to sort method list by NPath */ function cmp_npath($a, $b) { return intval($b["npath"]) - intval($a["npath"]); } /** * Print text table with summary for every class. * * @param array $class_list Array with per-class data. */ function print_summary_classes(array $class_list) { uasort($class_list, 'cmp_wmc'); printf( "\n%-20s %-35s %6s %8s %9s %7s %10s %5s\n". "------- ----- ". "--- -------- --------- ------- ---------- ---\n", "Package", "Class", "LoC", "%Comment", "Variables", "Methods", "Class_SiZe", "WMC" ); foreach ($class_list as $class) { printf( "%-20s %-35s %6d % 8.1f %9d %7d %10d %5d\n", $class["package"], $class["name"], $class["loc"], 100*$class["cloc"]/$class["loc"], $class["vars"], $class["nom"], $class["csz"], $class["wmc"] ); } printf("\n"); } /** * Print text table with summary for every method. * * @param array $method_list Array with per-method data. */ function print_summary_methods(array $method_list) { //uasort($method_list, 'cmp_class'); //uasort($method_list, 'cmp_name'); uasort($method_list, 'cmp_npath'); uasort($method_list, 'cmp_ccn'); printf( "\n%-25s %-35s %8s %8s %6s %8s\n". "------------- ------ ". " --- -------- --- -----\n", "Package/Class", "Method", "LoC", "%Comment", "CCN", "NPath" ); foreach ($method_list as $method) { printf( "%-25s %-35s %8d % 8.1f %6d %8d\n", $method["package"].'/'.$method["class"], $method["name"], $method["loc"], 100*$method["cloc"]/$method["loc"], $method["ccn"], $method["npath"] ); } printf("\n"); } /** * Wrapper to call pdepdend, get summary, and read xml. * * @param string $cmd_arguments argument passed to pdepend * * @return SimpleXMLElement */ function call_pdepend($cmd_arguments) { $temp_file = tempnam(sys_get_temp_dir(), 'pdepend-summary.xml.'); $output = system( "pdepend --summary-xml=$temp_file $cmd_arguments", $retval ); if ($retval) { print "pdepend returned an error. Output is: ".$output; exit(1); } $xml = simplexml_load_file($temp_file); unlink($temp_file); return $xml; } /** * Wrapper to open existing summary xml file. * * @param string $filename XML file to read. * * @return SimpleXMLElement */ function open_summary_file($filename) { return simplexml_load_file($filename); } /** * Auxillary function to check end of string. * * @param string $str Haystack. * @param string $sub Needle. * * @return bool */ function str_endswith($str, $sub) { return (substr($str, strlen($str) - strlen($sub)) === $sub); } if (count($argv) == 2 && ($argv[1] == "-h" || $argv[1] == "--help") ) { print <<<'EOD' There are two ways to use this tool: 1. pdepend_summary.php Given an .xml file as argument, the file is read as pdepend's summary format. 2. pdepend_summary.php [options] All other arguments are passed to call pdepend. EOD; return 0; } if (count($argv) == 2 && str_endswith($argv[1], ".xml") ) { $xml = open_summary_file($argv[1]); } else { $cmd_arguments = join(" ", array_slice($argv, 1)); $xml = call_pdepend($cmd_arguments); } list($class_list, $method_list) = read_data($xml); print_summary_classes($class_list); print_summary_methods($method_list); return 0;