| ## @file |
| # Common routines used by all tools |
| # |
| # Copyright (c) 2007, Intel Corporation |
| # All rights reserved. This program and the accompanying materials |
| # are licensed and made available under the terms and conditions of the BSD License |
| # which accompanies this distribution. The full text of the license may be found at |
| # http://opensource.org/licenses/bsd-license.php |
| # |
| # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. |
| # |
| |
| ## |
| # Import Modules |
| # |
| import os |
| import sys |
| import string |
| import thread |
| import threading |
| import time |
| import re |
| import cPickle |
| from UserDict import IterableUserDict |
| from UserList import UserList |
| |
| from Common import EdkLogger as EdkLogger |
| from Common import GlobalData as GlobalData |
| |
| from BuildToolError import * |
| |
| ## Regular expression used to find out place holders in string template |
| gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE|re.UNICODE) |
| |
| ## Dictionary used to store file time stamp for quick re-access |
| gFileTimeStampCache = {} # {file path : file time stamp} |
| |
| ## Dictionary used to store dependencies of files |
| gDependencyDatabase = {} # arch : {file path : [dependent files list]} |
| |
| ## callback routine for processing variable option |
| # |
| # This function can be used to process variable number of option values. The |
| # typical usage of it is specify architecure list on command line. |
| # (e.g. <tool> -a IA32 X64 IPF) |
| # |
| # @param Option Standard callback function parameter |
| # @param OptionString Standard callback function parameter |
| # @param Value Standard callback function parameter |
| # @param Parser Standard callback function parameter |
| # |
| # @retval |
| # |
| def ProcessVariableArgument(Option, OptionString, Value, Parser): |
| assert Value is None |
| Value = [] |
| RawArgs = Parser.rargs |
| while RawArgs: |
| Arg = RawArgs[0] |
| if (Arg[:2] == "--" and len(Arg) > 2) or \ |
| (Arg[:1] == "-" and len(Arg) > 1 and Arg[1] != "-"): |
| break |
| Value.append(Arg) |
| del RawArgs[0] |
| setattr(Parser.values, Option.dest, Value) |
| |
| ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style |
| # |
| # @param Guid The GUID string |
| # |
| # @retval string The GUID string in C structure style |
| # |
| def GuidStringToGuidStructureString(Guid): |
| GuidList = Guid.split('-') |
| Result = '{' |
| for Index in range(0,3,1): |
| Result = Result + '0x' + GuidList[Index] + ', ' |
| Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4] |
| for Index in range(0,12,2): |
| Result = Result + ', 0x' + GuidList[4][Index:Index+2] |
| Result += '}}' |
| return Result |
| |
| ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
| # |
| # @param GuidValue The GUID value in byte array |
| # |
| # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format |
| # |
| def GuidStructureByteArrayToGuidString(GuidValue): |
| guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "") |
| guidValueList = guidValueString.split(",") |
| if len(guidValueList) != 16: |
| return '' |
| #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue) |
| try: |
| return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % ( |
| int(guidValueList[3], 16), |
| int(guidValueList[2], 16), |
| int(guidValueList[1], 16), |
| int(guidValueList[0], 16), |
| int(guidValueList[5], 16), |
| int(guidValueList[4], 16), |
| int(guidValueList[7], 16), |
| int(guidValueList[6], 16), |
| int(guidValueList[8], 16), |
| int(guidValueList[9], 16), |
| int(guidValueList[10], 16), |
| int(guidValueList[11], 16), |
| int(guidValueList[12], 16), |
| int(guidValueList[13], 16), |
| int(guidValueList[14], 16), |
| int(guidValueList[15], 16) |
| ) |
| except: |
| return '' |
| |
| ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
| # |
| # @param GuidValue The GUID value in C structure format |
| # |
| # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format |
| # |
| def GuidStructureStringToGuidString(GuidValue): |
| guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "") |
| guidValueList = guidValueString.split(",") |
| if len(guidValueList) != 11: |
| return '' |
| #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue) |
| try: |
| return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % ( |
| int(guidValueList[0], 16), |
| int(guidValueList[1], 16), |
| int(guidValueList[2], 16), |
| int(guidValueList[3], 16), |
| int(guidValueList[4], 16), |
| int(guidValueList[5], 16), |
| int(guidValueList[6], 16), |
| int(guidValueList[7], 16), |
| int(guidValueList[8], 16), |
| int(guidValueList[9], 16), |
| int(guidValueList[10], 16) |
| ) |
| except: |
| return '' |
| |
| ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx |
| # |
| # @param GuidValue The GUID value in C structure format |
| # |
| # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format |
| # |
| def GuidStructureStringToGuidValueName(GuidValue): |
| guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "") |
| guidValueList = guidValueString.split(",") |
| if len(guidValueList) != 11: |
| EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue) |
| return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % ( |
| int(guidValueList[0], 16), |
| int(guidValueList[1], 16), |
| int(guidValueList[2], 16), |
| int(guidValueList[3], 16), |
| int(guidValueList[4], 16), |
| int(guidValueList[5], 16), |
| int(guidValueList[6], 16), |
| int(guidValueList[7], 16), |
| int(guidValueList[8], 16), |
| int(guidValueList[9], 16), |
| int(guidValueList[10], 16) |
| ) |
| |
| ## Create directories |
| # |
| # @param Directory The directory name |
| # |
| def CreateDirectory(Directory): |
| if Directory == None or Directory.strip() == "": |
| return True |
| try: |
| if not os.access(Directory, os.F_OK): |
| os.makedirs(Directory) |
| except: |
| return False |
| return True |
| |
| ## Remove directories, including files and sub-directories in it |
| # |
| # @param Directory The directory name |
| # |
| def RemoveDirectory(Directory, Recursively=False): |
| if Directory == None or Directory.strip() == "" or not os.path.exists(Directory): |
| return |
| if Recursively: |
| CurrentDirectory = os.getcwd() |
| os.chdir(Directory) |
| for File in os.listdir("."): |
| if os.path.isdir(File): |
| RemoveDirectory(File, Recursively) |
| else: |
| os.remove(File) |
| os.chdir(CurrentDirectory) |
| os.rmdir(Directory) |
| |
| ## Check if given file is changed or not |
| # |
| # This method is used to check if a file is changed or not between two build |
| # actions. It makes use a cache to store files timestamp. |
| # |
| # @param File The path of file |
| # |
| # @retval True If the given file is changed, doesn't exist, or can't be |
| # found in timestamp cache |
| # @retval False If the given file is changed |
| # |
| def IsChanged(File): |
| if not os.path.exists(File): |
| return True |
| |
| FileState = os.stat(File) |
| TimeStamp = FileState[-2] |
| |
| if File in gFileTimeStampCache and TimeStamp == gFileTimeStampCache[File]: |
| FileChanged = False |
| else: |
| FileChanged = True |
| gFileTimeStampCache[File] = TimeStamp |
| |
| return FileChanged |
| |
| ## Store content in file |
| # |
| # This method is used to save file only when its content is changed. This is |
| # quite useful for "make" system to decide what will be re-built and what won't. |
| # |
| # @param File The path of file |
| # @param Content The new content of the file |
| # @param IsBinaryFile The flag indicating if the file is binary file or not |
| # |
| # @retval True If the file content is changed and the file is renewed |
| # @retval False If the file content is the same |
| # |
| def SaveFileOnChange(File, Content, IsBinaryFile=True): |
| if not IsBinaryFile: |
| Content = Content.replace("\n", os.linesep) |
| |
| if os.path.exists(File): |
| try: |
| if Content == open(File, "rb").read(): |
| return False |
| except: |
| EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File) |
| |
| CreateDirectory(os.path.dirname(File)) |
| try: |
| if GlobalData.gIsWindows: |
| try: |
| from PyUtility import SaveFileToDisk |
| if not SaveFileToDisk(File, Content): |
| EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File) |
| except: |
| Fd = open(File, "wb") |
| Fd.write(Content) |
| Fd.close() |
| else: |
| Fd = open(File, "wb") |
| Fd.write(Content) |
| Fd.close() |
| except: |
| EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File) |
| |
| return True |
| |
| ## Make a Python object persistent on file system |
| # |
| # @param Data The object to be stored in file |
| # @param File The path of file to store the object |
| # |
| def DataDump(Data, File): |
| Fd = None |
| try: |
| Fd = open(File, 'wb') |
| cPickle.dump(Data, Fd, cPickle.HIGHEST_PROTOCOL) |
| except: |
| EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False) |
| finally: |
| if Fd != None: |
| Fd.close() |
| |
| ## Restore a Python object from a file |
| # |
| # @param File The path of file stored the object |
| # |
| # @retval object A python object |
| # @retval None If failure in file operation |
| # |
| def DataRestore(File): |
| Data = None |
| Fd = None |
| try: |
| Fd = open(File, 'rb') |
| Data = cPickle.load(Fd) |
| except Exception, e: |
| EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e))) |
| Data = None |
| finally: |
| if Fd != None: |
| Fd.close() |
| return Data |
| |
| ## Retrieve and cache the real path name in file system |
| # |
| # @param Root The root directory of path relative to |
| # |
| # @retval str The path string if the path exists |
| # @retval None If path doesn't exist |
| # |
| class DirCache: |
| _CACHE_ = {} |
| |
| def __init__(self, Root): |
| self._Root = Root |
| for F in os.listdir(Root): |
| self._CACHE_[F.upper()] = F |
| |
| # =[] operator |
| def __getitem__(self, Path): |
| Path = Path[len(os.path.commonprefix([Path, self._Root])):] |
| if not Path: |
| return self._Root |
| if Path and Path[0] == os.path.sep: |
| Path = Path[1:] |
| Path = Path.upper() |
| if Path in self._CACHE_: |
| return os.path.join(self._Root, self._CACHE_[Path]) |
| |
| IndexList = [] |
| LastSepIndex = -1 |
| SepIndex = Path.find(os.path.sep) |
| while SepIndex > -1: |
| Parent = Path[:SepIndex] |
| if Parent not in self._CACHE_: |
| break |
| LastSepIndex = SepIndex |
| SepIndex = Path.find(os.path.sep, LastSepIndex + 1) |
| |
| if LastSepIndex == -1: |
| return None |
| |
| Cwd = os.getcwd() |
| os.chdir(self._Root) |
| SepIndex = LastSepIndex |
| while SepIndex > -1: |
| ParentKey = Path[:SepIndex] |
| if ParentKey not in self._CACHE_: |
| os.chdir(Cwd) |
| return None |
| |
| ParentDir = self._CACHE_[ParentKey] |
| for F in os.listdir(ParentDir): |
| Dir = os.path.join(ParentDir, F) |
| self._CACHE_[Dir.upper()] = Dir |
| |
| SepIndex = Path.find(os.path.sep, SepIndex + 1) |
| |
| os.chdir(Cwd) |
| if Path not in self._CACHE_: |
| return None |
| return os.path.join(self._Root, self._CACHE_[Path]) |
| |
| ## Get all files of a directory |
| # |
| # @param Root: Root dir |
| # @param SkipList : The files need be skipped |
| # |
| # @retval A list of all files |
| # |
| def GetFiles(Root, SkipList=None, FullPath = True): |
| OriPath = Root |
| FileList = [] |
| for Root, Dirs, Files in os.walk(Root): |
| if SkipList: |
| for Item in SkipList: |
| if Item in Dirs: |
| Dirs.remove(Item) |
| |
| for File in Files: |
| File = os.path.normpath(os.path.join(Root, File)) |
| if not FullPath: |
| File = File[len(OriPath) + 1:] |
| FileList.append(File) |
| |
| return FileList |
| |
| ## Check if gvien file exists or not |
| # |
| # @param File File name or path to be checked |
| # @param Dir The directory the file is relative to |
| # |
| # @retval True if file exists |
| # @retval False if file doesn't exists |
| # |
| def ValidFile(File, Ext=None): |
| if Ext != None: |
| Dummy, FileExt = os.path.splitext(File) |
| if FileExt.lower() != Ext.lower(): |
| return False |
| if not os.path.exists(File): |
| return False |
| return True |
| |
| def RealPath(File, Dir='', OverrideDir=''): |
| NewFile = os.path.normpath(os.path.join(Dir, File)) |
| NewFile = GlobalData.gAllFiles[NewFile] |
| if not NewFile and OverrideDir: |
| NewFile = os.path.normpath(os.path.join(OverrideDir, File)) |
| NewFile = GlobalData.gAllFiles[NewFile] |
| return NewFile |
| |
| def RealPath2(File, Dir='', OverrideDir=''): |
| NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))] |
| if NewFile: |
| if Dir: |
| if Dir[-1] == os.path.sep: |
| return NewFile[len(Dir):], NewFile[0:len(Dir)] |
| else: |
| return NewFile[len(Dir)+1:], NewFile[0:len(Dir)] |
| else: |
| return NewFile, '' |
| |
| if OverrideDir: |
| NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))] |
| if NewFile: |
| return NewFile[len(OverrideDir)+1:], NewFile[0:len(OverrideDir)] |
| return None, None |
| |
| ## Check if gvien file exists or not |
| # |
| # |
| def ValidFile2(AllFiles, File, Ext=None, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''): |
| NewFile = File |
| if Ext != None: |
| Dummy, FileExt = os.path.splitext(File) |
| if FileExt.lower() != Ext.lower(): |
| return False, File |
| |
| # Replace the R8 macros |
| if OverrideDir != '' and OverrideDir != None: |
| if OverrideDir.find('$(EFI_SOURCE)') > -1: |
| OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource) |
| if OverrideDir.find('$(EDK_SOURCE)') > -1: |
| OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource) |
| |
| # Replace the default dir to current dir |
| if Dir == '.': |
| Dir = os.getcwd() |
| Dir = Dir[len(Workspace)+1:] |
| |
| # First check if File has R8 definition itself |
| if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1: |
| NewFile = File.replace('$(EFI_SOURCE)', EfiSource) |
| NewFile = NewFile.replace('$(EDK_SOURCE)', EdkSource) |
| NewFile = AllFiles[os.path.normpath(NewFile)] |
| if NewFile != None: |
| return True, NewFile |
| |
| # Second check the path with override value |
| if OverrideDir != '' and OverrideDir != None: |
| NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))] |
| if NewFile != None: |
| return True, NewFile |
| |
| # Last check the path with normal definitions |
| File = os.path.join(Dir, File) |
| NewFile = AllFiles[os.path.normpath(File)] |
| if NewFile != None: |
| return True, NewFile |
| |
| return False, File |
| |
| ## Check if gvien file exists or not |
| # |
| # |
| def ValidFile3(AllFiles, File, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''): |
| # Replace the R8 macros |
| if OverrideDir != '' and OverrideDir != None: |
| if OverrideDir.find('$(EFI_SOURCE)') > -1: |
| OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource) |
| if OverrideDir.find('$(EDK_SOURCE)') > -1: |
| OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource) |
| |
| # Replace the default dir to current dir |
| # Dir is current module dir related to workspace |
| if Dir == '.': |
| Dir = os.getcwd() |
| Dir = Dir[len(Workspace)+1:] |
| |
| NewFile = File |
| RelaPath = AllFiles[os.path.normpath(Dir)] |
| NewRelaPath = RelaPath |
| |
| while(True): |
| # First check if File has R8 definition itself |
| if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1: |
| File = File.replace('$(EFI_SOURCE)', EfiSource) |
| File = File.replace('$(EDK_SOURCE)', EdkSource) |
| NewFile = AllFiles[os.path.normpath(File)] |
| if NewFile != None: |
| NewRelaPath = os.path.dirname(NewFile) |
| File = os.path.basename(NewFile) |
| #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1] |
| break |
| |
| # Second check the path with override value |
| if OverrideDir != '' and OverrideDir != None: |
| NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))] |
| if NewFile != None: |
| #NewRelaPath = os.path.dirname(NewFile) |
| NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1] |
| break |
| |
| # Last check the path with normal definitions |
| NewFile = AllFiles[os.path.normpath(os.path.join(Dir, File))] |
| if NewFile != None: |
| break |
| |
| # No file found |
| break |
| |
| return NewRelaPath, RelaPath, File |
| |
| |
| def GetRelPath(Path1, Path2): |
| FileName = os.path.basename(Path2) |
| L1 = os.path.normpath(Path1).split(os.path.normpath('/')) |
| L2 = os.path.normpath(Path2).split(os.path.normpath('/')) |
| for Index in range(0, len(L1)): |
| if L1[Index] != L2[Index]: |
| FileName = '../' * (len(L1) - Index) |
| for Index2 in range(Index, len(L2)): |
| FileName = os.path.join(FileName, L2[Index2]) |
| break |
| return os.path.normpath(FileName) |
| |
| |
| ## Get GUID value from given packages |
| # |
| # @param CName The CName of the GUID |
| # @param PackageList List of packages looking-up in |
| # |
| # @retval GuidValue if the CName is found in any given package |
| # @retval None if the CName is not found in all given packages |
| # |
| def GuidValue(CName, PackageList): |
| for P in PackageList: |
| if CName in P.Guids: |
| return P.Guids[CName] |
| return None |
| |
| ## Get Protocol value from given packages |
| # |
| # @param CName The CName of the GUID |
| # @param PackageList List of packages looking-up in |
| # |
| # @retval GuidValue if the CName is found in any given package |
| # @retval None if the CName is not found in all given packages |
| # |
| def ProtocolValue(CName, PackageList): |
| for P in PackageList: |
| if CName in P.Protocols: |
| return P.Protocols[CName] |
| return None |
| |
| ## Get PPI value from given packages |
| # |
| # @param CName The CName of the GUID |
| # @param PackageList List of packages looking-up in |
| # |
| # @retval GuidValue if the CName is found in any given package |
| # @retval None if the CName is not found in all given packages |
| # |
| def PpiValue(CName, PackageList): |
| for P in PackageList: |
| if CName in P.Ppis: |
| return P.Ppis[CName] |
| return None |
| |
| ## A string template class |
| # |
| # This class implements a template for string replacement. A string template |
| # looks like following |
| # |
| # ${BEGIN} other_string ${placeholder_name} other_string ${END} |
| # |
| # The string between ${BEGIN} and ${END} will be repeated as many times as the |
| # length of "placeholder_name", which is a list passed through a dict. The |
| # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can |
| # be not used and, in this case, the "placeholder_name" must not a list and it |
| # will just be replaced once. |
| # |
| class TemplateString(object): |
| _REPEAT_START_FLAG = "BEGIN" |
| _REPEAT_END_FLAG = "END" |
| |
| class Section(object): |
| _LIST_TYPES = [type([]), type(set()), type((0,))] |
| |
| def __init__(self, TemplateSection, PlaceHolderList): |
| self._Template = TemplateSection |
| self._PlaceHolderList = [] |
| |
| # Split the section into sub-sections according to the position of placeholders |
| if PlaceHolderList: |
| self._SubSectionList = [] |
| SubSectionStart = 0 |
| # |
| # The placeholders passed in must be in the format of |
| # |
| # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint |
| # |
| for PlaceHolder,Start,End in PlaceHolderList: |
| self._SubSectionList.append(TemplateSection[SubSectionStart:Start]) |
| self._SubSectionList.append(TemplateSection[Start:End]) |
| self._PlaceHolderList.append(PlaceHolder) |
| SubSectionStart = End |
| if SubSectionStart < len(TemplateSection): |
| self._SubSectionList.append(TemplateSection[SubSectionStart:]) |
| else: |
| self._SubSectionList = [TemplateSection] |
| |
| def __str__(self): |
| return self._Template + " : " + str(self._PlaceHolderList) |
| |
| def Instantiate(self, PlaceHolderValues): |
| RepeatTime = -1 |
| RepeatPlaceHolders = {} |
| NonRepeatPlaceHolders = {} |
| |
| for PlaceHolder in self._PlaceHolderList: |
| if PlaceHolder not in PlaceHolderValues: |
| continue |
| Value = PlaceHolderValues[PlaceHolder] |
| if type(Value) in self._LIST_TYPES: |
| if RepeatTime < 0: |
| RepeatTime = len(Value) |
| elif RepeatTime != len(Value): |
| EdkLogger.error( |
| "TemplateString", |
| PARAMETER_INVALID, |
| "${%s} has different repeat time from others!" % PlaceHolder, |
| ExtraData=str(self._Template) |
| ) |
| RepeatPlaceHolders["${%s}" % PlaceHolder] = Value |
| else: |
| NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value |
| |
| if NonRepeatPlaceHolders: |
| StringList = [] |
| for S in self._SubSectionList: |
| if S not in NonRepeatPlaceHolders: |
| StringList.append(S) |
| else: |
| StringList.append(str(NonRepeatPlaceHolders[S])) |
| else: |
| StringList = self._SubSectionList |
| |
| if RepeatPlaceHolders: |
| TempStringList = [] |
| for Index in range(RepeatTime): |
| for S in StringList: |
| if S not in RepeatPlaceHolders: |
| TempStringList.append(S) |
| else: |
| TempStringList.append(str(RepeatPlaceHolders[S][Index])) |
| StringList = TempStringList |
| |
| return "".join(StringList) |
| |
| ## Constructor |
| def __init__(self, Template=None): |
| self.String = '' |
| self._Template = Template |
| self._TemplateSectionList = self._Parse(Template) |
| |
| ## str() operator |
| # |
| # @retval string The string replaced |
| # |
| def __str__(self): |
| return self.String |
| |
| ## Split the template string into fragments per the ${BEGIN} and ${END} flags |
| # |
| # @retval list A list of TemplateString.Section objects |
| # |
| def _Parse(self, Template): |
| SectionStart = 0 |
| SearchFrom = 0 |
| MatchEnd = 0 |
| PlaceHolderList = [] |
| TemplateSectionList = [] |
| while Template: |
| MatchObj = gPlaceholderPattern.search(Template, SearchFrom) |
| if not MatchObj: |
| if MatchEnd < len(Template): |
| TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList) |
| TemplateSectionList.append(TemplateSection) |
| break |
| |
| MatchString = MatchObj.group(1) |
| MatchStart = MatchObj.start() |
| MatchEnd = MatchObj.end() |
| |
| if MatchString == self._REPEAT_START_FLAG: |
| if MatchStart > SectionStart: |
| TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList) |
| TemplateSectionList.append(TemplateSection) |
| SectionStart = MatchEnd |
| PlaceHolderList = [] |
| elif MatchString == self._REPEAT_END_FLAG: |
| TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList) |
| TemplateSectionList.append(TemplateSection) |
| SectionStart = MatchEnd |
| PlaceHolderList = [] |
| else: |
| PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart)) |
| SearchFrom = MatchEnd |
| return TemplateSectionList |
| |
| ## Replace the string template with dictionary of placeholders and append it to previous one |
| # |
| # @param AppendString The string template to append |
| # @param Dictionary The placeholder dictionaries |
| # |
| def Append(self, AppendString, Dictionary=None): |
| if Dictionary: |
| SectionList = self._Parse(AppendString) |
| self.String += "".join([S.Instantiate(Dictionary) for S in SectionList]) |
| else: |
| self.String += AppendString |
| |
| ## Replace the string template with dictionary of placeholders |
| # |
| # @param Dictionary The placeholder dictionaries |
| # |
| # @retval str The string replaced with placeholder values |
| # |
| def Replace(self, Dictionary=None): |
| return "".join([S.Instantiate(Dictionary) for S in self._TemplateSectionList]) |
| |
| ## Progress indicator class |
| # |
| # This class makes use of thread to print progress on console. |
| # |
| class Progressor: |
| # for avoiding deadloop |
| _StopFlag = None |
| _ProgressThread = None |
| _CheckInterval = 0.25 |
| |
| ## Constructor |
| # |
| # @param OpenMessage The string printed before progress charaters |
| # @param CloseMessage The string printed after progress charaters |
| # @param ProgressChar The charater used to indicate the progress |
| # @param Interval The interval in seconds between two progress charaters |
| # |
| def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0): |
| self.PromptMessage = OpenMessage |
| self.CodaMessage = CloseMessage |
| self.ProgressChar = ProgressChar |
| self.Interval = Interval |
| if Progressor._StopFlag == None: |
| Progressor._StopFlag = threading.Event() |
| |
| ## Start to print progress charater |
| # |
| # @param OpenMessage The string printed before progress charaters |
| # |
| def Start(self, OpenMessage=None): |
| if OpenMessage != None: |
| self.PromptMessage = OpenMessage |
| Progressor._StopFlag.clear() |
| if Progressor._ProgressThread == None: |
| Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry) |
| Progressor._ProgressThread.setDaemon(False) |
| Progressor._ProgressThread.start() |
| |
| ## Stop printing progress charater |
| # |
| # @param CloseMessage The string printed after progress charaters |
| # |
| def Stop(self, CloseMessage=None): |
| OriginalCodaMessage = self.CodaMessage |
| if CloseMessage != None: |
| self.CodaMessage = CloseMessage |
| self.Abort() |
| self.CodaMessage = OriginalCodaMessage |
| |
| ## Thread entry method |
| def _ProgressThreadEntry(self): |
| sys.stdout.write(self.PromptMessage + " ") |
| sys.stdout.flush() |
| TimeUp = 0.0 |
| while not Progressor._StopFlag.isSet(): |
| if TimeUp <= 0.0: |
| sys.stdout.write(self.ProgressChar) |
| sys.stdout.flush() |
| TimeUp = self.Interval |
| time.sleep(self._CheckInterval) |
| TimeUp -= self._CheckInterval |
| sys.stdout.write(" " + self.CodaMessage + "\n") |
| sys.stdout.flush() |
| |
| ## Abort the progress display |
| @staticmethod |
| def Abort(): |
| if Progressor._StopFlag != None: |
| Progressor._StopFlag.set() |
| if Progressor._ProgressThread != None: |
| Progressor._ProgressThread.join() |
| Progressor._ProgressThread = None |
| |
| ## A dict which can access its keys and/or values orderly |
| # |
| # The class implements a new kind of dict which its keys or values can be |
| # accessed in the order they are added into the dict. It guarantees the order |
| # by making use of an internal list to keep a copy of keys. |
| # |
| class sdict(IterableUserDict): |
| ## Constructor |
| def __init__(self): |
| IterableUserDict.__init__(self) |
| self._key_list = [] |
| |
| ## [] operator |
| def __setitem__(self, key, value): |
| if key not in self._key_list: |
| self._key_list.append(key) |
| IterableUserDict.__setitem__(self, key, value) |
| |
| ## del operator |
| def __delitem__(self, key): |
| self._key_list.remove(key) |
| IterableUserDict.__delitem__(self, key) |
| |
| ## used in "for k in dict" loop to ensure the correct order |
| def __iter__(self): |
| return self.iterkeys() |
| |
| ## len() support |
| def __len__(self): |
| return len(self._key_list) |
| |
| ## "in" test support |
| def __contains__(self, key): |
| return key in self._key_list |
| |
| ## indexof support |
| def index(self, key): |
| return self._key_list.index(key) |
| |
| ## insert support |
| def insert(self, key, newkey, newvalue, order): |
| index = self._key_list.index(key) |
| if order == 'BEFORE': |
| self._key_list.insert(index, newkey) |
| IterableUserDict.__setitem__(self, newkey, newvalue) |
| elif order == 'AFTER': |
| self._key_list.insert(index + 1, newkey) |
| IterableUserDict.__setitem__(self, newkey, newvalue) |
| |
| ## append support |
| def append(self, sdict): |
| for key in sdict: |
| if key not in self._key_list: |
| self._key_list.append(key) |
| IterableUserDict.__setitem__(self, key, sdict[key]) |
| |
| def has_key(self, key): |
| return key in self._key_list |
| |
| ## Empty the dict |
| def clear(self): |
| self._key_list = [] |
| IterableUserDict.clear(self) |
| |
| ## Return a copy of keys |
| def keys(self): |
| keys = [] |
| for key in self._key_list: |
| keys.append(key) |
| return keys |
| |
| ## Return a copy of values |
| def values(self): |
| values = [] |
| for key in self._key_list: |
| values.append(self[key]) |
| return values |
| |
| ## Return a copy of (key, value) list |
| def items(self): |
| items = [] |
| for key in self._key_list: |
| items.append((key, self[key])) |
| return items |
| |
| ## Iteration support |
| def iteritems(self): |
| return iter(self.items()) |
| |
| ## Keys interation support |
| def iterkeys(self): |
| return iter(self.keys()) |
| |
| ## Values interation support |
| def itervalues(self): |
| return iter(self.values()) |
| |
| ## Return value related to a key, and remove the (key, value) from the dict |
| def pop(self, key, *dv): |
| value = None |
| if key in self._key_list: |
| value = self[key] |
| self.__delitem__(key) |
| elif len(dv) != 0 : |
| value = kv[0] |
| return value |
| |
| ## Return (key, value) pair, and remove the (key, value) from the dict |
| def popitem(self): |
| key = self._key_list[-1] |
| value = self[key] |
| self.__delitem__(key) |
| return key, value |
| |
| def update(self, dict=None, **kwargs): |
| if dict != None: |
| for k, v in dict.items(): |
| self[k] = v |
| if len(kwargs): |
| for k, v in kwargs.items(): |
| self[k] = v |
| |
| ## Dictionary with restricted keys |
| # |
| class rdict(dict): |
| ## Constructor |
| def __init__(self, KeyList): |
| for Key in KeyList: |
| dict.__setitem__(self, Key, "") |
| |
| ## []= operator |
| def __setitem__(self, key, value): |
| if key not in self: |
| EdkLogger.error("RestrictedDict", ATTRIBUTE_SET_FAILURE, "Key [%s] is not allowed" % key, |
| ExtraData=", ".join(dict.keys(self))) |
| dict.__setitem__(self, key, value) |
| |
| ## =[] operator |
| def __getitem__(self, key): |
| if key not in self: |
| return "" |
| return dict.__getitem__(self, key) |
| |
| ## del operator |
| def __delitem__(self, key): |
| EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="del") |
| |
| ## Empty the dict |
| def clear(self): |
| for Key in self: |
| self.__setitem__(Key, "") |
| |
| ## Return value related to a key, and remove the (key, value) from the dict |
| def pop(self, key, *dv): |
| EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="pop") |
| |
| ## Return (key, value) pair, and remove the (key, value) from the dict |
| def popitem(self): |
| EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="popitem") |
| |
| ## Dictionary using prioritized list as key |
| # |
| class tdict: |
| _ListType = type([]) |
| _TupleType = type(()) |
| _Wildcard = 'COMMON' |
| _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM'] |
| |
| def __init__(self, _Single_=False, _Level_=2): |
| self._Level_ = _Level_ |
| self.data = {} |
| self._Single_ = _Single_ |
| |
| # =[] operator |
| def __getitem__(self, key): |
| KeyType = type(key) |
| RestKeys = None |
| if KeyType == self._ListType or KeyType == self._TupleType: |
| FirstKey = key[0] |
| if len(key) > 1: |
| RestKeys = key[1:] |
| elif self._Level_ > 1: |
| RestKeys = [self._Wildcard for i in range(0, self._Level_-1)] |
| else: |
| FirstKey = key |
| if self._Level_ > 1: |
| RestKeys = [self._Wildcard for i in range(0, self._Level_-1)] |
| |
| if FirstKey == None or str(FirstKey).upper() in self._ValidWildcardList: |
| FirstKey = self._Wildcard |
| |
| if self._Single_: |
| return self._GetSingleValue(FirstKey, RestKeys) |
| else: |
| return self._GetAllValues(FirstKey, RestKeys) |
| |
| def _GetSingleValue(self, FirstKey, RestKeys): |
| Value = None |
| #print "%s-%s" % (FirstKey, self._Level_) , |
| if self._Level_ > 1: |
| if FirstKey == self._Wildcard: |
| if FirstKey in self.data: |
| Value = self.data[FirstKey][RestKeys] |
| if Value == None: |
| for Key in self.data: |
| Value = self.data[Key][RestKeys] |
| if Value != None: break |
| else: |
| if FirstKey in self.data: |
| Value = self.data[FirstKey][RestKeys] |
| if Value == None and self._Wildcard in self.data: |
| #print "Value=None" |
| Value = self.data[self._Wildcard][RestKeys] |
| else: |
| if FirstKey == self._Wildcard: |
| if FirstKey in self.data: |
| Value = self.data[FirstKey] |
| if Value == None: |
| for Key in self.data: |
| Value = self.data[Key] |
| if Value != None: break |
| else: |
| if FirstKey in self.data: |
| Value = self.data[FirstKey] |
| elif self._Wildcard in self.data: |
| Value = self.data[self._Wildcard] |
| return Value |
| |
| def _GetAllValues(self, FirstKey, RestKeys): |
| Value = [] |
| if self._Level_ > 1: |
| if FirstKey == self._Wildcard: |
| for Key in self.data: |
| Value += self.data[Key][RestKeys] |
| else: |
| if FirstKey in self.data: |
| Value += self.data[FirstKey][RestKeys] |
| if self._Wildcard in self.data: |
| Value += self.data[self._Wildcard][RestKeys] |
| else: |
| if FirstKey == self._Wildcard: |
| for Key in self.data: |
| Value.append(self.data[Key]) |
| else: |
| if FirstKey in self.data: |
| Value.append(self.data[FirstKey]) |
| if self._Wildcard in self.data: |
| Value.append(self.data[self._Wildcard]) |
| return Value |
| |
| ## []= operator |
| def __setitem__(self, key, value): |
| KeyType = type(key) |
| RestKeys = None |
| if KeyType == self._ListType or KeyType == self._TupleType: |
| FirstKey = key[0] |
| if len(key) > 1: |
| RestKeys = key[1:] |
| else: |
| RestKeys = [self._Wildcard for i in range(0, self._Level_-1)] |
| else: |
| FirstKey = key |
| if self._Level_ > 1: |
| RestKeys = [self._Wildcard for i in range(0, self._Level_-1)] |
| |
| if FirstKey in self._ValidWildcardList: |
| FirstKey = self._Wildcard |
| |
| if FirstKey not in self.data and self._Level_ > 0: |
| self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1) |
| |
| if self._Level_ > 1: |
| self.data[FirstKey][RestKeys] = value |
| else: |
| self.data[FirstKey] = value |
| |
| def SetGreedyMode(self): |
| self._Single_ = False |
| if self._Level_ > 1: |
| for Key in self.data: |
| self.data[Key].SetGreedyMode() |
| |
| def SetSingleMode(self): |
| self._Single_ = True |
| if self._Level_ > 1: |
| for Key in self.data: |
| self.data[Key].SetSingleMode() |
| |
| ## Boolean chain list |
| # |
| class Blist(UserList): |
| def __init__(self, initlist=None): |
| UserList.__init__(self, initlist) |
| def __setitem__(self, i, item): |
| if item not in [True, False]: |
| if item == 0: |
| item = False |
| else: |
| item = True |
| self.data[i] = item |
| def _GetResult(self): |
| Value = True |
| for item in self.data: |
| Value &= item |
| return Value |
| Result = property(_GetResult) |
| |
| def ParseConsoleLog(Filename): |
| Opr = open(os.path.normpath(Filename), 'r') |
| Opw = open(os.path.normpath(Filename + '.New'), 'w+') |
| for Line in Opr.readlines(): |
| if Line.find('.efi') > -1: |
| Line = Line[Line.rfind(' ') : Line.rfind('.efi')].strip() |
| Opw.write('%s\n' % Line) |
| |
| Opr.close() |
| Opw.close() |
| |
| ## check format of PCD value against its the datum type |
| # |
| # For PCD value setting |
| # |
| def CheckPcdDatum(Type, Value): |
| if Type == "VOID*": |
| if not ((Value.startswith('L"') or Value.startswith('"') and Value.endswith('"')) |
| or (Value.startswith('{') and Value.endswith('}')) |
| ): |
| return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\ |
| ", or \"...\" for string, or L\"...\" for unicode string" % (Value, Type) |
| elif Type == 'BOOLEAN': |
| if Value not in ['TRUE', 'FALSE']: |
| return False, "Invalid value [%s] of type [%s]; must be TRUE or FALSE" % (Value, Type) |
| elif type(Value) == type(""): |
| try: |
| Value = long(Value, 0) |
| except: |
| return False, "Invalid value [%s] of type [%s];"\ |
| " must be a hexadecimal, decimal or octal in C language format."\ |
| % (Value, Type) |
| |
| return True, "" |
| |
| ## Split command line option string to list |
| # |
| # subprocess.Popen needs the args to be a sequence. Otherwise there's problem |
| # in non-windows platform to launch command |
| # |
| def SplitOption(OptionString): |
| OptionList = [] |
| LastChar = " " |
| OptionStart = 0 |
| QuotationMark = "" |
| for Index in range(0, len(OptionString)): |
| CurrentChar = OptionString[Index] |
| if CurrentChar in ['"', "'"]: |
| if QuotationMark == CurrentChar: |
| QuotationMark = "" |
| elif QuotationMark == "": |
| QuotationMark = CurrentChar |
| continue |
| elif QuotationMark: |
| continue |
| |
| if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]: |
| if Index > OptionStart: |
| OptionList.append(OptionString[OptionStart:Index-1]) |
| OptionStart = Index |
| LastChar = CurrentChar |
| OptionList.append(OptionString[OptionStart:]) |
| return OptionList |
| |
| def CommonPath(PathList): |
| P1 = min(PathList).split(os.path.sep) |
| P2 = max(PathList).split(os.path.sep) |
| for Index in xrange(min(len(P1), len(P2))): |
| if P1[Index] != P2[Index]: |
| return os.path.sep.join(P1[:Index]) |
| return os.path.sep.join(P1) |
| |
| class PathClass(object): |
| def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False, |
| Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''): |
| self.Arch = Arch |
| self.File = str(File) |
| if os.path.isabs(self.File): |
| self.Root = '' |
| self.AlterRoot = '' |
| else: |
| self.Root = str(Root) |
| self.AlterRoot = str(AlterRoot) |
| |
| # Remove any '.' and '..' in path |
| if self.Root: |
| self.Path = os.path.normpath(os.path.join(self.Root, self.File)) |
| self.Root = os.path.normpath(CommonPath([self.Root, self.Path])) |
| # eliminate the side-effect of 'C:' |
| if self.Root[-1] == ':': |
| self.Root += os.path.sep |
| # file path should not start with path separator |
| if self.Root[-1] == os.path.sep: |
| self.File = self.Path[len(self.Root):] |
| else: |
| self.File = self.Path[len(self.Root)+1:] |
| else: |
| self.Path = os.path.normpath(self.File) |
| |
| self.SubDir, self.Name = os.path.split(self.File) |
| self.BaseName, self.Ext = os.path.splitext(self.Name) |
| |
| if self.Root: |
| if self.SubDir: |
| self.Dir = os.path.join(self.Root, self.SubDir) |
| else: |
| self.Dir = self.Root |
| else: |
| self.Dir = self.SubDir |
| |
| if IsBinary: |
| self.Type = Type |
| else: |
| self.Type = self.Ext.lower() |
| |
| self.IsBinary = IsBinary |
| self.Target = Target |
| self.TagName = TagName |
| self.ToolCode = ToolCode |
| self.ToolChainFamily = ToolChainFamily |
| |
| self._Key = None |
| |
| ## Convert the object of this class to a string |
| # |
| # Convert member Path of the class to a string |
| # |
| # @retval string Formatted String |
| # |
| def __str__(self): |
| return self.Path |
| |
| ## Override __eq__ function |
| # |
| # Check whether PathClass are the same |
| # |
| # @retval False The two PathClass are different |
| # @retval True The two PathClass are the same |
| # |
| def __eq__(self, Other): |
| if type(Other) == type(self): |
| return self.Path == Other.Path |
| else: |
| return self.Path == str(Other) |
| |
| ## Override __hash__ function |
| # |
| # Use Path as key in hash table |
| # |
| # @retval string Key for hash table |
| # |
| def __hash__(self): |
| return hash(self.Path) |
| |
| def _GetFileKey(self): |
| if self._Key == None: |
| self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target |
| return self._Key |
| |
| def Validate(self, Type='', CaseSensitive=True): |
| if GlobalData.gCaseInsensitive: |
| CaseSensitive = False |
| if Type and Type.lower() != self.Type: |
| return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type) |
| |
| RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot) |
| if not RealRoot and not RealFile: |
| return FILE_NOT_FOUND, self.File |
| |
| ErrorCode = 0 |
| ErrorInfo = '' |
| if RealRoot != self.Root or RealFile != self.File: |
| if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)): |
| ErrorCode = FILE_CASE_MISMATCH |
| ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]" |
| |
| self.SubDir, self.Name = os.path.split(RealFile) |
| self.BaseName, self.Ext = os.path.splitext(self.Name) |
| if self.SubDir: |
| self.Dir = os.path.join(RealRoot, self.SubDir) |
| else: |
| self.Dir = RealRoot |
| self.File = RealFile |
| self.Root = RealRoot |
| self.Path = os.path.join(RealRoot, RealFile) |
| return ErrorCode, ErrorInfo |
| |
| Key = property(_GetFileKey) |
| |
| ## |
| # |
| # This acts like the main() function for the script, unless it is 'import'ed into another |
| # script. |
| # |
| if __name__ == '__main__': |
| pass |
| |