]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Ecc/Ecc.py
There is a limitation on WINDOWS OS for the length of entire file path can’t be large...
[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
fd171542 183\r
30fdf114
LG
184 ## BuildMetaDataFileDatabase\r
185 #\r
186 # Build the database for meta data files\r
187 #\r
e4ac870f
LG
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
30fdf114
LG
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
fd171542 199 SkipDirString = string.join(SkipDirs, '|')\r
e4ac870f
LG
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
30fdf114 205 continue\r
e4ac870f
LG
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
30fdf114 249 Op.close()\r
fd171542 250\r
30fdf114
LG
251 # Commit to database\r
252 EccGlobalData.gDb.Conn.commit()\r
fd171542 253\r
30fdf114 254 EdkLogger.quiet("Building database for meta data files done!")\r
fd171542 255\r
30fdf114
LG
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
fd171542 265\r
30fdf114
LG
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
fd171542 274\r
30fdf114
LG
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
fd171542 288\r
30fdf114
LG
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
fd171542 296\r
30fdf114
LG
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
fd171542 307\r
30fdf114 308 return RealPath\r
fd171542 309\r
30fdf114
LG
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
fd171542 317\r
52302d4d
LG
318 if Options.Workspace:\r
319 os.environ["WORKSPACE"] = Options.Workspace\r
e56468c0 320\r
30fdf114
LG
321 # Check workspace envirnoment\r
322 if "WORKSPACE" not in os.environ:\r
fd171542 323 EdkLogger.error("ECC", BuildToolError.ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
30fdf114
LG
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
fd171542 332\r
30fdf114
LG
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
52302d4d
LG
340 if Options.ExceptionFile != None:\r
341 self.ExceptionFile = Options.ExceptionFile\r
30fdf114
LG
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
e4ac870f
LG
358 if Options.folders != None:\r
359 self.OnlyScan = True\r
fd171542 360\r
30fdf114
LG
361 ## SetLogLevel\r
362 #\r
363 # Set current log level of the tool based on args\r
364 #\r
fd171542 365 # @param Option: The option list including log level setting\r
30fdf114
LG
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
52302d4d
LG
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
30fdf114
LG
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
fd171542 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
30fdf114
LG
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
52302d4d 409 Parser.add_option("-w", "--workspace", action="store", type="string", dest='Workspace', help="Specify workspace.")\r
e4ac870f 410 Parser.add_option("-f", "--folders", action="store_true", type=None, help="Only scanning specified folders which are recorded in config.ini file.")\r
fd171542 411\r
30fdf114 412 (Opt, Args)=Parser.parse_args()\r
fd171542 413\r
30fdf114
LG
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