git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10502 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			326 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
## @file
 | 
						|
# Collects the Guid Information in current workspace.
 | 
						|
#
 | 
						|
# Copyright (c) 2007, 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.
 | 
						|
#
 | 
						|
 | 
						|
##
 | 
						|
# 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)
 |