Updated SVN revision support to pull file contents from SVN before scanning to ensure the correct changes are being scanned Mantis: 2691
git-svn-id: file:///srv/svn/scanner/trunk@7 a0501263-5b7a-4423-a8ba-1edf086583e7
This commit is contained in:
parent
af5fc8a017
commit
fc258c4230
3 changed files with 79 additions and 34 deletions
|
@ -1,18 +1,19 @@
|
||||||
<?php
|
<?php
|
||||||
$FunctionsModule_functions = array();
|
$FunctionsModule_functions = array();
|
||||||
$FunctionsModule_local_functions = array();
|
$FunctionsModule_local_functions = array();
|
||||||
|
$FunctionsModule_file = '';
|
||||||
$FunctionsModule_instance = new FunctionsModule();
|
$FunctionsModule_instance = new FunctionsModule();
|
||||||
|
|
||||||
function FunctionsModule_callback_global( $object ) {
|
function FunctionsModule_callback_global( $object ) {
|
||||||
global $FunctionsModule_functions;
|
global $FunctionsModule_functions, $FunctionsModule_file;
|
||||||
$FunctionsModule_functions[$object['name']] = array(
|
$FunctionsModule_functions[$object['name']] = array(
|
||||||
'used' => 0,
|
'used' => 0,
|
||||||
'file' => $object['file']
|
'file' => $FunctionsModule_file
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
function FunctionsModule_callback_local( $object ) {
|
function FunctionsModule_callback_local( $object ) {
|
||||||
global $FunctionsModule_local_functions;
|
global $FunctionsModule_local_functions, $FunctionsModule_file;
|
||||||
$file = filename( $object['file'] );
|
$file = $FunctionsModule_file;
|
||||||
if( !isset( $FunctionsModule_local_functions[$file] ) ) {
|
if( !isset( $FunctionsModule_local_functions[$file] ) ) {
|
||||||
$FunctionsModule_local_functions[$file] = array();
|
$FunctionsModule_local_functions[$file] = array();
|
||||||
}
|
}
|
||||||
|
@ -83,6 +84,9 @@ class FunctionsModule extends ScannerModule {
|
||||||
function parserCallback( $object ) {
|
function parserCallback( $object ) {
|
||||||
global $FunctionsModule_functions;
|
global $FunctionsModule_functions;
|
||||||
global $FunctionsModule_local_functions;
|
global $FunctionsModule_local_functions;
|
||||||
|
global $FunctionsModule_file;
|
||||||
|
|
||||||
|
$FunctionsModule_file = filename( $object['file'] );
|
||||||
switch( $object['type'] ) {
|
switch( $object['type'] ) {
|
||||||
case PHPPARSER_INCLUDE:
|
case PHPPARSER_INCLUDE:
|
||||||
$this->included_files[] = $object;
|
$this->included_files[] = $object;
|
||||||
|
@ -131,14 +135,20 @@ class FunctionsModule extends ScannerModule {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function preScan( $filename ) {
|
function preScan( $file ) {
|
||||||
parent::preScan( $filename );
|
parent::preScan( $file );
|
||||||
global $FunctionsModule_local_functions;
|
global $FunctionsModule_local_functions, $FunctionsModule_file;
|
||||||
|
$FunctionsModule_file = filename( $file['filename'] );
|
||||||
$FunctionsModule_local_functions = array();
|
$FunctionsModule_local_functions = array();
|
||||||
$FunctionsModule_local_functions[filename( $filename)] = array();
|
$FunctionsModule_local_functions[filename( $file['filename'] )] = array();
|
||||||
$parser = new PHPParser( PHPPARSER_FETCH_FUNCTIONS );
|
$parser = new PHPParser( PHPPARSER_FETCH_FUNCTIONS );
|
||||||
$parser->registerCallback( 'FunctionsModule_callback_local' );
|
$parser->registerCallback( 'FunctionsModule_callback_local' );
|
||||||
$parser->parseFile( $filename );
|
if( $file['revision'] > 0 ) {
|
||||||
|
$file_contents = isset( $file['contents'] ) ? $file['contents'] : shell_exec( "svn cat -r {$file['revision']} {$svn_root}{$svn_base}/{$file['filename']} 2>/dev/null" );
|
||||||
|
$parser->parse( $file_contents );
|
||||||
|
} else {
|
||||||
|
$parser->parseFile( $file['filename'] );
|
||||||
|
}
|
||||||
$this->included_files = array();
|
$this->included_files = array();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,20 +3,26 @@ class LintModule extends ScannerModule {
|
||||||
function LintModule() {
|
function LintModule() {
|
||||||
$this->ScannerModule();
|
$this->ScannerModule();
|
||||||
}
|
}
|
||||||
function preScan( $filename ) {
|
function preScan( $file ) {
|
||||||
parent::preScan( $filename );
|
parent::preScan( $file );
|
||||||
$output = array();
|
$output = array();
|
||||||
exec( "php -l '$filename' 2>/dev/null", $output, $result );
|
if( $file['revision'] > 0 ) {
|
||||||
|
global $svn_root, $svn_base;
|
||||||
|
exec( "svn cat -r {$file['revision']} {$svn_root}{$svn_base}/{$file['filename']} 2>/dev/null | php -l 2>/dev/null", $output, $result );
|
||||||
|
$file_contents = isset( $file['contents'] ) ? $file['contents'] : shell_exec( "svn cat -r {$file['revision']} {$svn_root}{$svn_base}/{$file['filename']} 2>/dev/null" );
|
||||||
|
} else {
|
||||||
|
exec( "php -l '{$file['filename']}' 2>/dev/null", $output, $result );
|
||||||
|
$file_contents = file( $file['filename'] );
|
||||||
|
}
|
||||||
if( $result != 0 ) {
|
if( $result != 0 ) {
|
||||||
$file = file( $filename );
|
|
||||||
foreach( $output as $linterror ) {
|
foreach( $output as $linterror ) {
|
||||||
$matches = array();
|
$matches = array();
|
||||||
if( preg_match( '/error:.*?on line (\d+)$/i', $linterror, $matches ) == 0 ) { continue; }
|
if( preg_match( '/error:.*?on line (\d+)$/i', $linterror, $matches ) == 0 ) { continue; }
|
||||||
$this->fault(
|
$this->fault(
|
||||||
array(
|
array(
|
||||||
'file' => $filename,
|
'file' => $file['filename'],
|
||||||
'line' => $matches[1],
|
'line' => $matches[1],
|
||||||
'context' => $file[$matches[1] - 1]
|
'context' => $file_contents[$matches[1] - 1]
|
||||||
),
|
),
|
||||||
FAULT_MAJOR,
|
FAULT_MAJOR,
|
||||||
$linterror
|
$linterror
|
||||||
|
|
67
scanner.php
67
scanner.php
|
@ -52,6 +52,7 @@ $faults = array();
|
||||||
class ScannerModule {
|
class ScannerModule {
|
||||||
var $faults;
|
var $faults;
|
||||||
var $blame;
|
var $blame;
|
||||||
|
var $file;
|
||||||
|
|
||||||
function ScannerModule() {
|
function ScannerModule() {
|
||||||
$this->faults = array();
|
$this->faults = array();
|
||||||
|
@ -60,7 +61,7 @@ class ScannerModule {
|
||||||
}
|
}
|
||||||
function fault( $object, $level, $reason = '' ) {
|
function fault( $object, $level, $reason = '' ) {
|
||||||
global $config, $revisions, $faults;
|
global $config, $revisions, $faults;
|
||||||
if( count( $revisions ) > 0 && !in_array( $this->blame[$object['line']]['revision'], $revisions ) ) {
|
if( $this->file['revision'] > 0 && $this->blame[$object['line']]['revision'] != $this->file['revision'] ) {
|
||||||
/* If files have been added using SVN revisions, filter out any faulty
|
/* If files have been added using SVN revisions, filter out any faulty
|
||||||
changes that aren't a part of the requested changeset(s).
|
changes that aren't a part of the requested changeset(s).
|
||||||
*/
|
*/
|
||||||
|
@ -70,19 +71,26 @@ class ScannerModule {
|
||||||
$faults[] = $this->faults[] = array(
|
$faults[] = $this->faults[] = array(
|
||||||
'module' => get_class( $this ),
|
'module' => get_class( $this ),
|
||||||
'object' => $object,
|
'object' => $object,
|
||||||
|
'file' => $this->file,
|
||||||
'level' => $level,
|
'level' => $level,
|
||||||
'reason' => $reason,
|
'reason' => $reason,
|
||||||
'svn' => ( $config['svn'] === true ) ? $this->blame[$object['line']] : ''
|
'svn' => ( $config['svn'] === true ) ? $this->blame[$object['line']] : ''
|
||||||
);
|
);
|
||||||
|
//var_dump( $faults ); die();
|
||||||
}
|
}
|
||||||
function parserCallback( $object ) {
|
function parserCallback( $object ) {
|
||||||
}
|
}
|
||||||
function preScan( $filename ) {
|
function preScan( $file ) {
|
||||||
global $config;
|
global $config, $svn_root, $svn_base;
|
||||||
|
$this->file = $file;
|
||||||
if( $config['svn'] === true ) {
|
if( $config['svn'] === true ) {
|
||||||
$this->blame = array();
|
$this->blame = array();
|
||||||
$output = array();
|
$output = array();
|
||||||
exec( "svn blame '$filename' 2>/dev/null", $output, $result );
|
if( $file['revision'] > 0 ) {
|
||||||
|
exec( "svn blame -r {$file['revision']} {$svn_root}{$svn_base}/{$file['filename']} 2>/dev/null", $output, $result );
|
||||||
|
} else {
|
||||||
|
exec( "svn blame '{$file['filename']}' 2>/dev/null", $output, $result );
|
||||||
|
}
|
||||||
if( $result == 0 ) {
|
if( $result == 0 ) {
|
||||||
foreach( $output as $line => $text ) {
|
foreach( $output as $line => $text ) {
|
||||||
$matches = array();
|
$matches = array();
|
||||||
|
@ -108,7 +116,8 @@ class OutputModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
function _callback( $object ) {
|
function _callback( $object ) {
|
||||||
global $modules;
|
global $modules, $files, $current_file;
|
||||||
|
$object['file'] = $files[$current_file - 1]['filename'];
|
||||||
foreach( $modules['scanner'] as $module ) {
|
foreach( $modules['scanner'] as $module ) {
|
||||||
$module->parserCallback( $object );
|
$module->parserCallback( $object );
|
||||||
}
|
}
|
||||||
|
@ -193,17 +202,24 @@ for( $i = 1; $i < $argc; $i++ ) {
|
||||||
$svn_base = substr( $svn_url, strlen( $svn_root ) );
|
$svn_base = substr( $svn_url, strlen( $svn_root ) );
|
||||||
foreach( $revs as $rev ) {
|
foreach( $revs as $rev ) {
|
||||||
$revisions[] = $rev = intval( $rev );
|
$revisions[] = $rev = intval( $rev );
|
||||||
$xml = shell_exec( "svn log -v --xml -r $rev $base_path" );
|
$xml = shell_exec( "svn log -v --xml -r $rev $base_path 2>/dev/null" );
|
||||||
$parser = xml_parser_create();
|
$parser = xml_parser_create();
|
||||||
xml_parser_set_option( $parser, XML_OPTION_SKIP_WHITE, 1 );
|
xml_parser_set_option( $parser, XML_OPTION_SKIP_WHITE, 1 );
|
||||||
xml_parse_into_struct( $parser, $xml, $values, $index );
|
xml_parse_into_struct( $parser, $xml, $values, $index );
|
||||||
xml_parser_free( $parser );
|
xml_parser_free( $parser );
|
||||||
foreach( $values as $value ) {
|
foreach( $values as $value ) {
|
||||||
if( $value['tag'] == 'PATH' ) {
|
if(
|
||||||
$file = realpath( $base_path . substr( $value['value'], strlen( $svn_base ) ) );
|
$value['tag'] == 'PATH'
|
||||||
if( !in_array( $file, $files ) ) {
|
&& isset( $value['attributes']['ACTION'] )
|
||||||
$files[] = $file;
|
&& in_array( $value['attributes']['ACTION'], array( 'A', 'M' ) )
|
||||||
}
|
&& strtolower( substr( $value['value'], -4 ) ) == '.php'
|
||||||
|
) {
|
||||||
|
$file = substr( $value['value'], strlen( $svn_base ) + 1 );
|
||||||
|
$files[] = array(
|
||||||
|
'filename' => $file,
|
||||||
|
'revision' => $rev,
|
||||||
|
'contents' => shell_exec( "svn cat -r {$rev} {$svn_root}{$value['value']} 2>/dev/null" )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,17 +229,29 @@ for( $i = 1; $i < $argc; $i++ ) {
|
||||||
default:
|
default:
|
||||||
if( file_exists( $argv[$i] ) && strtolower( substr( $argv[$i], -4 ) ) == '.php' ) {
|
if( file_exists( $argv[$i] ) && strtolower( substr( $argv[$i], -4 ) ) == '.php' ) {
|
||||||
$base_path = ( $base_path === false ) ? realpath( dirname( $argv[$i] ) ) . '/' : $base_path;
|
$base_path = ( $base_path === false ) ? realpath( dirname( $argv[$i] ) ) . '/' : $base_path;
|
||||||
$files[] = $argv[$i];
|
$files[] = array(
|
||||||
|
'filename' => $argv[$i],
|
||||||
|
'revision' => 0
|
||||||
|
);
|
||||||
} else if( is_dir( $argv[$i] ) ) {
|
} else if( is_dir( $argv[$i] ) ) {
|
||||||
$base_path = ( $base_path === false ) ? realpath( $argv[$i] ) . '/' : $base_path;
|
$base_path = ( $base_path === false ) ? realpath( $argv[$i] ) . '/' : $base_path;
|
||||||
exec( "find {$argv[$i]} -iname '*.php' 2>/dev/null", $output, $result );
|
exec( "find {$argv[$i]} -iname '*.php' 2>/dev/null", $output, $result );
|
||||||
$files = array_merge( $files, $output );
|
foreach( $output as $file ) {
|
||||||
|
$files[] = array(
|
||||||
|
'filename' => $file,
|
||||||
|
'revision' => 0
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if( count( $files ) == 0 ) {
|
if( count( $files ) == 0 ) {
|
||||||
die( $help );
|
if( count( $revisions ) > 0 ) {
|
||||||
|
die( "Revisions invalid or contained no files from the supplied path\n" );
|
||||||
|
} else {
|
||||||
|
die( $help );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dig into the modules folder and load up what we find
|
// Dig into the modules folder and load up what we find
|
||||||
|
@ -254,19 +282,20 @@ $parser = new PHPParser();
|
||||||
$parser->registerCallback( '_callback' );
|
$parser->registerCallback( '_callback' );
|
||||||
|
|
||||||
err( "Parsing files...\n" );
|
err( "Parsing files...\n" );
|
||||||
$counter = 0; $total = count( $files ); $lastpct = 0;
|
$current_file = 0; $total = count( $files ); $lastpct = 0;
|
||||||
foreach( $files as $file ) {
|
foreach( $files as $file ) {
|
||||||
$counter++;
|
$current_file++;
|
||||||
if( $counter == 1 ) { err( 0 ); }
|
if( $current_file == 1 ) { err( 0 ); }
|
||||||
else {
|
else {
|
||||||
$pct = intval( $counter / $total * 100 );
|
$pct = intval( $current_file / $total * 100 );
|
||||||
if( $pct != $lastpct && $pct % 2 == 0 ) {
|
if( $pct != $lastpct && $pct % 2 == 0 ) {
|
||||||
err( $pct % 10 == 0 ? $pct : '.' );
|
err( $pct % 10 == 0 ? $pct : '.' );
|
||||||
$lastpct = $pct;
|
$lastpct = $pct;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach( $modules['scanner'] as $module ) { $module->preScan( $file ); }
|
foreach( $modules['scanner'] as $module ) { $module->preScan( $file ); }
|
||||||
$parser->parseFile( $file );
|
$file_contents = ( $file['revision'] > 0 ? shell_exec( "svn cat -r {$rev} {$svn_root}{$svn_base}/{$file['filename']} 2>/dev/null" ) : file_get_contents( $file['filename'] ) );
|
||||||
|
$parser->parse( $file_contents );
|
||||||
}
|
}
|
||||||
err( "\n" );
|
err( "\n" );
|
||||||
$modules['output']->write( $config['output_file'] );
|
$modules['output']->write( $config['output_file'] );
|
||||||
|
|
Loading…
Add table
Reference in a new issue