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