| ## @file |
| # Common routines used by all tools |
| # |
| # Copyright (c) 2011, Intel Corporation. All rights reserved.<BR> |
| # |
| # 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. |
| # |
| |
| ''' |
| Misc |
| ''' |
| |
| ## |
| # Import Modules |
| # |
| import os.path |
| from os import access |
| from os import F_OK |
| from os import makedirs |
| from os import getcwd |
| from os import chdir |
| from os import listdir |
| from os import remove |
| from os import rmdir |
| from os import linesep |
| from os import walk |
| from os import environ |
| import re |
| from UserDict import IterableUserDict |
| |
| import Logger.Log as Logger |
| from Logger import StringTable as ST |
| from Logger import ToolError |
| from Library import GlobalData |
| from Library.DataType import SUP_MODULE_LIST |
| from Library.DataType import END_OF_LINE |
| from Library.DataType import TAB_SPLIT |
| from Library.DataType import LANGUAGE_EN_US |
| from Library.String import GetSplitValueList |
| from Library.ParserValidate import IsValidHexVersion |
| from Library.ParserValidate import IsValidPath |
| from Object.POM.CommonObject import TextObject |
| |
| ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C |
| # structure style |
| # |
| # @param Guid: The GUID string |
| # |
| 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 |
| |
| ## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
| # |
| # @param GuidValue: The GUID value |
| # |
| def CheckGuidRegFormat(GuidValue): |
| ## Regular expression used to find out register format of GUID |
| # |
| RegFormatGuidPattern = re.compile("^\s*([0-9a-fA-F]){8}-" |
| "([0-9a-fA-F]){4}-" |
| "([0-9a-fA-F]){4}-" |
| "([0-9a-fA-F]){4}-" |
| "([0-9a-fA-F]){12}\s*$") |
| |
| if RegFormatGuidPattern.match(GuidValue): |
| return True |
| else: |
| return False |
| |
| |
| ## Convert GUID string in C structure style to |
| # xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
| # |
| # @param GuidValue: The GUID value in C structure format |
| # |
| def GuidStructureStringToGuidString(GuidValue): |
| GuidValueString = GuidValue.lower().replace("{", "").replace("}", "").\ |
| replace(" ", "").replace(";", "") |
| GuidValueList = GuidValueString.split(",") |
| if len(GuidValueList) != 11: |
| return '' |
| 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 BaseException: |
| return '' |
| |
| ## Create directories |
| # |
| # @param Directory: The directory name |
| # |
| def CreateDirectory(Directory): |
| if Directory == None or Directory.strip() == "": |
| return True |
| try: |
| if not access(Directory, F_OK): |
| makedirs(Directory) |
| except BaseException: |
| 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 = getcwd() |
| chdir(Directory) |
| for File in listdir("."): |
| if os.path.isdir(File): |
| RemoveDirectory(File, Recursively) |
| else: |
| remove(File) |
| chdir(CurrentDirectory) |
| rmdir(Directory) |
| |
| ## 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 |
| # |
| def SaveFileOnChange(File, Content, IsBinaryFile=True): |
| if not IsBinaryFile: |
| Content = Content.replace("\n", linesep) |
| |
| if os.path.exists(File): |
| try: |
| if Content == open(File, "rb").read(): |
| return False |
| except BaseException: |
| Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File) |
| |
| CreateDirectory(os.path.dirname(File)) |
| try: |
| FileFd = open(File, "wb") |
| FileFd.write(Content) |
| FileFd.close() |
| except BaseException: |
| Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File) |
| |
| return True |
| |
| ## Get all files of a directory |
| # |
| # @param Root: Root dir |
| # @param SkipList : The files need be skipped |
| # |
| def GetFiles(Root, SkipList=None, FullPath=True): |
| OriPath = os.path.normpath(Root) |
| FileList = [] |
| for Root, Dirs, Files in walk(Root): |
| if SkipList: |
| for Item in SkipList: |
| if Item in Dirs: |
| Dirs.remove(Item) |
| for Dir in Dirs: |
| if Dir.startswith('.'): |
| Dirs.remove(Dir) |
| |
| for File in Files: |
| if File.startswith('.'): |
| continue |
| File = os.path.normpath(os.path.join(Root, File)) |
| if not FullPath: |
| File = File[len(OriPath) + 1:] |
| FileList.append(File) |
| |
| return FileList |
| |
| ## Get all non-metadata files of a directory |
| # |
| # @param Root: Root Dir |
| # @param SkipList : List of path need be skipped |
| # @param FullPath: True if the returned file should be full path |
| # @param PrefixPath: the path that need to be added to the files found |
| # @return: the list of files found |
| # |
| def GetNonMetaDataFiles(Root, SkipList, FullPath, PrefixPath): |
| FileList = GetFiles(Root, SkipList, FullPath) |
| NewFileList = [] |
| for File in FileList: |
| ExtName = os.path.splitext(File)[1] |
| # |
| # skip '.dec', '.inf', '.dsc', '.fdf' files |
| # |
| if ExtName.lower() not in ['.dec', '.inf', '.dsc', '.fdf']: |
| NewFileList.append(os.path.normpath(os.path.join(PrefixPath, File))) |
| |
| return NewFileList |
| |
| ## Check if given file exists or not |
| # |
| # @param File: File name or path to be checked |
| # @param Dir: The directory the file is relative to |
| # |
| def ValidFile(File, Ext=None): |
| File = File.replace('\\', '/') |
| if Ext != None: |
| FileExt = os.path.splitext(File)[1] |
| if FileExt.lower() != Ext.lower(): |
| return False |
| if not os.path.exists(File): |
| return False |
| return True |
| |
| ## RealPath |
| # |
| # @param File: File name or path to be checked |
| # @param Dir: The directory the file is relative to |
| # @param OverrideDir: The override directory |
| # |
| def RealPath(File, Dir='', OverrideDir=''): |
| NewFile = os.path.normpath(os.path.join(Dir, File)) |
| NewFile = GlobalData.gALL_FILES[NewFile] |
| if not NewFile and OverrideDir: |
| NewFile = os.path.normpath(os.path.join(OverrideDir, File)) |
| NewFile = GlobalData.gALL_FILES[NewFile] |
| return NewFile |
| |
| ## RealPath2 |
| # |
| # @param File: File name or path to be checked |
| # @param Dir: The directory the file is relative to |
| # @param OverrideDir: The override directory |
| # |
| def RealPath2(File, Dir='', OverrideDir=''): |
| if OverrideDir: |
| NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join\ |
| (OverrideDir, File))] |
| if NewFile: |
| if OverrideDir[-1] == os.path.sep: |
| return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)] |
| else: |
| return NewFile[len(OverrideDir) + 1:], \ |
| NewFile[0:len(OverrideDir)] |
| |
| NewFile = GlobalData.gALL_FILES[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, '' |
| |
| return None, 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, Sdict2): |
| for Key in Sdict2: |
| if Key not in self._key_list: |
| self._key_list.append(Key) |
| IterableUserDict.__setitem__(self, Key, Sdict2[Key]) |
| ## hash 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 = Dv[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 |
| ## update method |
| # |
| def update(self, Dict=None, **Kwargs): |
| if Dict != None: |
| for Key1, Val1 in Dict.items(): |
| self[Key1] = Val1 |
| if len(Kwargs): |
| for Key1, Val1 in Kwargs.items(): |
| self[Key1] = Val1 |
| |
| ## CommonPath |
| # |
| # @param PathList: PathList |
| # |
| def CommonPath(PathList): |
| Path1 = min(PathList).split(os.path.sep) |
| Path2 = max(PathList).split(os.path.sep) |
| for Index in xrange(min(len(Path1), len(Path2))): |
| if Path1[Index] != Path2[Index]: |
| return os.path.sep.join(Path1[:Index]) |
| return os.path.sep.join(Path1) |
| |
| ## PathClass |
| # |
| 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 |
| # |
| def __str__(self): |
| return self.Path |
| |
| ## Override __eq__ function |
| # |
| # Check whether 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 |
| # |
| def __hash__(self): |
| return hash(self.Path) |
| |
| ## _GetFileKey |
| # |
| def _GetFileKey(self): |
| if self._Key == None: |
| self._Key = self.Path.upper() |
| return self._Key |
| ## Validate |
| # |
| def Validate(self, Type='', CaseSensitive=True): |
| if GlobalData.gCASE_INSENSITIVE: |
| CaseSensitive = False |
| if Type and Type.lower() != self.Type: |
| return ToolError.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: |
| RealFile = self.File |
| if self.AlterRoot: |
| RealFile = os.path.join(self.AlterRoot, self.File) |
| elif self.Root: |
| RealFile = os.path.join(self.Root, self.File) |
| return ToolError.FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile) |
| |
| 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 = ToolError.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) |
| |
| ## Check environment variables |
| # |
| # Check environment variables that must be set for build. Currently they are |
| # |
| # WORKSPACE The directory all packages/platforms start from |
| # EDK_TOOLS_PATH The directory contains all tools needed by the build |
| # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH |
| # |
| # If any of above environment variable is not set or has error, the build |
| # will be broken. |
| # |
| def CheckEnvVariable(): |
| # |
| # check WORKSPACE |
| # |
| if "WORKSPACE" not in environ: |
| Logger.Error("UPT", |
| ToolError.UPT_ENVIRON_MISSING_ERROR, |
| ST.ERR_NOT_FOUND_ENVIRONMENT, |
| ExtraData="WORKSPACE") |
| |
| WorkspaceDir = os.path.normpath(environ["WORKSPACE"]) |
| if not os.path.exists(WorkspaceDir): |
| Logger.Error("UPT", |
| ToolError.UPT_ENVIRON_MISSING_ERROR, |
| ST.ERR_WORKSPACE_NOTEXIST, |
| ExtraData="%s" % WorkspaceDir) |
| elif ' ' in WorkspaceDir: |
| Logger.Error("UPT", |
| ToolError.FORMAT_NOT_SUPPORTED, |
| ST.ERR_SPACE_NOTALLOWED, |
| ExtraData=WorkspaceDir) |
| |
| ## Check whether all module types are in list |
| # |
| # check whether all module types (SUP_MODULE_LIST) are in list |
| # |
| # @param ModuleList: a list of ModuleType |
| # |
| def IsAllModuleList(ModuleList): |
| NewModuleList = [Module.upper() for Module in ModuleList] |
| for Module in SUP_MODULE_LIST: |
| if Module not in NewModuleList: |
| return False |
| else: |
| return True |
| |
| ## Dictionary that use comment(GenericComment, TailComment) as value, |
| # if a new comment which key already in the dic is inserted, then the |
| # comment will be merged. |
| # Key is (Statement, SupArch), when TailComment is added, it will ident |
| # according to Statement |
| # |
| class MergeCommentDict(dict): |
| ## []= operator |
| # |
| def __setitem__(self, Key, CommentVal): |
| GenericComment, TailComment = CommentVal |
| if Key in self: |
| OrigVal1, OrigVal2 = dict.__getitem__(self, Key) |
| Statement = Key[0] |
| dict.__setitem__(self, Key, (OrigVal1 + GenericComment, OrigVal2 \ |
| + len(Statement) * ' ' + TailComment)) |
| else: |
| dict.__setitem__(self, Key, (GenericComment, TailComment)) |
| |
| ## =[] operator |
| # |
| def __getitem__(self, Key): |
| return dict.__getitem__(self, Key) |
| |
| |
| ## GenDummyHelpTextObj |
| # |
| # @retval HelpTxt: Generated dummy help text object |
| # |
| def GenDummyHelpTextObj(): |
| HelpTxt = TextObject() |
| HelpTxt.SetLang(LANGUAGE_EN_US) |
| HelpTxt.SetString(' ') |
| return HelpTxt |
| |
| ## ConvertVersionToDecimal, the minor version should be within 0 - 99 |
| # <HexVersion> ::= "0x" <Major> <Minor> |
| # <Major> ::= (a-fA-F0-9){4} |
| # <Minor> ::= (a-fA-F0-9){4} |
| # <DecVersion> ::= (0-65535) ["." (0-99)] |
| # |
| # @param StringIn: The string contains version defined in INF file. |
| # It can be Decimal or Hex |
| # |
| def ConvertVersionToDecimal(StringIn): |
| if IsValidHexVersion(StringIn): |
| Value = int(StringIn, 16) |
| Major = Value >> 16 |
| Minor = Value & 0xFFFF |
| MinorStr = str(Minor) |
| if len(MinorStr) == 1: |
| MinorStr = '0' + MinorStr |
| return str(Major) + '.' + MinorStr |
| else: |
| if StringIn.find(TAB_SPLIT) != -1: |
| return StringIn |
| elif StringIn: |
| return StringIn + '.0' |
| else: |
| # |
| # when StringIn is '', return it directly |
| # |
| return StringIn |
| |
| ## GetHelpStringByRemoveHashKey |
| # |
| # Remove hash key at the header of string and return the remain. |
| # |
| # @param String: The string need to be processed. |
| # |
| def GetHelpStringByRemoveHashKey(String): |
| ReturnString = '' |
| PattenRemoveHashKey = re.compile(r"^[#+\s]+", re.DOTALL) |
| String = String.strip() |
| if String == '': |
| return String |
| |
| LineList = GetSplitValueList(String, END_OF_LINE) |
| for Line in LineList: |
| ValueList = PattenRemoveHashKey.split(Line) |
| if len(ValueList) == 1: |
| ReturnString += ValueList[0] + END_OF_LINE |
| else: |
| ReturnString += ValueList[1] + END_OF_LINE |
| |
| if ReturnString.endswith('\n') and not ReturnString.endswith('\n\n') and ReturnString != '\n': |
| ReturnString = ReturnString[:-1] |
| |
| return ReturnString |
| |
| ## ConvPathFromAbsToRel |
| # |
| # Get relative file path from absolute path. |
| # |
| # @param Path: The string contain file absolute path. |
| # @param Root: The string contain the parent path of Path in. |
| # |
| # |
| def ConvPathFromAbsToRel(Path, Root): |
| Path = os.path.normpath(Path) |
| Root = os.path.normpath(Root) |
| FullPath = os.path.normpath(os.path.join(Root, Path)) |
| |
| # |
| # If Path is absolute path. |
| # It should be in Root. |
| # |
| if os.path.isabs(Path): |
| return FullPath[FullPath.find(Root) + len(Root) + 1:] |
| |
| else: |
| return Path |
| |
| ## ConvertPath |
| # |
| # Convert special characters to '_', '\' to '/' |
| # return converted path: Test!1.inf -> Test_1.inf |
| # |
| # @param Path: Path to be converted |
| # |
| def ConvertPath(Path): |
| RetPath = '' |
| for Char in Path.strip(): |
| if Char.isalnum() or Char in '.-_/': |
| RetPath = RetPath + Char |
| elif Char == '\\': |
| RetPath = RetPath + '/' |
| else: |
| RetPath = RetPath + '_' |
| return RetPath |
| |
| ## ConvertSpec |
| # |
| # during install, convert the Spec string extract from UPD into INF allowable definition, |
| # the difference is period is allowed in the former (not the first letter) but not in the latter. |
| # return converted Spec string |
| # |
| # @param SpecStr: SpecStr to be converted |
| # |
| def ConvertSpec(SpecStr): |
| RetStr = '' |
| for Char in SpecStr: |
| if Char.isalnum() or Char == '_': |
| RetStr = RetStr + Char |
| else: |
| RetStr = RetStr + '_' |
| |
| return RetStr |
| |
| |
| ## IsEqualList |
| # |
| # Judge two lists are identical(contain same item). |
| # The rule is elements in List A are in List B and elements in List B are in List A. |
| # |
| # @param ListA, ListB Lists need to be judged. |
| # |
| # @return True ListA and ListB are identical |
| # @return False ListA and ListB are different with each other |
| # |
| def IsEqualList(ListA, ListB): |
| if ListA == ListB: |
| return True |
| |
| for ItemA in ListA: |
| if not ItemA in ListB: |
| return False |
| |
| for ItemB in ListB: |
| if not ItemB in ListA: |
| return False |
| |
| return True |
| |
| ## ConvertArchList |
| # |
| # Convert item in ArchList if the start character is lower case. |
| # In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])* |
| # |
| # @param ArchList The ArchList need to be converted. |
| # |
| # @return NewList The ArchList been converted. |
| # |
| def ConvertArchList(ArchList): |
| NewArchList = [] |
| if not ArchList: |
| return NewArchList |
| |
| if type(ArchList) == list: |
| for Arch in ArchList: |
| Arch = Arch.upper() |
| NewArchList.append(Arch) |
| elif type(ArchList) == str: |
| ArchList = ArchList.upper() |
| NewArchList.append(ArchList) |
| |
| return NewArchList |
| |
| ## ProcessLineExtender |
| # |
| # Process the LineExtender of Line in LineList. |
| # If one line ends with a line extender, then it will be combined together with next line. |
| # |
| # @param LineList The LineList need to be processed. |
| # |
| # @return NewList The ArchList been processed. |
| # |
| def ProcessLineExtender(LineList): |
| NewList = [] |
| Count = 0 |
| while Count < len(LineList): |
| if LineList[Count].strip().endswith("\\") and Count + 1 < len(LineList): |
| NewList.append(LineList[Count].strip()[:-2] + LineList[Count + 1]) |
| Count = Count + 1 |
| else: |
| NewList.append(LineList[Count]) |
| |
| Count = Count + 1 |
| |
| return NewList |
| |
| ## ProcessEdkComment |
| # |
| # Process EDK style comment in LineList: c style /* */ comment or cpp style // comment |
| # |
| # |
| # @param LineList The LineList need to be processed. |
| # |
| # @return LineList The LineList been processed. |
| # @return FirstPos Where Edk comment is first found, -1 if not found |
| # |
| def ProcessEdkComment(LineList): |
| FindEdkBlockComment = False |
| Count = 0 |
| StartPos = -1 |
| EndPos = -1 |
| FirstPos = -1 |
| |
| while(Count < len(LineList)): |
| Line = LineList[Count].strip() |
| if Line.startswith("/*"): |
| # |
| # handling c style comment |
| # |
| StartPos = Count |
| while Count < len(LineList): |
| Line = LineList[Count].strip() |
| if Line.endswith("*/"): |
| if (Count == StartPos) and Line.strip() == '/*/': |
| Count = Count + 1 |
| continue |
| EndPos = Count |
| FindEdkBlockComment = True |
| break |
| Count = Count + 1 |
| |
| if FindEdkBlockComment: |
| if FirstPos == -1: |
| FirstPos = StartPos |
| for Index in xrange(StartPos, EndPos+1): |
| LineList[Index] = '' |
| FindEdkBlockComment = False |
| elif Line.find("//") != -1 and not Line.startswith("#"): |
| # |
| # handling cpp style comment |
| # |
| LineList[Count] = Line.replace("//", '#') |
| if FirstPos == -1: |
| FirstPos = Count |
| |
| Count = Count + 1 |
| |
| return LineList, FirstPos |
| |
| ## GetLibInstanceInfo |
| # |
| # Get the information from Library Instance INF file. |
| # |
| # @param string. A string start with # and followed by INF file path |
| # @param WorkSpace. The WorkSpace directory used to combined with INF file path. |
| # |
| # @return GUID, Version |
| def GetLibInstanceInfo(String, WorkSpace, LineNo): |
| |
| FileGuidString = "" |
| VerString = "" |
| |
| OrignalString = String |
| String = String.strip() |
| if not String: |
| return None, None |
| # |
| # Remove "#" characters at the beginning |
| # |
| String = GetHelpStringByRemoveHashKey(String) |
| String = String.strip() |
| |
| # |
| # Validate file name exist. |
| # |
| FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, String))) |
| if not (ValidFile(FullFileName)): |
| Logger.Error("InfParser", |
| ToolError.FORMAT_INVALID, |
| ST.ERR_FILELIST_EXIST % (String), |
| File=GlobalData.gINF_MODULE_NAME, |
| Line=LineNo, |
| ExtraData=OrignalString) |
| |
| # |
| # Validate file exist/format. |
| # |
| if IsValidPath(String, WorkSpace): |
| IsValidFileFlag = True |
| else: |
| Logger.Error("InfParser", |
| ToolError.FORMAT_INVALID, |
| ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID % (String), |
| File=GlobalData.gINF_MODULE_NAME, |
| Line=LineNo, |
| ExtraData=OrignalString) |
| return False |
| if IsValidFileFlag: |
| FileLinesList = [] |
| |
| try: |
| FInputfile = open(FullFileName, "rb", 0) |
| try: |
| FileLinesList = FInputfile.readlines() |
| except BaseException: |
| Logger.Error("InfParser", |
| ToolError.FILE_READ_FAILURE, |
| ST.ERR_FILE_OPEN_FAILURE, |
| File=FullFileName) |
| finally: |
| FInputfile.close() |
| except BaseException: |
| Logger.Error("InfParser", |
| ToolError.FILE_READ_FAILURE, |
| ST.ERR_FILE_OPEN_FAILURE, |
| File=FullFileName) |
| |
| ReFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$") |
| ReVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$") |
| |
| FileLinesList = ProcessLineExtender(FileLinesList) |
| |
| for Line in FileLinesList: |
| if ReFileGuidPattern.match(Line): |
| FileGuidString = Line |
| if ReVerStringPattern.match(Line): |
| VerString = Line |
| |
| if FileGuidString: |
| FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1] |
| if VerString: |
| VerString = GetSplitValueList(VerString, '=', 1)[1] |
| |
| return FileGuidString, VerString |