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
33 from Exception import *
37 # This class is used to define Ecc main entrance
39 # @param object: Inherited from object class
43 # Version and Copyright
44 self
.VersionNumber
= "0.01"
45 self
.Version
= "%prog Version " + self
.VersionNumber
46 self
.Copyright
= "Copyright (c) 2009, Intel Corporation All rights reserved."
48 self
.InitDefaultConfigIni()
49 self
.OutputFile
= 'output.txt'
50 self
.ReportFile
= 'Report.csv'
51 self
.ExceptionFile
= 'exception.xml'
53 self
.ScanSourceCode
= True
54 self
.ScanMetaData
= True
56 # Parse the options and args
59 # Generate checkpoints list
60 EccGlobalData
.gConfig
= Configuration(self
.ConfigFile
)
62 # Generate exception list
63 EccGlobalData
.gException
= ExceptionCheck(self
.ExceptionFile
)
66 EccGlobalData
.gDb
= Database
.Database(Database
.DATABASE_PATH
)
67 EccGlobalData
.gDb
.InitDatabase(self
.IsInit
)
79 EccGlobalData
.gDb
.Close()
81 def InitDefaultConfigIni(self
):
82 paths
= map(lambda p
: os
.path
.join(p
, 'Ecc', 'config.ini'), sys
.path
)
83 paths
= (os
.path
.realpath('config.ini'),) + tuple(paths
)
85 if os
.path
.exists(path
):
86 self
.ConfigFile
= path
88 self
.ConfigFile
= 'config.ini'
92 # Build the database for target
94 def BuildDatabase(self
):
96 EccGlobalData
.gDb
.TblReport
.Drop()
97 EccGlobalData
.gDb
.TblReport
.Create()
101 if self
.ScanSourceCode
:
102 EdkLogger
.quiet("Building database for source code ...")
103 c
.CollectSourceCodeDataIntoDB(EccGlobalData
.gTarget
)
104 if self
.ScanMetaData
:
105 EdkLogger
.quiet("Building database for source code done!")
106 self
.BuildMetaDataFileDatabase()
108 EccGlobalData
.gIdentifierTableList
= GetTableList((MODEL_FILE_C
, MODEL_FILE_H
), 'Identifier', EccGlobalData
.gDb
)
110 ## BuildMetaDataFileDatabase
112 # Build the database for meta data files
114 def BuildMetaDataFileDatabase(self
):
115 EdkLogger
.quiet("Building database for meta data files ...")
116 Op
= open(EccGlobalData
.gConfig
.MetaDataFileCheckPathOfGenerateFileList
, 'w+')
117 #SkipDirs = Read from config file
118 SkipDirs
= EccGlobalData
.gConfig
.SkipDirList
119 SkipDirString
= string
.join(SkipDirs
, '|')
120 p
= re
.compile(r
'.*[\\/](?:%s)[\\/]?.*' % SkipDirString
)
121 for Root
, Dirs
, Files
in os
.walk(EccGlobalData
.gTarget
):
122 if p
.match(Root
.upper()):
126 Dirname
= os
.path
.join(Root
, Dir
)
127 if os
.path
.islink(Dirname
):
128 Dirname
= os
.path
.realpath(Dirname
)
129 if os
.path
.isdir(Dirname
):
130 # symlinks to directories are treated as directories
135 if len(File
) > 4 and File
[-4:].upper() == ".DEC":
136 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
137 EdkLogger
.quiet("Parsing %s" % Filename
)
138 Op
.write("%s\r" % Filename
)
139 Dec(Filename
, True, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
141 if len(File
) > 4 and File
[-4:].upper() == ".DSC":
142 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
143 EdkLogger
.quiet("Parsing %s" % Filename
)
144 Op
.write("%s\r" % Filename
)
145 Dsc(Filename
, True, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
147 if len(File
) > 4 and File
[-4:].upper() == ".INF":
148 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
149 EdkLogger
.quiet("Parsing %s" % Filename
)
150 Op
.write("%s\r" % Filename
)
151 Inf(Filename
, True, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
153 if len(File
) > 4 and File
[-4:].upper() == ".FDF":
154 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
155 EdkLogger
.quiet("Parsing %s" % Filename
)
156 Op
.write("%s\r" % Filename
)
157 Fdf(Filename
, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
162 EccGlobalData
.gDb
.Conn
.commit()
164 EdkLogger
.quiet("Building database for meta data files done!")
168 # Check each checkpoint
171 EdkLogger
.quiet("Checking ...")
174 EdkLogger
.quiet("Checking done!")
178 # Generate the scan report
181 EdkLogger
.quiet("Generating report ...")
182 EccGlobalData
.gDb
.TblReport
.ToCSV(self
.ReportFile
)
183 EdkLogger
.quiet("Generating report done!")
185 def GetRealPathCase(self
, path
):
186 TmpPath
= path
.rstrip(os
.sep
)
187 PathParts
= TmpPath
.split(os
.sep
)
188 if len(PathParts
) == 0:
190 if len(PathParts
) == 1:
191 if PathParts
[0].strip().endswith(':'):
192 return PathParts
[0].upper()
193 # Relative dir, list . current dir
194 Dirs
= os
.listdir('.')
196 if Dir
.upper() == PathParts
[0].upper():
199 if PathParts
[0].strip().endswith(':'):
200 PathParts
[0] = PathParts
[0].upper()
201 ParentDir
= PathParts
[0]
203 if PathParts
[0] == '':
207 PathParts
.remove(PathParts
[0]) # need to remove the parent
208 for Part
in PathParts
:
209 Dirs
= os
.listdir(ParentDir
+ os
.sep
)
211 if Dir
.upper() == Part
.upper():
224 def ParseOption(self
):
225 EdkLogger
.quiet("Loading ECC configuration ... done")
226 (Options
, Target
) = self
.EccOptionParser()
228 # Check workspace envirnoment
229 if "WORKSPACE" not in os
.environ
:
230 EdkLogger
.error("ECC", BuildToolError
.ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
231 ExtraData
="WORKSPACE")
233 EccGlobalData
.gWorkspace
= os
.path
.normpath(os
.getenv("WORKSPACE"))
234 if not os
.path
.exists(EccGlobalData
.gWorkspace
):
235 EdkLogger
.error("ECC", BuildToolError
.FILE_NOT_FOUND
, ExtraData
="WORKSPACE = %s" % EccGlobalData
.gWorkspace
)
236 os
.environ
["WORKSPACE"] = EccGlobalData
.gWorkspace
238 self
.SetLogLevel(Options
)
241 if Options
.ConfigFile
!= None:
242 self
.ConfigFile
= Options
.ConfigFile
243 if Options
.OutputFile
!= None:
244 self
.OutputFile
= Options
.OutputFile
245 if Options
.ReportFile
!= None:
246 self
.ReportFile
= Options
.ReportFile
247 if Options
.Target
!= None:
248 if not os
.path
.isdir(Options
.Target
):
249 EdkLogger
.error("ECC", BuildToolError
.OPTION_VALUE_INVALID
, ExtraData
="Target [%s] does NOT exist" % Options
.Target
)
251 EccGlobalData
.gTarget
= self
.GetRealPathCase(os
.path
.normpath(Options
.Target
))
253 EdkLogger
.warn("Ecc", EdkLogger
.ECC_ERROR
, "The target source tree was not specified, using current WORKSPACE instead!")
254 EccGlobalData
.gTarget
= os
.path
.normpath(os
.getenv("WORKSPACE"))
255 if Options
.keepdatabase
!= None:
257 if Options
.metadata
!= None and Options
.sourcecode
!= None:
258 EdkLogger
.error("ECC", BuildToolError
.OPTION_CONFLICT
, ExtraData
="-m and -s can't be specified at one time")
259 if Options
.metadata
!= None:
260 self
.ScanSourceCode
= False
261 if Options
.sourcecode
!= None:
262 self
.ScanMetaData
= False
266 # Set current log level of the tool based on args
268 # @param Option: The option list including log level setting
270 def SetLogLevel(self
, Option
):
271 if Option
.verbose
!= None:
272 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
273 elif Option
.quiet
!= None:
274 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
275 elif Option
.debug
!= None:
276 EdkLogger
.SetLevel(Option
.debug
+ 1)
278 EdkLogger
.SetLevel(EdkLogger
.INFO
)
280 ## Parse command line options
282 # Using standard Python module optparse to parse command line option of this tool.
284 # @retval Opt A optparse.Values object containing the parsed options
285 # @retval Args Target of build command
287 def EccOptionParser(self
):
288 Parser
= OptionParser(description
= self
.Copyright
, version
= self
.Version
, prog
= "Ecc.exe", usage
= "%prog [options]")
289 Parser
.add_option("-t", "--target sourcepath", action
="store", type="string", dest
='Target',
290 help="Check all files under the target workspace.")
291 Parser
.add_option("-c", "--config filename", action
="store", type="string", dest
="ConfigFile",
292 help="Specify a configuration file. Defaultly use config.ini under ECC tool directory.")
293 Parser
.add_option("-o", "--outfile filename", action
="store", type="string", dest
="OutputFile",
294 help="Specify the name of an output file, if and only if one filename was specified.")
295 Parser
.add_option("-r", "--reportfile filename", action
="store", type="string", dest
="ReportFile",
296 help="Specify the name of an report file, if and only if one filename was specified.")
297 Parser
.add_option("-m", "--metadata", action
="store_true", type=None, help="Only scan meta-data files information if this option is specified.")
298 Parser
.add_option("-s", "--sourcecode", action
="store_true", type=None, help="Only scan source code files information if this option is specified.")
299 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.")
300 Parser
.add_option("-l", "--log filename", action
="store", dest
="LogFile", help="""If specified, the tool should emit the changes that
301 were made by the tool after printing the result message.
302 If filename, the emit to the file, otherwise emit to
303 standard output. If no modifications were made, then do not
304 create a log file, or output a log message.""")
305 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
306 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
307 "including library instances selected, final dependency expression, "\
308 "and warning messages, etc.")
309 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
311 (Opt
, Args
)=Parser
.parse_args()
317 # This acts like the main() function for the script, unless it is 'import'ed into another
320 if __name__
== '__main__':
321 # Initialize log system
322 EdkLogger
.Initialize()
323 EdkLogger
.IsRaiseError
= False
324 EdkLogger
.quiet(time
.strftime("%H:%M:%S, %b.%d %Y ", time
.localtime()) + "[00:00]" + "\n")
326 StartTime
= time
.clock()
328 FinishTime
= time
.clock()
330 BuildDuration
= time
.strftime("%M:%S", time
.gmtime(int(round(FinishTime
- StartTime
))))
331 EdkLogger
.quiet("\n%s [%s]" % (time
.strftime("%H:%M:%S, %b.%d %Y", time
.localtime()), BuildDuration
))