]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/Misc.py
Check In tool source code based on Build tool project revision r1655.
[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 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]
422 if NewFile:
423 if Dir:
424 if Dir[-1] == os.path.sep:
425 return NewFile[len(Dir):], NewFile[0:len(Dir)]
426 else:
427 return NewFile[len(Dir)+1:], NewFile[0:len(Dir)]
428 else:
429 return NewFile, ''
430
431 if OverrideDir:
432 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
433 if NewFile:
434 return NewFile[len(OverrideDir)+1:], NewFile[0:len(OverrideDir)]
435 return None, None
436
437 ## Check if gvien file exists or not
438 #
439 #
440 def ValidFile2(AllFiles, File, Ext=None, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''):
441 NewFile = File
442 if Ext != None:
443 Dummy, FileExt = os.path.splitext(File)
444 if FileExt.lower() != Ext.lower():
445 return False, File
446
447 # Replace the R8 macros
448 if OverrideDir != '' and OverrideDir != None:
449 if OverrideDir.find('$(EFI_SOURCE)') > -1:
450 OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)
451 if OverrideDir.find('$(EDK_SOURCE)') > -1:
452 OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource)
453
454 # Replace the default dir to current dir
455 if Dir == '.':
456 Dir = os.getcwd()
457 Dir = Dir[len(Workspace)+1:]
458
459 # First check if File has R8 definition itself
460 if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:
461 NewFile = File.replace('$(EFI_SOURCE)', EfiSource)
462 NewFile = NewFile.replace('$(EDK_SOURCE)', EdkSource)
463 NewFile = AllFiles[os.path.normpath(NewFile)]
464 if NewFile != None:
465 return True, NewFile
466
467 # Second check the path with override value
468 if OverrideDir != '' and OverrideDir != None:
469 NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
470 if NewFile != None:
471 return True, NewFile
472
473 # Last check the path with normal definitions
474 File = os.path.join(Dir, File)
475 NewFile = AllFiles[os.path.normpath(File)]
476 if NewFile != None:
477 return True, NewFile
478
479 return False, File
480
481 ## Check if gvien file exists or not
482 #
483 #
484 def ValidFile3(AllFiles, File, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''):
485 # Replace the R8 macros
486 if OverrideDir != '' and OverrideDir != None:
487 if OverrideDir.find('$(EFI_SOURCE)') > -1:
488 OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource)
489 if OverrideDir.find('$(EDK_SOURCE)') > -1:
490 OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource)
491
492 # Replace the default dir to current dir
493 # Dir is current module dir related to workspace
494 if Dir == '.':
495 Dir = os.getcwd()
496 Dir = Dir[len(Workspace)+1:]
497
498 NewFile = File
499 RelaPath = AllFiles[os.path.normpath(Dir)]
500 NewRelaPath = RelaPath
501
502 while(True):
503 # First check if File has R8 definition itself
504 if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1:
505 File = File.replace('$(EFI_SOURCE)', EfiSource)
506 File = File.replace('$(EDK_SOURCE)', EdkSource)
507 NewFile = AllFiles[os.path.normpath(File)]
508 if NewFile != None:
509 NewRelaPath = os.path.dirname(NewFile)
510 File = os.path.basename(NewFile)
511 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
512 break
513
514 # Second check the path with override value
515 if OverrideDir != '' and OverrideDir != None:
516 NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
517 if NewFile != None:
518 #NewRelaPath = os.path.dirname(NewFile)
519 NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
520 break
521
522 # Last check the path with normal definitions
523 NewFile = AllFiles[os.path.normpath(os.path.join(Dir, File))]
524 if NewFile != None:
525 break
526
527 # No file found
528 break
529
530 return NewRelaPath, RelaPath, File
531
532
533 def GetRelPath(Path1, Path2):
534 FileName = os.path.basename(Path2)
535 L1 = os.path.normpath(Path1).split(os.path.normpath('/'))
536 L2 = os.path.normpath(Path2).split(os.path.normpath('/'))
537 for Index in range(0, len(L1)):
538 if L1[Index] != L2[Index]:
539 FileName = '../' * (len(L1) - Index)
540 for Index2 in range(Index, len(L2)):
541 FileName = os.path.join(FileName, L2[Index2])
542 break
543 return os.path.normpath(FileName)
544
545
546 ## Get GUID value from given packages
547 #
548 # @param CName The CName of the GUID
549 # @param PackageList List of packages looking-up in
550 #
551 # @retval GuidValue if the CName is found in any given package
552 # @retval None if the CName is not found in all given packages
553 #
554 def GuidValue(CName, PackageList):
555 for P in PackageList:
556 if CName in P.Guids:
557 return P.Guids[CName]
558 return None
559
560 ## Get Protocol value from given packages
561 #
562 # @param CName The CName of the GUID
563 # @param PackageList List of packages looking-up in
564 #
565 # @retval GuidValue if the CName is found in any given package
566 # @retval None if the CName is not found in all given packages
567 #
568 def ProtocolValue(CName, PackageList):
569 for P in PackageList:
570 if CName in P.Protocols:
571 return P.Protocols[CName]
572 return None
573
574 ## Get PPI value from given packages
575 #
576 # @param CName The CName of the GUID
577 # @param PackageList List of packages looking-up in
578 #
579 # @retval GuidValue if the CName is found in any given package
580 # @retval None if the CName is not found in all given packages
581 #
582 def PpiValue(CName, PackageList):
583 for P in PackageList:
584 if CName in P.Ppis:
585 return P.Ppis[CName]
586 return None
587
588 ## A string template class
589 #
590 # This class implements a template for string replacement. A string template
591 # looks like following
592 #
593 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
594 #
595 # The string between ${BEGIN} and ${END} will be repeated as many times as the
596 # length of "placeholder_name", which is a list passed through a dict. The
597 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
598 # be not used and, in this case, the "placeholder_name" must not a list and it
599 # will just be replaced once.
600 #
601 class TemplateString(object):
602 _REPEAT_START_FLAG = "BEGIN"
603 _REPEAT_END_FLAG = "END"
604
605 class Section(object):
606 _LIST_TYPES = [type([]), type(set()), type((0,))]
607
608 def __init__(self, TemplateSection, PlaceHolderList):
609 self._Template = TemplateSection
610 self._PlaceHolderList = []
611
612 # Split the section into sub-sections according to the position of placeholders
613 if PlaceHolderList:
614 self._SubSectionList = []
615 SubSectionStart = 0
616 #
617 # The placeholders passed in must be in the format of
618 #
619 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
620 #
621 for PlaceHolder,Start,End in PlaceHolderList:
622 self._SubSectionList.append(TemplateSection[SubSectionStart:Start])
623 self._SubSectionList.append(TemplateSection[Start:End])
624 self._PlaceHolderList.append(PlaceHolder)
625 SubSectionStart = End
626 if SubSectionStart < len(TemplateSection):
627 self._SubSectionList.append(TemplateSection[SubSectionStart:])
628 else:
629 self._SubSectionList = [TemplateSection]
630
631 def __str__(self):
632 return self._Template + " : " + str(self._PlaceHolderList)
633
634 def Instantiate(self, PlaceHolderValues):
635 RepeatTime = -1
636 RepeatPlaceHolders = {}
637 NonRepeatPlaceHolders = {}
638
639 for PlaceHolder in self._PlaceHolderList:
640 if PlaceHolder not in PlaceHolderValues:
641 continue
642 Value = PlaceHolderValues[PlaceHolder]
643 if type(Value) in self._LIST_TYPES:
644 if RepeatTime < 0:
645 RepeatTime = len(Value)
646 elif RepeatTime != len(Value):
647 EdkLogger.error(
648 "TemplateString",
649 PARAMETER_INVALID,
650 "${%s} has different repeat time from others!" % PlaceHolder,
651 ExtraData=str(self._Template)
652 )
653 RepeatPlaceHolders["${%s}" % PlaceHolder] = Value
654 else:
655 NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value
656
657 if NonRepeatPlaceHolders:
658 StringList = []
659 for S in self._SubSectionList:
660 if S not in NonRepeatPlaceHolders:
661 StringList.append(S)
662 else:
663 StringList.append(str(NonRepeatPlaceHolders[S]))
664 else:
665 StringList = self._SubSectionList
666
667 if RepeatPlaceHolders:
668 TempStringList = []
669 for Index in range(RepeatTime):
670 for S in StringList:
671 if S not in RepeatPlaceHolders:
672 TempStringList.append(S)
673 else:
674 TempStringList.append(str(RepeatPlaceHolders[S][Index]))
675 StringList = TempStringList
676
677 return "".join(StringList)
678
679 ## Constructor
680 def __init__(self, Template=None):
681 self.String = ''
682 self._Template = Template
683 self._TemplateSectionList = self._Parse(Template)
684
685 ## str() operator
686 #
687 # @retval string The string replaced
688 #
689 def __str__(self):
690 return self.String
691
692 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
693 #
694 # @retval list A list of TemplateString.Section objects
695 #
696 def _Parse(self, Template):
697 SectionStart = 0
698 SearchFrom = 0
699 MatchEnd = 0
700 PlaceHolderList = []
701 TemplateSectionList = []
702 while Template:
703 MatchObj = gPlaceholderPattern.search(Template, SearchFrom)
704 if not MatchObj:
705 if MatchEnd < len(Template):
706 TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)
707 TemplateSectionList.append(TemplateSection)
708 break
709
710 MatchString = MatchObj.group(1)
711 MatchStart = MatchObj.start()
712 MatchEnd = MatchObj.end()
713
714 if MatchString == self._REPEAT_START_FLAG:
715 if MatchStart > SectionStart:
716 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
717 TemplateSectionList.append(TemplateSection)
718 SectionStart = MatchEnd
719 PlaceHolderList = []
720 elif MatchString == self._REPEAT_END_FLAG:
721 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
722 TemplateSectionList.append(TemplateSection)
723 SectionStart = MatchEnd
724 PlaceHolderList = []
725 else:
726 PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))
727 SearchFrom = MatchEnd
728 return TemplateSectionList
729
730 ## Replace the string template with dictionary of placeholders and append it to previous one
731 #
732 # @param AppendString The string template to append
733 # @param Dictionary The placeholder dictionaries
734 #
735 def Append(self, AppendString, Dictionary=None):
736 if Dictionary:
737 SectionList = self._Parse(AppendString)
738 self.String += "".join([S.Instantiate(Dictionary) for S in SectionList])
739 else:
740 self.String += AppendString
741
742 ## Replace the string template with dictionary of placeholders
743 #
744 # @param Dictionary The placeholder dictionaries
745 #
746 # @retval str The string replaced with placeholder values
747 #
748 def Replace(self, Dictionary=None):
749 return "".join([S.Instantiate(Dictionary) for S in self._TemplateSectionList])
750
751 ## Progress indicator class
752 #
753 # This class makes use of thread to print progress on console.
754 #
755 class Progressor:
756 # for avoiding deadloop
757 _StopFlag = None
758 _ProgressThread = None
759 _CheckInterval = 0.25
760
761 ## Constructor
762 #
763 # @param OpenMessage The string printed before progress charaters
764 # @param CloseMessage The string printed after progress charaters
765 # @param ProgressChar The charater used to indicate the progress
766 # @param Interval The interval in seconds between two progress charaters
767 #
768 def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):
769 self.PromptMessage = OpenMessage
770 self.CodaMessage = CloseMessage
771 self.ProgressChar = ProgressChar
772 self.Interval = Interval
773 if Progressor._StopFlag == None:
774 Progressor._StopFlag = threading.Event()
775
776 ## Start to print progress charater
777 #
778 # @param OpenMessage The string printed before progress charaters
779 #
780 def Start(self, OpenMessage=None):
781 if OpenMessage != None:
782 self.PromptMessage = OpenMessage
783 Progressor._StopFlag.clear()
784 if Progressor._ProgressThread == None:
785 Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)
786 Progressor._ProgressThread.setDaemon(False)
787 Progressor._ProgressThread.start()
788
789 ## Stop printing progress charater
790 #
791 # @param CloseMessage The string printed after progress charaters
792 #
793 def Stop(self, CloseMessage=None):
794 OriginalCodaMessage = self.CodaMessage
795 if CloseMessage != None:
796 self.CodaMessage = CloseMessage
797 self.Abort()
798 self.CodaMessage = OriginalCodaMessage
799
800 ## Thread entry method
801 def _ProgressThreadEntry(self):
802 sys.stdout.write(self.PromptMessage + " ")
803 sys.stdout.flush()
804 TimeUp = 0.0
805 while not Progressor._StopFlag.isSet():
806 if TimeUp <= 0.0:
807 sys.stdout.write(self.ProgressChar)
808 sys.stdout.flush()
809 TimeUp = self.Interval
810 time.sleep(self._CheckInterval)
811 TimeUp -= self._CheckInterval
812 sys.stdout.write(" " + self.CodaMessage + "\n")
813 sys.stdout.flush()
814
815 ## Abort the progress display
816 @staticmethod
817 def Abort():
818 if Progressor._StopFlag != None:
819 Progressor._StopFlag.set()
820 if Progressor._ProgressThread != None:
821 Progressor._ProgressThread.join()
822 Progressor._ProgressThread = None
823
824 ## A dict which can access its keys and/or values orderly
825 #
826 # The class implements a new kind of dict which its keys or values can be
827 # accessed in the order they are added into the dict. It guarantees the order
828 # by making use of an internal list to keep a copy of keys.
829 #
830 class sdict(IterableUserDict):
831 ## Constructor
832 def __init__(self):
833 IterableUserDict.__init__(self)
834 self._key_list = []
835
836 ## [] operator
837 def __setitem__(self, key, value):
838 if key not in self._key_list:
839 self._key_list.append(key)
840 IterableUserDict.__setitem__(self, key, value)
841
842 ## del operator
843 def __delitem__(self, key):
844 self._key_list.remove(key)
845 IterableUserDict.__delitem__(self, key)
846
847 ## used in "for k in dict" loop to ensure the correct order
848 def __iter__(self):
849 return self.iterkeys()
850
851 ## len() support
852 def __len__(self):
853 return len(self._key_list)
854
855 ## "in" test support
856 def __contains__(self, key):
857 return key in self._key_list
858
859 ## indexof support
860 def index(self, key):
861 return self._key_list.index(key)
862
863 ## insert support
864 def insert(self, key, newkey, newvalue, order):
865 index = self._key_list.index(key)
866 if order == 'BEFORE':
867 self._key_list.insert(index, newkey)
868 IterableUserDict.__setitem__(self, newkey, newvalue)
869 elif order == 'AFTER':
870 self._key_list.insert(index + 1, newkey)
871 IterableUserDict.__setitem__(self, newkey, newvalue)
872
873 ## append support
874 def append(self, sdict):
875 for key in sdict:
876 if key not in self._key_list:
877 self._key_list.append(key)
878 IterableUserDict.__setitem__(self, key, sdict[key])
879
880 def has_key(self, key):
881 return key in self._key_list
882
883 ## Empty the dict
884 def clear(self):
885 self._key_list = []
886 IterableUserDict.clear(self)
887
888 ## Return a copy of keys
889 def keys(self):
890 keys = []
891 for key in self._key_list:
892 keys.append(key)
893 return keys
894
895 ## Return a copy of values
896 def values(self):
897 values = []
898 for key in self._key_list:
899 values.append(self[key])
900 return values
901
902 ## Return a copy of (key, value) list
903 def items(self):
904 items = []
905 for key in self._key_list:
906 items.append((key, self[key]))
907 return items
908
909 ## Iteration support
910 def iteritems(self):
911 return iter(self.items())
912
913 ## Keys interation support
914 def iterkeys(self):
915 return iter(self.keys())
916
917 ## Values interation support
918 def itervalues(self):
919 return iter(self.values())
920
921 ## Return value related to a key, and remove the (key, value) from the dict
922 def pop(self, key, *dv):
923 value = None
924 if key in self._key_list:
925 value = self[key]
926 self.__delitem__(key)
927 elif len(dv) != 0 :
928 value = kv[0]
929 return value
930
931 ## Return (key, value) pair, and remove the (key, value) from the dict
932 def popitem(self):
933 key = self._key_list[-1]
934 value = self[key]
935 self.__delitem__(key)
936 return key, value
937
938 def update(self, dict=None, **kwargs):
939 if dict != None:
940 for k, v in dict.items():
941 self[k] = v
942 if len(kwargs):
943 for k, v in kwargs.items():
944 self[k] = v
945
946 ## Dictionary with restricted keys
947 #
948 class rdict(dict):
949 ## Constructor
950 def __init__(self, KeyList):
951 for Key in KeyList:
952 dict.__setitem__(self, Key, "")
953
954 ## []= operator
955 def __setitem__(self, key, value):
956 if key not in self:
957 EdkLogger.error("RestrictedDict", ATTRIBUTE_SET_FAILURE, "Key [%s] is not allowed" % key,
958 ExtraData=", ".join(dict.keys(self)))
959 dict.__setitem__(self, key, value)
960
961 ## =[] operator
962 def __getitem__(self, key):
963 if key not in self:
964 return ""
965 return dict.__getitem__(self, key)
966
967 ## del operator
968 def __delitem__(self, key):
969 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="del")
970
971 ## Empty the dict
972 def clear(self):
973 for Key in self:
974 self.__setitem__(Key, "")
975
976 ## Return value related to a key, and remove the (key, value) from the dict
977 def pop(self, key, *dv):
978 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="pop")
979
980 ## Return (key, value) pair, and remove the (key, value) from the dict
981 def popitem(self):
982 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="popitem")
983
984 ## Dictionary using prioritized list as key
985 #
986 class tdict:
987 _ListType = type([])
988 _TupleType = type(())
989 _Wildcard = 'COMMON'
990 _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
991
992 def __init__(self, _Single_=False, _Level_=2):
993 self._Level_ = _Level_
994 self.data = {}
995 self._Single_ = _Single_
996
997 # =[] operator
998 def __getitem__(self, key):
999 KeyType = type(key)
1000 RestKeys = None
1001 if KeyType == self._ListType or KeyType == self._TupleType:
1002 FirstKey = key[0]
1003 if len(key) > 1:
1004 RestKeys = key[1:]
1005 elif self._Level_ > 1:
1006 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1007 else:
1008 FirstKey = key
1009 if self._Level_ > 1:
1010 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1011
1012 if FirstKey == None or str(FirstKey).upper() in self._ValidWildcardList:
1013 FirstKey = self._Wildcard
1014
1015 if self._Single_:
1016 return self._GetSingleValue(FirstKey, RestKeys)
1017 else:
1018 return self._GetAllValues(FirstKey, RestKeys)
1019
1020 def _GetSingleValue(self, FirstKey, RestKeys):
1021 Value = None
1022 #print "%s-%s" % (FirstKey, self._Level_) ,
1023 if self._Level_ > 1:
1024 if FirstKey == self._Wildcard:
1025 if FirstKey in self.data:
1026 Value = self.data[FirstKey][RestKeys]
1027 if Value == None:
1028 for Key in self.data:
1029 Value = self.data[Key][RestKeys]
1030 if Value != None: break
1031 else:
1032 if FirstKey in self.data:
1033 Value = self.data[FirstKey][RestKeys]
1034 if Value == None and self._Wildcard in self.data:
1035 #print "Value=None"
1036 Value = self.data[self._Wildcard][RestKeys]
1037 else:
1038 if FirstKey == self._Wildcard:
1039 if FirstKey in self.data:
1040 Value = self.data[FirstKey]
1041 if Value == None:
1042 for Key in self.data:
1043 Value = self.data[Key]
1044 if Value != None: break
1045 else:
1046 if FirstKey in self.data:
1047 Value = self.data[FirstKey]
1048 elif self._Wildcard in self.data:
1049 Value = self.data[self._Wildcard]
1050 return Value
1051
1052 def _GetAllValues(self, FirstKey, RestKeys):
1053 Value = []
1054 if self._Level_ > 1:
1055 if FirstKey == self._Wildcard:
1056 for Key in self.data:
1057 Value += self.data[Key][RestKeys]
1058 else:
1059 if FirstKey in self.data:
1060 Value += self.data[FirstKey][RestKeys]
1061 if self._Wildcard in self.data:
1062 Value += self.data[self._Wildcard][RestKeys]
1063 else:
1064 if FirstKey == self._Wildcard:
1065 for Key in self.data:
1066 Value.append(self.data[Key])
1067 else:
1068 if FirstKey in self.data:
1069 Value.append(self.data[FirstKey])
1070 if self._Wildcard in self.data:
1071 Value.append(self.data[self._Wildcard])
1072 return Value
1073
1074 ## []= operator
1075 def __setitem__(self, key, value):
1076 KeyType = type(key)
1077 RestKeys = None
1078 if KeyType == self._ListType or KeyType == self._TupleType:
1079 FirstKey = key[0]
1080 if len(key) > 1:
1081 RestKeys = key[1:]
1082 else:
1083 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1084 else:
1085 FirstKey = key
1086 if self._Level_ > 1:
1087 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]
1088
1089 if FirstKey in self._ValidWildcardList:
1090 FirstKey = self._Wildcard
1091
1092 if FirstKey not in self.data and self._Level_ > 0:
1093 self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)
1094
1095 if self._Level_ > 1:
1096 self.data[FirstKey][RestKeys] = value
1097 else:
1098 self.data[FirstKey] = value
1099
1100 def SetGreedyMode(self):
1101 self._Single_ = False
1102 if self._Level_ > 1:
1103 for Key in self.data:
1104 self.data[Key].SetGreedyMode()
1105
1106 def SetSingleMode(self):
1107 self._Single_ = True
1108 if self._Level_ > 1:
1109 for Key in self.data:
1110 self.data[Key].SetSingleMode()
1111
1112 ## Boolean chain list
1113 #
1114 class Blist(UserList):
1115 def __init__(self, initlist=None):
1116 UserList.__init__(self, initlist)
1117 def __setitem__(self, i, item):
1118 if item not in [True, False]:
1119 if item == 0:
1120 item = False
1121 else:
1122 item = True
1123 self.data[i] = item
1124 def _GetResult(self):
1125 Value = True
1126 for item in self.data:
1127 Value &= item
1128 return Value
1129 Result = property(_GetResult)
1130
1131 def ParseConsoleLog(Filename):
1132 Opr = open(os.path.normpath(Filename), 'r')
1133 Opw = open(os.path.normpath(Filename + '.New'), 'w+')
1134 for Line in Opr.readlines():
1135 if Line.find('.efi') > -1:
1136 Line = Line[Line.rfind(' ') : Line.rfind('.efi')].strip()
1137 Opw.write('%s\n' % Line)
1138
1139 Opr.close()
1140 Opw.close()
1141
1142 ## check format of PCD value against its the datum type
1143 #
1144 # For PCD value setting
1145 #
1146 def CheckPcdDatum(Type, Value):
1147 if Type == "VOID*":
1148 if not ((Value.startswith('L"') or Value.startswith('"') and Value.endswith('"'))
1149 or (Value.startswith('{') and Value.endswith('}'))
1150 ):
1151 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1152 ", or \"...\" for string, or L\"...\" for unicode string" % (Value, Type)
1153 elif Type == 'BOOLEAN':
1154 if Value not in ['TRUE', 'FALSE']:
1155 return False, "Invalid value [%s] of type [%s]; must be TRUE or FALSE" % (Value, Type)
1156 elif type(Value) == type(""):
1157 try:
1158 Value = long(Value, 0)
1159 except:
1160 return False, "Invalid value [%s] of type [%s];"\
1161 " must be a hexadecimal, decimal or octal in C language format."\
1162 % (Value, Type)
1163
1164 return True, ""
1165
1166 ## Split command line option string to list
1167 #
1168 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1169 # in non-windows platform to launch command
1170 #
1171 def SplitOption(OptionString):
1172 OptionList = []
1173 LastChar = " "
1174 OptionStart = 0
1175 QuotationMark = ""
1176 for Index in range(0, len(OptionString)):
1177 CurrentChar = OptionString[Index]
1178 if CurrentChar in ['"', "'"]:
1179 if QuotationMark == CurrentChar:
1180 QuotationMark = ""
1181 elif QuotationMark == "":
1182 QuotationMark = CurrentChar
1183 continue
1184 elif QuotationMark:
1185 continue
1186
1187 if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]:
1188 if Index > OptionStart:
1189 OptionList.append(OptionString[OptionStart:Index-1])
1190 OptionStart = Index
1191 LastChar = CurrentChar
1192 OptionList.append(OptionString[OptionStart:])
1193 return OptionList
1194
1195 def CommonPath(PathList):
1196 P1 = min(PathList).split(os.path.sep)
1197 P2 = max(PathList).split(os.path.sep)
1198 for Index in xrange(min(len(P1), len(P2))):
1199 if P1[Index] != P2[Index]:
1200 return os.path.sep.join(P1[:Index])
1201 return os.path.sep.join(P1)
1202
1203 class PathClass(object):
1204 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,
1205 Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):
1206 self.Arch = Arch
1207 self.File = str(File)
1208 if os.path.isabs(self.File):
1209 self.Root = ''
1210 self.AlterRoot = ''
1211 else:
1212 self.Root = str(Root)
1213 self.AlterRoot = str(AlterRoot)
1214
1215 # Remove any '.' and '..' in path
1216 if self.Root:
1217 self.Path = os.path.normpath(os.path.join(self.Root, self.File))
1218 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))
1219 # eliminate the side-effect of 'C:'
1220 if self.Root[-1] == ':':
1221 self.Root += os.path.sep
1222 # file path should not start with path separator
1223 if self.Root[-1] == os.path.sep:
1224 self.File = self.Path[len(self.Root):]
1225 else:
1226 self.File = self.Path[len(self.Root)+1:]
1227 else:
1228 self.Path = os.path.normpath(self.File)
1229
1230 self.SubDir, self.Name = os.path.split(self.File)
1231 self.BaseName, self.Ext = os.path.splitext(self.Name)
1232
1233 if self.Root:
1234 if self.SubDir:
1235 self.Dir = os.path.join(self.Root, self.SubDir)
1236 else:
1237 self.Dir = self.Root
1238 else:
1239 self.Dir = self.SubDir
1240
1241 if IsBinary:
1242 self.Type = Type
1243 else:
1244 self.Type = self.Ext.lower()
1245
1246 self.IsBinary = IsBinary
1247 self.Target = Target
1248 self.TagName = TagName
1249 self.ToolCode = ToolCode
1250 self.ToolChainFamily = ToolChainFamily
1251
1252 self._Key = None
1253
1254 ## Convert the object of this class to a string
1255 #
1256 # Convert member Path of the class to a string
1257 #
1258 # @retval string Formatted String
1259 #
1260 def __str__(self):
1261 return self.Path
1262
1263 ## Override __eq__ function
1264 #
1265 # Check whether PathClass are the same
1266 #
1267 # @retval False The two PathClass are different
1268 # @retval True The two PathClass are the same
1269 #
1270 def __eq__(self, Other):
1271 if type(Other) == type(self):
1272 return self.Path == Other.Path
1273 else:
1274 return self.Path == str(Other)
1275
1276 ## Override __hash__ function
1277 #
1278 # Use Path as key in hash table
1279 #
1280 # @retval string Key for hash table
1281 #
1282 def __hash__(self):
1283 return hash(self.Path)
1284
1285 def _GetFileKey(self):
1286 if self._Key == None:
1287 self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1288 return self._Key
1289
1290 def Validate(self, Type='', CaseSensitive=True):
1291 if GlobalData.gCaseInsensitive:
1292 CaseSensitive = False
1293 if Type and Type.lower() != self.Type:
1294 return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type)
1295
1296 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)
1297 if not RealRoot and not RealFile:
1298 return FILE_NOT_FOUND, self.File
1299
1300 ErrorCode = 0
1301 ErrorInfo = ''
1302 if RealRoot != self.Root or RealFile != self.File:
1303 if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)):
1304 ErrorCode = FILE_CASE_MISMATCH
1305 ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]"
1306
1307 self.SubDir, self.Name = os.path.split(RealFile)
1308 self.BaseName, self.Ext = os.path.splitext(self.Name)
1309 if self.SubDir:
1310 self.Dir = os.path.join(RealRoot, self.SubDir)
1311 else:
1312 self.Dir = RealRoot
1313 self.File = RealFile
1314 self.Root = RealRoot
1315 self.Path = os.path.join(RealRoot, RealFile)
1316 return ErrorCode, ErrorInfo
1317
1318 Key = property(_GetFileKey)
1319
1320 ##
1321 #
1322 # This acts like the main() function for the script, unless it is 'import'ed into another
1323 # script.
1324 #
1325 if __name__ == '__main__':
1326 pass
1327