]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Ecc/Ecc.py
05dba2568bcc36683b50edb6bb85628f57f27fc2
[mirror_edk2.git] / BaseTools / Source / Python / Ecc / Ecc.py
1 ## @file
2 # This file is used to be the main entrance of ECC tool
3 #
4 # Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
9 #
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 #
13
14 ##
15 # Import Modules
16 #
17 import os, time, glob, sys
18 import Common.EdkLogger as EdkLogger
19 import Database
20 import EccGlobalData
21 from MetaDataParser import *
22 from optparse import OptionParser
23 from Configuration import Configuration
24 from Check import Check
25 from Common.InfClassObject import Inf
26 from Common.DecClassObject import Dec
27 from Common.DscClassObject import Dsc
28 from Common.FdfClassObject import Fdf
29 from Common.String import NormPath
30 from Common.BuildVersion import gBUILD_VERSION
31 from Common import BuildToolError
32 import c
33 import re, string
34 from Exception import *
35
36 ## Ecc
37 #
38 # This class is used to define Ecc main entrance
39 #
40 # @param object: Inherited from object class
41 #
42 class Ecc(object):
43 def __init__(self):
44 # Version and Copyright
45 self.VersionNumber = ("0.01" + " " + gBUILD_VERSION)
46 self.Version = "%prog Version " + self.VersionNumber
47 self.Copyright = "Copyright (c) 2009 - 2010, Intel Corporation All rights reserved."
48
49 self.InitDefaultConfigIni()
50 self.OutputFile = 'output.txt'
51 self.ReportFile = 'Report.csv'
52 self.ExceptionFile = 'exception.xml'
53 self.IsInit = True
54 self.ScanSourceCode = True
55 self.ScanMetaData = True
56
57 # Parse the options and args
58 self.ParseOption()
59
60 # Generate checkpoints list
61 EccGlobalData.gConfig = Configuration(self.ConfigFile)
62
63 # Generate exception list
64 EccGlobalData.gException = ExceptionCheck(self.ExceptionFile)
65
66 # Init Ecc database
67 EccGlobalData.gDb = Database.Database(Database.DATABASE_PATH)
68 EccGlobalData.gDb.InitDatabase(self.IsInit)
69
70 # Build ECC database
71 self.BuildDatabase()
72
73 # Start to check
74 self.Check()
75
76 # Show report
77 self.GenReport()
78
79 # Close Database
80 EccGlobalData.gDb.Close()
81
82 def InitDefaultConfigIni(self):
83 paths = map(lambda p: os.path.join(p, 'Ecc', 'config.ini'), sys.path)
84 paths = (os.path.realpath('config.ini'),) + tuple(paths)
85 for path in paths:
86 if os.path.exists(path):
87 self.ConfigFile = path
88 return
89 self.ConfigFile = 'config.ini'
90
91 ## BuildDatabase
92 #
93 # Build the database for target
94 #
95 def BuildDatabase(self):
96 # Clean report table
97 EccGlobalData.gDb.TblReport.Drop()
98 EccGlobalData.gDb.TblReport.Create()
99
100 # Build database
101 if self.IsInit:
102 if self.ScanSourceCode:
103 EdkLogger.quiet("Building database for source code ...")
104 c.CollectSourceCodeDataIntoDB(EccGlobalData.gTarget)
105 if self.ScanMetaData:
106 EdkLogger.quiet("Building database for source code done!")
107 self.BuildMetaDataFileDatabase()
108
109 EccGlobalData.gIdentifierTableList = GetTableList((MODEL_FILE_C, MODEL_FILE_H), 'Identifier', EccGlobalData.gDb)
110 EccGlobalData.gCFileList = GetFileList(MODEL_FILE_C, EccGlobalData.gDb)
111 EccGlobalData.gHFileList = GetFileList(MODEL_FILE_H, EccGlobalData.gDb)
112
113 ## BuildMetaDataFileDatabase
114 #
115 # Build the database for meta data files
116 #
117 def BuildMetaDataFileDatabase(self):
118 EdkLogger.quiet("Building database for meta data files ...")
119 Op = open(EccGlobalData.gConfig.MetaDataFileCheckPathOfGenerateFileList, 'w+')
120 #SkipDirs = Read from config file
121 SkipDirs = EccGlobalData.gConfig.SkipDirList
122 SkipDirString = string.join(SkipDirs, '|')
123 p = re.compile(r'.*[\\/](?:%s)[\\/]?.*' % SkipDirString)
124 for Root, Dirs, Files in os.walk(EccGlobalData.gTarget):
125 if p.match(Root.upper()):
126 continue
127
128 for Dir in Dirs:
129 Dirname = os.path.join(Root, Dir)
130 if os.path.islink(Dirname):
131 Dirname = os.path.realpath(Dirname)
132 if os.path.isdir(Dirname):
133 # symlinks to directories are treated as directories
134 Dirs.remove(Dir)
135 Dirs.append(Dirname)
136
137 for File in Files:
138 if len(File) > 4 and File[-4:].upper() == ".DEC":
139 Filename = os.path.normpath(os.path.join(Root, File))
140 EdkLogger.quiet("Parsing %s" % Filename)
141 Op.write("%s\r" % Filename)
142 Dec(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
143 continue
144 if len(File) > 4 and File[-4:].upper() == ".DSC":
145 Filename = os.path.normpath(os.path.join(Root, File))
146 EdkLogger.quiet("Parsing %s" % Filename)
147 Op.write("%s\r" % Filename)
148 Dsc(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
149 continue
150 if len(File) > 4 and File[-4:].upper() == ".INF":
151 Filename = os.path.normpath(os.path.join(Root, File))
152 EdkLogger.quiet("Parsing %s" % Filename)
153 Op.write("%s\r" % Filename)
154 Inf(Filename, True, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
155 continue
156 if len(File) > 4 and File[-4:].upper() == ".FDF":
157 Filename = os.path.normpath(os.path.join(Root, File))
158 EdkLogger.quiet("Parsing %s" % Filename)
159 Op.write("%s\r" % Filename)
160 Fdf(Filename, True, EccGlobalData.gWorkspace, EccGlobalData.gDb)
161 continue
162 Op.close()
163
164 # Commit to database
165 EccGlobalData.gDb.Conn.commit()
166
167 EdkLogger.quiet("Building database for meta data files done!")
168
169 ##
170 #
171 # Check each checkpoint
172 #
173 def Check(self):
174 EdkLogger.quiet("Checking ...")
175 EccCheck = Check()
176 EccCheck.Check()
177 EdkLogger.quiet("Checking done!")
178
179 ##
180 #
181 # Generate the scan report
182 #
183 def GenReport(self):
184 EdkLogger.quiet("Generating report ...")
185 EccGlobalData.gDb.TblReport.ToCSV(self.ReportFile)
186 EdkLogger.quiet("Generating report done!")
187
188 def GetRealPathCase(self, path):
189 TmpPath = path.rstrip(os.sep)
190 PathParts = TmpPath.split(os.sep)
191 if len(PathParts) == 0:
192 return path
193 if len(PathParts) == 1:
194 if PathParts[0].strip().endswith(':'):
195 return PathParts[0].upper()
196 # Relative dir, list . current dir
197 Dirs = os.listdir('.')
198 for Dir in Dirs:
199 if Dir.upper() == PathParts[0].upper():
200 return Dir
201
202 if PathParts[0].strip().endswith(':'):
203 PathParts[0] = PathParts[0].upper()
204 ParentDir = PathParts[0]
205 RealPath = ParentDir
206 if PathParts[0] == '':
207 RealPath = os.sep
208 ParentDir = os.sep
209
210 PathParts.remove(PathParts[0]) # need to remove the parent
211 for Part in PathParts:
212 Dirs = os.listdir(ParentDir + os.sep)
213 for Dir in Dirs:
214 if Dir.upper() == Part.upper():
215 RealPath += os.sep
216 RealPath += Dir
217 break
218 ParentDir += os.sep
219 ParentDir += Dir
220
221 return RealPath
222
223 ## ParseOption
224 #
225 # Parse options
226 #
227 def ParseOption(self):
228 EdkLogger.quiet("Loading ECC configuration ... done")
229 (Options, Target) = self.EccOptionParser()
230
231 if Options.Workspace:
232 os.environ["WORKSPACE"] = Options.Workspace
233
234 # Check workspace envirnoment
235 if "WORKSPACE" not in os.environ:
236 EdkLogger.error("ECC", BuildToolError.ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",
237 ExtraData="WORKSPACE")
238 else:
239 EccGlobalData.gWorkspace = os.path.normpath(os.getenv("WORKSPACE"))
240 if not os.path.exists(EccGlobalData.gWorkspace):
241 EdkLogger.error("ECC", BuildToolError.FILE_NOT_FOUND, ExtraData="WORKSPACE = %s" % EccGlobalData.gWorkspace)
242 os.environ["WORKSPACE"] = EccGlobalData.gWorkspace
243 # Set log level
244 self.SetLogLevel(Options)
245
246 # Set other options
247 if Options.ConfigFile != None:
248 self.ConfigFile = Options.ConfigFile
249 if Options.OutputFile != None:
250 self.OutputFile = Options.OutputFile
251 if Options.ReportFile != None:
252 self.ReportFile = Options.ReportFile
253 if Options.ExceptionFile != None:
254 self.ExceptionFile = Options.ExceptionFile
255 if Options.Target != None:
256 if not os.path.isdir(Options.Target):
257 EdkLogger.error("ECC", BuildToolError.OPTION_VALUE_INVALID, ExtraData="Target [%s] does NOT exist" % Options.Target)
258 else:
259 EccGlobalData.gTarget = self.GetRealPathCase(os.path.normpath(Options.Target))
260 else:
261 EdkLogger.warn("Ecc", EdkLogger.ECC_ERROR, "The target source tree was not specified, using current WORKSPACE instead!")
262 EccGlobalData.gTarget = os.path.normpath(os.getenv("WORKSPACE"))
263 if Options.keepdatabase != None:
264 self.IsInit = False
265 if Options.metadata != None and Options.sourcecode != None:
266 EdkLogger.error("ECC", BuildToolError.OPTION_CONFLICT, ExtraData="-m and -s can't be specified at one time")
267 if Options.metadata != None:
268 self.ScanSourceCode = False
269 if Options.sourcecode != None:
270 self.ScanMetaData = False
271
272 ## SetLogLevel
273 #
274 # Set current log level of the tool based on args
275 #
276 # @param Option: The option list including log level setting
277 #
278 def SetLogLevel(self, Option):
279 if Option.verbose != None:
280 EdkLogger.SetLevel(EdkLogger.VERBOSE)
281 elif Option.quiet != None:
282 EdkLogger.SetLevel(EdkLogger.QUIET)
283 elif Option.debug != None:
284 EdkLogger.SetLevel(Option.debug + 1)
285 else:
286 EdkLogger.SetLevel(EdkLogger.INFO)
287
288 ## Parse command line options
289 #
290 # Using standard Python module optparse to parse command line option of this tool.
291 #
292 # @retval Opt A optparse.Values object containing the parsed options
293 # @retval Args Target of build command
294 #
295 def EccOptionParser(self):
296 Parser = OptionParser(description = self.Copyright, version = self.Version, prog = "Ecc.exe", usage = "%prog [options]")
297 Parser.add_option("-t", "--target sourcepath", action="store", type="string", dest='Target',
298 help="Check all files under the target workspace.")
299 Parser.add_option("-c", "--config filename", action="store", type="string", dest="ConfigFile",
300 help="Specify a configuration file. Defaultly use config.ini under ECC tool directory.")
301 Parser.add_option("-o", "--outfile filename", action="store", type="string", dest="OutputFile",
302 help="Specify the name of an output file, if and only if one filename was specified.")
303 Parser.add_option("-r", "--reportfile filename", action="store", type="string", dest="ReportFile",
304 help="Specify the name of an report file, if and only if one filename was specified.")
305 Parser.add_option("-e", "--exceptionfile filename", action="store", type="string", dest="ExceptionFile",
306 help="Specify the name of an exception file, if and only if one filename was specified.")
307 Parser.add_option("-m", "--metadata", action="store_true", type=None, help="Only scan meta-data files information if this option is specified.")
308 Parser.add_option("-s", "--sourcecode", action="store_true", type=None, help="Only scan source code files information if this option is specified.")
309 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.")
310 Parser.add_option("-l", "--log filename", action="store", dest="LogFile", help="""If specified, the tool should emit the changes that
311 were made by the tool after printing the result message.
312 If filename, the emit to the file, otherwise emit to
313 standard output. If no modifications were made, then do not
314 create a log file, or output a log message.""")
315 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
316 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\
317 "including library instances selected, final dependency expression, "\
318 "and warning messages, etc.")
319 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
320 Parser.add_option("-w", "--workspace", action="store", type="string", dest='Workspace', help="Specify workspace.")
321
322 (Opt, Args)=Parser.parse_args()
323
324 return (Opt, Args)
325
326 ##
327 #
328 # This acts like the main() function for the script, unless it is 'import'ed into another
329 # script.
330 #
331 if __name__ == '__main__':
332 # Initialize log system
333 EdkLogger.Initialize()
334 EdkLogger.IsRaiseError = False
335 EdkLogger.quiet(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[00:00]" + "\n")
336
337 StartTime = time.clock()
338 Ecc = Ecc()
339 FinishTime = time.clock()
340
341 BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime))))
342 EdkLogger.quiet("\n%s [%s]" % (time.strftime("%H:%M:%S, %b.%d %Y", time.localtime()), BuildDuration))