]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/Misc.py
Sync basetools' source and binary files with r1707 of the basetools project.
[mirror_edk2.git] / BaseTools / Source / Python / Common / Misc.py
1 ## @file
2 # Common routines used by all tools
3 #
4 # Copyright (c) 2007, Intel Corporation
5 # All rights reserved. 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
18 import sys
19 import string
20 import thread
21 import threading
22 import time
23 import re
24 import cPickle
25 from UserDict import IterableUserDict
26 from UserList import UserList
27
28 from Common import EdkLogger as EdkLogger
29 from Common import GlobalData as GlobalData
30
31 from BuildToolError import *
32
33 ## Regular expression used to find out place holders in string template
34 gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE|re.UNICODE)
35
36 ## Dictionary used to store file time stamp for quick re-access
37 gFileTimeStampCache = {} # {file path : file time stamp}
38
39 ## Dictionary used to store dependencies of files
40 gDependencyDatabase = {} # arch : {file path : [dependent files list]}
41
42 ## callback routine for processing variable option
43 #
44 # This function can be used to process variable number of option values. The
45 # typical usage of it is specify architecure list on command line.
46 # (e.g. <tool> -a IA32 X64 IPF)
47 #
48 # @param Option Standard callback function parameter
49 # @param OptionString Standard callback function parameter
50 # @param Value Standard callback function parameter
51 # @param Parser Standard callback function parameter
52 #
53 # @retval
54 #
55 def ProcessVariableArgument(Option, OptionString, Value, Parser):
56 assert Value is None
57 Value = []
58 RawArgs = Parser.rargs
59 while RawArgs:
60 Arg = RawArgs[0]
61 if (Arg[:2] == "--" and len(Arg) > 2) or \
62 (Arg[:1] == "-" and len(Arg) > 1 and Arg[1] != "-"):
63 break
64 Value.append(Arg)
65 del RawArgs[0]
66 setattr(Parser.values, Option.dest, Value)
67
68 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
69 #
70 # @param Guid The GUID string
71 #
72 # @retval string The GUID string in C structure style
73 #
74 def GuidStringToGuidStructureString(Guid):
75 GuidList = Guid.split('-')
76 Result = '{'
77 for Index in range(0,3,1):
78 Result = Result + '0x' + GuidList[Index] + ', '
79 Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]
80 for Index in range(0,12,2):
81 Result = Result + ', 0x' + GuidList[4][Index:Index+2]
82 Result += '}}'
83 return Result
84
85 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
86 #
87 # @param GuidValue The GUID value in byte array
88 #
89 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
90 #
91 def GuidStructureByteArrayToGuidString(GuidValue):
92 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
93 guidValueList = guidValueString.split(",")
94 if len(guidValueList) != 16:
95 return ''
96 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
97 try:
98 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
99 int(guidValueList[3], 16),
100 int(guidValueList[2], 16),
101 int(guidValueList[1], 16),
102 int(guidValueList[0], 16),
103 int(guidValueList[5], 16),
104 int(guidValueList[4], 16),
105 int(guidValueList[7], 16),
106 int(guidValueList[6], 16),
107 int(guidValueList[8], 16),
108 int(guidValueList[9], 16),
109 int(guidValueList[10], 16),
110 int(guidValueList[11], 16),
111 int(guidValueList[12], 16),
112 int(guidValueList[13], 16),
113 int(guidValueList[14], 16),
114 int(guidValueList[15], 16)
115 )
116 except:
117 return ''
118
119 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
120 #
121 # @param GuidValue The GUID value in C structure format
122 #
123 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
124 #
125 def GuidStructureStringToGuidString(GuidValue):
126 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
127 guidValueList = guidValueString.split(",")
128 if len(guidValueList) != 11:
129 return ''
130 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
131 try:
132 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
133 int(guidValueList[0], 16),
134 int(guidValueList[1], 16),
135 int(guidValueList[2], 16),
136 int(guidValueList[3], 16),
137 int(guidValueList[4], 16),
138 int(guidValueList[5], 16),
139 int(guidValueList[6], 16),
140 int(guidValueList[7], 16),
141 int(guidValueList[8], 16),
142 int(guidValueList[9], 16),
143 int(guidValueList[10], 16)
144 )
145 except:
146 return ''
147
148 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
149 #
150 # @param GuidValue The GUID value in C structure format
151 #
152 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
153 #
154 def GuidStructureStringToGuidValueName(GuidValue):
155 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")
156 guidValueList = guidValueString.split(",")
157 if len(guidValueList) != 11:
158 EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
159 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
160 int(guidValueList[0], 16),
161 int(guidValueList[1], 16),
162 int(guidValueList[2], 16),
163 int(guidValueList[3], 16),
164 int(guidValueList[4], 16),
165 int(guidValueList[5], 16),
166 int(guidValueList[6], 16),
167 int(guidValueList[7], 16),
168 int(guidValueList[8], 16),
169 int(guidValueList[9], 16),
170 int(guidValueList[10], 16)
171 )
172
173 ## Create directories
174 #
175 # @param Directory The directory name
176 #
177 def CreateDirectory(Directory):
178 if Directory == None or Directory.strip() == "":
179 return True
180 try:
181 if not os.access(Directory, os.F_OK):
182 os.makedirs(Directory)
183 except:
184 return False
185 return True
186
187 ## Remove directories, including files and sub-directories in it
188 #
189 # @param Directory The directory name
190 #
191 def RemoveDirectory(Directory, Recursively=False):
192 if Directory == None or Directory.strip() == "" or not os.path.exists(Directory):
193 return
194 if Recursively:
195 CurrentDirectory = os.getcwd()
196 os.chdir(Directory)
197 for File in os.listdir("."):
198 if os.path.isdir(File):
199 RemoveDirectory(File, Recursively)
200 else:
201 os.remove(File)
202 os.chdir(CurrentDirectory)
203 os.rmdir(Directory)
204
205 ## Check if given file is changed or not
206 #
207 # This method is used to check if a file is changed or not between two build
208 # actions. It makes use a cache to store files timestamp.
209 #
210 # @param File The path of file
211 #
212 # @retval True If the given file is changed, doesn't exist, or can't be
213 # found in timestamp cache
214 # @retval False If the given file is changed
215 #
216 def IsChanged(File):
217 if not os.path.exists(File):
218 return True
219
220 FileState = os.stat(File)
221 TimeStamp = FileState[-2]
222
223 if File in gFileTimeStampCache and TimeStamp == gFileTimeStampCache[File]:
224 FileChanged = False
225 else:
226 FileChanged = True
227 gFileTimeStampCache[File] = TimeStamp
228
229 return FileChanged
230
231 ## Store content in file
232 #
233 # This method is used to save file only when its content is changed. This is
234 # quite useful for "make" system to decide what will be re-built and what won't.
235 #
236 # @param File The path of file
237 # @param Content The new content of the file
238 # @param IsBinaryFile The flag indicating if the file is binary file or not
239 #
240 # @retval True If the file content is changed and the file is renewed
241 # @retval False If the file content is the same
242 #
243 def SaveFileOnChange(File, Content, IsBinaryFile=True):
244 if not IsBinaryFile:
245 Content = Content.replace("\n", os.linesep)
246
247 if os.path.exists(File):
248 try:
249 if Content == open(File, "rb").read():
250 return False
251 except:
252 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)
253
254 CreateDirectory(os.path.dirname(File))
255 try:
256 if GlobalData.gIsWindows:
257 try:
258 from PyUtility import SaveFileToDisk
259 if not SaveFileToDisk(File, Content):
260 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File)
261 except:
262 Fd = open(File, "wb")
263 Fd.write(Content)
264 Fd.close()
265 else:
266 Fd = open(File, "wb")
267 Fd.write(Content)
268 Fd.close()
269 except:
270 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File)
271
272 return True
273
274 ## Make a Python object persistent on file system
275 #
276 # @param Data The object to be stored in file
277 # @param File The path of file to store the object
278 #
279 def DataDump(Data, File):
280 Fd = None
281 try:
282 Fd = open(File, 'wb')
283 cPickle.dump(Data, Fd, cPickle.HIGHEST_PROTOCOL)
284 except:
285 EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False)
286 finally:
287 if Fd != None:
288 Fd.close()
289
290 ## Restore a Python object from a file
291 #
292 # @param File The path of file stored the object
293 #
294 # @retval object A python object
295 # @retval None If failure in file operation
296 #
297 def DataRestore(File):
298 Data = None
299 Fd = None
300 try:
301 Fd = open(File, 'rb')
302 Data = cPickle.load(Fd)
303 except Exception, e:
304 EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e)))
305 Data = None
306 finally:
307 if Fd != None:
308 Fd.close()
309 return Data
310
311 ## Retrieve and cache the real path name in file system
312 #
313 # @param Root The root directory of path relative to
314 #
315 # @retval str The path string if the path exists
316 # @retval None If path doesn't exist
317 #
318 class DirCache:
319 _CACHE_ = {}
320
321 def __init__(self, Root):
322 self._Root = Root
323 for F in os.listdir(Root):
324 self._CACHE_[F.upper()] = F
325
326 # =[] operator
327 def __getitem__(self, Path):
328 Path = Path[len(os.path.commonprefix([Path, self._Root])):]
329 if not Path:
330 return self._Root
331 if Path and Path[0] == os.path.sep:
332 Path = Path[1:]
333 Path = Path.upper()
334 if Path in self._CACHE_:
335 return os.path.join(self._Root, self._CACHE_[Path])
336
337 IndexList = []
338 LastSepIndex = -1
339 SepIndex = Path.find(os.path.sep)
340 while SepIndex > -1:
341 Parent = Path[:SepIndex]
342 if Parent not in self._CACHE_:
343 break
344 LastSepIndex = SepIndex
345 SepIndex = Path.find(os.path.sep, LastSepIndex + 1)
346
347 if LastSepIndex == -1:
348 return None
349
350 Cwd = os.getcwd()
351 os.chdir(self._Root)
352 SepIndex = LastSepIndex
353 while SepIndex > -1:
354 ParentKey = Path[:SepIndex]
355 if ParentKey not in self._CACHE_:
356 os.chdir(Cwd)
357 return None
358
359 ParentDir = self._CACHE_[ParentKey]
360 for F in os.listdir(ParentDir):
361 Dir = os.path.join(ParentDir, F)
362 self._CACHE_[Dir.upper()] = Dir
363
364 SepIndex = Path.find(os.path.sep, SepIndex + 1)
365
366 os.chdir(Cwd)
367 if Path not in self._CACHE_:
368 return None
369 return os.path.join(self._Root, self._CACHE_[Path])
370
371 ## Get all files of a directory
372 #
373 # @param Root: Root dir
374 # @param SkipList : The files need be skipped
375 #
376 # @retval A list of all files
377 #
378 def GetFiles(Root, SkipList=None, FullPath = True):
379 OriPath = Root
380 FileList = []
381 for Root, Dirs, Files in os.walk(Root):
382 if SkipList:
383 for Item in SkipList:
384 if Item in Dirs:
385 Dirs.remove(Item)
386
387 for File in Files:
388 File = os.path.normpath(os.path.join(Root, File))
389 if not FullPath:
390 File = File[len(OriPath) + 1:]
391 FileList.append(File)
392
393 return FileList
394
395 ## Check if gvien file exists or not
396 #
397 # @param File File name or path to be checked
398 # @param Dir The directory the file is relative to
399 #
400 # @retval True if file exists
401 # @retval False if file doesn't exists
402 #
403 def ValidFile(File, Ext=None):
404 if Ext != None:
405 Dummy, FileExt = os.path.splitext(File)
406 if FileExt.lower() != Ext.lower():
407 return False
408 if not os.path.exists(File):
409 return False
410 return True
411
412 def RealPath(File, Dir='', OverrideDir=''):
413 NewFile = os.path.normpath(os.path.join(Dir, File))
414 NewFile = GlobalData.gAllFiles[NewFile]
415 if not NewFile and OverrideDir:
416 NewFile = os.path.normpath(os.path.join(OverrideDir, File))
417 NewFile = GlobalData.gAllFiles[NewFile]
418 return NewFile
419
420 def RealPath2(File, Dir='', OverrideDir=''):
421 if OverrideDir:
422 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
423 if NewFile:
424 if OverrideDir[-1] == os.path.sep:
425 return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]
426 else:
427 return NewFile[len(OverrideDir)+1:], NewFile[0:len(OverrideDir)]
428
429 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]
430 if NewFile:
431 if Dir:
432 if Dir[-1] == os.path.sep:
433 return NewFile[len(Dir):], NewFile[0:len(Dir)]
434 else:
435 return NewFile[len(Dir)+1:], NewFile[0:len(Dir)]
436 else:
437 return NewFile, ''
438
439 return None, None
440
441 ## Check if gvien file exists or not
442 #
443 #
444 def ValidFile2(AllFiles, File, Ext=None, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''):
445 NewFile = File
446 if Ext != None:
447 Dummy, FileExt = os.path.splitext(File)
448 if FileExt.lower() != Ext.lower():
449 return False, File
450
451 # Replace the R8 macros
452 if OverrideDir != '' and OverrideDir != None:
453 if OverrideDir.find('$(EFI_SOURCE)') > -1:
454 OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)
455 if OverrideDir.find('$(EDK_SOURCE)') > -1:
456 OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource)
457
458 # Replace the default dir to current dir
459 if Dir == '.':
460 Dir = os.getcwd()
461 Dir = Dir[len(Workspace)+1:]
462
463 # First check if File has R8 definition itself
464 if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:
465 NewFile = File.replace('$(EFI_SOURCE)', EfiSource)
466 NewFile = NewFile.replace('$(EDK_SOURCE)', EdkSource)
467 NewFile = AllFiles[os.path.normpath(NewFile)]
468 if NewFile != None:
469 return True, NewFile
470
471 # Second check the path with override value
472 if OverrideDir != '' and OverrideDir != None:
473 NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
474 if NewFile != None:
475 return True, NewFile
476
477 # Last check the path with normal definitions
478 File = os.path.join(Dir, File)
479 NewFile = AllFiles[os.path.normpath(File)]
480 if NewFile != None:
481 return True, NewFile
482
483 return False, File
484
485 ## Check if gvien file exists or not
486 #
487 #
488 def ValidFile3(AllFiles, File, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''):
489 # Replace the R8 macros
490 if OverrideDir != '' and OverrideDir != None:
491 if OverrideDir.find('$(EFI_SOURCE)') > -1:
492 OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)
493 if OverrideDir.find('$(EDK_SOURCE)') > -1:
494 OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource)
495
496 # Replace the default dir to current dir
497 # Dir is current module dir related to workspace
498 if Dir == '.':
499 Dir = os.getcwd()
500 Dir = Dir[len(Workspace)+1:]
501
502 NewFile = File
503 RelaPath = AllFiles[os.path.normpath(Dir)]
504 NewRelaPath = RelaPath
505
506 while(True):
507 # First check if File has R8 definition itself
508 if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:
509 File = File.replace('$(EFI_SOURCE)', EfiSource)
510 File = File.replace('$(EDK_SOURCE)', EdkSource)
511 NewFile = AllFiles[os.path.normpath(File)]
512 if NewFile != None:
513 NewRelaPath = os.path.dirname(NewFile)
514 File = os.path.basename(NewFile)
515 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
516 break
517
518 # Second check the path with override value
519 if OverrideDir != '' and OverrideDir != None:
520 NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
521 if NewFile != None:
522 #NewRelaPath = os.path.dirname(NewFile)
523 NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
524 break
525
526 # Last check the path with normal definitions
527 NewFile = AllFiles[os.path.normpath(os.path.join(Dir, File))]
528 if NewFile != None:
529 break
530
531 # No file found
532 break
533
534 return NewRelaPath, RelaPath, File
535
536
537 def GetRelPath(Path1, Path2):
538 FileName = os.path.basename(Path2)
539 L1 = os.path.normpath(Path1).split(os.path.normpath('/'))
540 L2 = os.path.normpath(Path2).split(os.path.normpath('/'))
541 for Index in range(0, len(L1)):
542 if L1[Index] != L2[Index]:
543 FileName = '../' * (len(L1) - Index)
544 for Index2 in range(Index, len(L2)):
545 FileName = os.path.join(FileName, L2[Index2])
546 break
547 return os.path.normpath(FileName)
548
549
550 ## Get GUID value from given packages
551 #
552 # @param CName The CName of the GUID
553 # @param PackageList List of packages looking-up in
554 #
555 # @retval GuidValue if the CName is found in any given package
556 # @retval None if the CName is not found in all given packages
557 #
558 def GuidValue(CName, PackageList):
559 for P in PackageList:
560 if CName in P.Guids:
561 return P.Guids[CName]
562 return None
563
564 ## Get Protocol value from given packages
565 #
566 # @param CName The CName of the GUID
567 # @param PackageList List of packages looking-up in
568 #
569 # @retval GuidValue if the CName is found in any given package
570 # @retval None if the CName is not found in all given packages
571 #
572 def ProtocolValue(CName, PackageList):
573 for P in PackageList:
574 if CName in P.Protocols:
575 return P.Protocols[CName]
576 return None
577
578 ## Get PPI value from given packages
579 #
580 # @param CName The CName of the GUID
581 # @param PackageList List of packages looking-up in
582 #
583 # @retval GuidValue if the CName is found in any given package
584 # @retval None if the CName is not found in all given packages
585 #
586 def PpiValue(CName, PackageList):
587 for P in PackageList:
588 if CName in P.Ppis:
589 return P.Ppis[CName]
590 return None
591
592 ## A string template class
593 #
594 # This class implements a template for string replacement. A string template
595 # looks like following
596 #
597 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
598 #
599 # The string between ${BEGIN} and ${END} will be repeated as many times as the
600 # length of "placeholder_name", which is a list passed through a dict. The
601 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
602 # be not used and, in this case, the "placeholder_name" must not a list and it
603 # will just be replaced once.
604 #
605 class TemplateString(object):
606 _REPEAT_START_FLAG = "BEGIN"
607 _REPEAT_END_FLAG = "END"
608
609 class Section(object):
610 _LIST_TYPES = [type([]), type(set()), type((0,))]
611
612 def __init__(self, TemplateSection, PlaceHolderList):
613 self._Template = TemplateSection
614 self._PlaceHolderList = []
615
616 # Split the section into sub-sections according to the position of placeholders
617 if PlaceHolderList:
618 self._SubSectionList = []
619 SubSectionStart = 0
620 #
621 # The placeholders passed in must be in the format of
622 #
623 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
624 #
625 for PlaceHolder,Start,End in PlaceHolderList:
626 self._SubSectionList.append(TemplateSection[SubSectionStart:Start])
627 self._SubSectionList.append(TemplateSection[Start:End])
628 self._PlaceHolderList.append(PlaceHolder)
629 SubSectionStart = End
630 if SubSectionStart < len(TemplateSection):
631 self._SubSectionList.append(TemplateSection[SubSectionStart:])
632 else:
633 self._SubSectionList = [TemplateSection]
634
635 def __str__(self):
636 return self._Template + " : " + str(self._PlaceHolderList)
637
638 def Instantiate(self, PlaceHolderValues):
639 RepeatTime = -1
640 RepeatPlaceHolders = {}
641 NonRepeatPlaceHolders = {}
642
643 for PlaceHolder in self._PlaceHolderList:
644 if PlaceHolder not in PlaceHolderValues:
645 continue
646 Value = PlaceHolderValues[PlaceHolder]
647 if type(Value) in self._LIST_TYPES:
648 if RepeatTime < 0:
649 RepeatTime = len(Value)
650 elif RepeatTime != len(Value):
651 EdkLogger.error(
652 "TemplateString",
653 PARAMETER_INVALID,
654 "${%s} has different repeat time from others!" % PlaceHolder,
655 ExtraData=str(self._Template)
656 )
657 RepeatPlaceHolders["${%s}" % PlaceHolder] = Value
658 else:
659 NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value
660
661 if NonRepeatPlaceHolders:
662 StringList = []
663 for S in self._SubSectionList:
664 if S not in NonRepeatPlaceHolders:
665 StringList.append(S)
666 else:
667 StringList.append(str(NonRepeatPlaceHolders[S]))
668 else:
669 StringList = self._SubSectionList
670
671 if RepeatPlaceHolders:
672 TempStringList = []
673 for Index in range(RepeatTime):
674 for S in StringList:
675 if S not in RepeatPlaceHolders:
676 TempStringList.append(S)
677 else:
678 TempStringList.append(str(RepeatPlaceHolders[S][Index]))
679 StringList = TempStringList
680
681 return "".join(StringList)
682
683 ## Constructor
684 def __init__(self, Template=None):
685 self.String = ''
686 self._Template = Template
687 self._TemplateSectionList = self._Parse(Template)
688
689 ## str() operator
690 #
691 # @retval string The string replaced
692 #
693 def __str__(self):
694 return self.String
695
696 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
697 #
698 # @retval list A list of TemplateString.Section objects
699 #
700 def _Parse(self, Template):
701 SectionStart = 0
702 SearchFrom = 0
703 MatchEnd = 0
704 PlaceHolderList = []
705 TemplateSectionList = []
706 while Template:
707 MatchObj = gPlaceholderPattern.search(Template, SearchFrom)
708 if not MatchObj:
709 if MatchEnd < len(Template):
710 TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)
711 TemplateSectionList.append(TemplateSection)
712 break
713
714 MatchString = MatchObj.group(1)
715 MatchStart = MatchObj.start()
716 MatchEnd = MatchObj.end()
717
718 if MatchString == self._REPEAT_START_FLAG:
719 if MatchStart > SectionStart:
720 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
721 TemplateSectionList.append(TemplateSection)
722 SectionStart = MatchEnd
723 PlaceHolderList = []
724 elif MatchString == self._REPEAT_END_FLAG:
725 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
726 TemplateSectionList.append(TemplateSection)
727 SectionStart = MatchEnd
728 PlaceHolderList = []
729 else:
730 PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))
731 SearchFrom = MatchEnd
732 return TemplateSectionList
733
734 ## Replace the string template with dictionary of placeholders and append it to previous one
735 #
736 # @param AppendString The string template to append
737 # @param Dictionary The placeholder dictionaries
738 #
739 def Append(self, AppendString, Dictionary=None):
740 if Dictionary:
741 SectionList = self._Parse(AppendString)
742 self.String += "".join([S.Instantiate(Dictionary) for S in SectionList])
743 else:
744 self.String += AppendString
745
746 ## Replace the string template with dictionary of placeholders
747 #
748 # @param Dictionary The placeholder dictionaries
749 #
750 # @retval str The string replaced with placeholder values
751 #
752 def Replace(self, Dictionary=None):
753 return "".join([S.Instantiate(Dictionary) for S in self._TemplateSectionList])
754
755 ## Progress indicator class
756 #
757 # This class makes use of thread to print progress on console.
758 #
759 class Progressor:
760 # for avoiding deadloop
761 _StopFlag = None
762 _ProgressThread = None
763 _CheckInterval = 0.25
764
765 ## Constructor
766 #
767 # @param OpenMessage The string printed before progress charaters
768 # @param CloseMessage The string printed after progress charaters
769 # @param ProgressChar The charater used to indicate the progress
770 # @param Interval The interval in seconds between two progress charaters
771 #
772 def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):
773 self.PromptMessage = OpenMessage
774 self.CodaMessage = CloseMessage
775 self.ProgressChar = ProgressChar
776 self.Interval = Interval
777 if Progressor._StopFlag == None:
778 Progressor._StopFlag = threading.Event()
779
780 ## Start to print progress charater
781 #
782 # @param OpenMessage The string printed before progress charaters
783 #
784 def Start(self, OpenMessage=None):
785 if OpenMessage != None:
786 self.PromptMessage = OpenMessage
787 Progressor._StopFlag.clear()
788 if Progressor._ProgressThread == None:
789 Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)
790 Progressor._ProgressThread.setDaemon(False)
791 Progressor._ProgressThread.start()
792
793 ## Stop printing progress charater
794 #
795 # @param CloseMessage The string printed after progress charaters
796 #
797 def Stop(self, CloseMessage=None):
798 OriginalCodaMessage = self.CodaMessage
799 if CloseMessage != None:
800 self.CodaMessage = CloseMessage
801 self.Abort()
802 self.CodaMessage = OriginalCodaMessage
803
804 ## Thread entry method
805 def _ProgressThreadEntry(self):
806 sys.stdout.write(self.PromptMessage + " ")
807 sys.stdout.flush()
808 TimeUp = 0.0
809 while not Progressor._StopFlag.isSet():
810 if TimeUp <= 0.0:
811 sys.stdout.write(self.ProgressChar)
812 sys.stdout.flush()
813 TimeUp = self.Interval
814 time.sleep(self._CheckInterval)
815 TimeUp -= self._CheckInterval
816 sys.stdout.write(" " + self.CodaMessage + "\n")
817 sys.stdout.flush()
818
819 ## Abort the progress display
820 @staticmethod
821 def Abort():
822 if Progressor._StopFlag != None:
823 Progressor._StopFlag.set()
824 if Progressor._ProgressThread != None:
825 Progressor._ProgressThread.join()
826 Progressor._ProgressThread = None
827
828 ## A dict which can access its keys and/or values orderly
829 #
830 # The class implements a new kind of dict which its keys or values can be
831 # accessed in the order they are added into the dict. It guarantees the order
832 # by making use of an internal list to keep a copy of keys.
833 #
834 class sdict(IterableUserDict):
835 ## Constructor
836 def __init__(self):
837 IterableUserDict.__init__(self)
838 self._key_list = []
839
840 ## [] operator
841 def __setitem__(self, key, value):
842 if key not in self._key_list:
843 self._key_list.append(key)
844 IterableUserDict.__setitem__(self, key, value)
845
846 ## del operator
847 def __delitem__(self, key):
848 self._key_list.remove(key)
849 IterableUserDict.__delitem__(self, key)
850
851 ## used in "for k in dict" loop to ensure the correct order
852 def __iter__(self):
853 return self.iterkeys()
854
855 ## len() support
856 def __len__(self):
857 return len(self._key_list)
858
859 ## "in" test support
860 def __contains__(self, key):
861 return key in self._key_list
862
863 ## indexof support
864 def index(self, key):
865 return self._key_list.index(key)
866
867 ## insert support
868 def insert(self, key, newkey, newvalue, order):
869 index = self._key_list.index(key)
870 if order == 'BEFORE':
871 self._key_list.insert(index, newkey)
872 IterableUserDict.__setitem__(self, newkey, newvalue)
873 elif order == 'AFTER':
874 self._key_list.insert(index + 1, newkey)
875 IterableUserDict.__setitem__(self, newkey, newvalue)
876
877 ## append support
878 def append(self, sdict):
879 for key in sdict:
880 if key not in self._key_list:
881 self._key_list.append(key)
882 IterableUserDict.__setitem__(self, key, sdict[key])
883
884 def has_key(self, key):
885 return key in self._key_list
886
887 ## Empty the dict
888 def clear(self):
889 self._key_list = []
890 IterableUserDict.clear(self)
891
892 ## Return a copy of keys
893 def keys(self):
894 keys = []
895 for key in self._key_list:
896 keys.append(key)
897 return keys
898
899 ## Return a copy of values
900 def values(self):
901 values = []
902 for key in self._key_list:
903 values.append(self[key])
904 return values
905
906 ## Return a copy of (key, value) list
907 def items(self):
908 items = []
909 for key in self._key_list:
910 items.append((key, self[key]))
911 return items
912
913 ## Iteration support
914 def iteritems(self):
915 return iter(self.items())
916
917 ## Keys interation support
918 def iterkeys(self):
919 return iter(self.keys())
920
921 ## Values interation support
922 def itervalues(self):
923 return iter(self.values())
924
925 ## Return value related to a key, and remove the (key, value) from the dict
926 def pop(self, key, *dv):
927 value = None
928 if key in self._key_list:
929 value = self[key]
930 self.__delitem__(key)
931 elif len(dv) != 0 :
932 value = kv[0]
933 return value
934
935 ## Return (key, value) pair, and remove the (key, value) from the dict
936 def popitem(self):
937 key = self._key_list[-1]
938 value = self[key]
939 self.__delitem__(key)
940 return key, value
941
942 def update(self, dict=None, **kwargs):
943 if dict != None:
944 for k, v in dict.items():
945 self[k] = v
946 if len(kwargs):
947 for k, v in kwargs.items():
948 self[k] = v
949
950 ## Dictionary with restricted keys
951 #
952 class rdict(dict):
953 ## Constructor
954 def __init__(self, KeyList):
955 for Key in KeyList:
956 dict.__setitem__(self, Key, "")
957
958 ## []= operator
959 def __setitem__(self, key, value):
960 if key not in self:
961 EdkLogger.error("RestrictedDict", ATTRIBUTE_SET_FAILURE, "Key [%s] is not allowed" % key,
962 ExtraData=", ".join(dict.keys(self)))
963 dict.__setitem__(self, key, value)
964
965 ## =[] operator
966 def __getitem__(self, key):
967 if key not in self:
968 return ""
969 return dict.__getitem__(self, key)
970
971 ## del operator
972 def __delitem__(self, key):
973 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="del")
974
975 ## Empty the dict
976 def clear(self):
977 for Key in self:
978 self.__setitem__(Key, "")
979
980 ## Return value related to a key, and remove the (key, value) from the dict
981 def pop(self, key, *dv):
982 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="pop")
983
984 ## Return (key, value) pair, and remove the (key, value) from the dict
985 def popitem(self):
986 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="popitem")
987
988 ## Dictionary using prioritized list as key
989 #
990 class tdict:
991 _ListType = type([])
992 _TupleType = type(())
993 _Wildcard = 'COMMON'
994 _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
995
996 def __init__(self, _Single_=False, _Level_=2):
997 self._Level_ = _Level_
998 self.data = {}
999 self._Single_ = _Single_
1000
1001 # =[] operator
1002 def __getitem__(self, key):
1003 KeyType = type(key)
1004 RestKeys = None
1005 if KeyType == self._ListType or KeyType == self._TupleType:
1006 FirstKey = key[0]
1007 if len(key) > 1:
1008 RestKeys = key[1:]
1009 elif self._Level_ > 1:
1010 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1011 else:
1012 FirstKey = key
1013 if self._Level_ > 1:
1014 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1015
1016 if FirstKey == None or str(FirstKey).upper() in self._ValidWildcardList:
1017 FirstKey = self._Wildcard
1018
1019 if self._Single_:
1020 return self._GetSingleValue(FirstKey, RestKeys)
1021 else:
1022 return self._GetAllValues(FirstKey, RestKeys)
1023
1024 def _GetSingleValue(self, FirstKey, RestKeys):
1025 Value = None
1026 #print "%s-%s" % (FirstKey, self._Level_) ,
1027 if self._Level_ > 1:
1028 if FirstKey == self._Wildcard:
1029 if FirstKey in self.data:
1030 Value = self.data[FirstKey][RestKeys]
1031 if Value == None:
1032 for Key in self.data:
1033 Value = self.data[Key][RestKeys]
1034 if Value != None: break
1035 else:
1036 if FirstKey in self.data:
1037 Value = self.data[FirstKey][RestKeys]
1038 if Value == None and self._Wildcard in self.data:
1039 #print "Value=None"
1040 Value = self.data[self._Wildcard][RestKeys]
1041 else:
1042 if FirstKey == self._Wildcard:
1043 if FirstKey in self.data:
1044 Value = self.data[FirstKey]
1045 if Value == None:
1046 for Key in self.data:
1047 Value = self.data[Key]
1048 if Value != None: break
1049 else:
1050 if FirstKey in self.data:
1051 Value = self.data[FirstKey]
1052 elif self._Wildcard in self.data:
1053 Value = self.data[self._Wildcard]
1054 return Value
1055
1056 def _GetAllValues(self, FirstKey, RestKeys):
1057 Value = []
1058 if self._Level_ > 1:
1059 if FirstKey == self._Wildcard:
1060 for Key in self.data:
1061 Value += self.data[Key][RestKeys]
1062 else:
1063 if FirstKey in self.data:
1064 Value += self.data[FirstKey][RestKeys]
1065 if self._Wildcard in self.data:
1066 Value += self.data[self._Wildcard][RestKeys]
1067 else:
1068 if FirstKey == self._Wildcard:
1069 for Key in self.data:
1070 Value.append(self.data[Key])
1071 else:
1072 if FirstKey in self.data:
1073 Value.append(self.data[FirstKey])
1074 if self._Wildcard in self.data:
1075 Value.append(self.data[self._Wildcard])
1076 return Value
1077
1078 ## []= operator
1079 def __setitem__(self, key, value):
1080 KeyType = type(key)
1081 RestKeys = None
1082 if KeyType == self._ListType or KeyType == self._TupleType:
1083 FirstKey = key[0]
1084 if len(key) > 1:
1085 RestKeys = key[1:]
1086 else:
1087 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1088 else:
1089 FirstKey = key
1090 if self._Level_ > 1:
1091 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1092
1093 if FirstKey in self._ValidWildcardList:
1094 FirstKey = self._Wildcard
1095
1096 if FirstKey not in self.data and self._Level_ > 0:
1097 self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)
1098
1099 if self._Level_ > 1:
1100 self.data[FirstKey][RestKeys] = value
1101 else:
1102 self.data[FirstKey] = value
1103
1104 def SetGreedyMode(self):
1105 self._Single_ = False
1106 if self._Level_ > 1:
1107 for Key in self.data:
1108 self.data[Key].SetGreedyMode()
1109
1110 def SetSingleMode(self):
1111 self._Single_ = True
1112 if self._Level_ > 1:
1113 for Key in self.data:
1114 self.data[Key].SetSingleMode()
1115
1116 ## Boolean chain list
1117 #
1118 class Blist(UserList):
1119 def __init__(self, initlist=None):
1120 UserList.__init__(self, initlist)
1121 def __setitem__(self, i, item):
1122 if item not in [True, False]:
1123 if item == 0:
1124 item = False
1125 else:
1126 item = True
1127 self.data[i] = item
1128 def _GetResult(self):
1129 Value = True
1130 for item in self.data:
1131 Value &= item
1132 return Value
1133 Result = property(_GetResult)
1134
1135 def ParseConsoleLog(Filename):
1136 Opr = open(os.path.normpath(Filename), 'r')
1137 Opw = open(os.path.normpath(Filename + '.New'), 'w+')
1138 for Line in Opr.readlines():
1139 if Line.find('.efi') > -1:
1140 Line = Line[Line.rfind(' ') : Line.rfind('.efi')].strip()
1141 Opw.write('%s\n' % Line)
1142
1143 Opr.close()
1144 Opw.close()
1145
1146 ## check format of PCD value against its the datum type
1147 #
1148 # For PCD value setting
1149 #
1150 def CheckPcdDatum(Type, Value):
1151 if Type == "VOID*":
1152 if not ((Value.startswith('L"') or Value.startswith('"') and Value.endswith('"'))
1153 or (Value.startswith('{') and Value.endswith('}'))
1154 ):
1155 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1156 ", or \"...\" for string, or L\"...\" for unicode string" % (Value, Type)
1157 elif Type == 'BOOLEAN':
1158 if Value not in ['TRUE', 'FALSE']:
1159 return False, "Invalid value [%s] of type [%s]; must be TRUE or FALSE" % (Value, Type)
1160 elif type(Value) == type(""):
1161 try:
1162 Value = long(Value, 0)
1163 except:
1164 return False, "Invalid value [%s] of type [%s];"\
1165 " must be a hexadecimal, decimal or octal in C language format."\
1166 % (Value, Type)
1167
1168 return True, ""
1169
1170 ## Split command line option string to list
1171 #
1172 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1173 # in non-windows platform to launch command
1174 #
1175 def SplitOption(OptionString):
1176 OptionList = []
1177 LastChar = " "
1178 OptionStart = 0
1179 QuotationMark = ""
1180 for Index in range(0, len(OptionString)):
1181 CurrentChar = OptionString[Index]
1182 if CurrentChar in ['"', "'"]:
1183 if QuotationMark == CurrentChar:
1184 QuotationMark = ""
1185 elif QuotationMark == "":
1186 QuotationMark = CurrentChar
1187 continue
1188 elif QuotationMark:
1189 continue
1190
1191 if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]:
1192 if Index > OptionStart:
1193 OptionList.append(OptionString[OptionStart:Index-1])
1194 OptionStart = Index
1195 LastChar = CurrentChar
1196 OptionList.append(OptionString[OptionStart:])
1197 return OptionList
1198
1199 def CommonPath(PathList):
1200 P1 = min(PathList).split(os.path.sep)
1201 P2 = max(PathList).split(os.path.sep)
1202 for Index in xrange(min(len(P1), len(P2))):
1203 if P1[Index] != P2[Index]:
1204 return os.path.sep.join(P1[:Index])
1205 return os.path.sep.join(P1)
1206
1207 class PathClass(object):
1208 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,
1209 Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):
1210 self.Arch = Arch
1211 self.File = str(File)
1212 if os.path.isabs(self.File):
1213 self.Root = ''
1214 self.AlterRoot = ''
1215 else:
1216 self.Root = str(Root)
1217 self.AlterRoot = str(AlterRoot)
1218
1219 # Remove any '.' and '..' in path
1220 if self.Root:
1221 self.Path = os.path.normpath(os.path.join(self.Root, self.File))
1222 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))
1223 # eliminate the side-effect of 'C:'
1224 if self.Root[-1] == ':':
1225 self.Root += os.path.sep
1226 # file path should not start with path separator
1227 if self.Root[-1] == os.path.sep:
1228 self.File = self.Path[len(self.Root):]
1229 else:
1230 self.File = self.Path[len(self.Root)+1:]
1231 else:
1232 self.Path = os.path.normpath(self.File)
1233
1234 self.SubDir, self.Name = os.path.split(self.File)
1235 self.BaseName, self.Ext = os.path.splitext(self.Name)
1236
1237 if self.Root:
1238 if self.SubDir:
1239 self.Dir = os.path.join(self.Root, self.SubDir)
1240 else:
1241 self.Dir = self.Root
1242 else:
1243 self.Dir = self.SubDir
1244
1245 if IsBinary:
1246 self.Type = Type
1247 else:
1248 self.Type = self.Ext.lower()
1249
1250 self.IsBinary = IsBinary
1251 self.Target = Target
1252 self.TagName = TagName
1253 self.ToolCode = ToolCode
1254 self.ToolChainFamily = ToolChainFamily
1255
1256 self._Key = None
1257
1258 ## Convert the object of this class to a string
1259 #
1260 # Convert member Path of the class to a string
1261 #
1262 # @retval string Formatted String
1263 #
1264 def __str__(self):
1265 return self.Path
1266
1267 ## Override __eq__ function
1268 #
1269 # Check whether PathClass are the same
1270 #
1271 # @retval False The two PathClass are different
1272 # @retval True The two PathClass are the same
1273 #
1274 def __eq__(self, Other):
1275 if type(Other) == type(self):
1276 return self.Path == Other.Path
1277 else:
1278 return self.Path == str(Other)
1279
1280 ## Override __hash__ function
1281 #
1282 # Use Path as key in hash table
1283 #
1284 # @retval string Key for hash table
1285 #
1286 def __hash__(self):
1287 return hash(self.Path)
1288
1289 def _GetFileKey(self):
1290 if self._Key == None:
1291 self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1292 return self._Key
1293
1294 def Validate(self, Type='', CaseSensitive=True):
1295 if GlobalData.gCaseInsensitive:
1296 CaseSensitive = False
1297 if Type and Type.lower() != self.Type:
1298 return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type)
1299
1300 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)
1301 if not RealRoot and not RealFile:
1302 return FILE_NOT_FOUND, self.File
1303
1304 ErrorCode = 0
1305 ErrorInfo = ''
1306 if RealRoot != self.Root or RealFile != self.File:
1307 if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)):
1308 ErrorCode = FILE_CASE_MISMATCH
1309 ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]"
1310
1311 self.SubDir, self.Name = os.path.split(RealFile)
1312 self.BaseName, self.Ext = os.path.splitext(self.Name)
1313 if self.SubDir:
1314 self.Dir = os.path.join(RealRoot, self.SubDir)
1315 else:
1316 self.Dir = RealRoot
1317 self.File = RealFile
1318 self.Root = RealRoot
1319 self.Path = os.path.join(RealRoot, RealFile)
1320 return ErrorCode, ErrorInfo
1321
1322 Key = property(_GetFileKey)
1323
1324 ##
1325 #
1326 # This acts like the main() function for the script, unless it is 'import'ed into another
1327 # script.
1328 #
1329 if __name__ == '__main__':
1330 pass
1331