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