]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/Misc.py
2 # Common routines used by all tools
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
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.
25 from UserDict
import IterableUserDict
26 from UserList
import UserList
28 from Common
import EdkLogger
as EdkLogger
29 from Common
import GlobalData
as GlobalData
31 from BuildToolError
import *
33 ## Regular expression used to find out place holders in string template
34 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE|re
.UNICODE
)
36 ## Dictionary used to store file time stamp for quick re-access
37 gFileTimeStampCache
= {} # {file path : file time stamp}
39 ## Dictionary used to store dependencies of files
40 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
42 ## callback routine for processing variable option
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)
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
55 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
58 RawArgs
= Parser
.rargs
61 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
62 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
66 setattr(Parser
.values
, Option
.dest
, Value
)
68 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
70 # @param Guid The GUID string
72 # @retval string The GUID string in C structure style
74 def GuidStringToGuidStructureString(Guid
):
75 GuidList
= Guid
.split('-')
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]
85 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
87 # @param GuidValue The GUID value in byte array
89 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
91 def GuidStructureByteArrayToGuidString(GuidValue
):
92 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
93 guidValueList
= guidValueString
.split(",")
94 if len(guidValueList
) != 16:
96 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
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)
119 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
121 # @param GuidValue The GUID value in C structure format
123 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
125 def GuidStructureStringToGuidString(GuidValue
):
126 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
127 guidValueList
= guidValueString
.split(",")
128 if len(guidValueList
) != 11:
130 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
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)
148 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
150 # @param GuidValue The GUID value in C structure format
152 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
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)
173 ## Create directories
175 # @param Directory The directory name
177 def CreateDirectory(Directory
):
178 if Directory
== None or Directory
.strip() == "":
181 if not os
.access(Directory
, os
.F_OK
):
182 os
.makedirs(Directory
)
187 ## Remove directories, including files and sub-directories in it
189 # @param Directory The directory name
191 def RemoveDirectory(Directory
, Recursively
=False):
192 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
195 CurrentDirectory
= os
.getcwd()
197 for File
in os
.listdir("."):
198 if os
.path
.isdir(File
):
199 RemoveDirectory(File
, Recursively
)
202 os
.chdir(CurrentDirectory
)
205 ## Check if given file is changed or not
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.
210 # @param File The path of file
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
217 if not os
.path
.exists(File
):
220 FileState
= os
.stat(File
)
221 TimeStamp
= FileState
[-2]
223 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
227 gFileTimeStampCache
[File
] = TimeStamp
231 ## Store content in file
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.
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
240 # @retval True If the file content is changed and the file is renewed
241 # @retval False If the file content is the same
243 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
245 Content
= Content
.replace("\n", os
.linesep
)
247 if os
.path
.exists(File
):
249 if Content
== open(File
, "rb").read():
252 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
254 CreateDirectory(os
.path
.dirname(File
))
256 if GlobalData
.gIsWindows
:
258 from PyUtility
import SaveFileToDisk
259 if not SaveFileToDisk(File
, Content
):
260 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
262 Fd
= open(File
, "wb")
266 Fd
= open(File
, "wb")
270 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
274 ## Make a Python object persistent on file system
276 # @param Data The object to be stored in file
277 # @param File The path of file to store the object
279 def DataDump(Data
, File
):
282 Fd
= open(File
, 'wb')
283 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
285 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
290 ## Restore a Python object from a file
292 # @param File The path of file stored the object
294 # @retval object A python object
295 # @retval None If failure in file operation
297 def DataRestore(File
):
301 Fd
= open(File
, 'rb')
302 Data
= cPickle
.load(Fd
)
304 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
311 ## Retrieve and cache the real path name in file system
313 # @param Root The root directory of path relative to
315 # @retval str The path string if the path exists
316 # @retval None If path doesn't exist
321 def __init__(self
, Root
):
323 for F
in os
.listdir(Root
):
324 self
._CACHE
_[F
.upper()] = F
327 def __getitem__(self
, Path
):
328 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
331 if Path
and Path
[0] == os
.path
.sep
:
334 if Path
in self
._CACHE
_:
335 return os
.path
.join(self
._Root
, self
._CACHE
_[Path
])
339 SepIndex
= Path
.find(os
.path
.sep
)
341 Parent
= Path
[:SepIndex
]
342 if Parent
not in self
._CACHE
_:
344 LastSepIndex
= SepIndex
345 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
347 if LastSepIndex
== -1:
352 SepIndex
= LastSepIndex
354 ParentKey
= Path
[:SepIndex
]
355 if ParentKey
not in self
._CACHE
_:
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
364 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
367 if Path
not in self
._CACHE
_:
369 return os
.path
.join(self
._Root
, self
._CACHE
_[Path
])
371 ## Get all files of a directory
373 # @param Root: Root dir
374 # @param SkipList : The files need be skipped
376 # @retval A list of all files
378 def GetFiles(Root
, SkipList
=None, FullPath
= True):
381 for Root
, Dirs
, Files
in os
.walk(Root
):
383 for Item
in SkipList
:
388 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
390 File
= File
[len(OriPath
) + 1:]
391 FileList
.append(File
)
395 ## Check if gvien file exists or not
397 # @param File File name or path to be checked
398 # @param Dir The directory the file is relative to
400 # @retval True if file exists
401 # @retval False if file doesn't exists
403 def ValidFile(File
, Ext
=None):
405 Dummy
, FileExt
= os
.path
.splitext(File
)
406 if FileExt
.lower() != Ext
.lower():
408 if not os
.path
.exists(File
):
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
]
420 def RealPath2(File
, Dir
='', OverrideDir
=''):
422 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
424 if OverrideDir
[-1] == os
.path
.sep
:
425 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
427 return NewFile
[len(OverrideDir
)+1:], NewFile
[0:len(OverrideDir
)]
429 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
432 if Dir
[-1] == os
.path
.sep
:
433 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
435 return NewFile
[len(Dir
)+1:], NewFile
[0:len(Dir
)]
441 ## Check if gvien file exists or not
444 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
447 Dummy
, FileExt
= os
.path
.splitext(File
)
448 if FileExt
.lower() != Ext
.lower():
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
)
458 # Replace the default dir to current dir
461 Dir
= Dir
[len(Workspace
)+1:]
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
)]
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
))]
477 # Last check the path with normal definitions
478 File
= os
.path
.join(Dir
, File
)
479 NewFile
= AllFiles
[os
.path
.normpath(File
)]
485 ## Check if gvien file exists or not
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
)
496 # Replace the default dir to current dir
497 # Dir is current module dir related to workspace
500 Dir
= Dir
[len(Workspace
)+1:]
503 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
504 NewRelaPath
= RelaPath
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
)]
513 NewRelaPath
= os
.path
.dirname(NewFile
)
514 File
= os
.path
.basename(NewFile
)
515 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
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
))]
522 #NewRelaPath = os.path.dirname(NewFile)
523 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
526 # Last check the path with normal definitions
527 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
534 return NewRelaPath
, RelaPath
, File
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
])
547 return os
.path
.normpath(FileName
)
550 ## Get GUID value from given packages
552 # @param CName The CName of the GUID
553 # @param PackageList List of packages looking-up in
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
558 def GuidValue(CName
, PackageList
):
559 for P
in PackageList
:
561 return P
.Guids
[CName
]
564 ## Get Protocol value from given packages
566 # @param CName The CName of the GUID
567 # @param PackageList List of packages looking-up in
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
572 def ProtocolValue(CName
, PackageList
):
573 for P
in PackageList
:
574 if CName
in P
.Protocols
:
575 return P
.Protocols
[CName
]
578 ## Get PPI value from given packages
580 # @param CName The CName of the GUID
581 # @param PackageList List of packages looking-up in
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
586 def PpiValue(CName
, PackageList
):
587 for P
in PackageList
:
592 ## A string template class
594 # This class implements a template for string replacement. A string template
595 # looks like following
597 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
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.
605 class TemplateString(object):
606 _REPEAT_START_FLAG
= "BEGIN"
607 _REPEAT_END_FLAG
= "END"
609 class Section(object):
610 _LIST_TYPES
= [type([]), type(set()), type((0,))]
612 def __init__(self
, TemplateSection
, PlaceHolderList
):
613 self
._Template
= TemplateSection
614 self
._PlaceHolderList
= []
616 # Split the section into sub-sections according to the position of placeholders
618 self
._SubSectionList
= []
621 # The placeholders passed in must be in the format of
623 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
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
:])
633 self
._SubSectionList
= [TemplateSection
]
636 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
638 def Instantiate(self
, PlaceHolderValues
):
640 RepeatPlaceHolders
= {}
641 NonRepeatPlaceHolders
= {}
643 for PlaceHolder
in self
._PlaceHolderList
:
644 if PlaceHolder
not in PlaceHolderValues
:
646 Value
= PlaceHolderValues
[PlaceHolder
]
647 if type(Value
) in self
._LIST
_TYPES
:
649 RepeatTime
= len(Value
)
650 elif RepeatTime
!= len(Value
):
654 "${%s} has different repeat time from others!" % PlaceHolder
,
655 ExtraData
=str(self
._Template
)
657 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
659 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
661 if NonRepeatPlaceHolders
:
663 for S
in self
._SubSectionList
:
664 if S
not in NonRepeatPlaceHolders
:
667 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
669 StringList
= self
._SubSectionList
671 if RepeatPlaceHolders
:
673 for Index
in range(RepeatTime
):
675 if S
not in RepeatPlaceHolders
:
676 TempStringList
.append(S
)
678 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
679 StringList
= TempStringList
681 return "".join(StringList
)
684 def __init__(self
, Template
=None):
686 self
._Template
= Template
687 self
._TemplateSectionList
= self
._Parse
(Template
)
691 # @retval string The string replaced
696 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
698 # @retval list A list of TemplateString.Section objects
700 def _Parse(self
, Template
):
705 TemplateSectionList
= []
707 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
709 if MatchEnd
< len(Template
):
710 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
711 TemplateSectionList
.append(TemplateSection
)
714 MatchString
= MatchObj
.group(1)
715 MatchStart
= MatchObj
.start()
716 MatchEnd
= MatchObj
.end()
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
724 elif MatchString
== self
._REPEAT
_END
_FLAG
:
725 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
726 TemplateSectionList
.append(TemplateSection
)
727 SectionStart
= MatchEnd
730 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
731 SearchFrom
= MatchEnd
732 return TemplateSectionList
734 ## Replace the string template with dictionary of placeholders and append it to previous one
736 # @param AppendString The string template to append
737 # @param Dictionary The placeholder dictionaries
739 def Append(self
, AppendString
, Dictionary
=None):
741 SectionList
= self
._Parse
(AppendString
)
742 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
744 self
.String
+= AppendString
746 ## Replace the string template with dictionary of placeholders
748 # @param Dictionary The placeholder dictionaries
750 # @retval str The string replaced with placeholder values
752 def Replace(self
, Dictionary
=None):
753 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
755 ## Progress indicator class
757 # This class makes use of thread to print progress on console.
760 # for avoiding deadloop
762 _ProgressThread
= None
763 _CheckInterval
= 0.25
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
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()
780 ## Start to print progress charater
782 # @param OpenMessage The string printed before progress charaters
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()
793 ## Stop printing progress charater
795 # @param CloseMessage The string printed after progress charaters
797 def Stop(self
, CloseMessage
=None):
798 OriginalCodaMessage
= self
.CodaMessage
799 if CloseMessage
!= None:
800 self
.CodaMessage
= CloseMessage
802 self
.CodaMessage
= OriginalCodaMessage
804 ## Thread entry method
805 def _ProgressThreadEntry(self
):
806 sys
.stdout
.write(self
.PromptMessage
+ " ")
809 while not Progressor
._StopFlag
.isSet():
811 sys
.stdout
.write(self
.ProgressChar
)
813 TimeUp
= self
.Interval
814 time
.sleep(self
._CheckInterval
)
815 TimeUp
-= self
._CheckInterval
816 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
819 ## Abort the progress display
822 if Progressor
._StopFlag
!= None:
823 Progressor
._StopFlag
.set()
824 if Progressor
._ProgressThread
!= None:
825 Progressor
._ProgressThread
.join()
826 Progressor
._ProgressThread
= None
828 ## A dict which can access its keys and/or values orderly
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.
834 class sdict(IterableUserDict
):
837 IterableUserDict
.__init
__(self
)
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
)
847 def __delitem__(self
, key
):
848 self
._key
_list
.remove(key
)
849 IterableUserDict
.__delitem
__(self
, key
)
851 ## used in "for k in dict" loop to ensure the correct order
853 return self
.iterkeys()
857 return len(self
._key
_list
)
860 def __contains__(self
, key
):
861 return key
in self
._key
_list
864 def index(self
, key
):
865 return self
._key
_list
.index(key
)
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
)
878 def append(self
, sdict
):
880 if key
not in self
._key
_list
:
881 self
._key
_list
.append(key
)
882 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
884 def has_key(self
, key
):
885 return key
in self
._key
_list
890 IterableUserDict
.clear(self
)
892 ## Return a copy of keys
895 for key
in self
._key
_list
:
899 ## Return a copy of values
902 for key
in self
._key
_list
:
903 values
.append(self
[key
])
906 ## Return a copy of (key, value) list
909 for key
in self
._key
_list
:
910 items
.append((key
, self
[key
]))
915 return iter(self
.items())
917 ## Keys interation support
919 return iter(self
.keys())
921 ## Values interation support
922 def itervalues(self
):
923 return iter(self
.values())
925 ## Return value related to a key, and remove the (key, value) from the dict
926 def pop(self
, key
, *dv
):
928 if key
in self
._key
_list
:
930 self
.__delitem
__(key
)
935 ## Return (key, value) pair, and remove the (key, value) from the dict
937 key
= self
._key
_list
[-1]
939 self
.__delitem
__(key
)
942 def update(self
, dict=None, **kwargs
):
944 for k
, v
in dict.items():
947 for k
, v
in kwargs
.items():
950 ## Dictionary with restricted keys
954 def __init__(self
, KeyList
):
956 dict.__setitem
__(self
, Key
, "")
959 def __setitem__(self
, key
, value
):
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
)
966 def __getitem__(self
, key
):
969 return dict.__getitem
__(self
, key
)
972 def __delitem__(self
, key
):
973 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
978 self
.__setitem
__(Key
, "")
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")
984 ## Return (key, value) pair, and remove the (key, value) from the dict
986 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
988 ## Dictionary using prioritized list as key
992 _TupleType
= type(())
994 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
996 def __init__(self
, _Single_
=False, _Level_
=2):
997 self
._Level
_ = _Level_
999 self
._Single
_ = _Single_
1002 def __getitem__(self
, key
):
1005 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1009 elif self
._Level
_ > 1:
1010 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1013 if self
._Level
_ > 1:
1014 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1016 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1017 FirstKey
= self
._Wildcard
1020 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1022 return self
._GetAllValues
(FirstKey
, RestKeys
)
1024 def _GetSingleValue(self
, FirstKey
, RestKeys
):
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
]
1032 for Key
in self
.data
:
1033 Value
= self
.data
[Key
][RestKeys
]
1034 if Value
!= None: break
1036 if FirstKey
in self
.data
:
1037 Value
= self
.data
[FirstKey
][RestKeys
]
1038 if Value
== None and self
._Wildcard
in self
.data
:
1040 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1042 if FirstKey
== self
._Wildcard
:
1043 if FirstKey
in self
.data
:
1044 Value
= self
.data
[FirstKey
]
1046 for Key
in self
.data
:
1047 Value
= self
.data
[Key
]
1048 if Value
!= None: break
1050 if FirstKey
in self
.data
:
1051 Value
= self
.data
[FirstKey
]
1052 elif self
._Wildcard
in self
.data
:
1053 Value
= self
.data
[self
._Wildcard
]
1056 def _GetAllValues(self
, FirstKey
, RestKeys
):
1058 if self
._Level
_ > 1:
1059 if FirstKey
== self
._Wildcard
:
1060 for Key
in self
.data
:
1061 Value
+= self
.data
[Key
][RestKeys
]
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
]
1068 if FirstKey
== self
._Wildcard
:
1069 for Key
in self
.data
:
1070 Value
.append(self
.data
[Key
])
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
])
1079 def __setitem__(self
, key
, value
):
1082 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1087 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1090 if self
._Level
_ > 1:
1091 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1093 if FirstKey
in self
._ValidWildcardList
:
1094 FirstKey
= self
._Wildcard
1096 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1097 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1099 if self
._Level
_ > 1:
1100 self
.data
[FirstKey
][RestKeys
] = value
1102 self
.data
[FirstKey
] = value
1104 def SetGreedyMode(self
):
1105 self
._Single
_ = False
1106 if self
._Level
_ > 1:
1107 for Key
in self
.data
:
1108 self
.data
[Key
].SetGreedyMode()
1110 def SetSingleMode(self
):
1111 self
._Single
_ = True
1112 if self
._Level
_ > 1:
1113 for Key
in self
.data
:
1114 self
.data
[Key
].SetSingleMode()
1116 ## Boolean chain list
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]:
1128 def _GetResult(self
):
1130 for item
in self
.data
:
1133 Result
= property(_GetResult
)
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
)
1146 ## check format of PCD value against its the datum type
1148 # For PCD value setting
1150 def CheckPcdDatum(Type
, Value
):
1152 if not ((Value
.startswith('L"') or Value
.startswith('"') and Value
.endswith('"'))
1153 or (Value
.startswith('{') and Value
.endswith('}'))
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(""):
1162 Value
= long(Value
, 0)
1164 return False, "Invalid value [%s] of type [%s];"\
1165 " must be a hexadecimal, decimal or octal in C language format."\
1170 ## Split command line option string to list
1172 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1173 # in non-windows platform to launch command
1175 def SplitOption(OptionString
):
1180 for Index
in range(0, len(OptionString
)):
1181 CurrentChar
= OptionString
[Index
]
1182 if CurrentChar
in ['"', "'"]:
1183 if QuotationMark
== CurrentChar
:
1185 elif QuotationMark
== "":
1186 QuotationMark
= CurrentChar
1191 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1192 if Index
> OptionStart
:
1193 OptionList
.append(OptionString
[OptionStart
:Index
-1])
1195 LastChar
= CurrentChar
1196 OptionList
.append(OptionString
[OptionStart
:])
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
)
1207 class PathClass(object):
1208 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1209 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1211 self
.File
= str(File
)
1212 if os
.path
.isabs(self
.File
):
1216 self
.Root
= str(Root
)
1217 self
.AlterRoot
= str(AlterRoot
)
1219 # Remove any '.' and '..' in path
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
):]
1230 self
.File
= self
.Path
[len(self
.Root
)+1:]
1232 self
.Path
= os
.path
.normpath(self
.File
)
1234 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1235 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1239 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1241 self
.Dir
= self
.Root
1243 self
.Dir
= self
.SubDir
1248 self
.Type
= self
.Ext
.lower()
1250 self
.IsBinary
= IsBinary
1251 self
.Target
= Target
1252 self
.TagName
= TagName
1253 self
.ToolCode
= ToolCode
1254 self
.ToolChainFamily
= ToolChainFamily
1258 ## Convert the object of this class to a string
1260 # Convert member Path of the class to a string
1262 # @retval string Formatted String
1267 ## Override __eq__ function
1269 # Check whether PathClass are the same
1271 # @retval False The two PathClass are different
1272 # @retval True The two PathClass are the same
1274 def __eq__(self
, Other
):
1275 if type(Other
) == type(self
):
1276 return self
.Path
== Other
.Path
1278 return self
.Path
== str(Other
)
1280 ## Override __hash__ function
1282 # Use Path as key in hash table
1284 # @retval string Key for hash table
1287 return hash(self
.Path
)
1289 def _GetFileKey(self
):
1290 if self
._Key
== None:
1291 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
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
)
1300 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1301 if not RealRoot
and not RealFile
:
1302 return FILE_NOT_FOUND
, self
.File
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]"
1311 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1312 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1314 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1317 self
.File
= RealFile
1318 self
.Root
= RealRoot
1319 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1320 return ErrorCode
, ErrorInfo
1322 Key
= property(_GetFileKey
)
1326 # This acts like the main() function for the script, unless it is 'import'ed into another
1329 if __name__
== '__main__':