system76-edk2/BaseTools/Source/Python/Common/MigrationUtilities.py
Hess Chen 1be2ed90a2 There is a limitation on WINDOWS OS for the length of entire file path can’t be larger than 255. There is an OS API provided by Microsoft to add “\\?\” before the path header to support the long file path. Enable this feature on basetools.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hess Chen <hesheng.chen@intel.com>
Reviewed-by: Yingke Liu <yingke.d.liu@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15809 6f19259b-4bc3-4df7-8a09-765794883524
2014-08-15 03:06:48 +00:00

569 lines
20 KiB
Python

## @file
# Contains several utilitities shared by migration tools.
#
# Copyright (c) 2007 - 2014, 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 Common.LongFilePathOs as os
import re
import EdkLogger
from optparse import OptionParser
from Common.BuildToolError import *
from XmlRoutines import *
from CommonDataClass.CommonClass import *
from Common.LongFilePathSupport import OpenLongFilePath as open
## Set all fields of CommonClass object.
#
# Set all attributes of CommonClass object from XML Dom object of XmlCommon.
#
# @param Common The destine CommonClass object.
# @param XmlCommon The source XML Dom object.
#
def SetCommon(Common, XmlCommon):
XmlTag = "Usage"
Common.Usage = XmlAttribute(XmlCommon, XmlTag).split()
XmlTag = "FeatureFlag"
Common.FeatureFlag = XmlAttribute(XmlCommon, XmlTag)
XmlTag = "SupArchList"
Common.SupArchList = XmlAttribute(XmlCommon, XmlTag).split()
XmlTag = XmlNodeName(XmlCommon) + "/" + "HelpText"
Common.HelpText = XmlElement(XmlCommon, XmlTag)
## Set some fields of CommonHeaderClass object.
#
# Set Name, Guid, FileName and FullPath fields of CommonHeaderClass object from
# XML Dom object of XmlCommonHeader, NameTag and FileName.
#
# @param CommonHeader The destine CommonClass object.
# @param XmlCommonHeader The source XML Dom object.
# @param NameTag The name tag in XML Dom object.
# @param FileName The file name of the XML file.
#
def SetIdentification(CommonHeader, XmlCommonHeader, NameTag, FileName):
XmlParentTag = XmlNodeName(XmlCommonHeader)
XmlTag = XmlParentTag + "/" + NameTag
CommonHeader.Name = XmlElement(XmlCommonHeader, XmlTag)
XmlTag = XmlParentTag + "/" + "GuidValue"
CommonHeader.Guid = XmlElement(XmlCommonHeader, XmlTag)
XmlTag = XmlParentTag + "/" + "Version"
CommonHeader.Version = XmlElement(XmlCommonHeader, XmlTag)
CommonHeader.FileName = os.path.basename(FileName)
CommonHeader.FullPath = os.path.abspath(FileName)
## Regular expression to match specification and value.
mReSpecification = re.compile(r"(?P<Specification>\w+)\s+(?P<Value>\w*)")
## Add specification to specification dictionary.
#
# Abstract specification name, value pair from Specification String and add them
# to specification dictionary.
#
# @param SpecificationDict The destine Specification dictionary.
# @param SpecificationString The source Specification String from which the
# specification name and value pair is abstracted.
#
def AddToSpecificationDict(SpecificationDict, SpecificationString):
"""Abstract specification name, value pair from Specification String"""
for SpecificationMatch in mReSpecification.finditer(SpecificationString):
Specification = SpecificationMatch.group("Specification")
Value = SpecificationMatch.group("Value")
SpecificationDict[Specification] = Value
## Set all fields of CommonHeaderClass object.
#
# Set all attributes of CommonHeaderClass object from XML Dom object of
# XmlCommonHeader, NameTag and FileName.
#
# @param CommonHeader The destine CommonClass object.
# @param XmlCommonHeader The source XML Dom object.
# @param NameTag The name tag in XML Dom object.
# @param FileName The file name of the XML file.
#
def SetCommonHeader(CommonHeader, XmlCommonHeader):
"""Set all attributes of CommonHeaderClass object from XmlCommonHeader"""
XmlParent = XmlNodeName(XmlCommonHeader)
XmlTag = XmlParent + "/" + "Abstract"
CommonHeader.Abstract = XmlElement(XmlCommonHeader, XmlTag)
XmlTag = XmlParent + "/" + "Description"
CommonHeader.Description = XmlElement(XmlCommonHeader, XmlTag)
XmlTag = XmlParent + "/" + "Copyright"
CommonHeader.Copyright = XmlElement(XmlCommonHeader, XmlTag)
XmlTag = XmlParent + "/" + "License"
CommonHeader.License = XmlElement(XmlCommonHeader, XmlTag)
XmlTag = XmlParent + "/" + "Specification"
Specification = XmlElement(XmlCommonHeader, XmlTag)
AddToSpecificationDict(CommonHeader.Specification, Specification)
XmlTag = XmlParent + "/" + "ModuleType"
CommonHeader.ModuleType = XmlElement(XmlCommonHeader, XmlTag)
## Load a new Cloned Record class object.
#
# Read an input XML ClonedRecord DOM object and return an object of Cloned Record
# contained in the DOM object.
#
# @param XmlCloned A child XML DOM object in a Common XML DOM.
#
# @retvel ClonedRecord A new Cloned Record object created by XmlCloned.
#
def LoadClonedRecord(XmlCloned):
ClonedRecord = ClonedRecordClass()
XmlTag = "Id"
ClonedRecord.Id = int(XmlAttribute(XmlCloned, XmlTag))
XmlTag = "FarGuid"
ClonedRecord.FarGuid = XmlAttribute(XmlCloned, XmlTag)
XmlTag = "Cloned/PackageGuid"
ClonedRecord.PackageGuid = XmlElement(XmlCloned, XmlTag)
XmlTag = "Cloned/PackageVersion"
ClonedRecord.PackageVersion = XmlElement(XmlCloned, XmlTag)
XmlTag = "Cloned/ModuleGuid"
ClonedRecord.ModuleGuid = XmlElement(XmlCloned, XmlTag)
XmlTag = "Cloned/ModuleVersion"
ClonedRecord.ModuleVersion = XmlElement(XmlCloned, XmlTag)
return ClonedRecord
## Load a new Guid/Protocol/Ppi common class object.
#
# Read an input XML Guid/Protocol/Ppi DOM object and return an object of
# Guid/Protocol/Ppi contained in the DOM object.
#
# @param XmlGuidProtocolPpiCommon A child XML DOM object in a Common XML DOM.
#
# @retvel GuidProtocolPpiCommon A new GuidProtocolPpiCommon class object
# created by XmlGuidProtocolPpiCommon.
#
def LoadGuidProtocolPpiCommon(XmlGuidProtocolPpiCommon):
GuidProtocolPpiCommon = GuidProtocolPpiCommonClass()
XmlTag = "Name"
GuidProtocolPpiCommon.Name = XmlAttribute(XmlGuidProtocolPpiCommon, XmlTag)
XmlParent = XmlNodeName(XmlGuidProtocolPpiCommon)
if XmlParent == "Entry":
XmlTag = "%s/C_Name" % XmlParent
elif XmlParent == "GuidCNames":
XmlTag = "%s/GuidCName" % XmlParent
else:
XmlTag = "%s/%sCName" % (XmlParent, XmlParent)
GuidProtocolPpiCommon.CName = XmlElement(XmlGuidProtocolPpiCommon, XmlTag)
XmlTag = XmlParent + "/" + "GuidValue"
GuidProtocolPpiCommon.Guid = XmlElement(XmlGuidProtocolPpiCommon, XmlTag)
if XmlParent.endswith("Notify"):
GuidProtocolPpiCommon.Notify = True
XmlTag = "GuidTypeList"
GuidTypes = XmlAttribute(XmlGuidProtocolPpiCommon, XmlTag)
GuidProtocolPpiCommon.GuidTypeList = GuidTypes.split()
XmlTag = "SupModuleList"
SupModules = XmlAttribute(XmlGuidProtocolPpiCommon, XmlTag)
GuidProtocolPpiCommon.SupModuleList = SupModules.split()
SetCommon(GuidProtocolPpiCommon, XmlGuidProtocolPpiCommon)
return GuidProtocolPpiCommon
## Load a new Pcd class object.
#
# Read an input XML Pcd DOM object and return an object of Pcd
# contained in the DOM object.
#
# @param XmlPcd A child XML DOM object in a Common XML DOM.
#
# @retvel Pcd A new Pcd object created by XmlPcd.
#
def LoadPcd(XmlPcd):
"""Return a new PcdClass object equivalent to XmlPcd"""
Pcd = PcdClass()
XmlTag = "PcdEntry/C_Name"
Pcd.CName = XmlElement(XmlPcd, XmlTag)
XmlTag = "PcdEntry/Token"
Pcd.Token = XmlElement(XmlPcd, XmlTag)
XmlTag = "PcdEntry/TokenSpaceGuidCName"
Pcd.TokenSpaceGuidCName = XmlElement(XmlPcd, XmlTag)
XmlTag = "PcdEntry/DatumType"
Pcd.DatumType = XmlElement(XmlPcd, XmlTag)
XmlTag = "PcdEntry/MaxDatumSize"
Pcd.MaxDatumSize = XmlElement(XmlPcd, XmlTag)
XmlTag = "PcdEntry/DefaultValue"
Pcd.DefaultValue = XmlElement(XmlPcd, XmlTag)
XmlTag = "PcdItemType"
Pcd.ItemType = XmlAttribute(XmlPcd, XmlTag)
XmlTag = "PcdEntry/ValidUsage"
Pcd.ValidUsage = XmlElement(XmlPcd, XmlTag).split()
XmlTag = "SupModuleList"
Pcd.SupModuleList = XmlAttribute(XmlPcd, XmlTag).split()
SetCommon(Pcd, XmlPcd)
return Pcd
## Load a new LibraryClass class object.
#
# Read an input XML LibraryClass DOM object and return an object of LibraryClass
# contained in the DOM object.
#
# @param XmlLibraryClass A child XML DOM object in a Common XML DOM.
#
# @retvel LibraryClass A new LibraryClass object created by XmlLibraryClass.
#
def LoadLibraryClass(XmlLibraryClass):
LibraryClass = LibraryClassClass()
XmlTag = "LibraryClass/Keyword"
LibraryClass.LibraryClass = XmlElement(XmlLibraryClass, XmlTag)
if LibraryClass.LibraryClass == "":
XmlTag = "Name"
LibraryClass.LibraryClass = XmlAttribute(XmlLibraryClass, XmlTag)
XmlTag = "LibraryClass/IncludeHeader"
LibraryClass.IncludeHeader = XmlElement(XmlLibraryClass, XmlTag)
XmlTag = "RecommendedInstanceVersion"
RecommendedInstanceVersion = XmlAttribute(XmlLibraryClass, XmlTag)
LibraryClass.RecommendedInstanceVersion = RecommendedInstanceVersion
XmlTag = "RecommendedInstanceGuid"
RecommendedInstanceGuid = XmlAttribute(XmlLibraryClass, XmlTag)
LibraryClass.RecommendedInstanceGuid = RecommendedInstanceGuid
XmlTag = "SupModuleList"
SupModules = XmlAttribute(XmlLibraryClass, XmlTag)
LibraryClass.SupModuleList = SupModules.split()
SetCommon(LibraryClass, XmlLibraryClass)
return LibraryClass
## Load a new Build Option class object.
#
# Read an input XML BuildOption DOM object and return an object of Build Option
# contained in the DOM object.
#
# @param XmlBuildOption A child XML DOM object in a Common XML DOM.
#
# @retvel BuildOption A new Build Option object created by XmlBuildOption.
#
def LoadBuildOption(XmlBuildOption):
"""Return a new BuildOptionClass object equivalent to XmlBuildOption"""
BuildOption = BuildOptionClass()
BuildOption.Option = XmlElementData(XmlBuildOption)
XmlTag = "BuildTargets"
BuildOption.BuildTargetList = XmlAttribute(XmlBuildOption, XmlTag).split()
XmlTag = "ToolChainFamily"
BuildOption.ToolChainFamily = XmlAttribute(XmlBuildOption, XmlTag)
XmlTag = "TagName"
BuildOption.TagName = XmlAttribute(XmlBuildOption, XmlTag)
XmlTag = "ToolCode"
BuildOption.ToolCode = XmlAttribute(XmlBuildOption, XmlTag)
XmlTag = "SupArchList"
BuildOption.SupArchList = XmlAttribute(XmlBuildOption, XmlTag).split()
return BuildOption
## Load a new User Extensions class object.
#
# Read an input XML UserExtensions DOM object and return an object of User
# Extensions contained in the DOM object.
#
# @param XmlUserExtensions A child XML DOM object in a Common XML DOM.
#
# @retvel UserExtensions A new User Extensions object created by
# XmlUserExtensions.
#
def LoadUserExtensions(XmlUserExtensions):
UserExtensions = UserExtensionsClass()
XmlTag = "UserID"
UserExtensions.UserID = XmlAttribute(XmlUserExtensions, XmlTag)
XmlTag = "Identifier"
UserExtensions.Identifier = XmlAttribute(XmlUserExtensions, XmlTag)
UserExtensions.Content = XmlElementData(XmlUserExtensions)
return UserExtensions
## Store content to a text file object.
#
# Write some text file content to a text file object. The contents may echo
# in screen in a verbose way.
#
# @param TextFile The text file object.
# @param Content The string object to be written to a text file.
#
def StoreTextFile(TextFile, Content):
EdkLogger.verbose(Content)
TextFile.write(Content)
## Add item to a section.
#
# Add an Item with specific CPU architecture to section dictionary.
# The possible duplication is ensured to be removed.
#
# @param Section Section dictionary indexed by CPU architecture.
# @param Arch CPU architecture: Ia32, X64, Ipf, ARM, AARCH64, Ebc or Common.
# @param Item The Item to be added to section dictionary.
#
def AddToSection(Section, Arch, Item):
SectionArch = Section.get(Arch, [])
if Item not in SectionArch:
SectionArch.append(Item)
Section[Arch] = SectionArch
## Get section contents.
#
# Return the content of section named SectionName.
# the contents is based on Methods and ObjectLists.
#
# @param SectionName The name of the section.
# @param Method A function returning a string item of an object.
# @param ObjectList The list of object.
#
# @retval Section The string content of a section.
#
def GetSection(SectionName, Method, ObjectList):
SupportedArches = ["common", "Ia32", "X64", "Ipf", "Ebc", "ARM", "AARCH64"]
SectionDict = {}
for Object in ObjectList:
Item = Method(Object)
if Item == "":
continue
Item = " %s" % Item
Arches = Object.SupArchList
if len(Arches) == 0:
AddToSection(SectionDict, "common", Item)
else:
for Arch in SupportedArches:
if Arch.upper() in Arches:
AddToSection(SectionDict, Arch, Item)
Section = ""
for Arch in SupportedArches:
SectionArch = "\n".join(SectionDict.get(Arch, []))
if SectionArch != "":
Section += "[%s.%s]\n%s\n" % (SectionName, Arch, SectionArch)
Section += "\n"
if Section != "":
Section += "\n"
return Section
## Store file header to a text file.
#
# Write standard file header to a text file. The content includes copyright,
# abstract, description and license extracted from CommonHeader class object.
#
# @param TextFile The text file object.
# @param CommonHeader The source CommonHeader class object.
#
def StoreHeader(TextFile, CommonHeader):
CopyRight = CommonHeader.Copyright
Abstract = CommonHeader.Abstract
Description = CommonHeader.Description
License = CommonHeader.License
Header = "#/** @file\n#\n"
Header += "# " + Abstract + "\n#\n"
Header += "# " + Description.strip().replace("\n", "\n# ") + "\n"
Header += "# " + CopyRight + "\n#\n"
Header += "# " + License.replace("\n", "\n# ").replace(" ", " ")
Header += "\n#\n#**/\n\n"
StoreTextFile(TextFile, Header)
## Store file header to a text file.
#
# Write Defines section to a text file. DefinesTupleList determines the content.
#
# @param TextFile The text file object.
# @param DefinesTupleList The list of (Tag, Value) to be added as one item.
#
def StoreDefinesSection(TextFile, DefinesTupleList):
Section = "[Defines]\n"
for DefineItem in DefinesTupleList:
Section += " %-30s = %s\n" % DefineItem
Section += "\n\n"
StoreTextFile(TextFile, Section)
## Return one User Extension section.
#
# Read the input UserExtentsions class object and return one section.
#
# @param UserExtensions An input UserExtensions class object.
#
# @retval UserExtensionSection A section representing UserExtensions object.
#
def GetUserExtensions(UserExtensions):
UserId = UserExtensions.UserID
Identifier = UserExtensions.Identifier
Content = UserExtensions.Content
return "[UserExtensions.%s.%s]\n %s\n\n" % (UserId, Identifier, Content)
## Regular expression to match an equation.
mReEquation = re.compile(r"\s*(\S+)\s*=\s*(\S*)\s*")
## Return a value tuple matching information in a text fle.
#
# Parse the text file and return a value tuple corresponding to an input tag
# tuple. In case of any error, an tuple of empty strings is returned.
#
# @param FileName The file name of the text file.
# @param TagTuple A tuple of tags as the key to the value.
#
# @param ValueTupe The returned tuple corresponding to the tag tuple.
#
def GetTextFileInfo(FileName, TagTuple):
ValueTuple = [""] * len(TagTuple)
try:
for Line in open(FileName):
Line = Line.split("#", 1)[0]
MatchEquation = mReEquation.match(Line)
if MatchEquation:
Tag = MatchEquation.group(1).upper()
Value = MatchEquation.group(2)
for Index in range(len(TagTuple)):
if TagTuple[Index] == Tag:
ValueTuple[Index] = Value
except:
EdkLogger.info("IO Error in reading file %s" % FileName)
return ValueTuple
## Return a value tuple matching information in an XML fle.
#
# Parse the XML file and return a value tuple corresponding to an input tag
# tuple. In case of any error, an tuple of empty strings is returned.
#
# @param FileName The file name of the XML file.
# @param TagTuple A tuple of tags as the key to the value.
#
# @param ValueTupe The returned tuple corresponding to the tag tuple.
#
def GetXmlFileInfo(FileName, TagTuple):
XmlDom = XmlParseFile(FileName)
return tuple([XmlElement(XmlDom, XmlTag) for XmlTag in TagTuple])
## Parse migration command line options
#
# Use standard Python module optparse to parse command line option of this tool.
#
# @param Source The source file type.
# @param Destinate The destinate file type.
#
# @retval Options A optparse object containing the parsed options.
# @retval InputFile Path of an source file to be migrated.
#
def MigrationOptionParser(Source, Destinate, ToolName, VersionNumber = 1.0):
# use clearer usage to override default usage message
UsageString = "%s [-a] [-v|-q] [-o <output_file>] <input_file>" % ToolName
Version = "%s Version %.2f" % (ToolName, VersionNumber)
Copyright = "Copyright (c) 2007, Intel Corporation. All rights reserved."
Parser = OptionParser(description=Copyright, version=Version, usage=UsageString)
Parser.add_option("-o", "--output", dest="OutputFile", help="The name of the %s file to be created." % Destinate)
Parser.add_option("-a", "--auto", dest="AutoWrite", action="store_true", default=False, help="Automatically create the %s file using the name of the %s file and replacing file extension" % (Source, Destinate))
Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")
Options, Args = Parser.parse_args()
# Set logging level
if Options.verbose:
EdkLogger.setLevel(EdkLogger.VERBOSE)
elif Options.quiet:
EdkLogger.setLevel(EdkLogger.QUIET)
else:
EdkLogger.setLevel(EdkLogger.INFO)
# error check
if len(Args) == 0:
raise MigrationError(PARAMETER_MISSING, name="Input file", usage=Parser.get_usage())
if len(Args) > 1:
raise MigrationError(PARAMETER_INVALID, name="Too many input files", usage=Parser.get_usage())
InputFile = Args[0]
if not os.path.exists(InputFile):
raise MigrationError(FILE_NOT_FOUND, name=InputFile)
if Options.OutputFile:
if Options.AutoWrite:
raise MigrationError(OPTION_CONFLICT, arg1="-o", arg2="-a", usage=Parser.get_usage())
else:
if Options.AutoWrite:
Options.OutputFile = os.path.splitext(InputFile)[0] + "." + Destinate.lower()
else:
raise MigrationError(OPTION_MISSING, name="-o", usage=Parser.get_usage())
return Options, InputFile
# This acts like the main() function for the script, unless it is 'import'ed
# into another script.
if __name__ == '__main__':
pass