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