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