2 # This file is used to be the main entrance of ECC tool
4 # Copyright (c) 2009 - 2018, 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 from __future__
import absolute_import
18 import Common
.LongFilePathOs
as os
, time
, glob
, sys
19 import Common
.EdkLogger
as EdkLogger
20 from Ecc
import Database
21 from Ecc
import EccGlobalData
22 from Ecc
.MetaDataParser
import *
23 from optparse
import OptionParser
24 from Ecc
.Configuration
import Configuration
25 from Ecc
.Check
import Check
26 import Common
.GlobalData
as GlobalData
28 from Common
.StringUtils
import NormPath
29 from Common
.BuildVersion
import gBUILD_VERSION
30 from Common
import BuildToolError
31 from Common
.Misc
import PathClass
32 from Common
.Misc
import DirCache
33 from Ecc
.MetaFileWorkspace
.MetaFileParser
import DscParser
34 from Ecc
.MetaFileWorkspace
.MetaFileParser
import DecParser
35 from Ecc
.MetaFileWorkspace
.MetaFileParser
import InfParser
36 from Ecc
.MetaFileWorkspace
.MetaFileParser
import Fdf
37 from Ecc
.MetaFileWorkspace
.MetaFileTable
import MetaFileStorage
40 from Ecc
.Exception import *
41 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
42 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
46 # This class is used to define Ecc main entrance
48 # @param object: Inherited from object class
52 # Version and Copyright
53 self
.VersionNumber
= ("1.0" + " Build " + gBUILD_VERSION
)
54 self
.Version
= "%prog Version " + self
.VersionNumber
55 self
.Copyright
= "Copyright (c) 2009 - 2018, Intel Corporation All rights reserved."
57 self
.InitDefaultConfigIni()
58 self
.OutputFile
= 'output.txt'
59 self
.ReportFile
= 'Report.csv'
60 self
.ExceptionFile
= 'exception.xml'
62 self
.ScanSourceCode
= True
63 self
.ScanMetaData
= True
67 # Parse the options and args
69 EdkLogger
.info(time
.strftime("%H:%M:%S, %b.%d %Y ", time
.localtime()) + "[00:00]" + "\n")
71 WorkspaceDir
= os
.path
.normcase(os
.path
.normpath(os
.environ
["WORKSPACE"]))
72 os
.environ
["WORKSPACE"] = WorkspaceDir
74 # set multiple workspace
75 PackagesPath
= os
.getenv("PACKAGES_PATH")
76 mws
.setWs(WorkspaceDir
, PackagesPath
)
78 GlobalData
.gWorkspace
= WorkspaceDir
80 GlobalData
.gGlobalDefines
["WORKSPACE"] = WorkspaceDir
82 EdkLogger
.info("Loading ECC configuration ... done")
83 # Generate checkpoints list
84 EccGlobalData
.gConfig
= Configuration(self
.ConfigFile
)
86 # Generate exception list
87 EccGlobalData
.gException
= ExceptionCheck(self
.ExceptionFile
)
90 EccGlobalData
.gDb
= Database
.Database(Database
.DATABASE_PATH
)
91 EccGlobalData
.gDb
.InitDatabase(self
.IsInit
)
94 # Get files real name in workspace dir
96 GlobalData
.gAllFiles
= DirCache(GlobalData
.gWorkspace
)
99 # self.BuildDatabase()
100 self
.DetectOnlyScanDirs()
109 EccGlobalData
.gDb
.Close()
111 def InitDefaultConfigIni(self
):
112 paths
= map(lambda p
: os
.path
.join(p
, 'Ecc', 'config.ini'), sys
.path
)
113 paths
= (os
.path
.realpath('config.ini'),) + tuple(paths
)
115 if os
.path
.exists(path
):
116 self
.ConfigFile
= path
118 self
.ConfigFile
= 'config.ini'
123 # Detect whether only scanned folders have been enabled
125 def DetectOnlyScanDirs(self
):
126 if self
.OnlyScan
== True:
128 # Use regex here if multiple spaces or TAB exists in ScanOnlyDirList in config.ini file
129 for folder
in re
.finditer(r
'\S+', EccGlobalData
.gConfig
.ScanOnlyDirList
):
130 OnlyScanDirs
.append(folder
.group())
131 if len(OnlyScanDirs
) != 0:
132 self
.BuildDatabase(OnlyScanDirs
)
134 EdkLogger
.error("ECC", BuildToolError
.OPTION_VALUE_INVALID
, ExtraData
="Use -f option need to fill specific folders in config.ini file")
141 # Build the database for target
143 def BuildDatabase(self
, SpeciDirs
= None):
145 EccGlobalData
.gDb
.TblReport
.Drop()
146 EccGlobalData
.gDb
.TblReport
.Create()
150 if self
.ScanMetaData
:
151 EdkLogger
.quiet("Building database for Meta Data File ...")
152 self
.BuildMetaDataFileDatabase(SpeciDirs
)
153 if self
.ScanSourceCode
:
154 EdkLogger
.quiet("Building database for Meta Data File Done!")
155 if SpeciDirs
is None:
156 c
.CollectSourceCodeDataIntoDB(EccGlobalData
.gTarget
)
158 for specificDir
in SpeciDirs
:
159 c
.CollectSourceCodeDataIntoDB(os
.path
.join(EccGlobalData
.gTarget
, specificDir
))
161 EccGlobalData
.gIdentifierTableList
= GetTableList((MODEL_FILE_C
, MODEL_FILE_H
), 'Identifier', EccGlobalData
.gDb
)
162 EccGlobalData
.gCFileList
= GetFileList(MODEL_FILE_C
, EccGlobalData
.gDb
)
163 EccGlobalData
.gHFileList
= GetFileList(MODEL_FILE_H
, EccGlobalData
.gDb
)
164 EccGlobalData
.gUFileList
= GetFileList(MODEL_FILE_UNI
, EccGlobalData
.gDb
)
166 ## BuildMetaDataFileDatabase
168 # Build the database for meta data files
170 def BuildMetaDataFileDatabase(self
, SpecificDirs
= None):
172 if SpecificDirs
is None:
173 ScanFolders
.append(EccGlobalData
.gTarget
)
175 for specificDir
in SpecificDirs
:
176 ScanFolders
.append(os
.path
.join(EccGlobalData
.gTarget
, specificDir
))
177 EdkLogger
.quiet("Building database for meta data files ...")
178 Op
= open(EccGlobalData
.gConfig
.MetaDataFileCheckPathOfGenerateFileList
, 'w+')
179 #SkipDirs = Read from config file
180 SkipDirs
= EccGlobalData
.gConfig
.SkipDirList
181 SkipDirString
= '|'.join(SkipDirs
)
182 # p = re.compile(r'.*[\\/](?:%s)[\\/]?.*' % SkipDirString)
183 p
= re
.compile(r
'.*[\\/](?:%s^\S)[\\/]?.*' % SkipDirString
)
184 for scanFolder
in ScanFolders
:
185 for Root
, Dirs
, Files
in os
.walk(scanFolder
):
186 if p
.match(Root
.upper()):
189 Dirname
= os
.path
.join(Root
, Dir
)
190 if os
.path
.islink(Dirname
):
191 Dirname
= os
.path
.realpath(Dirname
)
192 if os
.path
.isdir(Dirname
):
193 # symlinks to directories are treated as directories
198 if len(File
) > 4 and File
[-4:].upper() == ".DEC":
199 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
200 EdkLogger
.quiet("Parsing %s" % Filename
)
201 Op
.write("%s\r" % Filename
)
202 #Dec(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
203 self
.MetaFile
= DecParser(Filename
, MODEL_FILE_DEC
, EccGlobalData
.gDb
.TblDec
)
204 self
.MetaFile
.Start()
206 if len(File
) > 4 and File
[-4:].upper() == ".DSC":
207 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
208 EdkLogger
.quiet("Parsing %s" % Filename
)
209 Op
.write("%s\r" % Filename
)
210 #Dsc(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
211 self
.MetaFile
= DscParser(PathClass(Filename
, Root
), MODEL_FILE_DSC
, MetaFileStorage(EccGlobalData
.gDb
.TblDsc
.Cur
, Filename
, MODEL_FILE_DSC
, True))
212 # alwasy do post-process, in case of macros change
213 self
.MetaFile
.DoPostProcess()
214 self
.MetaFile
.Start()
215 self
.MetaFile
._PostProcess
()
217 if len(File
) > 4 and File
[-4:].upper() == ".INF":
218 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
219 EdkLogger
.quiet("Parsing %s" % Filename
)
220 Op
.write("%s\r" % Filename
)
221 #Inf(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
222 self
.MetaFile
= InfParser(Filename
, MODEL_FILE_INF
, EccGlobalData
.gDb
.TblInf
)
223 self
.MetaFile
.Start()
225 if len(File
) > 4 and File
[-4:].upper() == ".FDF":
226 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
227 EdkLogger
.quiet("Parsing %s" % Filename
)
228 Op
.write("%s\r" % Filename
)
229 Fdf(Filename
, True, EccGlobalData
.gWorkspace
, EccGlobalData
.gDb
)
231 if len(File
) > 4 and File
[-4:].upper() == ".UNI":
232 Filename
= os
.path
.normpath(os
.path
.join(Root
, File
))
233 EdkLogger
.quiet("Parsing %s" % Filename
)
234 Op
.write("%s\r" % Filename
)
235 FileID
= EccGlobalData
.gDb
.TblFile
.InsertFile(Filename
, MODEL_FILE_UNI
)
236 EccGlobalData
.gDb
.TblReport
.UpdateBelongsToItemByFile(FileID
, File
)
242 EccGlobalData
.gDb
.Conn
.commit()
244 EdkLogger
.quiet("Building database for meta data files done!")
248 # Check each checkpoint
251 EdkLogger
.quiet("Checking ...")
254 EdkLogger
.quiet("Checking done!")
258 # Generate the scan report
261 EdkLogger
.quiet("Generating report ...")
262 EccGlobalData
.gDb
.TblReport
.ToCSV(self
.ReportFile
)
263 EdkLogger
.quiet("Generating report done!")
265 def GetRealPathCase(self
, path
):
266 TmpPath
= path
.rstrip(os
.sep
)
267 PathParts
= TmpPath
.split(os
.sep
)
268 if len(PathParts
) == 0:
270 if len(PathParts
) == 1:
271 if PathParts
[0].strip().endswith(':'):
272 return PathParts
[0].upper()
273 # Relative dir, list . current dir
274 Dirs
= os
.listdir('.')
276 if Dir
.upper() == PathParts
[0].upper():
279 if PathParts
[0].strip().endswith(':'):
280 PathParts
[0] = PathParts
[0].upper()
281 ParentDir
= PathParts
[0]
283 if PathParts
[0] == '':
287 PathParts
.remove(PathParts
[0]) # need to remove the parent
288 for Part
in PathParts
:
289 Dirs
= os
.listdir(ParentDir
+ os
.sep
)
291 if Dir
.upper() == Part
.upper():
304 def ParseOption(self
):
305 (Options
, Target
) = self
.EccOptionParser()
307 if Options
.Workspace
:
308 os
.environ
["WORKSPACE"] = Options
.Workspace
310 # Check workspace envirnoment
311 if "WORKSPACE" not in os
.environ
:
312 EdkLogger
.error("ECC", BuildToolError
.ATTRIBUTE_NOT_AVAILABLE
, "Environment variable not found",
313 ExtraData
="WORKSPACE")
315 EccGlobalData
.gWorkspace
= os
.path
.normpath(os
.getenv("WORKSPACE"))
316 if not os
.path
.exists(EccGlobalData
.gWorkspace
):
317 EdkLogger
.error("ECC", BuildToolError
.FILE_NOT_FOUND
, ExtraData
="WORKSPACE = %s" % EccGlobalData
.gWorkspace
)
318 os
.environ
["WORKSPACE"] = EccGlobalData
.gWorkspace
320 self
.SetLogLevel(Options
)
323 if Options
.ConfigFile
is not None:
324 self
.ConfigFile
= Options
.ConfigFile
325 if Options
.OutputFile
is not None:
326 self
.OutputFile
= Options
.OutputFile
327 if Options
.ReportFile
is not None:
328 self
.ReportFile
= Options
.ReportFile
329 if Options
.ExceptionFile
is not None:
330 self
.ExceptionFile
= Options
.ExceptionFile
331 if Options
.Target
is not None:
332 if not os
.path
.isdir(Options
.Target
):
333 EdkLogger
.error("ECC", BuildToolError
.OPTION_VALUE_INVALID
, ExtraData
="Target [%s] does NOT exist" % Options
.Target
)
335 EccGlobalData
.gTarget
= self
.GetRealPathCase(os
.path
.normpath(Options
.Target
))
337 EdkLogger
.warn("Ecc", EdkLogger
.ECC_ERROR
, "The target source tree was not specified, using current WORKSPACE instead!")
338 EccGlobalData
.gTarget
= os
.path
.normpath(os
.getenv("WORKSPACE"))
339 if Options
.keepdatabase
is not None:
341 if Options
.metadata
is not None and Options
.sourcecode
is not None:
342 EdkLogger
.error("ECC", BuildToolError
.OPTION_CONFLICT
, ExtraData
="-m and -s can't be specified at one time")
343 if Options
.metadata
is not None:
344 self
.ScanSourceCode
= False
345 if Options
.sourcecode
is not None:
346 self
.ScanMetaData
= False
347 if Options
.folders
is not None:
352 # Set current log level of the tool based on args
354 # @param Option: The option list including log level setting
356 def SetLogLevel(self
, Option
):
357 if Option
.verbose
is not None:
358 EdkLogger
.SetLevel(EdkLogger
.VERBOSE
)
359 elif Option
.quiet
is not None:
360 EdkLogger
.SetLevel(EdkLogger
.QUIET
)
361 elif Option
.debug
is not None:
362 EdkLogger
.SetLevel(Option
.debug
+ 1)
364 EdkLogger
.SetLevel(EdkLogger
.INFO
)
366 ## Parse command line options
368 # Using standard Python module optparse to parse command line option of this tool.
370 # @retval Opt A optparse.Values object containing the parsed options
371 # @retval Args Target of build command
373 def EccOptionParser(self
):
374 Parser
= OptionParser(description
= self
.Copyright
, version
= self
.Version
, prog
= "Ecc.exe", usage
= "%prog [options]")
375 Parser
.add_option("-t", "--target sourcepath", action
="store", type="string", dest
='Target',
376 help="Check all files under the target workspace.")
377 Parser
.add_option("-c", "--config filename", action
="store", type="string", dest
="ConfigFile",
378 help="Specify a configuration file. Defaultly use config.ini under ECC tool directory.")
379 Parser
.add_option("-o", "--outfile filename", action
="store", type="string", dest
="OutputFile",
380 help="Specify the name of an output file, if and only if one filename was specified.")
381 Parser
.add_option("-r", "--reportfile filename", action
="store", type="string", dest
="ReportFile",
382 help="Specify the name of an report file, if and only if one filename was specified.")
383 Parser
.add_option("-e", "--exceptionfile filename", action
="store", type="string", dest
="ExceptionFile",
384 help="Specify the name of an exception file, if and only if one filename was specified.")
385 Parser
.add_option("-m", "--metadata", action
="store_true", type=None, help="Only scan meta-data files information if this option is specified.")
386 Parser
.add_option("-s", "--sourcecode", action
="store_true", type=None, help="Only scan source code files information if this option is specified.")
387 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.")
388 Parser
.add_option("-l", "--log filename", action
="store", dest
="LogFile", help="""If specified, the tool should emit the changes that
389 were made by the tool after printing the result message.
390 If filename, the emit to the file, otherwise emit to
391 standard output. If no modifications were made, then do not
392 create a log file, or output a log message.""")
393 Parser
.add_option("-q", "--quiet", action
="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
394 Parser
.add_option("-v", "--verbose", action
="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
395 "including library instances selected, final dependency expression, "\
396 "and warning messages, etc.")
397 Parser
.add_option("-d", "--debug", action
="store", type="int", help="Enable debug messages at specified level.")
398 Parser
.add_option("-w", "--workspace", action
="store", type="string", dest
='Workspace', help="Specify workspace.")
399 Parser
.add_option("-f", "--folders", action
="store_true", type=None, help="Only scanning specified folders which are recorded in config.ini file.")
401 (Opt
, Args
)=Parser
.parse_args()
407 # This acts like the main() function for the script, unless it is 'import'ed into another
410 if __name__
== '__main__':
411 # Initialize log system
412 EdkLogger
.Initialize()
413 EdkLogger
.IsRaiseError
= False
415 StartTime
= time
.clock()
417 FinishTime
= time
.clock()
419 BuildDuration
= time
.strftime("%M:%S", time
.gmtime(int(round(FinishTime
- StartTime
))))
420 EdkLogger
.quiet("\n%s [%s]" % (time
.strftime("%H:%M:%S, %b.%d %Y", time
.localtime()), BuildDuration
))