#!/usr/bin/env php . // Copyright © 2007-2014 Erwan Briand // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, version 3 only. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public // License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . set_time_limit(0); // This script *NEEDS* cloc (http://cloc.sourceforge.net) ob_start(); passthru('which cloc'); $return = ob_get_clean(); if (empty($return)) { echo "cloc was not found in the path, aborting!\n"; exit(1); } // Find were we are $base = dirname(__FILE__); $whereis = '/scripts/miscellaneous'; $length = -mb_strlen($whereis); if (mb_substr($base, $length, mb_strlen($base)) == $whereis) { // Set the CodingTeam basedir $basedir = mb_substr($base, 0, $length); define('CT_BASEDIR', $basedir); require($basedir.'/inc/globalFunctions.php'); // Check if the configuration file exist if (!file_exists($basedir.'/inc/codingteam.cfg')) die ('There are no configuration file. CodingTeam cannot start.'); // Check if the configuration file is well formed $xml = new DomDocument(); $xml->load($basedir.'/inc/codingteam.cfg'); if (!$xml->schemaValidate($basedir.'/inc/codingteam-conf.xsd')) exit('CODE-STATS JOB FAILED'); // Import configuration $xml = simplexml_load_file($basedir.'/inc/codingteam.cfg'); $db_type = $xml->db->type; $db_hostname = $xml->db->hostname; $db_database = $xml->db->database; $db_username = $xml->db->username; $db_password = $xml->db->password; // Define constants for SCMs define('CT_SVN_SUBDOMAIN', $xml->svn->subdomain); define('CT_SVN_LOCATION', $xml->svn->location); define('CT_HG_SUBDOMAIN', $xml->hg->subdomain); define('CT_HG_LOCATION', $xml->hg->location); define('CT_GIT_SUBDOMAIN', $xml->git->subdomain); define('CT_GIT_LOCATION', $xml->git->location); // Global statistics $global_statistics = array('delayed' => 0, 'ignored' => 0, 'failures' => 0, 'successes' => 0); // Require data $cloc_to_ct_languages = array('ABAP' => 'abap', 'ActionScript' => 'actionscript', 'Ada' => 'ada', 'ASP' => 'asp', 'ASP.Net' => 'asp', 'Assembly' => 'asm', 'Bourne Again Shell' => 'bash', 'C' => 'c', 'C Shell' => 'c', 'C#' => 'csharp', 'C++' => 'cpp', 'C/C++ Header' => 'c', 'COBOL' => 'cobol', 'ColdFusion' => 'cfm', 'CSS' => 'css', 'D' => 'd', 'DOS Batch' => 'dos', 'Fortran 77' => 'fortran', 'Fortran 90' => 'fortran', 'Fortran 95' => 'fortran', 'Groovy' => 'groovy', 'Haskell' => 'haskell', 'HTML' => 'html4strict', 'IDL' => 'idl', 'Java' => 'java', 'Javascript' => 'javascript', 'Lisp' => 'lisp', 'Lua' => 'lua', 'MATLAB' => 'matlab', 'Objective C' => 'objc', 'Oracle Forms' => 'oracle8', 'Oracle Reports' => 'oracle8', 'Pascal' => 'pascal', 'Perl' => 'perl', 'PHP' => 'php', 'Python' => 'python', 'Ruby' => 'ruby', 'Ruby HTML' => 'ruby', 'Scala' => 'scala', 'SQL' => 'sql', 'Tcl/Tk' => 'tcl', 'Visual Basic' => 'vb', 'XML' => 'xml'); // Database connection require($basedir.'/inc/classes/db.php'); $ct_db = new Database($db_type, $db_hostname, $db_database, $db_username, $db_password); $req = $ct_db->select('projects', ''); foreach ($req as $prj) { // Project identifier $prj_class = getClass('projects.projects', $ct_db); $prj_obj = $prj_class->load($prj['id']); if ($prj_obj) $prj_id = $prj_class->getId(); else exit('SCRIPT FAILED'); // Get project's dbname $dbname = htmlspecialchars($prj_class->getDbname()); $scm = $prj_class->getSCM(); echo 'Creating stats for '.$dbname.'…'; // Do we really need to do the job? $datafile = $basedir.'/public/codestats/reports/'.$dbname; if (is_file($datafile)) { // Get the latest commit $commits_cl = getClass('projects.commits', $ct_db); $latest = $commits_cl->getLatests($prj['id'], 1); if (count($latest) == 1) $new_latest_commit = $latest[0]['id']; // Get the latest stored commit $content = unserialize(file_get_contents($datafile)); if (array_key_exists('last_commit_id', $content)) $last_commit_id = $content['last_commit_id']; // Compare these values if (isset($new_latest_commit) && isset($last_commit_id)) { if ($new_latest_commit == $last_commit_id) { echo " nothing new over there.\n"; $global_statistics['delayed'] += 1; continue; } } } // Get the sources if ($scm == 'subversion' && is_dir($basedir.'/public/svn/'.$dbname)) { if (!is_dir($basedir.'/public/codestats/temp/'.$dbname)) $command = 'svn co '.CT_SVN_SUBDOMAIN.CT_SVN_LOCATION.$dbname; else $command = 'svn up'; exec('cd '.$basedir.'/public/codestats/temp && '.$command); } elseif ($scm == 'mercurial' && is_dir($basedir.'/public/hg/'.$dbname)) { if (!is_dir($basedir.'/public/codestats/temp/'.$dbname)) $command = 'hg clone '.CT_HG_SUBDOMAIN.CT_HG_LOCATION.$dbname; else $command = 'hg pull'; exec('cd '.$basedir.'/public/codestats/temp && '.$command); } elseif ($scm == 'git' && is_dir($basedir.'/public/git/'.$dbname)) { if (!is_dir($basedir.'/public/codestats/temp/'.$dbname)) $command = 'git clone '.CT_GIT_SUBDOMAIN.CT_GIT_LOCATION.$dbname; else $command = 'git pull'; exec('cd '.$basedir.'/public/codestats/temp && '.$command); } $stats = array('total' => array('files' => 0, 'lines' => 0, 'lines_code' => 0, 'lines_comment' => 0, 'comment_ratio' => 0)); $tempfile = $basedir.'/public/codestats/temp/'.$dbname; if (!is_dir($tempfile)) { echo " no repository.\n"; $global_statistics['ignored'] += 1; continue; } // If SCM is Subversion, try to select the trunk if ($scm == 'subversion') { $n = $tempfile .= '/trunk'; if (is_dir($n)) $tempfile = $n; } ob_start(); passthru('cloc --quiet --xml '.$tempfile.' 2>/dev/null'); $return = ob_get_clean(); $cleaning = explode("\n", $return); array_shift($cleaning); $clean_return = implode("\n", $cleaning); if (empty($clean_return)) { echo " cloc returned nothing.\n"; $global_statistics['failures'] += 1; continue; } $xml = simplexml_load_string($clean_return); $stats['languages'] = array(); foreach ($xml->languages->language as $language) { $attr = $language->attributes(); $name = (string)$attr['name']; if (array_key_exists($name, $cloc_to_ct_languages)) { $ct_name = $cloc_to_ct_languages[$name]; array_push($stats['languages'], array('name' => $ct_name, 'files' => (int)$attr['files_count'], 'lines_code' => (int)$attr['code'], 'lines_comment' => (int)$attr['comment'], 'percentage' => array())); $stats['total']['files'] += (int)$attr['files_count']; $stats['total']['lines'] += ((int)$attr['code'] + (int)$attr['comment']); $stats['total']['lines_code'] += (int)$attr['code']; $stats['total']['lines_comment'] += (int)$attr['comment']; } } foreach ($stats['languages'] as &$lang) { if ($stats['total']['files'] > 0) $p_files = $lang['files'] / $stats['total']['files'] * 100; else $p_files = 0; if ($stats['total']['lines'] > 0) $p_lines = ($lang['lines_code'] + $lang['lines_comment']) / $stats['total']['lines'] * 100; else $p_lines = 0; if ($stats['total']['lines_code'] > 0) $p_lines_code = $lang['lines_code'] / $stats['total']['lines_code'] * 100; else $p_lines_code = 0; if ($stats['total']['lines_comment'] > 0) $p_lines_comment = $lang['lines_comment'] / $stats['total']['lines_comment'] * 100; else $p_lines_comment = 0; $lang['percentage']['files'] = round($p_files, 2); $lang['percentage']['lines'] = round($p_lines, 2); $lang['percentage']['lines_code'] = round($p_lines_code, 2); $lang['percentage']['lines_comment'] = round($p_lines_comment, 2); } $p_ratio = $stats['total']['lines_comment'] / $stats['total']['lines'] * 100; $stats['total']['comment_ratio'] = round($p_ratio, 2); if (isset($new_latest_commit)) $stats['last_commit_id'] = $new_latest_commit; $stats_serialized = serialize($stats); file_put_contents($basedir.'/public/codestats/reports/'.$dbname, $stats_serialized); $prj_class->unload(); deleteCacheVersion('/project/'.$dbname.'/statistics', TRUE); exec('rm -rf '.$basedir.'/public/codestats/temp/'.$dbname); echo " ok.\n"; $global_statistics['successes'] += 1; } echo "\n\n"; echo 'Ok, job ended.'."\n"; echo 'delayed: '.$global_statistics['delayed']."\n"; echo 'ignored: '.$global_statistics['ignored']."\n"; echo 'failures: '.$global_statistics['failures']."\n"; echo 'successes: '.$global_statistics['successes']."\n"; } ?>