mirror of https://github.com/acidanthera/audk.git
327 lines
14 KiB
Python
327 lines
14 KiB
Python
|
## @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 initialized
|
||
|
# to avoid re-collection collected.
|
||
|
self.__PackageGuidInitialized = False
|
||
|
# The internal flag to indicate whether module Guids info has been initialized
|
||
|
# 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
|
||
|
# @param FilePath The Guid related file path
|
||
|
#
|
||
|
# @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 Module 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.ResolvePlatformFilePath(UefiLibGuid)
|
||
|
# print gEdkIIWorkspaceGuidsInfo.ResolvePlatformFilePath(UefiDriverModelLibGuid)
|
||
|
pass
|