BaseTools: Use absolute import in Ecc
[mirror_edk2.git] / BaseTools / Source / Python / Ecc / MetaDataParser.py
1 ## @file
2 # This file is used to define common parser functions for meta-data
3 #
4 # Copyright (c) 2008 - 2018, 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 from __future__ import absolute_import
15 import Common.LongFilePathOs as os
16 from CommonDataClass.DataClass import *
17 from .EccToolError import *
18 from Common.MultipleWorkspace import MultipleWorkspace as mws
19 from . import EccGlobalData
20 import re
21 ## Get the inlcude path list for a source file
22 #
23 # 1. Find the source file belongs to which inf file
24 # 2. Find the inf's package
25 # 3. Return the include path list of the package
26 #
27 def GetIncludeListOfFile(WorkSpace, Filepath, Db):
28 IncludeList = []
29 Filepath = os.path.normpath(Filepath)
30 SqlCommand = """
31 select Value1, FullPath from Inf, File where Inf.Model = %s and Inf.BelongsToFile in(
32 select distinct B.BelongsToFile from File as A left join Inf as B
33 where A.ID = B.BelongsToFile and B.Model = %s and (A.Path || '%s' || B.Value1) = '%s')
34 and Inf.BelongsToFile = File.ID""" \
35 % (MODEL_META_DATA_PACKAGE, MODEL_EFI_SOURCE_FILE, '\\', Filepath)
36 RecordSet = Db.TblFile.Exec(SqlCommand)
37 for Record in RecordSet:
38 DecFullPath = os.path.normpath(mws.join(WorkSpace, Record[0]))
39 InfFullPath = os.path.normpath(mws.join(WorkSpace, Record[1]))
40 (DecPath, DecName) = os.path.split(DecFullPath)
41 (InfPath, InfName) = os.path.split(InfFullPath)
42 SqlCommand = """select Value1 from Dec where BelongsToFile =
43 (select ID from File where FullPath = '%s') and Model = %s""" \
44 % (DecFullPath, MODEL_EFI_INCLUDE)
45 NewRecordSet = Db.TblDec.Exec(SqlCommand)
46 if InfPath not in IncludeList:
47 IncludeList.append(InfPath)
48 for NewRecord in NewRecordSet:
49 IncludePath = os.path.normpath(os.path.join(DecPath, NewRecord[0]))
50 if IncludePath not in IncludeList:
51 IncludeList.append(IncludePath)
52
53 return IncludeList
54
55 ## Get the file list
56 #
57 # Search table file and find all specific type files
58 #
59 def GetFileList(FileModel, Db):
60 FileList = []
61 SqlCommand = """select FullPath from File where Model = %s""" % str(FileModel)
62 RecordSet = Db.TblFile.Exec(SqlCommand)
63 for Record in RecordSet:
64 FileList.append(Record[0])
65
66 return FileList
67
68 ## Get the table list
69 #
70 # Search table file and find all small tables
71 #
72 def GetTableList(FileModelList, Table, Db):
73 TableList = []
74 SqlCommand = """select ID from File where Model in %s""" % str(FileModelList)
75 RecordSet = Db.TblFile.Exec(SqlCommand)
76 for Record in RecordSet:
77 TableName = Table + str(Record[0])
78 TableList.append(TableName)
79
80 return TableList
81
82 ## ParseHeaderCommentSection
83 #
84 # Parse Header comment section lines, extract Abstract, Description, Copyright
85 # , License lines
86 #
87 # @param CommentList: List of (Comment, LineNumber)
88 # @param FileName: FileName of the comment
89 #
90 def ParseHeaderCommentSection(CommentList, FileName = None):
91
92 Abstract = ''
93 Description = ''
94 Copyright = ''
95 License = ''
96 EndOfLine = "\n"
97 STR_HEADER_COMMENT_START = "@file"
98
99 #
100 # used to indicate the state of processing header comment section of dec,
101 # inf files
102 #
103 HEADER_COMMENT_NOT_STARTED = -1
104 HEADER_COMMENT_STARTED = 0
105 HEADER_COMMENT_FILE = 1
106 HEADER_COMMENT_ABSTRACT = 2
107 HEADER_COMMENT_DESCRIPTION = 3
108 HEADER_COMMENT_COPYRIGHT = 4
109 HEADER_COMMENT_LICENSE = 5
110 HEADER_COMMENT_END = 6
111 #
112 # first find the last copyright line
113 #
114 Last = 0
115 HeaderCommentStage = HEADER_COMMENT_NOT_STARTED
116 for Index in xrange(len(CommentList)-1, 0, -1):
117 Line = CommentList[Index][0]
118 if _IsCopyrightLine(Line):
119 Last = Index
120 break
121
122 for Item in CommentList:
123 Line = Item[0]
124 LineNo = Item[1]
125
126 if not Line.startswith('#') and Line:
127 SqlStatement = """ select ID from File where FullPath like '%s'""" % FileName
128 ResultSet = EccGlobalData.gDb.TblFile.Exec(SqlStatement)
129 for Result in ResultSet:
130 Msg = 'Comment must start with #'
131 EccGlobalData.gDb.TblReport.Insert(ERROR_DOXYGEN_CHECK_FILE_HEADER, Msg, "File", Result[0])
132 Comment = CleanString2(Line)[1]
133 Comment = Comment.strip()
134 #
135 # if there are blank lines between License or Description, keep them as they would be
136 # indication of different block; or in the position that Abstract should be, also keep it
137 # as it indicates that no abstract
138 #
139 if not Comment and HeaderCommentStage not in [HEADER_COMMENT_LICENSE, \
140 HEADER_COMMENT_DESCRIPTION, HEADER_COMMENT_ABSTRACT]:
141 continue
142
143 if HeaderCommentStage == HEADER_COMMENT_NOT_STARTED:
144 if Comment.startswith(STR_HEADER_COMMENT_START):
145 HeaderCommentStage = HEADER_COMMENT_ABSTRACT
146 else:
147 License += Comment + EndOfLine
148 else:
149 if HeaderCommentStage == HEADER_COMMENT_ABSTRACT:
150 #
151 # in case there is no abstract and description
152 #
153 if not Comment:
154 Abstract = ''
155 HeaderCommentStage = HEADER_COMMENT_DESCRIPTION
156 elif _IsCopyrightLine(Comment):
157 Copyright += Comment + EndOfLine
158 HeaderCommentStage = HEADER_COMMENT_COPYRIGHT
159 else:
160 Abstract += Comment + EndOfLine
161 HeaderCommentStage = HEADER_COMMENT_DESCRIPTION
162 elif HeaderCommentStage == HEADER_COMMENT_DESCRIPTION:
163 #
164 # in case there is no description
165 #
166 if _IsCopyrightLine(Comment):
167 Copyright += Comment + EndOfLine
168 HeaderCommentStage = HEADER_COMMENT_COPYRIGHT
169 else:
170 Description += Comment + EndOfLine
171 elif HeaderCommentStage == HEADER_COMMENT_COPYRIGHT:
172 if _IsCopyrightLine(Comment):
173 Copyright += Comment + EndOfLine
174 else:
175 #
176 # Contents after copyright line are license, those non-copyright lines in between
177 # copyright line will be discarded
178 #
179 if LineNo > Last:
180 if License:
181 License += EndOfLine
182 License += Comment + EndOfLine
183 HeaderCommentStage = HEADER_COMMENT_LICENSE
184 else:
185 if not Comment and not License:
186 continue
187 License += Comment + EndOfLine
188
189 if not Copyright.strip():
190 SqlStatement = """ select ID from File where FullPath like '%s'""" % FileName
191 ResultSet = EccGlobalData.gDb.TblFile.Exec(SqlStatement)
192 for Result in ResultSet:
193 Msg = 'Header comment section must have copyright information'
194 EccGlobalData.gDb.TblReport.Insert(ERROR_DOXYGEN_CHECK_FILE_HEADER, Msg, "File", Result[0])
195
196 if not License.strip():
197 SqlStatement = """ select ID from File where FullPath like '%s'""" % FileName
198 ResultSet = EccGlobalData.gDb.TblFile.Exec(SqlStatement)
199 for Result in ResultSet:
200 Msg = 'Header comment section must have license information'
201 EccGlobalData.gDb.TblReport.Insert(ERROR_DOXYGEN_CHECK_FILE_HEADER, Msg, "File", Result[0])
202
203 if not Abstract.strip() or Abstract.find('Component description file') > -1:
204 SqlStatement = """ select ID from File where FullPath like '%s'""" % FileName
205 ResultSet = EccGlobalData.gDb.TblFile.Exec(SqlStatement)
206 for Result in ResultSet:
207 Msg = 'Header comment section must have Abstract information.'
208 EccGlobalData.gDb.TblReport.Insert(ERROR_DOXYGEN_CHECK_FILE_HEADER, Msg, "File", Result[0])
209
210 return Abstract.strip(), Description.strip(), Copyright.strip(), License.strip()
211
212 ## _IsCopyrightLine
213 # check whether current line is copyright line, the criteria is whether there is case insensitive keyword "Copyright"
214 # followed by zero or more white space characters followed by a "(" character
215 #
216 # @param LineContent: the line need to be checked
217 # @return: True if current line is copyright line, False else
218 #
219 def _IsCopyrightLine (LineContent):
220 LineContent = LineContent.upper()
221 Result = False
222
223 ReIsCopyrightRe = re.compile(r"""(^|\s)COPYRIGHT *\(""", re.DOTALL)
224 if ReIsCopyrightRe.search(LineContent):
225 Result = True
226
227 return Result
228
229
230 ## CleanString2
231 #
232 # Split comments in a string
233 # Remove spaces
234 #
235 # @param Line: The string to be cleaned
236 # @param CommentCharacter: Comment char, used to ignore comment content,
237 # default is DataType.TAB_COMMENT_SPLIT
238 #
239 def CleanString2(Line, CommentCharacter='#', AllowCppStyleComment=False):
240 #
241 # remove whitespace
242 #
243 Line = Line.strip()
244 #
245 # Replace EDK1's comment character
246 #
247 if AllowCppStyleComment:
248 Line = Line.replace('//', CommentCharacter)
249 #
250 # separate comments and statements
251 #
252 LineParts = Line.split(CommentCharacter, 1)
253 #
254 # remove whitespace again
255 #
256 Line = LineParts[0].strip()
257 if len(LineParts) > 1:
258 Comment = LineParts[1].strip()
259 #
260 # Remove prefixed and trailing comment characters
261 #
262 Start = 0
263 End = len(Comment)
264 while Start < End and Comment.startswith(CommentCharacter, Start, End):
265 Start += 1
266 while End >= 0 and Comment.endswith(CommentCharacter, Start, End):
267 End -= 1
268 Comment = Comment[Start:End]
269 Comment = Comment.strip()
270 else:
271 Comment = ''
272
273 return Line, Comment