2 # This file is used to be the main entrance of ECC tool
4 # Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 import os
, time
, glob
, sys
18 import Common
.EdkLogger
as EdkLogger
21 from MetaDataParser
import *
22 from optparse
import OptionParser
23 from Configuration
import Configuration
24 from Check
import Check
25 from Common
.InfClassObject
import Inf
26 from Common
.DecClassObject
import Dec
27 from Common
.DscClassObject
import Dsc
28 from Common
.FdfClassObject
import Fdf
29 from Common
.String
import NormPath
30 from Common
.BuildVersion
import gBUILD_VERSION
31 from Common
import BuildToolError
34 from Exception import *
38 # This class is used to define Ecc main entrance
40 # @param object: Inherited from object class
44 # Version and Copyright
45 self
.VersionNumber
= ("0.01" + " " + gBUILD_VERSION
)
46 self
.Version
= "%prog Version " + self
.VersionNumber
47 self
.Copyright
= "Copyright (c) 2009 - 2010, Intel Corporation All rights reserved."
49 self
.InitDefaultConfigIni()
50 self
.OutputFile
= 'output.txt'
51 self
.ReportFile
= 'Report.csv'
52 self
.ExceptionFile
= 'exception.xml'
54 self
.ScanSourceCode
= True
55 self
.ScanMetaData
= True
57 # Parse the options and args
60 # Generate checkpoints list
61 EccGlobalData
.gConfig
= Configuration(self
.ConfigFile
)
63 # Generate exception list
64 EccGlobalData
.gException
= ExceptionCheck(self
.ExceptionFile
)
67 EccGlobalData
.gDb
= Database
.Database(Database
.DATABASE_PATH
)
68 EccGlobalData
.gDb
.InitDatabase(self
.IsInit
)
80 EccGlobalData
.gDb
.Close()
82 def InitDefaultConfigIni(self
):
83 paths
= map(lambda p
: os
.path
.join(p
, 'Ecc', 'config.ini'), sys
.path
)
84 paths
= (os
.path
.realpath('config.ini'),) + tuple(paths
)
86 if os
.path
.exists(path
):
87 self
.ConfigFile
= path
89 self
.ConfigFile
= 'config.ini'
93 # Build the database for target
95 def BuildDatabase(self
):
97 EccGlobalData
.gDb
.TblReport
.Drop()
98 EccGlobalData
.gDb
.TblReport
.Create()
102 if self
.ScanSourceCode
:
103 EdkLogger
.quiet("Building database for source code ...")
104 c
.CollectSourceCodeDataIntoDB(EccGlobalData
.gTarget
)
105 if self
.ScanMetaData
:
106 EdkLogger
.quiet("Building database for source code done!")
107 self
.BuildMetaDataFileDatabase()
109 EccGlobalData
.gIdentifierTableList
= GetTableList((MODEL_FILE_C
, MODEL_FILE_H
), 'Identifier', EccGlobalData
.gDb
)
110 EccGlobalData
.gCFileList
= GetFileList(MODEL_FILE_C
, EccGlobalData
.gDb
)
111 EccGlobalData
.gHFileList
= GetFileList(MODEL_FILE_H
, EccGlobalData
.gDb
)
113 ## BuildMetaDataFileDatabase
115 # Build the database for meta data files
117 def BuildMetaDataFileDatabase(self
):
118 EdkLogger
.quiet("Building database for meta data files ...")
119 Op
= open(EccGlobalData
.gConfig
.MetaDataFileCheckPathOfGenerateFileList
, 'w+')
120 #SkipDirs = Read from config file
121 SkipDirs
= EccGlobalData
.gConfig
.SkipDirList
122 SkipDirString
= string
.join(SkipDirs
, '|')
123 p
= re
.compile(r
'.*[\\/](?:%s)[\\/]?.*' % SkipDirString
)
124 for Root
, Dirs
, Files
in os
.walk(EccGlobalData
.gTarget
):
125 if p
.match(Root
.upper()):
129 Dirname
= os
.path
.join(Root
, Dir
)
130 if os
.path
.islink(Dirname
):
131 Dirname
= os
.path
.realpath(Dirname
)
132 if os
.path
.isdir(Dirname
):
133 # symlinks to directories are treated as directories
138 if len(File
) > 4 and File
[-4:].upper() == ".DEC":
139 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
140 EdkLogger
.quiet("Parsing %s" % Filename
)
141 Op
.write("%s\r" % Filename
)
142 Dec(Filename
, True, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
144 if len(File
) > 4 and File
[-4:].upper() == ".DSC":
145 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
146 EdkLogger
.quiet("Parsing %s" % Filename
)
147 Op
.write("%s\r" % Filename
)
148 Dsc(Filename
, True, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
150 if len(File
) > 4 and File
[-4:].upper() == ".INF":
151 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
152 EdkLogger
.quiet("Parsing %s" % Filename
)
153 Op
.write("%s\r" % Filename
)
154 Inf(Filename
, True, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
156 if len(File
) > 4 and File
[-4:].upper() == ".FDF":
157 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
158 EdkLogger
.quiet("Parsing %s" % Filename
)
159 Op
.write("%s\r" % Filename
)
160 Fdf(Filename
, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
165 EccGlobalData
.gDb
.Conn
.commit()
167 EdkLogger
.quiet("Building database for meta data files done!")
171 # Check each checkpoint
174 EdkLogger
.quiet("Checking ...")
177 EdkLogger
.quiet("Checking done!")
181 # Generate the scan report
184 EdkLogger
.quiet("Generating report ...")
185 EccGlobalData
.gDb
.TblReport
.ToCSV(self
.ReportFile
)
186 EdkLogger
.quiet("Generating report done!")
188 def GetRealPathCase(self
, path
):
189 TmpPath
= path
.rstrip(os
.sep
)
190 PathParts
= TmpPath
.split(os
.sep
)
191 if len(PathParts
) == 0:
193 if len(PathParts
) == 1:
194 if PathParts
[0].strip().endswith(':'):
195 return PathParts
[0].upper()
196 # Relative dir, list . current dir
197 Dirs
= os
.listdir('.')
199 if Dir
.upper() == PathParts
[0].upper():
202 if PathParts
[0].strip().endswith(':'):
203 PathParts
[0] = PathParts
[0].upper()
204 ParentDir
= PathParts
[0]
206 if PathParts
[0] == '':
210 PathParts
.remove(PathParts
[0]) # need to remove the parent
211 for Part
in PathParts
:
212 Dirs
= os
.listdir(ParentDir
+ os
.sep
)
214 if Dir
.upper() == Part
.upper():
227 def ParseOption(self
):
228 EdkLogger
.quiet("Loading ECC configuration ... done")
229 (Options
, Target
) = self
.EccOptionParser()
231 if Options
.Workspace
:
232 os
.environ
["WORKSPACE"] = Options
.Workspace
234 # Check workspace envirnoment
235 if "WORKSPACE" not in os
.environ
:
236 EdkLogger
.error("ECC", BuildToolError
.ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
237 ExtraData
="WORKSPACE")
239 EccGlobalData
.gWorkspace
= os
.path
.normpath(os
.getenv("WORKSPACE"))
240 if not os
.path
.exists(EccGlobalData
.gWorkspace
):
241 EdkLogger
.error("ECC", BuildToolError
.FILE_NOT_FOUND
, ExtraData
="WORKSPACE = %s" % EccGlobalData
.gWorkspace
)
242 os
.environ
["WORKSPACE"] = EccGlobalData
.gWorkspace
244 self
.SetLogLevel(Options
)
247 if Options
.ConfigFile
!= None:
248 self
.ConfigFile
= Options
.ConfigFile
249 if Options
.OutputFile
!= None:
250 self
.OutputFile
= Options
.OutputFile
251 if Options
.ReportFile
!= None:
252 self
.ReportFile
= Options
.ReportFile
253 if Options
.ExceptionFile
!= None:
254 self
.ExceptionFile
= Options
.ExceptionFile
255 if Options
.Target
!= None:
256 if not os
.path
.isdir(Options
.Target
):
257 EdkLogger
.error("ECC", BuildToolError
.OPTION_VALUE_INVALID
, ExtraData
="Target [%s] does NOT exist" % Options
.Target
)
259 EccGlobalData
.gTarget
= self
.GetRealPathCase(os
.path
.normpath(Options
.Target
))
261 EdkLogger
.warn("Ecc", EdkLogger
.ECC_ERROR
, "The target source tree was not specified, using current WORKSPACE instead!")
262 EccGlobalData
.gTarget
= os
.path
.normpath(os
.getenv("WORKSPACE"))
263 if Options
.keepdatabase
!= None:
265 if Options
.metadata
!= None and Options
.sourcecode
!= None:
266 EdkLogger
.error("ECC", BuildToolError
.OPTION_CONFLICT
, ExtraData
="-m and -s can't be specified at one time")
267 if Options
.metadata
!= None:
268 self
.ScanSourceCode
= False
269 if Options
.sourcecode
!= None:
270 self
.ScanMetaData
= False
274 # Set current log level of the tool based on args
276 # @param Option: The option list including log level setting
278 def SetLogLevel(self
, Option
):
279 if Option
.verbose
!= None:
280 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
281 elif Option
.quiet
!= None:
282 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
283 elif Option
.debug
!= None:
284 EdkLogger
.SetLevel(Option
.debug
+ 1)
286 EdkLogger
.SetLevel(EdkLogger
.INFO
)
288 ## Parse command line options
290 # Using standard Python module optparse to parse command line option of this tool.
292 # @retval Opt A optparse.Values object containing the parsed options
293 # @retval Args Target of build command
295 def EccOptionParser(self
):
296 Parser
= OptionParser(description
= self
.Copyright
, version
= self
.Version
, prog
= "Ecc.exe", usage
= "%prog [options]")
297 Parser
.add_option("-t", "--target sourcepath", action
="store", type="string", dest
='Target',
298 help="Check all files under the target workspace.")
299 Parser
.add_option("-c", "--config filename", action
="store", type="string", dest
="ConfigFile",
300 help="Specify a configuration file. Defaultly use config.ini under ECC tool directory.")
301 Parser
.add_option("-o", "--outfile filename", action
="store", type="string", dest
="OutputFile",
302 help="Specify the name of an output file, if and only if one filename was specified.")
303 Parser
.add_option("-r", "--reportfile filename", action
="store", type="string", dest
="ReportFile",
304 help="Specify the name of an report file, if and only if one filename was specified.")
305 Parser
.add_option("-e", "--exceptionfile filename", action
="store", type="string", dest
="ExceptionFile",
306 help="Specify the name of an exception file, if and only if one filename was specified.")
307 Parser
.add_option("-m", "--metadata", action
="store_true", type=None, help="Only scan meta-data files information if this option is specified.")
308 Parser
.add_option("-s", "--sourcecode", action
="store_true", type=None, help="Only scan source code files information if this option is specified.")
309 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.")
310 Parser
.add_option("-l", "--log filename", action
="store", dest
="LogFile", help="""If specified, the tool should emit the changes that
311 were made by the tool after printing the result message.
312 If filename, the emit to the file, otherwise emit to
313 standard output. If no modifications were made, then do not
314 create a log file, or output a log message.""")
315 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
316 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
317 "including library instances selected, final dependency expression, "\
318 "and warning messages, etc.")
319 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
320 Parser
.add_option("-w", "--workspace", action
="store", type="string", dest
='Workspace', help="Specify workspace.")
322 (Opt
, Args
)=Parser
.parse_args()
328 # This acts like the main() function for the script, unless it is 'import'ed into another
331 if __name__
== '__main__':
332 # Initialize log system
333 EdkLogger
.Initialize()
334 EdkLogger
.IsRaiseError
= False
335 EdkLogger
.quiet(time
.strftime("%H:%M:%S, %b.%d %Y ", time
.localtime()) + "[00:00]" + "\n")
337 StartTime
= time
.clock()
339 FinishTime
= time
.clock()
341 BuildDuration
= time
.strftime("%M:%S", time
.gmtime(int(round(FinishTime
- StartTime
))))
342 EdkLogger
.quiet("\n%s [%s]" % (time
.strftime("%H:%M:%S, %b.%d %Y", time
.localtime()), BuildDuration
))