2009-07-17 11:10:31 +02:00
## @file
# This file is used to be the main entrance of ECC tool
#
2010-05-18 07:04:32 +02:00
# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
2009-07-17 11:10:31 +02:00
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
# Import Modules
#
import os , time , glob , sys
import Common . EdkLogger as EdkLogger
import Database
import EccGlobalData
from MetaDataParser import *
from optparse import OptionParser
from Configuration import Configuration
from Check import Check
2011-12-16 09:52:13 +01:00
import Common . GlobalData as GlobalData
2011-12-07 07:19:28 +01:00
2009-07-17 11:10:31 +02:00
from Common . String import NormPath
2011-09-18 14:17:25 +02:00
from Common . BuildVersion import gBUILD_VERSION
2009-07-17 11:10:31 +02:00
from Common import BuildToolError
2011-12-16 09:52:13 +01:00
from Common . Misc import PathClass
2011-12-07 07:19:28 +01:00
from MetaFileWorkspace . MetaFileParser import DscParser
from MetaFileWorkspace . MetaFileParser import DecParser
from MetaFileWorkspace . MetaFileParser import InfParser
from MetaFileWorkspace . MetaFileParser import Fdf
from MetaFileWorkspace . MetaFileTable import MetaFileStorage
2009-07-17 11:10:31 +02:00
import c
2009-09-11 05:14:43 +02:00
import re , string
2009-07-17 11:10:31 +02:00
from Exception import *
## Ecc
#
# This class is used to define Ecc main entrance
#
# @param object: Inherited from object class
#
class Ecc ( object ) :
def __init__ ( self ) :
# Version and Copyright
2011-09-18 14:17:25 +02:00
self . VersionNumber = ( " 0.01 " + " " + gBUILD_VERSION )
2009-07-17 11:10:31 +02:00
self . Version = " % prog Version " + self . VersionNumber
2010-03-01 00:39:39 +01:00
self . Copyright = " Copyright (c) 2009 - 2010, Intel Corporation All rights reserved. "
2009-07-17 11:10:31 +02:00
self . InitDefaultConfigIni ( )
self . OutputFile = ' output.txt '
self . ReportFile = ' Report.csv '
self . ExceptionFile = ' exception.xml '
self . IsInit = True
self . ScanSourceCode = True
self . ScanMetaData = True
2011-12-07 07:19:28 +01:00
self . MetaFile = ' '
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
# Parse the options and args
self . ParseOption ( )
2011-12-16 09:52:13 +01:00
#
# Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP
#
WorkspaceDir = os . path . normcase ( os . path . normpath ( os . environ [ " WORKSPACE " ] ) )
os . environ [ " WORKSPACE " ] = WorkspaceDir
if " ECP_SOURCE " not in os . environ :
os . environ [ " ECP_SOURCE " ] = os . path . join ( WorkspaceDir , GlobalData . gEdkCompatibilityPkg )
if " EFI_SOURCE " not in os . environ :
os . environ [ " EFI_SOURCE " ] = os . environ [ " ECP_SOURCE " ]
if " EDK_SOURCE " not in os . environ :
os . environ [ " EDK_SOURCE " ] = os . environ [ " ECP_SOURCE " ]
#
# Unify case of characters on case-insensitive systems
#
EfiSourceDir = os . path . normcase ( os . path . normpath ( os . environ [ " EFI_SOURCE " ] ) )
EdkSourceDir = os . path . normcase ( os . path . normpath ( os . environ [ " EDK_SOURCE " ] ) )
EcpSourceDir = os . path . normcase ( os . path . normpath ( os . environ [ " ECP_SOURCE " ] ) )
os . environ [ " EFI_SOURCE " ] = EfiSourceDir
os . environ [ " EDK_SOURCE " ] = EdkSourceDir
os . environ [ " ECP_SOURCE " ] = EcpSourceDir
GlobalData . gWorkspace = WorkspaceDir
GlobalData . gEfiSource = EfiSourceDir
GlobalData . gEdkSource = EdkSourceDir
GlobalData . gEcpSource = EcpSourceDir
GlobalData . gGlobalDefines [ " WORKSPACE " ] = WorkspaceDir
GlobalData . gGlobalDefines [ " EFI_SOURCE " ] = EfiSourceDir
GlobalData . gGlobalDefines [ " EDK_SOURCE " ] = EdkSourceDir
GlobalData . gGlobalDefines [ " ECP_SOURCE " ] = EcpSourceDir
2009-07-17 11:10:31 +02:00
# Generate checkpoints list
EccGlobalData . gConfig = Configuration ( self . ConfigFile )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
# Generate exception list
EccGlobalData . gException = ExceptionCheck ( self . ExceptionFile )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
# Init Ecc database
EccGlobalData . gDb = Database . Database ( Database . DATABASE_PATH )
EccGlobalData . gDb . InitDatabase ( self . IsInit )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
# Build ECC database
self . BuildDatabase ( )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
# Start to check
self . Check ( )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
# Show report
self . GenReport ( )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
# Close Database
EccGlobalData . gDb . Close ( )
def InitDefaultConfigIni ( self ) :
paths = map ( lambda p : os . path . join ( p , ' Ecc ' , ' config.ini ' ) , sys . path )
paths = ( os . path . realpath ( ' config.ini ' ) , ) + tuple ( paths )
for path in paths :
if os . path . exists ( path ) :
self . ConfigFile = path
return
self . ConfigFile = ' config.ini '
## BuildDatabase
#
# Build the database for target
#
def BuildDatabase ( self ) :
# Clean report table
EccGlobalData . gDb . TblReport . Drop ( )
EccGlobalData . gDb . TblReport . Create ( )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
# Build database
if self . IsInit :
if self . ScanSourceCode :
EdkLogger . quiet ( " Building database for source code ... " )
c . CollectSourceCodeDataIntoDB ( EccGlobalData . gTarget )
if self . ScanMetaData :
EdkLogger . quiet ( " Building database for source code done! " )
self . BuildMetaDataFileDatabase ( )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
EccGlobalData . gIdentifierTableList = GetTableList ( ( MODEL_FILE_C , MODEL_FILE_H ) , ' Identifier ' , EccGlobalData . gDb )
2010-09-06 03:58:00 +02:00
EccGlobalData . gCFileList = GetFileList ( MODEL_FILE_C , EccGlobalData . gDb )
EccGlobalData . gHFileList = GetFileList ( MODEL_FILE_H , EccGlobalData . gDb )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
## BuildMetaDataFileDatabase
#
# Build the database for meta data files
#
def BuildMetaDataFileDatabase ( self ) :
EdkLogger . quiet ( " Building database for meta data files ... " )
Op = open ( EccGlobalData . gConfig . MetaDataFileCheckPathOfGenerateFileList , ' w+ ' )
#SkipDirs = Read from config file
SkipDirs = EccGlobalData . gConfig . SkipDirList
2009-09-11 05:14:43 +02:00
SkipDirString = string . join ( SkipDirs , ' | ' )
p = re . compile ( r ' .*[ \\ /](?: %s )[ \\ /]?.* ' % SkipDirString )
2009-07-17 11:10:31 +02:00
for Root , Dirs , Files in os . walk ( EccGlobalData . gTarget ) :
2009-09-11 05:14:43 +02:00
if p . match ( Root . upper ( ) ) :
continue
2009-07-17 11:10:31 +02:00
for Dir in Dirs :
Dirname = os . path . join ( Root , Dir )
if os . path . islink ( Dirname ) :
Dirname = os . path . realpath ( Dirname )
if os . path . isdir ( Dirname ) :
# symlinks to directories are treated as directories
Dirs . remove ( Dir )
Dirs . append ( Dirname )
for File in Files :
if len ( File ) > 4 and File [ - 4 : ] . upper ( ) == " .DEC " :
Filename = os . path . normpath ( os . path . join ( Root , File ) )
EdkLogger . quiet ( " Parsing %s " % Filename )
Op . write ( " %s \r " % Filename )
2011-12-07 07:19:28 +01:00
#Dec(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
self . MetaFile = DecParser ( Filename , MODEL_FILE_DEC , EccGlobalData . gDb . TblDec )
self . MetaFile . Start ( )
2009-07-17 11:10:31 +02:00
continue
if len ( File ) > 4 and File [ - 4 : ] . upper ( ) == " .DSC " :
Filename = os . path . normpath ( os . path . join ( Root , File ) )
EdkLogger . quiet ( " Parsing %s " % Filename )
Op . write ( " %s \r " % Filename )
2011-12-07 07:19:28 +01:00
#Dsc(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
2011-12-16 09:52:13 +01:00
self . MetaFile = DscParser ( PathClass ( Filename , Root ) , MODEL_FILE_DSC , MetaFileStorage ( EccGlobalData . gDb . TblDsc . Cur , Filename , MODEL_FILE_DSC , True ) )
2011-12-07 07:19:28 +01:00
# alwasy do post-process, in case of macros change
self . MetaFile . DoPostProcess ( )
self . MetaFile . Start ( )
self . MetaFile . _PostProcess ( )
2009-07-17 11:10:31 +02:00
continue
if len ( File ) > 4 and File [ - 4 : ] . upper ( ) == " .INF " :
Filename = os . path . normpath ( os . path . join ( Root , File ) )
EdkLogger . quiet ( " Parsing %s " % Filename )
Op . write ( " %s \r " % Filename )
2011-12-07 07:19:28 +01:00
#Inf(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
self . MetaFile = InfParser ( Filename , MODEL_FILE_INF , EccGlobalData . gDb . TblInf )
self . MetaFile . Start ( )
2009-07-17 11:10:31 +02:00
continue
if len ( File ) > 4 and File [ - 4 : ] . upper ( ) == " .FDF " :
Filename = os . path . normpath ( os . path . join ( Root , File ) )
EdkLogger . quiet ( " Parsing %s " % Filename )
Op . write ( " %s \r " % Filename )
2009-09-11 05:14:43 +02:00
Fdf ( Filename , True , EccGlobalData . gWorkspace , EccGlobalData . gDb )
2009-07-17 11:10:31 +02:00
continue
Op . close ( )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
# Commit to database
EccGlobalData . gDb . Conn . commit ( )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
EdkLogger . quiet ( " Building database for meta data files done! " )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
##
#
# Check each checkpoint
#
def Check ( self ) :
EdkLogger . quiet ( " Checking ... " )
EccCheck = Check ( )
EccCheck . Check ( )
EdkLogger . quiet ( " Checking done! " )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
##
#
# Generate the scan report
#
def GenReport ( self ) :
EdkLogger . quiet ( " Generating report ... " )
EccGlobalData . gDb . TblReport . ToCSV ( self . ReportFile )
EdkLogger . quiet ( " Generating report done! " )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
def GetRealPathCase ( self , path ) :
TmpPath = path . rstrip ( os . sep )
PathParts = TmpPath . split ( os . sep )
if len ( PathParts ) == 0 :
return path
if len ( PathParts ) == 1 :
if PathParts [ 0 ] . strip ( ) . endswith ( ' : ' ) :
return PathParts [ 0 ] . upper ( )
# Relative dir, list . current dir
Dirs = os . listdir ( ' . ' )
for Dir in Dirs :
if Dir . upper ( ) == PathParts [ 0 ] . upper ( ) :
return Dir
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
if PathParts [ 0 ] . strip ( ) . endswith ( ' : ' ) :
PathParts [ 0 ] = PathParts [ 0 ] . upper ( )
ParentDir = PathParts [ 0 ]
RealPath = ParentDir
if PathParts [ 0 ] == ' ' :
RealPath = os . sep
ParentDir = os . sep
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
PathParts . remove ( PathParts [ 0 ] ) # need to remove the parent
for Part in PathParts :
Dirs = os . listdir ( ParentDir + os . sep )
for Dir in Dirs :
if Dir . upper ( ) == Part . upper ( ) :
RealPath + = os . sep
RealPath + = Dir
break
ParentDir + = os . sep
ParentDir + = Dir
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
return RealPath
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
## ParseOption
#
# Parse options
#
def ParseOption ( self ) :
EdkLogger . quiet ( " Loading ECC configuration ... done " )
( Options , Target ) = self . EccOptionParser ( )
2009-09-11 05:14:43 +02:00
2010-03-01 00:39:39 +01:00
if Options . Workspace :
os . environ [ " WORKSPACE " ] = Options . Workspace
2010-09-06 03:58:00 +02:00
2009-07-17 11:10:31 +02:00
# Check workspace envirnoment
if " WORKSPACE " not in os . environ :
2009-09-11 05:14:43 +02:00
EdkLogger . error ( " ECC " , BuildToolError . ATTRIBUTE_NOT_AVAILABLE , " Environment variable not found " ,
2009-07-17 11:10:31 +02:00
ExtraData = " WORKSPACE " )
else :
EccGlobalData . gWorkspace = os . path . normpath ( os . getenv ( " WORKSPACE " ) )
if not os . path . exists ( EccGlobalData . gWorkspace ) :
EdkLogger . error ( " ECC " , BuildToolError . FILE_NOT_FOUND , ExtraData = " WORKSPACE = %s " % EccGlobalData . gWorkspace )
os . environ [ " WORKSPACE " ] = EccGlobalData . gWorkspace
# Set log level
self . SetLogLevel ( Options )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
# Set other options
if Options . ConfigFile != None :
self . ConfigFile = Options . ConfigFile
if Options . OutputFile != None :
self . OutputFile = Options . OutputFile
if Options . ReportFile != None :
self . ReportFile = Options . ReportFile
2010-03-01 00:39:39 +01:00
if Options . ExceptionFile != None :
self . ExceptionFile = Options . ExceptionFile
2009-07-17 11:10:31 +02:00
if Options . Target != None :
if not os . path . isdir ( Options . Target ) :
EdkLogger . error ( " ECC " , BuildToolError . OPTION_VALUE_INVALID , ExtraData = " Target [ %s ] does NOT exist " % Options . Target )
else :
EccGlobalData . gTarget = self . GetRealPathCase ( os . path . normpath ( Options . Target ) )
else :
EdkLogger . warn ( " Ecc " , EdkLogger . ECC_ERROR , " The target source tree was not specified, using current WORKSPACE instead! " )
EccGlobalData . gTarget = os . path . normpath ( os . getenv ( " WORKSPACE " ) )
if Options . keepdatabase != None :
self . IsInit = False
if Options . metadata != None and Options . sourcecode != None :
EdkLogger . error ( " ECC " , BuildToolError . OPTION_CONFLICT , ExtraData = " -m and -s can ' t be specified at one time " )
if Options . metadata != None :
self . ScanSourceCode = False
if Options . sourcecode != None :
self . ScanMetaData = False
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
## SetLogLevel
#
# Set current log level of the tool based on args
#
2009-09-11 05:14:43 +02:00
# @param Option: The option list including log level setting
2009-07-17 11:10:31 +02:00
#
def SetLogLevel ( self , Option ) :
if Option . verbose != None :
EdkLogger . SetLevel ( EdkLogger . VERBOSE )
elif Option . quiet != None :
EdkLogger . SetLevel ( EdkLogger . QUIET )
elif Option . debug != None :
EdkLogger . SetLevel ( Option . debug + 1 )
else :
EdkLogger . SetLevel ( EdkLogger . INFO )
## Parse command line options
#
# Using standard Python module optparse to parse command line option of this tool.
#
# @retval Opt A optparse.Values object containing the parsed options
# @retval Args Target of build command
#
def EccOptionParser ( self ) :
Parser = OptionParser ( description = self . Copyright , version = self . Version , prog = " Ecc.exe " , usage = " % prog [options] " )
Parser . add_option ( " -t " , " --target sourcepath " , action = " store " , type = " string " , dest = ' Target ' ,
help = " Check all files under the target workspace. " )
Parser . add_option ( " -c " , " --config filename " , action = " store " , type = " string " , dest = " ConfigFile " ,
help = " Specify a configuration file. Defaultly use config.ini under ECC tool directory. " )
Parser . add_option ( " -o " , " --outfile filename " , action = " store " , type = " string " , dest = " OutputFile " ,
help = " Specify the name of an output file, if and only if one filename was specified. " )
Parser . add_option ( " -r " , " --reportfile filename " , action = " store " , type = " string " , dest = " ReportFile " ,
help = " Specify the name of an report file, if and only if one filename was specified. " )
2010-03-01 00:39:39 +01:00
Parser . add_option ( " -e " , " --exceptionfile filename " , action = " store " , type = " string " , dest = " ExceptionFile " ,
help = " Specify the name of an exception file, if and only if one filename was specified. " )
2009-07-17 11:10:31 +02:00
Parser . add_option ( " -m " , " --metadata " , action = " store_true " , type = None , help = " Only scan meta-data files information if this option is specified. " )
Parser . add_option ( " -s " , " --sourcecode " , action = " store_true " , type = None , help = " Only scan source code files information if this option is specified. " )
Parser . add_option ( " -k " , " --keepdatabase " , action = " store_true " , type = None , help = " The existing Ecc database will not be cleaned except report information if this option is specified. " )
2009-09-11 05:14:43 +02:00
Parser . add_option ( " -l " , " --log filename " , action = " store " , dest = " LogFile " , help = """ If specified, the tool should emit the changes that
were made by the tool after printing the result message .
If filename , the emit to the file , otherwise emit to
standard output . If no modifications were made , then do not
2009-07-17 11:10:31 +02:00
create a log file , or output a log message . """ )
Parser . add_option ( " -q " , " --quiet " , action = " store_true " , type = None , help = " Disable all messages except FATAL ERRORS. " )
Parser . add_option ( " -v " , " --verbose " , action = " store_true " , type = None , help = " Turn on verbose output with informational messages printed, " \
" including library instances selected, final dependency expression, " \
" and warning messages, etc. " )
Parser . add_option ( " -d " , " --debug " , action = " store " , type = " int " , help = " Enable debug messages at specified level. " )
2010-03-01 00:39:39 +01:00
Parser . add_option ( " -w " , " --workspace " , action = " store " , type = " string " , dest = ' Workspace ' , help = " Specify workspace. " )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
( Opt , Args ) = Parser . parse_args ( )
2009-09-11 05:14:43 +02:00
2009-07-17 11:10:31 +02:00
return ( Opt , Args )
##
#
# This acts like the main() function for the script, unless it is 'import'ed into another
# script.
#
if __name__ == ' __main__ ' :
# Initialize log system
EdkLogger . Initialize ( )
EdkLogger . IsRaiseError = False
EdkLogger . quiet ( time . strftime ( " % H: % M: % S, % b. %d % Y " , time . localtime ( ) ) + " [00:00] " + " \n " )
StartTime = time . clock ( )
Ecc = Ecc ( )
FinishTime = time . clock ( )
BuildDuration = time . strftime ( " % M: % S " , time . gmtime ( int ( round ( FinishTime - StartTime ) ) ) )
EdkLogger . quiet ( " \n %s [ %s ] " % ( time . strftime ( " % H: % M: % S, % b. %d % Y " , time . localtime ( ) ) , BuildDuration ) )