Text output is now tab delimited, one fault per line. Added an html output module. Mantis: 2691
git-svn-id: file:///srv/svn/scanner/trunk@5 a0501263-5b7a-4423-a8ba-1edf086583e7
This commit is contained in:
parent
d0714c149b
commit
2386113895
7 changed files with 210 additions and 33 deletions
109
modules/output_html.php
Normal file
109
modules/output_html.php
Normal file
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
class HTMLOutput extends OutputModule {
|
||||
function write( $filename ) {
|
||||
global $faults, $files;
|
||||
$output = fopen( $filename, 'w' );
|
||||
if( $output === false ) {
|
||||
err( "Cannot write to $filename\n" );
|
||||
return false;
|
||||
}
|
||||
fwrite( $output,
|
||||
'<html>
|
||||
<head>
|
||||
<title>Code Scanner Output</title>
|
||||
<style type="text/css">
|
||||
.fault {
|
||||
padding: 5px;
|
||||
margin-bottom: 5px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
}
|
||||
.fault.level_0 {
|
||||
color: #3f1c00;
|
||||
background-color: #cf5c00;
|
||||
border-color: #8f4000;
|
||||
}
|
||||
.fault.level_1 {
|
||||
color: #3f0000;
|
||||
background-color: #cf0000;
|
||||
border-color: #8f0000;
|
||||
}
|
||||
.fault.level_2 {
|
||||
color: #eee;
|
||||
background-color: #333;
|
||||
border-color: #999;
|
||||
}
|
||||
.fault dt {
|
||||
cursor: pointer;
|
||||
}
|
||||
.fault code {
|
||||
color: #000;
|
||||
display: block;
|
||||
margin-left: 10px;
|
||||
border: 1px dashed #999;
|
||||
background-color: #eee;
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
function toggleDisplay( id ) {
|
||||
var e = document.getElementById( "info_" + id );
|
||||
if( e.style.display == "none" ) {
|
||||
e.style.display = "block";
|
||||
} else {
|
||||
e.style.display = "none";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Code Scanner Output</h1>
|
||||
<h2>Summary</h2>
|
||||
<p>Found ' . count( $faults ) . ' faults in ' . count( $files ) . ' files</p>
|
||||
<h2>Faults by file</h2>
|
||||
<dl>'
|
||||
);
|
||||
$current_file = '';
|
||||
foreach( $faults as $id => $fault ) {
|
||||
$svn = serialize( $fault['svn'] );
|
||||
if( $current_file != $fault['object']['file'] ) {
|
||||
if( $current_file != '' ) {
|
||||
fwrite( $output, '</ul></dd>' );
|
||||
}
|
||||
$current_file = $fault['object']['file'];
|
||||
fwrite( $output, "<dt>$current_file</dt><dd><ul>" );
|
||||
}
|
||||
fprintf( $output,
|
||||
'<li>
|
||||
<dl class="fault level_%s">
|
||||
<dt onclick="toggleDisplay( ' . $id . ')"><strong>%s:</strong> <span class="reason">%s</span></dt>
|
||||
<dd id="info_' . $id . '" style="display: none;">
|
||||
<strong>Line:</strong> <span class="line">%d</span><br />
|
||||
<strong>Author:</strong> <span class="author">%s</span><br />
|
||||
<strong>Revision:</strong> <span class="revision">%s</span><br />
|
||||
<strong>Code:</strong>
|
||||
<code>%s</code>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>',
|
||||
|
||||
$fault['level'],
|
||||
$fault['module'],
|
||||
$fault['reason'],
|
||||
$fault['object']['line'],
|
||||
isset( $fault['svn']['author'] ) ? $fault['svn']['author'] : 'Unknown',
|
||||
isset( $fault['svn']['revision'] ) ? $fault['svn']['revision'] : 'Unknown',
|
||||
$fault['object']['context']
|
||||
);
|
||||
}
|
||||
fwrite( $output,
|
||||
' </dl>
|
||||
</body>
|
||||
</html>' . "\n"
|
||||
);
|
||||
fclose( $output );
|
||||
}
|
||||
}
|
||||
|
||||
addModule( new HTMLOutput() );
|
||||
?>
|
27
modules/output_text.php
Normal file
27
modules/output_text.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
class TextOutput extends OutputModule {
|
||||
function write( $filename ) {
|
||||
global $faults;
|
||||
$output = fopen( $filename, 'w' );
|
||||
if( $output === false ) {
|
||||
err( "Cannot write to $filename\n" );
|
||||
return false;
|
||||
}
|
||||
foreach( $faults as $fault ) {
|
||||
$svn = serialize( $fault['svn'] );
|
||||
fprintf( $output, "%s\t%d\t%s\t%d\t%s\t%d\t%s\n",
|
||||
$fault['module'],
|
||||
$fault['level'],
|
||||
$fault['object']['file'],
|
||||
$fault['object']['line'],
|
||||
isset( $fault['svn']['author'] ) ? $fault['svn']['author'] : '?',
|
||||
isset( $fault['svn']['revision'] ) ? $fault['svn']['revision'] : '0',
|
||||
$fault['reason']
|
||||
);
|
||||
}
|
||||
fclose( $output );
|
||||
}
|
||||
}
|
||||
|
||||
addModule( new TextOutput() );
|
||||
?>
|
|
@ -143,5 +143,5 @@ class FunctionsModule extends ScannerModule {
|
|||
}
|
||||
}
|
||||
|
||||
$modules[] = $FunctionsModule_instance;
|
||||
addModule( $FunctionsModule_instance );
|
||||
?>
|
|
@ -8,13 +8,15 @@ class LintModule extends ScannerModule {
|
|||
$output = array();
|
||||
exec( "php -l '$filename' 2>/dev/null", $output, $result );
|
||||
if( $result != 0 ) {
|
||||
$file = file( $filename );
|
||||
foreach( $output as $linterror ) {
|
||||
$matches = array();
|
||||
if( preg_match( '/error:.*?on line (\d+)$/i', $linterror, $matches ) == 0 ) { continue; }
|
||||
$this->fault(
|
||||
array(
|
||||
'file' => $filename,
|
||||
'line' => $matches[1]
|
||||
'line' => $matches[1],
|
||||
'context' => $file[$matches[1] - 1]
|
||||
),
|
||||
FAULT_MAJOR,
|
||||
$linterror
|
||||
|
@ -24,5 +26,5 @@ class LintModule extends ScannerModule {
|
|||
}
|
||||
}
|
||||
|
||||
$modules[] = new LintModule();
|
||||
addModule( new LintModule() );
|
||||
?>
|
|
@ -41,5 +41,5 @@ class PatternModule extends ScannerModule {
|
|||
}
|
||||
}
|
||||
|
||||
$modules[] = new PatternModule();
|
||||
addModule( new PatternModule() );
|
||||
?>
|
|
@ -75,7 +75,7 @@ class PHPParser {
|
|||
|
||||
function parse( $content ) {
|
||||
$tokens = token_get_all( $content );
|
||||
|
||||
$lines = preg_split( '/\r?(\n|\r)/', $content );
|
||||
$line = 1;
|
||||
$depth = 0;
|
||||
$block = 0;
|
||||
|
@ -144,6 +144,7 @@ class PHPParser {
|
|||
'type' => PHPPARSER_FUNCTION_CALL,
|
||||
'name' => strtolower( $string ),
|
||||
'file' => $this->file_name,
|
||||
'context' => $lines[$line],
|
||||
'line' => $line,
|
||||
'block' => $block,
|
||||
'depth' => $depth,
|
||||
|
@ -160,6 +161,7 @@ class PHPParser {
|
|||
'type' => PHPPARSER_EXPRESSION,
|
||||
'name' => trim( $expression ),
|
||||
'file' => $this->file_name,
|
||||
'context' => $lines[$line],
|
||||
'line' => $line,
|
||||
'block' => $block,
|
||||
'depth' => $depth,
|
||||
|
@ -188,6 +190,7 @@ class PHPParser {
|
|||
'type' => PHPPARSER_CLASS_DEF,
|
||||
'name' => strtolower( $string ),
|
||||
'file' => $this->file_name,
|
||||
'context' => $lines[$line],
|
||||
'line' => $line,
|
||||
'block' => $block,
|
||||
'depth' => $depth,
|
||||
|
@ -203,6 +206,7 @@ class PHPParser {
|
|||
'type' => PHPPARSER_FUNCTION_DEF,
|
||||
'name' => strtolower( $string ),
|
||||
'file' => $this->file_name,
|
||||
'context' => $lines[$line],
|
||||
'line' => $line,
|
||||
'block' => $block,
|
||||
'depth' => $depth,
|
||||
|
@ -225,6 +229,7 @@ class PHPParser {
|
|||
'type' => PHPPARSER_INCLUDE,
|
||||
'name' => trim( str_replace( '\'', '', $text ) ),
|
||||
'file' => $this->file_name,
|
||||
'context' => $lines[$line],
|
||||
'line' => $line,
|
||||
'block' => $block,
|
||||
'depth' => $depth,
|
||||
|
@ -275,6 +280,7 @@ class PHPParser {
|
|||
'type' => PHPPARSER_LANGUAGE_CONSTRUCT,
|
||||
'name' => $text,
|
||||
'file' => $this->file_name,
|
||||
'context' => $lines[$line],
|
||||
'line' => $line,
|
||||
'block' => $block,
|
||||
'depth' => $depth,
|
||||
|
|
89
scanner.php
89
scanner.php
|
@ -5,19 +5,27 @@ define( 'FAULT_MINOR', 0 );
|
|||
define( 'FAULT_MEDIUM', 1 );
|
||||
define( 'FAULT_MAJOR', 2 );
|
||||
|
||||
$modules = array();
|
||||
$modules = array(
|
||||
'scanner' => array(),
|
||||
'output' => new OutputModule()
|
||||
);
|
||||
$stderr = fopen( 'php://stderr', 'w' );
|
||||
$config = array(
|
||||
'svn' => false,
|
||||
'modules' => array(),
|
||||
'output_format' => 'text',
|
||||
'output_file' => 'php://stdout',
|
||||
'quiet' => false,
|
||||
);
|
||||
$help = "Usage: {$argv[0]} [options] file|path [file|path ...]
|
||||
Options:
|
||||
-b Set the base path for the scan. Useful if you want
|
||||
--base-path to scan individual files in a code base that don't
|
||||
-b path Set the base path for the scan. Useful if you want
|
||||
--base-path path to scan individual files in a code base that don't
|
||||
live in the project's base directory.
|
||||
|
||||
-f format Select the output format. Defaults to text.
|
||||
--format format
|
||||
|
||||
-h Display this usage information
|
||||
--help
|
||||
|
||||
|
@ -25,11 +33,15 @@ Options:
|
|||
--module modulename parameter is not specified, all available modules
|
||||
will be loaded.
|
||||
|
||||
-o filename Write output to a file instead of stdout
|
||||
--output filename
|
||||
|
||||
-q Suppresses all progress output
|
||||
--quiet
|
||||
|
||||
--svn Enables SVN integration
|
||||
";
|
||||
$faults = array();
|
||||
|
||||
class ScannerModule {
|
||||
var $faults;
|
||||
|
@ -41,9 +53,10 @@ class ScannerModule {
|
|||
err( "Initializing " . get_class( $this ) . "...\n" );
|
||||
}
|
||||
function fault( $object, $level, $reason = '' ) {
|
||||
global $config;
|
||||
global $config, $faults;
|
||||
$object['file'] = filename( $object['file'] );
|
||||
$this->faults[] = array(
|
||||
$faults[] = $this->faults[] = array(
|
||||
'module' => get_class( $this ),
|
||||
'object' => $object,
|
||||
'level' => $level,
|
||||
'reason' => $reason,
|
||||
|
@ -74,12 +87,28 @@ class ScannerModule {
|
|||
}
|
||||
}
|
||||
|
||||
class OutputModule {
|
||||
function display() {
|
||||
$this->write( 'php://output' );
|
||||
}
|
||||
function write( $filename ) {
|
||||
}
|
||||
}
|
||||
|
||||
function _callback( $object ) {
|
||||
global $modules;
|
||||
foreach( $modules as $module ) {
|
||||
foreach( $modules['scanner'] as $module ) {
|
||||
$module->parserCallback( $object );
|
||||
}
|
||||
}
|
||||
function addModule( $module_instance ) {
|
||||
global $modules;
|
||||
if( $module_instance instanceof ScannerModule ) {
|
||||
$modules['scanner'][] = $module_instance;
|
||||
} elseif( $module_instance instanceof OutputModule ) {
|
||||
$modules['output'] = $module_instance;
|
||||
}
|
||||
}
|
||||
function filename( $filename ) {
|
||||
global $base_path;
|
||||
$filename = realpath( $filename );
|
||||
|
@ -108,6 +137,10 @@ for( $i = 1; $i < $argc; $i++ ) {
|
|||
$base_path = realpath( $new_base ) . '/';
|
||||
}
|
||||
break;
|
||||
case '-f':
|
||||
case '--format':
|
||||
$config['output_format'] = $argv[++$i];
|
||||
break;
|
||||
case '-h':
|
||||
case '--help':
|
||||
die( $help );
|
||||
|
@ -116,6 +149,10 @@ for( $i = 1; $i < $argc; $i++ ) {
|
|||
case '--module':
|
||||
$config['modules'][] = $argv[++$i];
|
||||
break;
|
||||
case '-o':
|
||||
case '--output':
|
||||
$config['output_file'] = $argv[++$i];
|
||||
break;
|
||||
case '-q':
|
||||
case '--quiet':
|
||||
$config['quiet'] = true;
|
||||
|
@ -144,11 +181,21 @@ $module_files = scandir( 'modules' );
|
|||
foreach( $module_files as $module_file ) {
|
||||
if( strtolower( substr( $module_file, -4 ) ) == '.php' ) {
|
||||
$module = substr( $module_file, 0, strlen( $module_file ) - 4 );
|
||||
if(
|
||||
count( $config['modules'] ) == 0
|
||||
|| ( in_array( $module, $config['modules'] ) )
|
||||
) {
|
||||
require_once( "modules/{$module_file}" );
|
||||
list( $type, $module ) = split( '_', $module );
|
||||
switch( $type ) {
|
||||
case 'output':
|
||||
if( $module == $config['output_format'] ) {
|
||||
require_once( "modules/{$module_file}" );
|
||||
}
|
||||
break;
|
||||
case 'scanner':
|
||||
if(
|
||||
count( $config['modules'] ) == 0
|
||||
|| in_array( $module, $config['modules'] )
|
||||
) {
|
||||
require_once( "modules/{$module_file}" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,24 +215,10 @@ foreach( $files as $file ) {
|
|||
$lastpct = $pct;
|
||||
}
|
||||
}
|
||||
foreach( $modules as $module ) { $module->preScan( $file ); }
|
||||
foreach( $modules['scanner'] as $module ) { $module->preScan( $file ); }
|
||||
$parser->parseFile( $file );
|
||||
}
|
||||
err( "\n" );
|
||||
|
||||
foreach( $modules as $module ) {
|
||||
foreach( $module->faults as $fault ) {
|
||||
$svn = serialize( $fault['svn'] );
|
||||
printf( "%s %s - %s\n -- %s:%d, %s r%d\n",
|
||||
get_class( $module ),
|
||||
$fault['level'],
|
||||
$fault['reason'],
|
||||
$fault['object']['file'],
|
||||
$fault['object']['line'],
|
||||
isset( $fault['svn']['author'] ) ? $fault['svn']['author'] : '?',
|
||||
isset( $fault['svn']['revision'] ) ? $fault['svn']['revision'] : '?'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$modules['output']->write( $config['output_file'] );
|
||||
err( sprintf( "Found %d faults in %d files.\n", count( $faults ), count( $files ) ) );
|
||||
?>
|
||||
|
|
Loading…
Reference in a new issue