2 # This file is used to be the main entrance of ECC tool
4 # Copyright (c) 2009, Intel Corporation
5 # All rights reserved. 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
import BuildToolError
32 from Exception import *
36 # This class is used to define Ecc main entrance
38 # @param object: Inherited from object class
42 # Version and Copyright
43 self
.VersionNumber
= "0.01"
44 self
.Version
= "%prog Version " + self
.VersionNumber
45 self
.Copyright
= "Copyright (c) 2009, Intel Corporation All rights reserved."
47 self
.InitDefaultConfigIni()
48 self
.OutputFile
= 'output.txt'
49 self
.ReportFile
= 'Report.csv'
50 self
.ExceptionFile
= 'exception.xml'
52 self
.ScanSourceCode
= True
53 self
.ScanMetaData
= True
55 # Parse the options and args
58 # Generate checkpoints list
59 EccGlobalData
.gConfig
= Configuration(self
.ConfigFile
)
61 # Generate exception list
62 EccGlobalData
.gException
= ExceptionCheck(self
.ExceptionFile
)
65 EccGlobalData
.gDb
= Database
.Database(Database
.DATABASE_PATH
)
66 EccGlobalData
.gDb
.InitDatabase(self
.IsInit
)
78 EccGlobalData
.gDb
.Close()
80 def InitDefaultConfigIni(self
):
81 paths
= map(lambda p
: os
.path
.join(p
, 'Ecc', 'config.ini'), sys
.path
)
82 paths
= (os
.path
.realpath('config.ini'),) + tuple(paths
)
84 if os
.path
.exists(path
):
85 self
.ConfigFile
= path
87 self
.ConfigFile
= 'config.ini'
91 # Build the database for target
93 def BuildDatabase(self
):
95 EccGlobalData
.gDb
.TblReport
.Drop()
96 EccGlobalData
.gDb
.TblReport
.Create()
100 if self
.ScanSourceCode
:
101 EdkLogger
.quiet("Building database for source code ...")
102 c
.CollectSourceCodeDataIntoDB(EccGlobalData
.gTarget
)
103 if self
.ScanMetaData
:
104 EdkLogger
.quiet("Building database for source code done!")
105 self
.BuildMetaDataFileDatabase()
107 EccGlobalData
.gIdentifierTableList
= GetTableList((MODEL_FILE_C
, MODEL_FILE_H
), 'Identifier', EccGlobalData
.gDb
)
109 ## BuildMetaDataFileDatabase
111 # Build the database for meta data files
113 def BuildMetaDataFileDatabase(self
):
114 EdkLogger
.quiet("Building database for meta data files ...")
115 Op
= open(EccGlobalData
.gConfig
.MetaDataFileCheckPathOfGenerateFileList
, 'w+')
116 #SkipDirs = Read from config file
117 SkipDirs
= EccGlobalData
.gConfig
.SkipDirList
118 for Root
, Dirs
, Files
in os
.walk(EccGlobalData
.gTarget
):
120 if Dir
.upper() in SkipDirs
:
124 Dirname
= os
.path
.join(Root
, Dir
)
125 if os
.path
.islink(Dirname
):
126 Dirname
= os
.path
.realpath(Dirname
)
127 if os
.path
.isdir(Dirname
):
128 # symlinks to directories are treated as directories
133 if len(File
) > 4 and File
[-4:].upper() == ".DEC":
134 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
135 EdkLogger
.quiet("Parsing %s" % Filename
)
136 Op
.write("%s\r" % Filename
)
137 Dec(Filename
, True, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
139 if len(File
) > 4 and File
[-4:].upper() == ".DSC":
140 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
141 EdkLogger
.quiet("Parsing %s" % Filename
)
142 Op
.write("%s\r" % Filename
)
143 Dsc(Filename
, True, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
145 if len(File
) > 4 and File
[-4:].upper() == ".INF":
146 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
147 EdkLogger
.quiet("Parsing %s" % Filename
)
148 Op
.write("%s\r" % Filename
)
149 Inf(Filename
, True, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
151 if len(File
) > 4 and File
[-4:].upper() == ".FDF":
152 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
153 EdkLogger
.quiet("Parsing %s" % Filename
)
154 Op
.write("%s\r" % Filename
)
155 Fdf(Filename
, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
160 EccGlobalData
.gDb
.Conn
.commit()
162 EdkLogger
.quiet("Building database for meta data files done!")
166 # Check each checkpoint
169 EdkLogger
.quiet("Checking ...")
172 EdkLogger
.quiet("Checking done!")
176 # Generate the scan report
179 EdkLogger
.quiet("Generating report ...")
180 EccGlobalData
.gDb
.TblReport
.ToCSV(self
.ReportFile
)
181 EdkLogger
.quiet("Generating report done!")
183 def GetRealPathCase(self
, path
):
184 TmpPath
= path
.rstrip(os
.sep
)
185 PathParts
= TmpPath
.split(os
.sep
)
186 if len(PathParts
) == 0:
188 if len(PathParts
) == 1:
189 if PathParts
[0].strip().endswith(':'):
190 return PathParts
[0].upper()
191 # Relative dir, list . current dir
192 Dirs
= os
.listdir('.')
194 if Dir
.upper() == PathParts
[0].upper():
197 if PathParts
[0].strip().endswith(':'):
198 PathParts
[0] = PathParts
[0].upper()
199 ParentDir
= PathParts
[0]
201 if PathParts
[0] == '':
205 PathParts
.remove(PathParts
[0]) # need to remove the parent
206 for Part
in PathParts
:
207 Dirs
= os
.listdir(ParentDir
+ os
.sep
)
209 if Dir
.upper() == Part
.upper():
222 def ParseOption(self
):
223 EdkLogger
.quiet("Loading ECC configuration ... done")
224 (Options
, Target
) = self
.EccOptionParser()
226 # Check workspace envirnoment
227 if "WORKSPACE" not in os
.environ
:
228 EdkLogger
.error("ECC", BuildToolError
.ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
229 ExtraData
="WORKSPACE")
231 EccGlobalData
.gWorkspace
= os
.path
.normpath(os
.getenv("WORKSPACE"))
232 if not os
.path
.exists(EccGlobalData
.gWorkspace
):
233 EdkLogger
.error("ECC", BuildToolError
.FILE_NOT_FOUND
, ExtraData
="WORKSPACE = %s" % EccGlobalData
.gWorkspace
)
234 os
.environ
["WORKSPACE"] = EccGlobalData
.gWorkspace
236 self
.SetLogLevel(Options
)
239 if Options
.ConfigFile
!= None:
240 self
.ConfigFile
= Options
.ConfigFile
241 if Options
.OutputFile
!= None:
242 self
.OutputFile
= Options
.OutputFile
243 if Options
.ReportFile
!= None:
244 self
.ReportFile
= Options
.ReportFile
245 if Options
.Target
!= None:
246 if not os
.path
.isdir(Options
.Target
):
247 EdkLogger
.error("ECC", BuildToolError
.OPTION_VALUE_INVALID
, ExtraData
="Target [%s] does NOT exist" % Options
.Target
)
249 EccGlobalData
.gTarget
= self
.GetRealPathCase(os
.path
.normpath(Options
.Target
))
251 EdkLogger
.warn("Ecc", EdkLogger
.ECC_ERROR
, "The target source tree was not specified, using current WORKSPACE instead!")
252 EccGlobalData
.gTarget
= os
.path
.normpath(os
.getenv("WORKSPACE"))
253 if Options
.keepdatabase
!= None:
255 if Options
.metadata
!= None and Options
.sourcecode
!= None:
256 EdkLogger
.error("ECC", BuildToolError
.OPTION_CONFLICT
, ExtraData
="-m and -s can't be specified at one time")
257 if Options
.metadata
!= None:
258 self
.ScanSourceCode
= False
259 if Options
.sourcecode
!= None:
260 self
.ScanMetaData
= False
264 # Set current log level of the tool based on args
266 # @param Option: The option list including log level setting
268 def SetLogLevel(self
, Option
):
269 if Option
.verbose
!= None:
270 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
271 elif Option
.quiet
!= None:
272 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
273 elif Option
.debug
!= None:
274 EdkLogger
.SetLevel(Option
.debug
+ 1)
276 EdkLogger
.SetLevel(EdkLogger
.INFO
)
278 ## Parse command line options
280 # Using standard Python module optparse to parse command line option of this tool.
282 # @retval Opt A optparse.Values object containing the parsed options
283 # @retval Args Target of build command
285 def EccOptionParser(self
):
286 Parser
= OptionParser(description
= self
.Copyright
, version
= self
.Version
, prog
= "Ecc.exe", usage
= "%prog [options]")
287 Parser
.add_option("-t", "--target sourcepath", action
="store", type="string", dest
='Target',
288 help="Check all files under the target workspace.")
289 Parser
.add_option("-c", "--config filename", action
="store", type="string", dest
="ConfigFile",
290 help="Specify a configuration file. Defaultly use config.ini under ECC tool directory.")
291 Parser
.add_option("-o", "--outfile filename", action
="store", type="string", dest
="OutputFile",
292 help="Specify the name of an output file, if and only if one filename was specified.")
293 Parser
.add_option("-r", "--reportfile filename", action
="store", type="string", dest
="ReportFile",
294 help="Specify the name of an report file, if and only if one filename was specified.")
295 Parser
.add_option("-m", "--metadata", action
="store_true", type=None, help="Only scan meta-data files information if this option is specified.")
296 Parser
.add_option("-s", "--sourcecode", action
="store_true", type=None, help="Only scan source code files information if this option is specified.")
297 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.")
298 Parser
.add_option("-l", "--log filename", action
="store", dest
="LogFile", help="""If specified, the tool should emit the changes that
299 were made by the tool after printing the result message.
300 If filename, the emit to the file, otherwise emit to
301 standard output. If no modifications were made, then do not
302 create a log file, or output a log message.""")
303 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
304 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
305 "including library instances selected, final dependency expression, "\
306 "and warning messages, etc.")
307 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
309 (Opt
, Args
)=Parser
.parse_args()
315 # This acts like the main() function for the script, unless it is 'import'ed into another
318 if __name__
== '__main__':
319 # Initialize log system
320 EdkLogger
.Initialize()
321 EdkLogger
.IsRaiseError
= False
322 EdkLogger
.quiet(time
.strftime("%H:%M:%S, %b.%d %Y ", time
.localtime()) + "[00:00]" + "\n")
324 StartTime
= time
.clock()
326 FinishTime
= time
.clock()
328 BuildDuration
= time
.strftime("%M:%S", time
.gmtime(int(round(FinishTime
- StartTime
))))
329 EdkLogger
.quiet("\n%s [%s]" % (time
.strftime("%H:%M:%S, %b.%d %Y", time
.localtime()), BuildDuration
))