1<?php 2// This file is part of Moodle - http://moodle.org/ 3// 4// Moodle is free software: you can redistribute it and/or modify 5// it under the terms of the GNU General Public License as published by 6// the Free Software Foundation, either version 3 of the License, or 7// (at your option) any later version. 8// 9// Moodle is distributed in the hope that it will be useful, 10// but WITHOUT ANY WARRANTY; without even the implied warranty of 11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12// GNU General Public License for more details. 13// 14// You should have received a copy of the GNU General Public License 15// along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17/** 18 * Check that, as in the coding guidelines, every to-do comment links to a tracker issue. 19 * 20 * As required by http://docs.moodle.org/dev/Coding_style. 21 * 22 * @package core 23 * @copyright 2009 Tim Hunt 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 27require(__DIR__ . '/../../../config.php'); 28 29require_login(); 30$context = context_system::instance(); 31require_capability('moodle/site:config', $context); 32 33$PAGE->set_url('/lib/tests/other/todochecker.php'); 34$PAGE->set_context($context); 35$PAGE->set_title('To-do checker'); 36$PAGE->set_heading('To-do checker'); 37 38$thirdparty = load_third_party_lib_list(); 39$extensionstotest = array('php'); 40$extensionsregex = '/\.(?:' . implode('|', $extensionstotest) . ')$/'; 41$patterntofind = 'TO' . 'DO'; // Make it not match the regex. 42$found = array(); 43 44echo $OUTPUT->header(); 45echo $OUTPUT->heading('To-do checker', 2); 46 47echo $OUTPUT->box_start(); 48echo 'Checking code ...'; 49flush(); 50recurseFolders($CFG->dirroot, 'check_to_dos', $extensionsregex, false, array_keys($thirdparty)); 51echo ' done.'; 52echo $OUTPUT->box_end(); 53 54if (empty($found)) { 55 echo '<p>No to-dos found.</p>'; 56} else { 57 $total = 0; 58 foreach ($found as $filepath => $matches) { 59 $total += count($matches); 60 } 61 62 echo '<p>' . $total . ' to-dos found:</p><dl>'; 63 foreach ($found as $filepath => $matches) { 64 echo '<dt>' . $filepath . ' <b>(' . count($matches) . ')</b></dt><dd><ul>'; 65 foreach ($matches as $lineno => $line) { 66 $url = 'http://cvs.moodle.org/moodle/' . $filepath . '?view=annotate#l' . $lineno; 67 $error = ''; 68 69 // Make sure there is a tracker issue id mentioned 70 $matches = array(); 71 if (preg_match('/\bTODO\b.*?\b(MDL-\d+)/', $line, $matches)) { 72 $issueid = $matches[1]; 73 $issueurl = 'http://tracker.moodle.org/browse/' . $issueid; 74 75 // Make sure the issue is still open. 76 list($issueopen, $issuesummary) = issue_info($issueid); 77 if ($issueopen) { 78 $issuename = $issueid; 79 } else { 80 $issuename = '<strike>' . $issueid . '</strike>'; 81 $error = 'The associated tracker issue is Resolved.'; 82 } 83 84 $line = str_replace($issueid, '<a href="' . $issueurl . '" title="' . s($issuesummary) . 85 '">' . $issuename . '</a>', htmlspecialchars($line)); 86 } else { 87 $line = htmlspecialchars($line); 88 $error = 'No associated tracker issue.'; 89 } 90 91 if ($error) { 92 $error = '<span class="error">' . $error . '</span>'; 93 } 94 echo '<li><a href="' . $url . '">' . $lineno . '</a>: ' . $line . $error . '</li>'; 95 } 96 echo '</ul></dd>'; 97 } 98 echo '</dl>'; 99} 100 101echo $OUTPUT->footer(); 102 103function check_to_dos($filepath) { 104 global $CFG, $found, $thirdparty; 105 if (isset($thirdparty[$filepath])) { 106 return; // Skip this file. 107 } 108 $lines = file($filepath); 109 $matchesinfile = array(); 110 foreach ($lines as $lineno => $line) { 111 if (preg_match('/(?<!->|\$)\bTODO\b/i', $line)) { 112 $matchesinfile[$lineno] = $line; 113 } 114 } 115 if (!empty($matchesinfile)) { 116 $shortpath = str_replace($CFG->dirroot . '/', '', $filepath); 117 $found[$shortpath] = $matchesinfile; 118 } 119} 120 121function issue_info($issueid) { 122 static $cache = array(); 123 if (array_key_exists($issueid, $cache)) { 124 return $cache[$issueid]; 125 } 126 127 $xmlurl = 'http://tracker.moodle.org/si/jira.issueviews:issue-xml/' . $issueid . '/' . $issueid . '.xml'; 128 $content = download_file_content($xmlurl); 129 130 // Get the status. 131 $open = preg_match('/Unresolved<\/resolution>/', $content); 132 133 // Get the summary. 134 $matches = array(); 135 preg_match('/<title>\[' . $issueid . '\]\s+(.*?)<\/title>/', $content, $matches); 136 $summary = $matches[1]; 137 preg_match('/<assignee[^>]*>(.*?)<\/assignee>/', $content, $matches); 138 $summary .= ' - Assignee: ' . $matches[1]; 139 140 $cache[$issueid] = array($open, $summary); 141 return $cache[$issueid]; 142} 143 144function load_third_party_lib_list() { 145 global $CFG; 146 $libs = array(); 147 $xml = simplexml_load_file($CFG->libdir . '/thirdpartylibs.xml'); 148 foreach ($xml->library as $libobject) { 149 $libs[$CFG->libdir . '/' . $libobject->location] = 1; 150 } 151 return $libs; 152} 153 154function recurseFolders($path, $callback, $fileregexp = '/.*/', $exclude = false, $ignorefolders = array()) { 155 $files = scandir($path); 156 157 foreach ($files as $file) { 158 $filepath = $path .'/'. $file; 159 if (strpos($file, '.') === 0) { 160 /// Don't check hidden files. 161 continue; 162 } else if (is_dir($filepath)) { 163 if (!in_array($filepath, $ignorefolders)) { 164 recurseFolders($filepath, $callback, $fileregexp, $exclude, $ignorefolders); 165 } 166 } else if ($exclude xor preg_match($fileregexp, $filepath)) { 167 call_user_func($callback, $filepath); 168 } 169 } 170} 171