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