| ## @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 |