]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Ecc/Ecc.py
Sync BaseTool trunk (version r2460) into EDKII BaseTools. The change mainly includes:
[mirror_edk2.git] / BaseTools / Source / Python / Ecc / Ecc.py
1 ## @file
2 # This file is used to be the main entrance of ECC tool
3 #
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
9 #
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.
12 #
13
14 ##
15 # Import Modules
16 #
17 import os, time, glob, sys
18 import Common.EdkLogger as EdkLogger
19 import Database
20 import EccGlobalData
21 from MetaDataParser import *
22 from optparse import OptionParser
23 from Configuration import Configuration
24 from Check import Check
25
26
27 from Common.String import NormPath
28 from Common.BuildVersion import gBUILD_VERSION
29 from Common import BuildToolError
30
31 from MetaFileWorkspace.MetaFileParser import DscParser
32 from MetaFileWorkspace.MetaFileParser import DecParser
33 from MetaFileWorkspace.MetaFileParser import InfParser
34 from MetaFileWorkspace.MetaFileParser import Fdf
35 from MetaFileWorkspace.MetaFileTable import MetaFileStorage
36 import c
37 import re, string
38 from Exception import *
39
40 ## Ecc
41 #
42 # This class is used to define Ecc main entrance
43 #
44 # @param object: Inherited from object class
45 #
46 class Ecc(object):
47 def __init__(self):
48 # Version and Copyright
49 self.VersionNumber = ("0.01" + " " + gBUILD_VERSION)
50 self.Version = "%prog Version " + self.VersionNumber
51 self.Copyright = "Copyright (c) 2009 - 2010, Intel Corporation All rights reserved."
52
53 self.InitDefaultConfigIni()
54 self.OutputFile = 'output.txt'
55 self.ReportFile = 'Report.csv'
56 self.ExceptionFile = 'exception.xml'
57 self.IsInit = True
58 self.ScanSourceCode = True
59 self.ScanMetaData = True
60 self.MetaFile = ''
61
62 # Parse the options and args
63 self.ParseOption()
64
65 # Generate checkpoints list
66 EccGlobalData.gConfig = Configuration(self.ConfigFile)
67
68 # Generate exception list
69 EccGlobalData.gException = ExceptionCheck(self.ExceptionFile)
70
71 # Init Ecc database
72 EccGlobalData.gDb = Database.Database(Database.DATABASE_PATH)
73 EccGlobalData.gDb.InitDatabase(self.IsInit)
74
75 # Build ECC database
76 self.BuildDatabase()
77
78 # Start to check
79 self.Check()
80
81 # Show report
82 self.GenReport()
83
84 # Close Database
85 EccGlobalData.gDb.Close()
86
87 def InitDefaultConfigIni(self):
88 paths = map(lambda p: os.path.join(p, 'Ecc', 'config.ini'), sys.path)
89 paths = (os.path.realpath('config.ini'),) + tuple(paths)
90 for path in paths:
91 if os.path.exists(path):
92 self.ConfigFile = path
93 return
94 self.ConfigFile = 'config.ini'
95
96 ## BuildDatabase
97 #
98 # Build the database for target
99 #
100 def BuildDatabase(self):
101 # Clean report table
102 EccGlobalData.gDb.TblReport.Drop()
103 EccGlobalData.gDb.TblReport.Create()
104
105 # Build database
106 if self.IsInit:
107 if self.ScanSourceCode:
108 EdkLogger.quiet("Building database for source code ...")
109 c.CollectSourceCodeDataIntoDB(EccGlobalData.gTarget)
110 if self.ScanMetaData:
111 EdkLogger.quiet("Building database for source code done!")
112 self.BuildMetaDataFileDatabase()
113
114 EccGlobalData.gIdentifierTableList = GetTableList((MODEL_FILE_C, MODEL_FILE_H), 'Identifier', EccGlobalData.gDb)
115 EccGlobalData.gCFileList = GetFileList(MODEL_FILE_C, EccGlobalData.gDb)
116 EccGlobalData.gHFileList = GetFileList(MODEL_FILE_H, EccGlobalData.gDb)
117
118 ## BuildMetaDataFileDatabase
119 #
120 # Build the database for meta data files
121 #
122 def BuildMetaDataFileDatabase(self):
123 EdkLogger.quiet("Building database for meta data files ...")
124 Op = open(EccGlobalData.gConfig.MetaDataFileCheckPathOfGenerateFileList, 'w+')
125 #SkipDirs = Read from config file
126 SkipDirs = EccGlobalData.gConfig.SkipDirList
127 SkipDirString = string.join(SkipDirs, '|')
128 p = re.compile(r'.*[\\/](?:%s)[\\/]?.*' % SkipDirString)
129 for Root, Dirs, Files in os.walk(EccGlobalData.gTarget):
130 if p.match(Root.upper()):
131 continue
132 for Dir in Dirs:
133 Dirname = os.path.join(Root, Dir)
134 if os.path.islink(Dirname):
135 Dirname = os.path.realpath(Dirname)
136 if os.path.isdir(Dirname):
137 # symlinks to directories are treated as directories
138 Dirs.remove(Dir)
139 Dirs.append(Dirname)
140
141 for File in Files:
142 if len(File) > 4 and File[-4:].upper() == ".DEC":
143 Filename = os.path.normpath(os.path.join(Root, File))
144 EdkLogger.quiet("Parsing %s" % Filename)
145 Op.write("%s\r" % Filename)
146 #Dec(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
147 self.MetaFile = DecParser(Filename, MODEL_FILE_DEC, EccGlobalData.gDb.TblDec)
148 self.MetaFile.Start()
149 continue
150 if len(File) > 4 and File[-4:].upper() == ".DSC":
151 Filename = os.path.normpath(os.path.join(Root, File))
152 EdkLogger.quiet("Parsing %s" % Filename)
153 Op.write("%s\r" % Filename)
154 #Dsc(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
155 self.MetaFile = DscParser(Filename, MODEL_FILE_DSC, MetaFileStorage(EccGlobalData.gDb.TblDsc.Cur, Filename, MODEL_FILE_DSC, True))
156 # alwasy do post-process, in case of macros change
157 self.MetaFile.DoPostProcess()
158 self.MetaFile.Start()
159 self.MetaFile._PostProcess()
160 continue
161 if len(File) > 4 and File[-4:].upper() == ".INF":
162 Filename = os.path.normpath(os.path.join(Root, File))
163 EdkLogger.quiet("Parsing %s" % Filename)
164 Op.write("%s\r" % Filename)
165 #Inf(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
166 self.MetaFile = InfParser(Filename, MODEL_FILE_INF, EccGlobalData.gDb.TblInf)
167 self.MetaFile.Start()
168 continue
169 if len(File) > 4 and File[-4:].upper() == ".FDF":
170 Filename = os.path.normpath(os.path.join(Root, File))
171 EdkLogger.quiet("Parsing %s" % Filename)
172 Op.write("%s\r" % Filename)
173 Fdf(Filename, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
174 continue
175 Op.close()
176
177 # Commit to database
178 EccGlobalData.gDb.Conn.commit()
179
180 EdkLogger.quiet("Building database for meta data files done!")
181
182 ##
183 #
184 # Check each checkpoint
185 #
186 def Check(self):
187 EdkLogger.quiet("Checking ...")
188 EccCheck = Check()
189 EccCheck.Check()
190 EdkLogger.quiet("Checking done!")
191
192 ##
193 #
194 # Generate the scan report
195 #
196 def GenReport(self):
197 EdkLogger.quiet("Generating report ...")
198 EccGlobalData.gDb.TblReport.ToCSV(self.ReportFile)
199 EdkLogger.quiet("Generating report done!")
200
201 def GetRealPathCase(self, path):
202 TmpPath = path.rstrip(os.sep)
203 PathParts = TmpPath.split(os.sep)
204 if len(PathParts) == 0:
205 return path
206 if len(PathParts) == 1:
207 if PathParts[0].strip().endswith(':'):
208 return PathParts[0].upper()
209 # Relative dir, list . current dir
210 Dirs = os.listdir('.')
211 for Dir in Dirs:
212 if Dir.upper() == PathParts[0].upper():
213 return Dir
214
215 if PathParts[0].strip().endswith(':'):
216 PathParts[0] = PathParts[0].upper()
217 ParentDir = PathParts[0]
218 RealPath = ParentDir
219 if PathParts[0] == '':
220 RealPath = os.sep
221 ParentDir = os.sep
222
223 PathParts.remove(PathParts[0]) # need to remove the parent
224 for Part in PathParts:
225 Dirs = os.listdir(ParentDir + os.sep)
226 for Dir in Dirs:
227 if Dir.upper() == Part.upper():
228 RealPath += os.sep
229 RealPath += Dir
230 break
231 ParentDir += os.sep
232 ParentDir += Dir
233
234 return RealPath
235
236 ## ParseOption
237 #
238 # Parse options
239 #
240 def ParseOption(self):
241 EdkLogger.quiet("Loading ECC configuration ... done")
242 (Options, Target) = self.EccOptionParser()
243
244 if Options.Workspace:
245 os.environ["WORKSPACE"] = Options.Workspace
246
247 # Check workspace envirnoment
248 if "WORKSPACE" not in os.environ:
249 EdkLogger.error("ECC", BuildToolError.ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
250 ExtraData="WORKSPACE")
251 else:
252 EccGlobalData.gWorkspace = os.path.normpath(os.getenv("WORKSPACE"))
253 if not os.path.exists(EccGlobalData.gWorkspace):
254 EdkLogger.error("ECC", BuildToolError.FILE_NOT_FOUND, ExtraData="WORKSPACE = %s" % EccGlobalData.gWorkspace)
255 os.environ["WORKSPACE"] = EccGlobalData.gWorkspace
256 # Set log level
257 self.SetLogLevel(Options)
258
259 # Set other options
260 if Options.ConfigFile != None:
261 self.ConfigFile = Options.ConfigFile
262 if Options.OutputFile != None:
263 self.OutputFile = Options.OutputFile
264 if Options.ReportFile != None:
265 self.ReportFile = Options.ReportFile
266 if Options.ExceptionFile != None:
267 self.ExceptionFile = Options.ExceptionFile
268 if Options.Target != None:
269 if not os.path.isdir(Options.Target):
270 EdkLogger.error("ECC", BuildToolError.OPTION_VALUE_INVALID, ExtraData="Target [%s] does NOT exist" % Options.Target)
271 else:
272 EccGlobalData.gTarget = self.GetRealPathCase(os.path.normpath(Options.Target))
273 else:
274 EdkLogger.warn("Ecc", EdkLogger.ECC_ERROR, "The target source tree was not specified, using current WORKSPACE instead!")
275 EccGlobalData.gTarget = os.path.normpath(os.getenv("WORKSPACE"))
276 if Options.keepdatabase != None:
277 self.IsInit = False
278 if Options.metadata != None and Options.sourcecode != None:
279 EdkLogger.error("ECC", BuildToolError.OPTION_CONFLICT, ExtraData="-m and -s can't be specified at one time")
280 if Options.metadata != None:
281 self.ScanSourceCode = False
282 if Options.sourcecode != None:
283 self.ScanMetaData = False
284
285 ## SetLogLevel
286 #
287 # Set current log level of the tool based on args
288 #
289 # @param Option: The option list including log level setting
290 #
291 def SetLogLevel(self, Option):
292 if Option.verbose != None:
293 EdkLogger.SetLevel(EdkLogger.VERBOSE)
294 elif Option.quiet != None:
295 EdkLogger.SetLevel(EdkLogger.QUIET)
296 elif Option.debug != None:
297 EdkLogger.SetLevel(Option.debug + 1)
298 else:
299 EdkLogger.SetLevel(EdkLogger.INFO)
300
301 ## Parse command line options
302 #
303 # Using standard Python module optparse to parse command line option of this tool.
304 #
305 # @retval Opt A optparse.Values object containing the parsed options
306 # @retval Args Target of build command
307 #
308 def EccOptionParser(self):
309 Parser = OptionParser(description = self.Copyright, version = self.Version, prog = "Ecc.exe", usage = "%prog [options]")
310 Parser.add_option("-t", "--target sourcepath", action="store", type="string", dest='Target',
311 help="Check all files under the target workspace.")
312 Parser.add_option("-c", "--config filename", action="store", type="string", dest="ConfigFile",
313 help="Specify a configuration file. Defaultly use config.ini under ECC tool directory.")
314 Parser.add_option("-o", "--outfile filename", action="store", type="string", dest="OutputFile",
315 help="Specify the name of an output file, if and only if one filename was specified.")
316 Parser.add_option("-r", "--reportfile filename", action="store", type="string", dest="ReportFile",
317 help="Specify the name of an report file, if and only if one filename was specified.")
318 Parser.add_option("-e", "--exceptionfile filename", action="store", type="string", dest="ExceptionFile",
319 help="Specify the name of an exception file, if and only if one filename was specified.")
320 Parser.add_option("-m", "--metadata", action="store_true", type=None, help="Only scan meta-data files information if this option is specified.")
321 Parser.add_option("-s", "--sourcecode", action="store_true", type=None, help="Only scan source code files information if this option is specified.")
322 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.")
323 Parser.add_option("-l", "--log filename", action="store", dest="LogFile", help="""If specified, the tool should emit the changes that
324 were made by the tool after printing the result message.
325 If filename, the emit to the file, otherwise emit to
326 standard output. If no modifications were made, then do not
327 create a log file, or output a log message.""")
328 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
329 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
330 "including library instances selected, final dependency expression, "\
331 "and warning messages, etc.")
332 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
333 Parser.add_option("-w", "--workspace", action="store", type="string", dest='Workspace', help="Specify workspace.")
334
335 (Opt, Args)=Parser.parse_args()
336
337 return (Opt, Args)
338
339 ##
340 #
341 # This acts like the main() function for the script, unless it is 'import'ed into another
342 # script.
343 #
344 if __name__ == '__main__':
345 # Initialize log system
346 EdkLogger.Initialize()
347 EdkLogger.IsRaiseError = False
348 EdkLogger.quiet(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[00:00]" + "\n")
349
350 StartTime = time.clock()
351 Ecc = Ecc()
352 FinishTime = time.clock()
353
354 BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime))))
355 EdkLogger.quiet("\n%s [%s]" % (time.strftime("%H:%M:%S, %b.%d %Y", time.localtime()), BuildDuration))