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