]>
Commit | Line | Data |
---|---|---|
4234283c LG |
1 | ## @file |
2 | # Common routines used by all tools | |
3 | # | |
4 | # Copyright (c) 2011, Intel Corporation. All rights reserved.<BR> | |
5 | # | |
6 | # This program and the accompanying materials are licensed and made available | |
7 | # under the terms and conditions of the BSD License which accompanies this | |
8 | # distribution. The full text of the license may be found at | |
9 | # http://opensource.org/licenses/bsd-license.php | |
10 | # | |
11 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
12 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
13 | # | |
14 | ||
15 | ''' | |
16 | Misc | |
17 | ''' | |
18 | ||
19 | ## | |
20 | # Import Modules | |
21 | # | |
22 | import os.path | |
23 | from os import access | |
24 | from os import F_OK | |
25 | from os import makedirs | |
26 | from os import getcwd | |
27 | from os import chdir | |
28 | from os import listdir | |
29 | from os import remove | |
30 | from os import rmdir | |
31 | from os import linesep | |
32 | from os import walk | |
33 | from os import environ | |
34 | import re | |
35 | from UserDict import IterableUserDict | |
36 | ||
37 | import Logger.Log as Logger | |
38 | from Logger import StringTable as ST | |
39 | from Logger import ToolError | |
40 | from Library import GlobalData | |
41 | from Library.DataType import SUP_MODULE_LIST | |
42 | from Library.DataType import END_OF_LINE | |
43 | from Library.DataType import TAB_SPLIT | |
44 | from Library.DataType import LANGUAGE_EN_US | |
45 | from Library.String import GetSplitValueList | |
46 | from Library.ParserValidate import IsValidHexVersion | |
47 | from Library.ParserValidate import IsValidPath | |
48 | from Object.POM.CommonObject import TextObject | |
49 | ||
50 | ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C | |
51 | # structure style | |
52 | # | |
53 | # @param Guid: The GUID string | |
54 | # | |
55 | def GuidStringToGuidStructureString(Guid): | |
56 | GuidList = Guid.split('-') | |
57 | Result = '{' | |
58 | for Index in range(0, 3, 1): | |
59 | Result = Result + '0x' + GuidList[Index] + ', ' | |
60 | Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4] | |
61 | for Index in range(0, 12, 2): | |
62 | Result = Result + ', 0x' + GuidList[4][Index:Index + 2] | |
63 | Result += '}}' | |
64 | return Result | |
65 | ||
66 | ## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | |
67 | # | |
68 | # @param GuidValue: The GUID value | |
69 | # | |
70 | def CheckGuidRegFormat(GuidValue): | |
71 | ## Regular expression used to find out register format of GUID | |
72 | # | |
73 | RegFormatGuidPattern = re.compile("^\s*([0-9a-fA-F]){8}-" | |
74 | "([0-9a-fA-F]){4}-" | |
75 | "([0-9a-fA-F]){4}-" | |
76 | "([0-9a-fA-F]){4}-" | |
77 | "([0-9a-fA-F]){12}\s*$") | |
78 | ||
79 | if RegFormatGuidPattern.match(GuidValue): | |
80 | return True | |
81 | else: | |
82 | return False | |
83 | ||
84 | ||
85 | ## Convert GUID string in C structure style to | |
86 | # xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | |
87 | # | |
88 | # @param GuidValue: The GUID value in C structure format | |
89 | # | |
90 | def GuidStructureStringToGuidString(GuidValue): | |
91 | GuidValueString = GuidValue.lower().replace("{", "").replace("}", "").\ | |
92 | replace(" ", "").replace(";", "") | |
93 | GuidValueList = GuidValueString.split(",") | |
94 | if len(GuidValueList) != 11: | |
95 | return '' | |
96 | try: | |
97 | return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % ( | |
98 | int(GuidValueList[0], 16), | |
99 | int(GuidValueList[1], 16), | |
100 | int(GuidValueList[2], 16), | |
101 | int(GuidValueList[3], 16), | |
102 | int(GuidValueList[4], 16), | |
103 | int(GuidValueList[5], 16), | |
104 | int(GuidValueList[6], 16), | |
105 | int(GuidValueList[7], 16), | |
106 | int(GuidValueList[8], 16), | |
107 | int(GuidValueList[9], 16), | |
108 | int(GuidValueList[10], 16) | |
109 | ) | |
110 | except BaseException: | |
111 | return '' | |
112 | ||
113 | ## Create directories | |
114 | # | |
115 | # @param Directory: The directory name | |
116 | # | |
117 | def CreateDirectory(Directory): | |
118 | if Directory == None or Directory.strip() == "": | |
119 | return True | |
120 | try: | |
121 | if not access(Directory, F_OK): | |
122 | makedirs(Directory) | |
123 | except BaseException: | |
124 | return False | |
125 | return True | |
126 | ||
127 | ## Remove directories, including files and sub-directories in it | |
128 | # | |
129 | # @param Directory: The directory name | |
130 | # | |
131 | def RemoveDirectory(Directory, Recursively=False): | |
132 | if Directory == None or Directory.strip() == "" or not \ | |
133 | os.path.exists(Directory): | |
134 | return | |
135 | if Recursively: | |
136 | CurrentDirectory = getcwd() | |
137 | chdir(Directory) | |
138 | for File in listdir("."): | |
139 | if os.path.isdir(File): | |
140 | RemoveDirectory(File, Recursively) | |
141 | else: | |
142 | remove(File) | |
143 | chdir(CurrentDirectory) | |
144 | rmdir(Directory) | |
145 | ||
146 | ## Store content in file | |
147 | # | |
148 | # This method is used to save file only when its content is changed. This is | |
149 | # quite useful for "make" system to decide what will be re-built and what | |
150 | # won't. | |
151 | # | |
152 | # @param File: The path of file | |
153 | # @param Content: The new content of the file | |
154 | # @param IsBinaryFile: The flag indicating if the file is binary file | |
155 | # or not | |
156 | # | |
157 | def SaveFileOnChange(File, Content, IsBinaryFile=True): | |
158 | if not IsBinaryFile: | |
159 | Content = Content.replace("\n", linesep) | |
160 | ||
161 | if os.path.exists(File): | |
162 | try: | |
163 | if Content == open(File, "rb").read(): | |
164 | return False | |
165 | except BaseException: | |
166 | Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File) | |
167 | ||
168 | CreateDirectory(os.path.dirname(File)) | |
169 | try: | |
170 | FileFd = open(File, "wb") | |
171 | FileFd.write(Content) | |
172 | FileFd.close() | |
173 | except BaseException: | |
174 | Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File) | |
175 | ||
176 | return True | |
177 | ||
178 | ## Get all files of a directory | |
179 | # | |
180 | # @param Root: Root dir | |
181 | # @param SkipList : The files need be skipped | |
182 | # | |
183 | def GetFiles(Root, SkipList=None, FullPath=True): | |
184 | OriPath = os.path.normpath(Root) | |
185 | FileList = [] | |
186 | for Root, Dirs, Files in walk(Root): | |
187 | if SkipList: | |
188 | for Item in SkipList: | |
189 | if Item in Dirs: | |
190 | Dirs.remove(Item) | |
191 | for Dir in Dirs: | |
192 | if Dir.startswith('.'): | |
193 | Dirs.remove(Dir) | |
194 | ||
195 | for File in Files: | |
196 | if File.startswith('.'): | |
197 | continue | |
198 | File = os.path.normpath(os.path.join(Root, File)) | |
199 | if not FullPath: | |
200 | File = File[len(OriPath) + 1:] | |
201 | FileList.append(File) | |
202 | ||
203 | return FileList | |
204 | ||
205 | ## Get all non-metadata files of a directory | |
206 | # | |
207 | # @param Root: Root Dir | |
208 | # @param SkipList : List of path need be skipped | |
209 | # @param FullPath: True if the returned file should be full path | |
210 | # @param PrefixPath: the path that need to be added to the files found | |
211 | # @return: the list of files found | |
212 | # | |
213 | def GetNonMetaDataFiles(Root, SkipList, FullPath, PrefixPath): | |
214 | FileList = GetFiles(Root, SkipList, FullPath) | |
215 | NewFileList = [] | |
216 | for File in FileList: | |
217 | ExtName = os.path.splitext(File)[1] | |
218 | # | |
219 | # skip '.dec', '.inf', '.dsc', '.fdf' files | |
220 | # | |
221 | if ExtName.lower() not in ['.dec', '.inf', '.dsc', '.fdf']: | |
222 | NewFileList.append(os.path.normpath(os.path.join(PrefixPath, File))) | |
223 | ||
224 | return NewFileList | |
225 | ||
226 | ## Check if given file exists or not | |
227 | # | |
228 | # @param File: File name or path to be checked | |
229 | # @param Dir: The directory the file is relative to | |
230 | # | |
231 | def ValidFile(File, Ext=None): | |
232 | File = File.replace('\\', '/') | |
233 | if Ext != None: | |
234 | FileExt = os.path.splitext(File)[1] | |
235 | if FileExt.lower() != Ext.lower(): | |
236 | return False | |
237 | if not os.path.exists(File): | |
238 | return False | |
239 | return True | |
240 | ||
241 | ## RealPath | |
242 | # | |
243 | # @param File: File name or path to be checked | |
244 | # @param Dir: The directory the file is relative to | |
245 | # @param OverrideDir: The override directory | |
246 | # | |
247 | def RealPath(File, Dir='', OverrideDir=''): | |
248 | NewFile = os.path.normpath(os.path.join(Dir, File)) | |
249 | NewFile = GlobalData.gALL_FILES[NewFile] | |
250 | if not NewFile and OverrideDir: | |
251 | NewFile = os.path.normpath(os.path.join(OverrideDir, File)) | |
252 | NewFile = GlobalData.gALL_FILES[NewFile] | |
253 | return NewFile | |
254 | ||
255 | ## RealPath2 | |
256 | # | |
257 | # @param File: File name or path to be checked | |
258 | # @param Dir: The directory the file is relative to | |
259 | # @param OverrideDir: The override directory | |
260 | # | |
261 | def RealPath2(File, Dir='', OverrideDir=''): | |
262 | if OverrideDir: | |
263 | NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join\ | |
264 | (OverrideDir, File))] | |
265 | if NewFile: | |
266 | if OverrideDir[-1] == os.path.sep: | |
267 | return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)] | |
268 | else: | |
269 | return NewFile[len(OverrideDir) + 1:], \ | |
270 | NewFile[0:len(OverrideDir)] | |
271 | ||
272 | NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join(Dir, File))] | |
273 | if NewFile: | |
274 | if Dir: | |
275 | if Dir[-1] == os.path.sep: | |
276 | return NewFile[len(Dir):], NewFile[0:len(Dir)] | |
277 | else: | |
278 | return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)] | |
279 | else: | |
280 | return NewFile, '' | |
281 | ||
282 | return None, None | |
283 | ||
284 | ## A dict which can access its keys and/or values orderly | |
285 | # | |
286 | # The class implements a new kind of dict which its keys or values can be | |
287 | # accessed in the order they are added into the dict. It guarantees the order | |
288 | # by making use of an internal list to keep a copy of keys. | |
289 | # | |
290 | class Sdict(IterableUserDict): | |
291 | ## Constructor | |
292 | # | |
293 | def __init__(self): | |
294 | IterableUserDict.__init__(self) | |
295 | self._key_list = [] | |
296 | ||
297 | ## [] operator | |
298 | # | |
299 | def __setitem__(self, Key, Value): | |
300 | if Key not in self._key_list: | |
301 | self._key_list.append(Key) | |
302 | IterableUserDict.__setitem__(self, Key, Value) | |
303 | ||
304 | ## del operator | |
305 | # | |
306 | def __delitem__(self, Key): | |
307 | self._key_list.remove(Key) | |
308 | IterableUserDict.__delitem__(self, Key) | |
309 | ||
310 | ## used in "for k in dict" loop to ensure the correct order | |
311 | # | |
312 | def __iter__(self): | |
313 | return self.iterkeys() | |
314 | ||
315 | ## len() support | |
316 | # | |
317 | def __len__(self): | |
318 | return len(self._key_list) | |
319 | ||
320 | ## "in" test support | |
321 | # | |
322 | def __contains__(self, Key): | |
323 | return Key in self._key_list | |
324 | ||
325 | ## indexof support | |
326 | # | |
327 | def index(self, Key): | |
328 | return self._key_list.index(Key) | |
329 | ||
330 | ## insert support | |
331 | # | |
332 | def insert(self, Key, Newkey, Newvalue, Order): | |
333 | Index = self._key_list.index(Key) | |
334 | if Order == 'BEFORE': | |
335 | self._key_list.insert(Index, Newkey) | |
336 | IterableUserDict.__setitem__(self, Newkey, Newvalue) | |
337 | elif Order == 'AFTER': | |
338 | self._key_list.insert(Index + 1, Newkey) | |
339 | IterableUserDict.__setitem__(self, Newkey, Newvalue) | |
340 | ||
341 | ## append support | |
342 | # | |
343 | def append(self, Sdict2): | |
344 | for Key in Sdict2: | |
345 | if Key not in self._key_list: | |
346 | self._key_list.append(Key) | |
347 | IterableUserDict.__setitem__(self, Key, Sdict2[Key]) | |
348 | ## hash key | |
349 | # | |
350 | def has_key(self, Key): | |
351 | return Key in self._key_list | |
352 | ||
353 | ## Empty the dict | |
354 | # | |
355 | def clear(self): | |
356 | self._key_list = [] | |
357 | IterableUserDict.clear(self) | |
358 | ||
359 | ## Return a copy of keys | |
360 | # | |
361 | def keys(self): | |
362 | Keys = [] | |
363 | for Key in self._key_list: | |
364 | Keys.append(Key) | |
365 | return Keys | |
366 | ||
367 | ## Return a copy of values | |
368 | # | |
369 | def values(self): | |
370 | Values = [] | |
371 | for Key in self._key_list: | |
372 | Values.append(self[Key]) | |
373 | return Values | |
374 | ||
375 | ## Return a copy of (key, value) list | |
376 | # | |
377 | def items(self): | |
378 | Items = [] | |
379 | for Key in self._key_list: | |
380 | Items.append((Key, self[Key])) | |
381 | return Items | |
382 | ||
383 | ## Iteration support | |
384 | # | |
385 | def iteritems(self): | |
386 | return iter(self.items()) | |
387 | ||
388 | ## Keys interation support | |
389 | # | |
390 | def iterkeys(self): | |
391 | return iter(self.keys()) | |
392 | ||
393 | ## Values interation support | |
394 | # | |
395 | def itervalues(self): | |
396 | return iter(self.values()) | |
397 | ||
398 | ## Return value related to a key, and remove the (key, value) from the dict | |
399 | # | |
400 | def pop(self, Key, *Dv): | |
401 | Value = None | |
402 | if Key in self._key_list: | |
403 | Value = self[Key] | |
404 | self.__delitem__(Key) | |
405 | elif len(Dv) != 0 : | |
406 | Value = Dv[0] | |
407 | return Value | |
408 | ||
409 | ## Return (key, value) pair, and remove the (key, value) from the dict | |
410 | # | |
411 | def popitem(self): | |
412 | Key = self._key_list[-1] | |
413 | Value = self[Key] | |
414 | self.__delitem__(Key) | |
415 | return Key, Value | |
416 | ## update method | |
417 | # | |
418 | def update(self, Dict=None, **Kwargs): | |
419 | if Dict != None: | |
420 | for Key1, Val1 in Dict.items(): | |
421 | self[Key1] = Val1 | |
422 | if len(Kwargs): | |
423 | for Key1, Val1 in Kwargs.items(): | |
424 | self[Key1] = Val1 | |
425 | ||
426 | ## CommonPath | |
427 | # | |
428 | # @param PathList: PathList | |
429 | # | |
430 | def CommonPath(PathList): | |
431 | Path1 = min(PathList).split(os.path.sep) | |
432 | Path2 = max(PathList).split(os.path.sep) | |
433 | for Index in xrange(min(len(Path1), len(Path2))): | |
434 | if Path1[Index] != Path2[Index]: | |
435 | return os.path.sep.join(Path1[:Index]) | |
436 | return os.path.sep.join(Path1) | |
437 | ||
438 | ## PathClass | |
439 | # | |
440 | class PathClass(object): | |
441 | def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False, | |
442 | Arch='COMMON', ToolChainFamily='', Target='', TagName='', \ | |
443 | ToolCode=''): | |
444 | self.Arch = Arch | |
445 | self.File = str(File) | |
446 | if os.path.isabs(self.File): | |
447 | self.Root = '' | |
448 | self.AlterRoot = '' | |
449 | else: | |
450 | self.Root = str(Root) | |
451 | self.AlterRoot = str(AlterRoot) | |
452 | ||
453 | # | |
454 | # Remove any '.' and '..' in path | |
455 | # | |
456 | if self.Root: | |
457 | self.Path = os.path.normpath(os.path.join(self.Root, self.File)) | |
458 | self.Root = os.path.normpath(CommonPath([self.Root, self.Path])) | |
459 | # | |
460 | # eliminate the side-effect of 'C:' | |
461 | # | |
462 | if self.Root[-1] == ':': | |
463 | self.Root += os.path.sep | |
464 | # | |
465 | # file path should not start with path separator | |
466 | # | |
467 | if self.Root[-1] == os.path.sep: | |
468 | self.File = self.Path[len(self.Root):] | |
469 | else: | |
470 | self.File = self.Path[len(self.Root) + 1:] | |
471 | else: | |
472 | self.Path = os.path.normpath(self.File) | |
473 | ||
474 | self.SubDir, self.Name = os.path.split(self.File) | |
475 | self.BaseName, self.Ext = os.path.splitext(self.Name) | |
476 | ||
477 | if self.Root: | |
478 | if self.SubDir: | |
479 | self.Dir = os.path.join(self.Root, self.SubDir) | |
480 | else: | |
481 | self.Dir = self.Root | |
482 | else: | |
483 | self.Dir = self.SubDir | |
484 | ||
485 | if IsBinary: | |
486 | self.Type = Type | |
487 | else: | |
488 | self.Type = self.Ext.lower() | |
489 | ||
490 | self.IsBinary = IsBinary | |
491 | self.Target = Target | |
492 | self.TagName = TagName | |
493 | self.ToolCode = ToolCode | |
494 | self.ToolChainFamily = ToolChainFamily | |
495 | ||
496 | self._Key = None | |
497 | ||
498 | ## Convert the object of this class to a string | |
499 | # | |
500 | # Convert member Path of the class to a string | |
501 | # | |
502 | def __str__(self): | |
503 | return self.Path | |
504 | ||
505 | ## Override __eq__ function | |
506 | # | |
507 | # Check whether PathClass are the same | |
508 | # | |
509 | def __eq__(self, Other): | |
510 | if type(Other) == type(self): | |
511 | return self.Path == Other.Path | |
512 | else: | |
513 | return self.Path == str(Other) | |
514 | ||
515 | ## Override __hash__ function | |
516 | # | |
517 | # Use Path as key in hash table | |
518 | # | |
519 | def __hash__(self): | |
520 | return hash(self.Path) | |
521 | ||
522 | ## _GetFileKey | |
523 | # | |
524 | def _GetFileKey(self): | |
525 | if self._Key == None: | |
526 | self._Key = self.Path.upper() | |
527 | return self._Key | |
528 | ## Validate | |
529 | # | |
530 | def Validate(self, Type='', CaseSensitive=True): | |
531 | if GlobalData.gCASE_INSENSITIVE: | |
532 | CaseSensitive = False | |
533 | if Type and Type.lower() != self.Type: | |
534 | return ToolError.FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % \ | |
535 | (self.File, Type, self.Type) | |
536 | ||
537 | RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot) | |
538 | if not RealRoot and not RealFile: | |
539 | RealFile = self.File | |
540 | if self.AlterRoot: | |
541 | RealFile = os.path.join(self.AlterRoot, self.File) | |
542 | elif self.Root: | |
543 | RealFile = os.path.join(self.Root, self.File) | |
544 | return ToolError.FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile) | |
545 | ||
546 | ErrorCode = 0 | |
547 | ErrorInfo = '' | |
548 | if RealRoot != self.Root or RealFile != self.File: | |
549 | if CaseSensitive and (RealFile != self.File or \ | |
550 | (RealRoot != self.Root and RealRoot != \ | |
551 | self.AlterRoot)): | |
552 | ErrorCode = ToolError.FILE_CASE_MISMATCH | |
553 | ErrorInfo = self.File + '\n\t' + RealFile + \ | |
554 | " [in file system]" | |
555 | ||
556 | self.SubDir, self.Name = os.path.split(RealFile) | |
557 | self.BaseName, self.Ext = os.path.splitext(self.Name) | |
558 | if self.SubDir: | |
559 | self.Dir = os.path.join(RealRoot, self.SubDir) | |
560 | else: | |
561 | self.Dir = RealRoot | |
562 | self.File = RealFile | |
563 | self.Root = RealRoot | |
564 | self.Path = os.path.join(RealRoot, RealFile) | |
565 | return ErrorCode, ErrorInfo | |
566 | ||
567 | Key = property(_GetFileKey) | |
568 | ||
569 | ## Check environment variables | |
570 | # | |
571 | # Check environment variables that must be set for build. Currently they are | |
572 | # | |
573 | # WORKSPACE The directory all packages/platforms start from | |
574 | # EDK_TOOLS_PATH The directory contains all tools needed by the build | |
575 | # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH | |
576 | # | |
577 | # If any of above environment variable is not set or has error, the build | |
578 | # will be broken. | |
579 | # | |
580 | def CheckEnvVariable(): | |
581 | # | |
582 | # check WORKSPACE | |
583 | # | |
584 | if "WORKSPACE" not in environ: | |
585 | Logger.Error("UPT", | |
586 | ToolError.UPT_ENVIRON_MISSING_ERROR, | |
587 | ST.ERR_NOT_FOUND_ENVIRONMENT, | |
588 | ExtraData="WORKSPACE") | |
589 | ||
590 | WorkspaceDir = os.path.normpath(environ["WORKSPACE"]) | |
591 | if not os.path.exists(WorkspaceDir): | |
592 | Logger.Error("UPT", | |
593 | ToolError.UPT_ENVIRON_MISSING_ERROR, | |
594 | ST.ERR_WORKSPACE_NOTEXIST, | |
595 | ExtraData="%s" % WorkspaceDir) | |
596 | elif ' ' in WorkspaceDir: | |
597 | Logger.Error("UPT", | |
598 | ToolError.FORMAT_NOT_SUPPORTED, | |
599 | ST.ERR_SPACE_NOTALLOWED, | |
600 | ExtraData=WorkspaceDir) | |
601 | ||
602 | ## Check whether all module types are in list | |
603 | # | |
604 | # check whether all module types (SUP_MODULE_LIST) are in list | |
605 | # | |
606 | # @param ModuleList: a list of ModuleType | |
607 | # | |
608 | def IsAllModuleList(ModuleList): | |
609 | NewModuleList = [Module.upper() for Module in ModuleList] | |
610 | for Module in SUP_MODULE_LIST: | |
611 | if Module not in NewModuleList: | |
612 | return False | |
613 | else: | |
614 | return True | |
615 | ||
616 | ## Dictionary that use comment(GenericComment, TailComment) as value, | |
617 | # if a new comment which key already in the dic is inserted, then the | |
618 | # comment will be merged. | |
619 | # Key is (Statement, SupArch), when TailComment is added, it will ident | |
620 | # according to Statement | |
621 | # | |
622 | class MergeCommentDict(dict): | |
623 | ## []= operator | |
624 | # | |
625 | def __setitem__(self, Key, CommentVal): | |
626 | GenericComment, TailComment = CommentVal | |
627 | if Key in self: | |
628 | OrigVal1, OrigVal2 = dict.__getitem__(self, Key) | |
629 | Statement = Key[0] | |
630 | dict.__setitem__(self, Key, (OrigVal1 + GenericComment, OrigVal2 \ | |
631 | + len(Statement) * ' ' + TailComment)) | |
632 | else: | |
633 | dict.__setitem__(self, Key, (GenericComment, TailComment)) | |
634 | ||
635 | ## =[] operator | |
636 | # | |
637 | def __getitem__(self, Key): | |
638 | return dict.__getitem__(self, Key) | |
639 | ||
640 | ||
641 | ## GenDummyHelpTextObj | |
642 | # | |
643 | # @retval HelpTxt: Generated dummy help text object | |
644 | # | |
645 | def GenDummyHelpTextObj(): | |
646 | HelpTxt = TextObject() | |
647 | HelpTxt.SetLang(LANGUAGE_EN_US) | |
648 | HelpTxt.SetString(' ') | |
649 | return HelpTxt | |
650 | ||
651 | ## ConvertVersionToDecimal, the minor version should be within 0 - 99 | |
652 | # <HexVersion> ::= "0x" <Major> <Minor> | |
653 | # <Major> ::= (a-fA-F0-9){4} | |
654 | # <Minor> ::= (a-fA-F0-9){4} | |
655 | # <DecVersion> ::= (0-65535) ["." (0-99)] | |
656 | # | |
657 | # @param StringIn: The string contains version defined in INF file. | |
658 | # It can be Decimal or Hex | |
659 | # | |
660 | def ConvertVersionToDecimal(StringIn): | |
661 | if IsValidHexVersion(StringIn): | |
662 | Value = int(StringIn, 16) | |
663 | Major = Value >> 16 | |
664 | Minor = Value & 0xFFFF | |
665 | MinorStr = str(Minor) | |
666 | if len(MinorStr) == 1: | |
667 | MinorStr = '0' + MinorStr | |
668 | return str(Major) + '.' + MinorStr | |
669 | else: | |
670 | if StringIn.find(TAB_SPLIT) != -1: | |
671 | return StringIn | |
672 | elif StringIn: | |
673 | return StringIn + '.0' | |
674 | else: | |
675 | # | |
676 | # when StringIn is '', return it directly | |
677 | # | |
678 | return StringIn | |
679 | ||
680 | ## GetHelpStringByRemoveHashKey | |
681 | # | |
682 | # Remove hash key at the header of string and return the remain. | |
683 | # | |
684 | # @param String: The string need to be processed. | |
685 | # | |
686 | def GetHelpStringByRemoveHashKey(String): | |
687 | ReturnString = '' | |
688 | PattenRemoveHashKey = re.compile(r"^[#+\s]+", re.DOTALL) | |
689 | String = String.strip() | |
690 | if String == '': | |
691 | return String | |
692 | ||
693 | LineList = GetSplitValueList(String, END_OF_LINE) | |
694 | for Line in LineList: | |
695 | ValueList = PattenRemoveHashKey.split(Line) | |
696 | if len(ValueList) == 1: | |
697 | ReturnString += ValueList[0] + END_OF_LINE | |
698 | else: | |
699 | ReturnString += ValueList[1] + END_OF_LINE | |
700 | ||
701 | if ReturnString.endswith('\n') and not ReturnString.endswith('\n\n') and ReturnString != '\n': | |
702 | ReturnString = ReturnString[:-1] | |
703 | ||
704 | return ReturnString | |
705 | ||
706 | ## ConvPathFromAbsToRel | |
707 | # | |
708 | # Get relative file path from absolute path. | |
709 | # | |
710 | # @param Path: The string contain file absolute path. | |
711 | # @param Root: The string contain the parent path of Path in. | |
712 | # | |
713 | # | |
714 | def ConvPathFromAbsToRel(Path, Root): | |
715 | Path = os.path.normpath(Path) | |
716 | Root = os.path.normpath(Root) | |
717 | FullPath = os.path.normpath(os.path.join(Root, Path)) | |
718 | ||
719 | # | |
720 | # If Path is absolute path. | |
721 | # It should be in Root. | |
722 | # | |
723 | if os.path.isabs(Path): | |
724 | return FullPath[FullPath.find(Root) + len(Root) + 1:] | |
725 | ||
726 | else: | |
727 | return Path | |
728 | ||
729 | ## ConvertPath | |
730 | # | |
731 | # Convert special characters to '_', '\' to '/' | |
732 | # return converted path: Test!1.inf -> Test_1.inf | |
733 | # | |
734 | # @param Path: Path to be converted | |
735 | # | |
736 | def ConvertPath(Path): | |
737 | RetPath = '' | |
738 | for Char in Path.strip(): | |
739 | if Char.isalnum() or Char in '.-_/': | |
740 | RetPath = RetPath + Char | |
741 | elif Char == '\\': | |
742 | RetPath = RetPath + '/' | |
743 | else: | |
744 | RetPath = RetPath + '_' | |
745 | return RetPath | |
746 | ||
747 | ## ConvertSpec | |
748 | # | |
749 | # during install, convert the Spec string extract from UPD into INF allowable definition, | |
750 | # the difference is period is allowed in the former (not the first letter) but not in the latter. | |
751 | # return converted Spec string | |
752 | # | |
753 | # @param SpecStr: SpecStr to be converted | |
754 | # | |
755 | def ConvertSpec(SpecStr): | |
756 | RetStr = '' | |
757 | for Char in SpecStr: | |
758 | if Char.isalnum() or Char == '_': | |
759 | RetStr = RetStr + Char | |
760 | else: | |
761 | RetStr = RetStr + '_' | |
762 | ||
763 | return RetStr | |
764 | ||
765 | ||
766 | ## IsEqualList | |
767 | # | |
768 | # Judge two lists are identical(contain same item). | |
769 | # The rule is elements in List A are in List B and elements in List B are in List A. | |
770 | # | |
771 | # @param ListA, ListB Lists need to be judged. | |
772 | # | |
773 | # @return True ListA and ListB are identical | |
774 | # @return False ListA and ListB are different with each other | |
775 | # | |
776 | def IsEqualList(ListA, ListB): | |
777 | if ListA == ListB: | |
778 | return True | |
779 | ||
780 | for ItemA in ListA: | |
781 | if not ItemA in ListB: | |
782 | return False | |
783 | ||
784 | for ItemB in ListB: | |
785 | if not ItemB in ListA: | |
786 | return False | |
787 | ||
788 | return True | |
789 | ||
790 | ## ConvertArchList | |
791 | # | |
792 | # Convert item in ArchList if the start character is lower case. | |
793 | # In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])* | |
794 | # | |
795 | # @param ArchList The ArchList need to be converted. | |
796 | # | |
797 | # @return NewList The ArchList been converted. | |
798 | # | |
799 | def ConvertArchList(ArchList): | |
800 | NewArchList = [] | |
801 | if not ArchList: | |
802 | return NewArchList | |
803 | ||
804 | if type(ArchList) == list: | |
805 | for Arch in ArchList: | |
806 | Arch = Arch.upper() | |
807 | NewArchList.append(Arch) | |
808 | elif type(ArchList) == str: | |
809 | ArchList = ArchList.upper() | |
810 | NewArchList.append(ArchList) | |
811 | ||
812 | return NewArchList | |
813 | ||
814 | ## ProcessLineExtender | |
815 | # | |
816 | # Process the LineExtender of Line in LineList. | |
817 | # If one line ends with a line extender, then it will be combined together with next line. | |
818 | # | |
819 | # @param LineList The LineList need to be processed. | |
820 | # | |
821 | # @return NewList The ArchList been processed. | |
822 | # | |
823 | def ProcessLineExtender(LineList): | |
824 | NewList = [] | |
825 | Count = 0 | |
826 | while Count < len(LineList): | |
827 | if LineList[Count].strip().endswith("\\") and Count + 1 < len(LineList): | |
828 | NewList.append(LineList[Count].strip()[:-2] + LineList[Count + 1]) | |
829 | Count = Count + 1 | |
830 | else: | |
831 | NewList.append(LineList[Count]) | |
832 | ||
833 | Count = Count + 1 | |
834 | ||
835 | return NewList | |
836 | ||
2bcc713e LG |
837 | ## ProcessEdkComment |
838 | # | |
839 | # Process EDK style comment in LineList: c style /* */ comment or cpp style // comment | |
840 | # | |
841 | # | |
842 | # @param LineList The LineList need to be processed. | |
843 | # | |
844 | # @return LineList The LineList been processed. | |
845 | # @return FirstPos Where Edk comment is first found, -1 if not found | |
846 | # | |
847 | def ProcessEdkComment(LineList): | |
848 | FindEdkBlockComment = False | |
849 | Count = 0 | |
850 | StartPos = -1 | |
851 | EndPos = -1 | |
852 | FirstPos = -1 | |
853 | ||
854 | while(Count < len(LineList)): | |
855 | Line = LineList[Count].strip() | |
856 | if Line.startswith("/*"): | |
857 | # | |
858 | # handling c style comment | |
859 | # | |
860 | StartPos = Count | |
861 | while Count < len(LineList): | |
862 | Line = LineList[Count].strip() | |
863 | if Line.endswith("*/"): | |
864 | if (Count == StartPos) and Line.strip() == '/*/': | |
865 | Count = Count + 1 | |
866 | continue | |
867 | EndPos = Count | |
868 | FindEdkBlockComment = True | |
869 | break | |
870 | Count = Count + 1 | |
871 | ||
872 | if FindEdkBlockComment: | |
873 | if FirstPos == -1: | |
874 | FirstPos = StartPos | |
875 | for Index in xrange(StartPos, EndPos+1): | |
876 | LineList[Index] = '' | |
877 | FindEdkBlockComment = False | |
d0acc87a | 878 | elif Line.find("//") != -1 and not Line.startswith("#"): |
2bcc713e LG |
879 | # |
880 | # handling cpp style comment | |
881 | # | |
882 | LineList[Count] = Line.replace("//", '#') | |
883 | if FirstPos == -1: | |
884 | FirstPos = Count | |
885 | ||
886 | Count = Count + 1 | |
887 | ||
888 | return LineList, FirstPos | |
889 | ||
4234283c LG |
890 | ## GetLibInstanceInfo |
891 | # | |
892 | # Get the information from Library Instance INF file. | |
893 | # | |
894 | # @param string. A string start with # and followed by INF file path | |
895 | # @param WorkSpace. The WorkSpace directory used to combined with INF file path. | |
896 | # | |
897 | # @return GUID, Version | |
898 | def GetLibInstanceInfo(String, WorkSpace, LineNo): | |
899 | ||
900 | FileGuidString = "" | |
901 | VerString = "" | |
902 | ||
903 | OrignalString = String | |
904 | String = String.strip() | |
905 | if not String: | |
906 | return None, None | |
907 | # | |
908 | # Remove "#" characters at the beginning | |
909 | # | |
910 | String = GetHelpStringByRemoveHashKey(String) | |
911 | String = String.strip() | |
912 | ||
913 | # | |
914 | # Validate file name exist. | |
915 | # | |
916 | FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, String))) | |
917 | if not (ValidFile(FullFileName)): | |
918 | Logger.Error("InfParser", | |
919 | ToolError.FORMAT_INVALID, | |
920 | ST.ERR_FILELIST_EXIST % (String), | |
921 | File=GlobalData.gINF_MODULE_NAME, | |
922 | Line=LineNo, | |
923 | ExtraData=OrignalString) | |
924 | ||
925 | # | |
926 | # Validate file exist/format. | |
927 | # | |
928 | if IsValidPath(String, WorkSpace): | |
929 | IsValidFileFlag = True | |
930 | else: | |
931 | Logger.Error("InfParser", | |
932 | ToolError.FORMAT_INVALID, | |
933 | ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID % (String), | |
934 | File=GlobalData.gINF_MODULE_NAME, | |
935 | Line=LineNo, | |
936 | ExtraData=OrignalString) | |
937 | return False | |
938 | if IsValidFileFlag: | |
939 | FileLinesList = [] | |
940 | ||
941 | try: | |
942 | FInputfile = open(FullFileName, "rb", 0) | |
943 | try: | |
944 | FileLinesList = FInputfile.readlines() | |
945 | except BaseException: | |
946 | Logger.Error("InfParser", | |
947 | ToolError.FILE_READ_FAILURE, | |
948 | ST.ERR_FILE_OPEN_FAILURE, | |
949 | File=FullFileName) | |
950 | finally: | |
951 | FInputfile.close() | |
952 | except BaseException: | |
953 | Logger.Error("InfParser", | |
954 | ToolError.FILE_READ_FAILURE, | |
955 | ST.ERR_FILE_OPEN_FAILURE, | |
956 | File=FullFileName) | |
957 | ||
958 | ReFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$") | |
959 | ReVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$") | |
960 | ||
961 | FileLinesList = ProcessLineExtender(FileLinesList) | |
962 | ||
963 | for Line in FileLinesList: | |
964 | if ReFileGuidPattern.match(Line): | |
965 | FileGuidString = Line | |
966 | if ReVerStringPattern.match(Line): | |
967 | VerString = Line | |
968 | ||
969 | if FileGuidString: | |
970 | FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1] | |
971 | if VerString: | |
972 | VerString = GetSplitValueList(VerString, '=', 1)[1] | |
973 | ||
974 | return FileGuidString, VerString |