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