## @file # Collects the Guid Information in current workspace. # # 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 fnmatch from Common.EdkIIWorkspace import EdkIIWorkspace from Common.MigrationUtilities import * ## A class for EdkII work space to resolve Guids. # # This class inherits from EdkIIWorkspace and collects the Guids information # in current workspace. The Guids information is important to translate the # package Guids and recommended library instances Guids to relative file path # (to workspace directory) in MSA files. # class EdkIIWorkspaceGuidsInfo(EdkIIWorkspace): ## The classconstructor. # # The constructor initialize workspace directory. It does not collect # pakage and module Guids info at initialization; instead, it collects them # on the fly. # # @param self The object pointer. # def __init__(self): # Initialize parent class. EdkIIWorkspace.__init__(self) # The internal map from Guid to FilePath. self.__GuidToFilePath = {} # The internal package directory list. self.__PackageDirList = [] # The internal flag to indicate whether package Guids info has been # to avoid re-collection collected. self.__PackageGuidInitialized = False # The internal flag to indicate whether module Guids info has been # to avoid re-collection collected. self.__ModuleGuidInitialized = False ## Add Guid, Version and FilePath to Guids database. # # Add Guid, Version and FilePath to Guids database. It constructs a map # table from Guid, Version to FilePath internally. If also detects possible # Guid collision. For now, the version information is simply ignored and # Guid value itself acts as master key. # # @param self The object pointer. # @param Guid The Guid Value. # @param Version The version information # # @retval True The Guid value is successfully added to map table. # @retval False The Guid is an empty string or the map table # already contains a same Guid. # def __AddGuidToFilePath(self, Guid, Version, FilePath): if Guid == "": EdkLogger.info("Cannot find Guid in file %s" % FilePath) return False #Add the Guid value to map table to ensure case insensitive comparison. OldFilePath = self.__GuidToFilePath.setdefault(Guid.lower(), FilePath) if OldFilePath == FilePath: EdkLogger.verbose("File %s has new Guid '%s'" % (FilePath, Guid)) return True else: EdkLogger.info("File %s has duplicate Guid with & %s" % (FilePath, OldFilePath)) return False ## Gets file information from a module description file. # # Extracts Module Name, File Guid and Version number from INF, MSA and NMSA # file. It supports to exact such information from text based INF file or # XML based (N)MSA file. # # @param self The object pointer. # @param FileName The input module file name. # # @retval True This module file represents a new module discovered # in current workspace. # @retval False This module file is not regarded as a valid module. # The File Guid cannot be extracted or the another # file with the same Guid already exists # def __GetModuleFileInfo(self, FileName): if fnmatch.fnmatch(FileName, "*.inf"): TagTuple = ("BASE_NAME", "FILE_GUID", "VERSION_STRING") (Name, Guid, Version) = GetTextFileInfo(FileName, TagTuple) else : XmlTag1 = "ModuleSurfaceArea/MsaHeader/ModuleName" XmlTag2 = "ModuleSurfaceArea/MsaHeader/GuidValue" XmlTag3 = "ModuleSurfaceArea/MsaHeader/Version" TagTuple = (XmlTag1, XmlTag2, XmlTag3) (Name, Guid, Version) = GetXmlFileInfo(FileName, TagTuple) return self.__AddGuidToFilePath(Guid, Version, FileName) ## Gets file information from a package description file. # # Extracts Package Name, File Guid and Version number from INF, SPD and NSPD # file. It supports to exact such information from text based DEC file or # XML based (N)SPD file. EDK Compatibility Package is hardcoded to be # ignored since no EDKII INF file depends on that package. # # @param self The object pointer. # @param FileName The input package file name. # # @retval True This package file represents a new package # discovered in current workspace. # @retval False This package is not regarded as a valid package. # The File Guid cannot be extracted or the another # file with the same Guid already exists # def __GetPackageFileInfo(self, FileName): if fnmatch.fnmatch(FileName, "*.dec"): TagTuple = ("PACKAGE_NAME", "PACKAGE_GUID", "PACKAGE_VERSION") (Name, Guid, Version) = GetTextFileInfo(FileName, TagTuple) else: XmlTag1 = "PackageSurfaceArea/SpdHeader/PackageName" XmlTag2 = "PackageSurfaceArea/SpdHeader/GuidValue" XmlTag3 = "PackageSurfaceArea/SpdHeader/Version" TagTuple = (XmlTag1, XmlTag2, XmlTag3) (Name, Guid, Version) = GetXmlFileInfo(FileName, TagTuple) if Name == "EdkCompatibilityPkg": # Do not scan EDK compatibitilty package to avoid Guid collision # with those in EDK Glue Library. EdkLogger.verbose("Bypass EDK Compatibility Pkg") return False return self.__AddGuidToFilePath(Guid, Version, FileName) ## Iterate on all package files listed in framework database file. # # Yields all package description files listed in framework database files. # The framework database file describes the packages current workspace # includes. # # @param self The object pointer. # def __FrameworkDatabasePackageFiles(self): XmlFrameworkDb = XmlParseFile(self.WorkspaceFile) XmlTag = "FrameworkDatabase/PackageList/Filename" for PackageFile in XmlElementList(XmlFrameworkDb, XmlTag): yield os.path.join(self.WorkspaceDir, PackageFile) ## Iterate on all package files in current workspace directory. # # Yields all package description files listed in current workspace # directory. This happens when no framework database file exists. # # @param self The object pointer. # def __TraverseAllPackageFiles(self): for Path, Dirs, Files in os.walk(self.WorkspaceDir): # Ignore svn version control directory. if ".svn" in Dirs: Dirs.remove(".svn") if "Build" in Dirs: Dirs.remove("Build") # Assume priority from high to low: DEC, NSPD, SPD. PackageFiles = fnmatch.filter(Files, "*.dec") if len(PackageFiles) == 0: PackageFiles = fnmatch.filter(Files, "*.nspd") if len(PackageFiles) == 0: PackageFiles = fnmatch.filter(Files, "*.spd") for File in PackageFiles: # Assume no more package decription file in sub-directory. del Dirs[:] yield os.path.join(Path, File) ## Iterate on all module files in current package directory. # # Yields all module description files listed in current package # directory. # # @param self The object pointer. # def __TraverseAllModuleFiles(self): for PackageDir in self.__PackageDirList: for Path, Dirs, Files in os.walk(PackageDir): # Ignore svn version control directory. if ".svn" in Dirs: Dirs.remove(".svn") # Assume priority from high to low: INF, NMSA, MSA. ModuleFiles = fnmatch.filter(Files, "*.inf") if len(ModuleFiles) == 0: ModuleFiles = fnmatch.filter(Files, "*.nmsa") if len(ModuleFiles) == 0: ModuleFiles = fnmatch.filter(Files, "*.msa") for File in ModuleFiles: yield os.path.join(Path, File) ## Initialize package Guids info mapping table. # # Collects all package guids map to package decription file path. This # function is invokes on demand to avoid unnecessary directory scan. # # @param self The object pointer. # def __InitializePackageGuidInfo(self): if self.__PackageGuidInitialized: return EdkLogger.verbose("Start to collect Package Guids Info.") WorkspaceFile = os.path.join("Conf", "FrameworkDatabase.db") self.WorkspaceFile = os.path.join(self.WorkspaceDir, WorkspaceFile) # Try to find the frameworkdatabase file to discover package lists if os.path.exists(self.WorkspaceFile): TraversePackage = self.__FrameworkDatabasePackageFiles EdkLogger.verbose("Package list bases on: %s" % self.WorkspaceFile) else: TraversePackage = self.__TraverseAllPackageFiles EdkLogger.verbose("Package list in: %s" % self.WorkspaceDir) for FileName in TraversePackage(): if self.__GetPackageFileInfo(FileName): PackageDir = os.path.dirname(FileName) EdkLogger.verbose("Find new package directory %s" % PackageDir) self.__PackageDirList.append(PackageDir) self.__PackageGuidInitialized = True ## Initialize module Guids info mapping table. # # Collects all module guids map to module decription file path. This # function is invokes on demand to avoid unnecessary directory scan. # # @param self The object pointer. # def __InitializeModuleGuidInfo(self): if self.__ModuleGuidInitialized: return EdkLogger.verbose("Start to collect Module Guids Info") self.__InitializePackageGuidInfo() for FileName in self.__TraverseAllModuleFiles(): if self.__GetModuleFileInfo(FileName): EdkLogger.verbose("Find new module %s" % FileName) self.__ModuleGuidInitialized = True ## Get Package file path by Package guid and Version. # # Translates the Package Guid and Version to a file path relative # to workspace directory. If no package in current workspace match the # input Guid, an empty file path is returned. For now, the version # value is simply ignored. # # @param self The object pointer. # @param Guid The Package Guid value to look for. # @param Version The Package Version value to look for. # def ResolvePackageFilePath(self, Guid, Version = ""): self.__InitializePackageGuidInfo() EdkLogger.verbose("Resolve Package Guid '%s'" % Guid) FileName = self.__GuidToFilePath.get(Guid.lower(), "") if FileName == "": EdkLogger.info("Cannot resolve Package Guid '%s'" % Guid) else: FileName = self.WorkspaceRelativePath(FileName) FileName = os.path.splitext(FileName)[0] + ".dec" FileName = FileName.replace("\\", "/") return FileName ## Get Module file path by Package guid and Version. # # Translates the Module Guid and Version to a file path relative # to workspace directory. If no module in current workspace match the # input Guid, an empty file path is returned. For now, the version # value is simply ignored. # # @param self The object pointer. # @param Guid The Module Guid value to look for. # @param Version The Module Version value to look for. # def ResolveModuleFilePath(self, Guid, Version = ""): self.__InitializeModuleGuidInfo() EdkLogger.verbose("Resolve Module Guid '%s'" % Guid) FileName = self.__GuidToFilePath.get(Guid.lower(), "") if FileName == "": EdkLogger.info("Cannot resolve Module Guid '%s'" % Guid) else: FileName = self.WorkspaceRelativePath(FileName) FileName = os.path.splitext(FileName)[0] + ".inf" FileName = FileName.replace("\\", "/") return FileName # A global class object of EdkIIWorkspaceGuidsInfo for external reference. gEdkIIWorkspaceGuidsInfo = EdkIIWorkspaceGuidsInfo() # This acts like the main() function for the script, unless it is 'import'ed # into another script. if __name__ == '__main__': # Test the translation of package Guid. MdePkgGuid = "1E73767F-8F52-4603-AEB4-F29B510B6766" OldMdePkgGuid = "5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec" print gEdkIIWorkspaceGuidsInfo.ResolveModuleFilePath(MdePkgGuid) print gEdkIIWorkspaceGuidsInfo.ResolveModuleFilePath(OldMdePkgGuid) # Test the translation of module Guid. UefiLibGuid = "3a004ba5-efe0-4a61-9f1a-267a46ae5ba9" UefiDriverModelLibGuid = "52af22ae-9901-4484-8cdc-622dd5838b09" print gEdkIIWorkspaceGuidsInfo.ResolveModuleFilePath(UefiLibGuid) print gEdkIIWorkspaceGuidsInfo.ResolveModuleFilePath(UefiDriverModelLibGuid)