]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Ecc/Ecc.py
ShellPkg: Fix EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL_GUID to match UEFI Shell 2.1 spec
[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
e4ac870f 4# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
40d841f6 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
e4ac870f 62 self.OnlyScan = None\r
fd171542 63\r
30fdf114
LG
64 # Parse the options and args\r
65 self.ParseOption()\r
9508d0fa
LG
66 \r
67 #\r
68 # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP\r
69 #\r
70 WorkspaceDir = os.path.normcase(os.path.normpath(os.environ["WORKSPACE"]))\r
71 os.environ["WORKSPACE"] = WorkspaceDir\r
72 if "ECP_SOURCE" not in os.environ:\r
73 os.environ["ECP_SOURCE"] = os.path.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)\r
74 if "EFI_SOURCE" not in os.environ:\r
75 os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"]\r
76 if "EDK_SOURCE" not in os.environ:\r
77 os.environ["EDK_SOURCE"] = os.environ["ECP_SOURCE"]\r
78\r
79 #\r
80 # Unify case of characters on case-insensitive systems\r
81 #\r
82 EfiSourceDir = os.path.normcase(os.path.normpath(os.environ["EFI_SOURCE"]))\r
83 EdkSourceDir = os.path.normcase(os.path.normpath(os.environ["EDK_SOURCE"]))\r
84 EcpSourceDir = os.path.normcase(os.path.normpath(os.environ["ECP_SOURCE"]))\r
85 \r
86 os.environ["EFI_SOURCE"] = EfiSourceDir\r
87 os.environ["EDK_SOURCE"] = EdkSourceDir\r
88 os.environ["ECP_SOURCE"] = EcpSourceDir\r
89 \r
90 GlobalData.gWorkspace = WorkspaceDir\r
91 GlobalData.gEfiSource = EfiSourceDir\r
92 GlobalData.gEdkSource = EdkSourceDir\r
93 GlobalData.gEcpSource = EcpSourceDir\r
94\r
95 GlobalData.gGlobalDefines["WORKSPACE"] = WorkspaceDir\r
96 GlobalData.gGlobalDefines["EFI_SOURCE"] = EfiSourceDir\r
97 GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir\r
98 GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir\r
99 \r
100 \r
30fdf114
LG
101 # Generate checkpoints list\r
102 EccGlobalData.gConfig = Configuration(self.ConfigFile)\r
fd171542 103\r
30fdf114
LG
104 # Generate exception list\r
105 EccGlobalData.gException = ExceptionCheck(self.ExceptionFile)\r
fd171542 106\r
30fdf114
LG
107 # Init Ecc database\r
108 EccGlobalData.gDb = Database.Database(Database.DATABASE_PATH)\r
109 EccGlobalData.gDb.InitDatabase(self.IsInit)\r
fd171542 110\r
64b2609f
LG
111 #\r
112 # Get files real name in workspace dir\r
113 #\r
114 GlobalData.gAllFiles = DirCache(GlobalData.gWorkspace)\r
115 \r
30fdf114 116 # Build ECC database\r
e4ac870f
LG
117# self.BuildDatabase()\r
118 self.DetectOnlyScanDirs()\r
119 \r
30fdf114
LG
120 # Start to check\r
121 self.Check()\r
fd171542 122\r
30fdf114
LG
123 # Show report\r
124 self.GenReport()\r
fd171542 125\r
30fdf114
LG
126 # Close Database\r
127 EccGlobalData.gDb.Close()\r
128\r
129 def InitDefaultConfigIni(self):\r
130 paths = map(lambda p: os.path.join(p, 'Ecc', 'config.ini'), sys.path)\r
131 paths = (os.path.realpath('config.ini'),) + tuple(paths)\r
132 for path in paths:\r
133 if os.path.exists(path):\r
134 self.ConfigFile = path\r
135 return\r
136 self.ConfigFile = 'config.ini'\r
137\r
e4ac870f
LG
138\r
139 ## DetectOnlyScan\r
140 #\r
141 # Detect whether only scanned folders have been enabled\r
142 #\r
143 def DetectOnlyScanDirs(self):\r
144 if self.OnlyScan == True:\r
145 OnlyScanDirs = []\r
146 # Use regex here if multiple spaces or TAB exists in ScanOnlyDirList in config.ini file\r
147 for folder in re.finditer(r'\S+', EccGlobalData.gConfig.ScanOnlyDirList):\r
148 OnlyScanDirs.append(folder.group())\r
149 if len(OnlyScanDirs) != 0:\r
150 self.BuildDatabase(OnlyScanDirs)\r
151 else:\r
152 EdkLogger.error("ECC", BuildToolError.OPTION_VALUE_INVALID, ExtraData="Use -f option need to fill specific folders in config.ini file")\r
153 else:\r
154 self.BuildDatabase()\r
155 \r
156 \r
30fdf114
LG
157 ## BuildDatabase\r
158 #\r
159 # Build the database for target\r
160 #\r
e4ac870f 161 def BuildDatabase(self, SpeciDirs = None):\r
30fdf114
LG
162 # Clean report table\r
163 EccGlobalData.gDb.TblReport.Drop()\r
164 EccGlobalData.gDb.TblReport.Create()\r
fd171542 165\r
30fdf114 166 # Build database\r
64b2609f 167 if self.IsInit: \r
30fdf114 168 if self.ScanMetaData:\r
64b2609f 169 EdkLogger.quiet("Building database for Meta Data File ...")\r
e4ac870f 170 self.BuildMetaDataFileDatabase(SpeciDirs)\r
64b2609f
LG
171 if self.ScanSourceCode:\r
172 EdkLogger.quiet("Building database for Meta Data File Done!")\r
e4ac870f
LG
173 if SpeciDirs == None:\r
174 c.CollectSourceCodeDataIntoDB(EccGlobalData.gTarget)\r
175 else:\r
176 for specificDir in SpeciDirs:\r
177 c.CollectSourceCodeDataIntoDB(os.path.join(EccGlobalData.gTarget, specificDir))\r
fd171542 178\r
30fdf114 179 EccGlobalData.gIdentifierTableList = GetTableList((MODEL_FILE_C, MODEL_FILE_H), 'Identifier', EccGlobalData.gDb)\r
e56468c0 180 EccGlobalData.gCFileList = GetFileList(MODEL_FILE_C, EccGlobalData.gDb)\r
181 EccGlobalData.gHFileList = GetFileList(MODEL_FILE_H, EccGlobalData.gDb)\r
fd171542 182\r
30fdf114
LG
183 ## BuildMetaDataFileDatabase\r
184 #\r
185 # Build the database for meta data files\r
186 #\r
e4ac870f
LG
187 def BuildMetaDataFileDatabase(self, SpecificDirs = None):\r
188 ScanFolders = []\r
189 if SpecificDirs == None:\r
190 ScanFolders.append(EccGlobalData.gTarget)\r
191 else:\r
192 for specificDir in SpecificDirs: \r
193 ScanFolders.append(os.path.join(EccGlobalData.gTarget, specificDir))\r
30fdf114
LG
194 EdkLogger.quiet("Building database for meta data files ...")\r
195 Op = open(EccGlobalData.gConfig.MetaDataFileCheckPathOfGenerateFileList, 'w+')\r
196 #SkipDirs = Read from config file\r
197 SkipDirs = EccGlobalData.gConfig.SkipDirList\r
fd171542 198 SkipDirString = string.join(SkipDirs, '|')\r
e4ac870f
LG
199# p = re.compile(r'.*[\\/](?:%s)[\\/]?.*' % SkipDirString)\r
200 p = re.compile(r'.*[\\/](?:%s^\S)[\\/]?.*' % SkipDirString)\r
201 for scanFolder in ScanFolders:\r
202 for Root, Dirs, Files in os.walk(scanFolder):\r
203 if p.match(Root.upper()):\r
30fdf114 204 continue\r
e4ac870f
LG
205 for Dir in Dirs:\r
206 Dirname = os.path.join(Root, Dir)\r
207 if os.path.islink(Dirname):\r
208 Dirname = os.path.realpath(Dirname)\r
209 if os.path.isdir(Dirname):\r
210 # symlinks to directories are treated as directories\r
211 Dirs.remove(Dir)\r
212 Dirs.append(Dirname)\r
213 \r
214 for File in Files:\r
215 if len(File) > 4 and File[-4:].upper() == ".DEC":\r
216 Filename = os.path.normpath(os.path.join(Root, File))\r
217 EdkLogger.quiet("Parsing %s" % Filename)\r
218 Op.write("%s\r" % Filename)\r
219 #Dec(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)\r
220 self.MetaFile = DecParser(Filename, MODEL_FILE_DEC, EccGlobalData.gDb.TblDec)\r
221 self.MetaFile.Start()\r
222 continue\r
223 if len(File) > 4 and File[-4:].upper() == ".DSC":\r
224 Filename = os.path.normpath(os.path.join(Root, File))\r
225 EdkLogger.quiet("Parsing %s" % Filename)\r
226 Op.write("%s\r" % Filename)\r
227 #Dsc(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)\r
228 self.MetaFile = DscParser(PathClass(Filename, Root), MODEL_FILE_DSC, MetaFileStorage(EccGlobalData.gDb.TblDsc.Cur, Filename, MODEL_FILE_DSC, True))\r
229 # alwasy do post-process, in case of macros change\r
230 self.MetaFile.DoPostProcess()\r
231 self.MetaFile.Start()\r
232 self.MetaFile._PostProcess()\r
233 continue\r
234 if len(File) > 4 and File[-4:].upper() == ".INF":\r
235 Filename = os.path.normpath(os.path.join(Root, File))\r
236 EdkLogger.quiet("Parsing %s" % Filename)\r
237 Op.write("%s\r" % Filename)\r
238 #Inf(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)\r
239 self.MetaFile = InfParser(Filename, MODEL_FILE_INF, EccGlobalData.gDb.TblInf)\r
240 self.MetaFile.Start()\r
241 continue\r
242 if len(File) > 4 and File[-4:].upper() == ".FDF":\r
243 Filename = os.path.normpath(os.path.join(Root, File))\r
244 EdkLogger.quiet("Parsing %s" % Filename)\r
245 Op.write("%s\r" % Filename)\r
246 Fdf(Filename, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)\r
247 continue\r
30fdf114 248 Op.close()\r
fd171542 249\r
30fdf114
LG
250 # Commit to database\r
251 EccGlobalData.gDb.Conn.commit()\r
fd171542 252\r
30fdf114 253 EdkLogger.quiet("Building database for meta data files done!")\r
fd171542 254\r
30fdf114
LG
255 ##\r
256 #\r
257 # Check each checkpoint\r
258 #\r
259 def Check(self):\r
260 EdkLogger.quiet("Checking ...")\r
261 EccCheck = Check()\r
262 EccCheck.Check()\r
263 EdkLogger.quiet("Checking done!")\r
fd171542 264\r
30fdf114
LG
265 ##\r
266 #\r
267 # Generate the scan report\r
268 #\r
269 def GenReport(self):\r
270 EdkLogger.quiet("Generating report ...")\r
271 EccGlobalData.gDb.TblReport.ToCSV(self.ReportFile)\r
272 EdkLogger.quiet("Generating report done!")\r
fd171542 273\r
30fdf114
LG
274 def GetRealPathCase(self, path):\r
275 TmpPath = path.rstrip(os.sep)\r
276 PathParts = TmpPath.split(os.sep)\r
277 if len(PathParts) == 0:\r
278 return path\r
279 if len(PathParts) == 1:\r
280 if PathParts[0].strip().endswith(':'):\r
281 return PathParts[0].upper()\r
282 # Relative dir, list . current dir\r
283 Dirs = os.listdir('.')\r
284 for Dir in Dirs:\r
285 if Dir.upper() == PathParts[0].upper():\r
286 return Dir\r
fd171542 287\r
30fdf114
LG
288 if PathParts[0].strip().endswith(':'):\r
289 PathParts[0] = PathParts[0].upper()\r
290 ParentDir = PathParts[0]\r
291 RealPath = ParentDir\r
292 if PathParts[0] == '':\r
293 RealPath = os.sep\r
294 ParentDir = os.sep\r
fd171542 295\r
30fdf114
LG
296 PathParts.remove(PathParts[0]) # need to remove the parent\r
297 for Part in PathParts:\r
298 Dirs = os.listdir(ParentDir + os.sep)\r
299 for Dir in Dirs:\r
300 if Dir.upper() == Part.upper():\r
301 RealPath += os.sep\r
302 RealPath += Dir\r
303 break\r
304 ParentDir += os.sep\r
305 ParentDir += Dir\r
fd171542 306\r
30fdf114 307 return RealPath\r
fd171542 308\r
30fdf114
LG
309 ## ParseOption\r
310 #\r
311 # Parse options\r
312 #\r
313 def ParseOption(self):\r
314 EdkLogger.quiet("Loading ECC configuration ... done")\r
315 (Options, Target) = self.EccOptionParser()\r
fd171542 316\r
52302d4d
LG
317 if Options.Workspace:\r
318 os.environ["WORKSPACE"] = Options.Workspace\r
e56468c0 319\r
30fdf114
LG
320 # Check workspace envirnoment\r
321 if "WORKSPACE" not in os.environ:\r
fd171542 322 EdkLogger.error("ECC", BuildToolError.ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
30fdf114
LG
323 ExtraData="WORKSPACE")\r
324 else:\r
325 EccGlobalData.gWorkspace = os.path.normpath(os.getenv("WORKSPACE"))\r
326 if not os.path.exists(EccGlobalData.gWorkspace):\r
327 EdkLogger.error("ECC", BuildToolError.FILE_NOT_FOUND, ExtraData="WORKSPACE = %s" % EccGlobalData.gWorkspace)\r
328 os.environ["WORKSPACE"] = EccGlobalData.gWorkspace\r
329 # Set log level\r
330 self.SetLogLevel(Options)\r
fd171542 331\r
30fdf114
LG
332 # Set other options\r
333 if Options.ConfigFile != None:\r
334 self.ConfigFile = Options.ConfigFile\r
335 if Options.OutputFile != None:\r
336 self.OutputFile = Options.OutputFile\r
337 if Options.ReportFile != None:\r
338 self.ReportFile = Options.ReportFile\r
52302d4d
LG
339 if Options.ExceptionFile != None:\r
340 self.ExceptionFile = Options.ExceptionFile\r
30fdf114
LG
341 if Options.Target != None:\r
342 if not os.path.isdir(Options.Target):\r
343 EdkLogger.error("ECC", BuildToolError.OPTION_VALUE_INVALID, ExtraData="Target [%s] does NOT exist" % Options.Target)\r
344 else:\r
345 EccGlobalData.gTarget = self.GetRealPathCase(os.path.normpath(Options.Target))\r
346 else:\r
347 EdkLogger.warn("Ecc", EdkLogger.ECC_ERROR, "The target source tree was not specified, using current WORKSPACE instead!")\r
348 EccGlobalData.gTarget = os.path.normpath(os.getenv("WORKSPACE"))\r
349 if Options.keepdatabase != None:\r
350 self.IsInit = False\r
351 if Options.metadata != None and Options.sourcecode != None:\r
352 EdkLogger.error("ECC", BuildToolError.OPTION_CONFLICT, ExtraData="-m and -s can't be specified at one time")\r
353 if Options.metadata != None:\r
354 self.ScanSourceCode = False\r
355 if Options.sourcecode != None:\r
356 self.ScanMetaData = False\r
e4ac870f
LG
357 if Options.folders != None:\r
358 self.OnlyScan = True\r
fd171542 359\r
30fdf114
LG
360 ## SetLogLevel\r
361 #\r
362 # Set current log level of the tool based on args\r
363 #\r
fd171542 364 # @param Option: The option list including log level setting\r
30fdf114
LG
365 #\r
366 def SetLogLevel(self, Option):\r
367 if Option.verbose != None:\r
368 EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
369 elif Option.quiet != None:\r
370 EdkLogger.SetLevel(EdkLogger.QUIET)\r
371 elif Option.debug != None:\r
372 EdkLogger.SetLevel(Option.debug + 1)\r
373 else:\r
374 EdkLogger.SetLevel(EdkLogger.INFO)\r
375\r
376 ## Parse command line options\r
377 #\r
378 # Using standard Python module optparse to parse command line option of this tool.\r
379 #\r
380 # @retval Opt A optparse.Values object containing the parsed options\r
381 # @retval Args Target of build command\r
382 #\r
383 def EccOptionParser(self):\r
384 Parser = OptionParser(description = self.Copyright, version = self.Version, prog = "Ecc.exe", usage = "%prog [options]")\r
385 Parser.add_option("-t", "--target sourcepath", action="store", type="string", dest='Target',\r
386 help="Check all files under the target workspace.")\r
387 Parser.add_option("-c", "--config filename", action="store", type="string", dest="ConfigFile",\r
388 help="Specify a configuration file. Defaultly use config.ini under ECC tool directory.")\r
389 Parser.add_option("-o", "--outfile filename", action="store", type="string", dest="OutputFile",\r
390 help="Specify the name of an output file, if and only if one filename was specified.")\r
391 Parser.add_option("-r", "--reportfile filename", action="store", type="string", dest="ReportFile",\r
392 help="Specify the name of an report file, if and only if one filename was specified.")\r
52302d4d
LG
393 Parser.add_option("-e", "--exceptionfile filename", action="store", type="string", dest="ExceptionFile",\r
394 help="Specify the name of an exception file, if and only if one filename was specified.")\r
30fdf114
LG
395 Parser.add_option("-m", "--metadata", action="store_true", type=None, help="Only scan meta-data files information if this option is specified.")\r
396 Parser.add_option("-s", "--sourcecode", action="store_true", type=None, help="Only scan source code files information if this option is specified.")\r
397 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 398 Parser.add_option("-l", "--log filename", action="store", dest="LogFile", help="""If specified, the tool should emit the changes that\r
399 were made by the tool after printing the result message.\r
400 If filename, the emit to the file, otherwise emit to\r
401 standard output. If no modifications were made, then do not\r
30fdf114
LG
402 create a log file, or output a log message.""")\r
403 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
404 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\\r
405 "including library instances selected, final dependency expression, "\\r
406 "and warning messages, etc.")\r
407 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
52302d4d 408 Parser.add_option("-w", "--workspace", action="store", type="string", dest='Workspace', help="Specify workspace.")\r
e4ac870f 409 Parser.add_option("-f", "--folders", action="store_true", type=None, help="Only scanning specified folders which are recorded in config.ini file.")\r
fd171542 410\r
30fdf114 411 (Opt, Args)=Parser.parse_args()\r
fd171542 412\r
30fdf114
LG
413 return (Opt, Args)\r
414\r
415##\r
416#\r
417# This acts like the main() function for the script, unless it is 'import'ed into another\r
418# script.\r
419#\r
420if __name__ == '__main__':\r
421 # Initialize log system\r
422 EdkLogger.Initialize()\r
423 EdkLogger.IsRaiseError = False\r
424 EdkLogger.quiet(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[00:00]" + "\n")\r
425\r
426 StartTime = time.clock()\r
427 Ecc = Ecc()\r
428 FinishTime = time.clock()\r
429\r
430 BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime))))\r
431 EdkLogger.quiet("\n%s [%s]" % (time.strftime("%H:%M:%S, %b.%d %Y", time.localtime()), BuildDuration))\r