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