1## @file
2# Contains several utilitities shared by migration tools.
3#
4# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
5# This program and the accompanying materials
6# are licensed and made available under the terms and conditions of the BSD License
7# which accompanies this distribution.  The full text of the license may be found at
8# http://opensource.org/licenses/bsd-license.php
9#
10# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12#
13
14##
15# Import Modules
16#
17import Common.LongFilePathOs as os
18import re
19import EdkLogger
20from optparse import OptionParser
21from Common.BuildToolError import *
22from XmlRoutines import *
23from CommonDataClass.CommonClass import *
24from Common.LongFilePathSupport import OpenLongFilePath as open
25
26## Set all fields of CommonClass object.
27#
28# Set all attributes of CommonClass object from XML Dom object of XmlCommon.
29#
30# @param  Common     The destine CommonClass object.
31# @param  XmlCommon  The source XML Dom object.
32#
33def SetCommon(Common, XmlCommon):
34    XmlTag = "Usage"
35    Common.Usage = XmlAttribute(XmlCommon, XmlTag).split()
36
37    XmlTag = "FeatureFlag"
38    Common.FeatureFlag = XmlAttribute(XmlCommon, XmlTag)
39
40    XmlTag = "SupArchList"
41    Common.SupArchList = XmlAttribute(XmlCommon, XmlTag).split()
42
43    XmlTag = XmlNodeName(XmlCommon) + "/" + "HelpText"
44    Common.HelpText = XmlElement(XmlCommon, XmlTag)
45
46
47## Set some fields of CommonHeaderClass object.
48#
49# Set Name, Guid, FileName and FullPath fields of CommonHeaderClass object from
50# XML Dom object of XmlCommonHeader, NameTag and FileName.
51#
52# @param  CommonHeader       The destine CommonClass object.
53# @param  XmlCommonHeader    The source XML Dom object.
54# @param  NameTag            The name tag in XML Dom object.
55# @param  FileName           The file name of the XML file.
56#
57def SetIdentification(CommonHeader, XmlCommonHeader, NameTag, FileName):
58    XmlParentTag = XmlNodeName(XmlCommonHeader)
59
60    XmlTag = XmlParentTag + "/" + NameTag
61    CommonHeader.Name = XmlElement(XmlCommonHeader, XmlTag)
62
63    XmlTag = XmlParentTag + "/" + "GuidValue"
64    CommonHeader.Guid = XmlElement(XmlCommonHeader, XmlTag)
65
66    XmlTag = XmlParentTag + "/" + "Version"
67    CommonHeader.Version = XmlElement(XmlCommonHeader, XmlTag)
68
69    CommonHeader.FileName = os.path.basename(FileName)
70    CommonHeader.FullPath = os.path.abspath(FileName)
71
72
73## Regular expression to match specification and value.
74mReSpecification = re.compile(r"(?P<Specification>\w+)\s+(?P<Value>\w*)")
75
76## Add specification to specification dictionary.
77#
78# Abstract specification name, value pair from Specification String and add them
79# to specification dictionary.
80#
81# @param  SpecificationDict   The destine Specification dictionary.
82# @param  SpecificationString The source Specification String from which the
83#                             specification name and value pair is abstracted.
84#
85def AddToSpecificationDict(SpecificationDict, SpecificationString):
86    """Abstract specification name, value pair from Specification String"""
87    for SpecificationMatch in mReSpecification.finditer(SpecificationString):
88        Specification = SpecificationMatch.group("Specification")
89        Value = SpecificationMatch.group("Value")
90        SpecificationDict[Specification] = Value
91
92## Set all fields of CommonHeaderClass object.
93#
94# Set all attributes of CommonHeaderClass object from XML Dom object of
95# XmlCommonHeader, NameTag and FileName.
96#
97# @param  CommonHeader       The destine CommonClass object.
98# @param  XmlCommonHeader    The source XML Dom object.
99# @param  NameTag            The name tag in XML Dom object.
100# @param  FileName           The file name of the XML file.
101#
102def SetCommonHeader(CommonHeader, XmlCommonHeader):
103    """Set all attributes of CommonHeaderClass object from XmlCommonHeader"""
104    XmlParent = XmlNodeName(XmlCommonHeader)
105
106    XmlTag = XmlParent + "/" + "Abstract"
107    CommonHeader.Abstract = XmlElement(XmlCommonHeader, XmlTag)
108
109    XmlTag = XmlParent + "/" + "Description"
110    CommonHeader.Description = XmlElement(XmlCommonHeader, XmlTag)
111
112    XmlTag = XmlParent + "/" + "Copyright"
113    CommonHeader.Copyright = XmlElement(XmlCommonHeader, XmlTag)
114
115    XmlTag = XmlParent + "/" + "License"
116    CommonHeader.License = XmlElement(XmlCommonHeader, XmlTag)
117
118    XmlTag = XmlParent + "/" + "Specification"
119    Specification = XmlElement(XmlCommonHeader, XmlTag)
120
121    AddToSpecificationDict(CommonHeader.Specification, Specification)
122
123    XmlTag = XmlParent + "/" + "ModuleType"
124    CommonHeader.ModuleType = XmlElement(XmlCommonHeader, XmlTag)
125
126
127## Load a new Cloned Record class object.
128#
129# Read an input XML ClonedRecord DOM object and return an object of Cloned Record
130# contained in the DOM object.
131#
132# @param  XmlCloned            A child XML DOM object in a Common XML DOM.
133#
134# @retvel ClonedRecord         A new Cloned Record object created by XmlCloned.
135#
136def LoadClonedRecord(XmlCloned):
137    ClonedRecord = ClonedRecordClass()
138
139    XmlTag = "Id"
140    ClonedRecord.Id = int(XmlAttribute(XmlCloned, XmlTag))
141
142    XmlTag = "FarGuid"
143    ClonedRecord.FarGuid = XmlAttribute(XmlCloned, XmlTag)
144
145    XmlTag = "Cloned/PackageGuid"
146    ClonedRecord.PackageGuid = XmlElement(XmlCloned, XmlTag)
147
148    XmlTag = "Cloned/PackageVersion"
149    ClonedRecord.PackageVersion = XmlElement(XmlCloned, XmlTag)
150
151    XmlTag = "Cloned/ModuleGuid"
152    ClonedRecord.ModuleGuid = XmlElement(XmlCloned, XmlTag)
153
154    XmlTag = "Cloned/ModuleVersion"
155    ClonedRecord.ModuleVersion = XmlElement(XmlCloned, XmlTag)
156
157    return ClonedRecord
158
159
160## Load a new Guid/Protocol/Ppi common class object.
161#
162# Read an input XML Guid/Protocol/Ppi DOM object and return an object of
163# Guid/Protocol/Ppi contained in the DOM object.
164#
165# @param  XmlGuidProtocolPpiCommon A child XML DOM object in a Common XML DOM.
166#
167# @retvel GuidProtocolPpiCommon    A new GuidProtocolPpiCommon class object
168#                                  created by XmlGuidProtocolPpiCommon.
169#
170def LoadGuidProtocolPpiCommon(XmlGuidProtocolPpiCommon):
171    GuidProtocolPpiCommon = GuidProtocolPpiCommonClass()
172
173    XmlTag = "Name"
174    GuidProtocolPpiCommon.Name = XmlAttribute(XmlGuidProtocolPpiCommon, XmlTag)
175
176    XmlParent = XmlNodeName(XmlGuidProtocolPpiCommon)
177    if XmlParent == "Entry":
178        XmlTag = "%s/C_Name" % XmlParent
179    elif XmlParent == "GuidCNames":
180        XmlTag = "%s/GuidCName" % XmlParent
181    else:
182        XmlTag = "%s/%sCName" % (XmlParent, XmlParent)
183
184    GuidProtocolPpiCommon.CName = XmlElement(XmlGuidProtocolPpiCommon, XmlTag)
185
186    XmlTag = XmlParent + "/" + "GuidValue"
187    GuidProtocolPpiCommon.Guid = XmlElement(XmlGuidProtocolPpiCommon, XmlTag)
188
189    if XmlParent.endswith("Notify"):
190        GuidProtocolPpiCommon.Notify = True
191
192    XmlTag = "GuidTypeList"
193    GuidTypes = XmlAttribute(XmlGuidProtocolPpiCommon, XmlTag)
194    GuidProtocolPpiCommon.GuidTypeList = GuidTypes.split()
195
196    XmlTag = "SupModuleList"
197    SupModules = XmlAttribute(XmlGuidProtocolPpiCommon, XmlTag)
198    GuidProtocolPpiCommon.SupModuleList = SupModules.split()
199
200    SetCommon(GuidProtocolPpiCommon, XmlGuidProtocolPpiCommon)
201
202    return GuidProtocolPpiCommon
203
204
205## Load a new Pcd class object.
206#
207# Read an input XML Pcd DOM object and return an object of Pcd
208# contained in the DOM object.
209#
210# @param  XmlPcd               A child XML DOM object in a Common XML DOM.
211#
212# @retvel Pcd                  A new Pcd object created by XmlPcd.
213#
214def LoadPcd(XmlPcd):
215    """Return a new PcdClass object equivalent to XmlPcd"""
216    Pcd = PcdClass()
217
218    XmlTag = "PcdEntry/C_Name"
219    Pcd.CName = XmlElement(XmlPcd, XmlTag)
220
221    XmlTag = "PcdEntry/Token"
222    Pcd.Token = XmlElement(XmlPcd, XmlTag)
223
224    XmlTag = "PcdEntry/TokenSpaceGuidCName"
225    Pcd.TokenSpaceGuidCName = XmlElement(XmlPcd, XmlTag)
226
227    XmlTag = "PcdEntry/DatumType"
228    Pcd.DatumType = XmlElement(XmlPcd, XmlTag)
229
230    XmlTag = "PcdEntry/MaxDatumSize"
231    Pcd.MaxDatumSize = XmlElement(XmlPcd, XmlTag)
232
233    XmlTag = "PcdEntry/DefaultValue"
234    Pcd.DefaultValue = XmlElement(XmlPcd, XmlTag)
235
236    XmlTag = "PcdItemType"
237    Pcd.ItemType = XmlAttribute(XmlPcd, XmlTag)
238
239    XmlTag = "PcdEntry/ValidUsage"
240    Pcd.ValidUsage = XmlElement(XmlPcd, XmlTag).split()
241
242    XmlTag = "SupModuleList"
243    Pcd.SupModuleList = XmlAttribute(XmlPcd, XmlTag).split()
244
245    SetCommon(Pcd, XmlPcd)
246
247    return Pcd
248
249
250## Load a new LibraryClass class object.
251#
252# Read an input XML LibraryClass DOM object and return an object of LibraryClass
253# contained in the DOM object.
254#
255# @param  XmlLibraryClass    A child XML DOM object in a Common XML DOM.
256#
257# @retvel LibraryClass       A new LibraryClass object created by XmlLibraryClass.
258#
259def LoadLibraryClass(XmlLibraryClass):
260    LibraryClass = LibraryClassClass()
261
262    XmlTag = "LibraryClass/Keyword"
263    LibraryClass.LibraryClass = XmlElement(XmlLibraryClass, XmlTag)
264    if LibraryClass.LibraryClass == "":
265        XmlTag = "Name"
266        LibraryClass.LibraryClass = XmlAttribute(XmlLibraryClass, XmlTag)
267
268    XmlTag = "LibraryClass/IncludeHeader"
269    LibraryClass.IncludeHeader = XmlElement(XmlLibraryClass, XmlTag)
270
271    XmlTag = "RecommendedInstanceVersion"
272    RecommendedInstanceVersion = XmlAttribute(XmlLibraryClass, XmlTag)
273    LibraryClass.RecommendedInstanceVersion = RecommendedInstanceVersion
274
275    XmlTag = "RecommendedInstanceGuid"
276    RecommendedInstanceGuid = XmlAttribute(XmlLibraryClass, XmlTag)
277    LibraryClass.RecommendedInstanceGuid = RecommendedInstanceGuid
278
279    XmlTag = "SupModuleList"
280    SupModules = XmlAttribute(XmlLibraryClass, XmlTag)
281    LibraryClass.SupModuleList = SupModules.split()
282
283    SetCommon(LibraryClass, XmlLibraryClass)
284
285    return LibraryClass
286
287
288## Load a new Build Option class object.
289#
290# Read an input XML BuildOption DOM object and return an object of Build Option
291# contained in the DOM object.
292#
293# @param  XmlBuildOption       A child XML DOM object in a Common XML DOM.
294#
295# @retvel BuildOption          A new Build Option object created by XmlBuildOption.
296#
297def LoadBuildOption(XmlBuildOption):
298    """Return a new BuildOptionClass object equivalent to XmlBuildOption"""
299    BuildOption = BuildOptionClass()
300
301    BuildOption.Option = XmlElementData(XmlBuildOption)
302
303    XmlTag = "BuildTargets"
304    BuildOption.BuildTargetList = XmlAttribute(XmlBuildOption, XmlTag).split()
305
306    XmlTag = "ToolChainFamily"
307    BuildOption.ToolChainFamily = XmlAttribute(XmlBuildOption, XmlTag)
308
309    XmlTag = "TagName"
310    BuildOption.TagName = XmlAttribute(XmlBuildOption, XmlTag)
311
312    XmlTag = "ToolCode"
313    BuildOption.ToolCode = XmlAttribute(XmlBuildOption, XmlTag)
314
315    XmlTag = "SupArchList"
316    BuildOption.SupArchList = XmlAttribute(XmlBuildOption, XmlTag).split()
317
318    return BuildOption
319
320
321## Load a new User Extensions class object.
322#
323# Read an input XML UserExtensions DOM object and return an object of User
324# Extensions contained in the DOM object.
325#
326# @param  XmlUserExtensions    A child XML DOM object in a Common XML DOM.
327#
328# @retvel UserExtensions       A new User Extensions object created by
329#                              XmlUserExtensions.
330#
331def LoadUserExtensions(XmlUserExtensions):
332    UserExtensions = UserExtensionsClass()
333
334    XmlTag = "UserID"
335    UserExtensions.UserID = XmlAttribute(XmlUserExtensions, XmlTag)
336
337    XmlTag = "Identifier"
338    UserExtensions.Identifier = XmlAttribute(XmlUserExtensions, XmlTag)
339
340    UserExtensions.Content = XmlElementData(XmlUserExtensions)
341
342    return UserExtensions
343
344
345## Store content to a text file object.
346#
347# Write some text file content to a text file object. The contents may echo
348# in screen in a verbose way.
349#
350# @param  TextFile           The text file object.
351# @param  Content            The string object to be written to a text file.
352#
353def StoreTextFile(TextFile, Content):
354    EdkLogger.verbose(Content)
355    TextFile.write(Content)
356
357
358## Add item to a section.
359#
360# Add an Item with specific CPU architecture to section dictionary.
361# The possible duplication is ensured to be removed.
362#
363# @param  Section            Section dictionary indexed by CPU architecture.
364# @param  Arch               CPU architecture: Ia32, X64, Ipf, ARM, AARCH64, Ebc or Common.
365# @param  Item               The Item to be added to section dictionary.
366#
367def AddToSection(Section, Arch, Item):
368    SectionArch = Section.get(Arch, [])
369    if Item not in SectionArch:
370        SectionArch.append(Item)
371        Section[Arch] = SectionArch
372
373
374## Get section contents.
375#
376# Return the content of section named SectionName.
377# the contents is based on Methods and ObjectLists.
378#
379# @param  SectionName        The name of the section.
380# @param  Method             A function returning a string item of an object.
381# @param  ObjectList         The list of object.
382#
383# @retval Section            The string content of a section.
384#
385def GetSection(SectionName, Method, ObjectList):
386    SupportedArches = ["common", "Ia32", "X64", "Ipf", "Ebc", "ARM", "AARCH64"]
387    SectionDict = {}
388    for Object in ObjectList:
389        Item = Method(Object)
390        if Item == "":
391            continue
392        Item = "  %s" % Item
393        Arches = Object.SupArchList
394        if len(Arches) == 0:
395            AddToSection(SectionDict, "common", Item)
396        else:
397            for Arch in SupportedArches:
398                if Arch.upper() in Arches:
399                    AddToSection(SectionDict, Arch, Item)
400
401    Section = ""
402    for Arch in SupportedArches:
403        SectionArch = "\n".join(SectionDict.get(Arch, []))
404        if SectionArch != "":
405            Section += "[%s.%s]\n%s\n" % (SectionName, Arch, SectionArch)
406            Section += "\n"
407    if Section != "":
408        Section += "\n"
409    return Section
410
411
412## Store file header to a text file.
413#
414# Write standard file header to a text file. The content includes copyright,
415# abstract, description and license extracted from CommonHeader class object.
416#
417# @param  TextFile           The text file object.
418# @param  CommonHeader       The source CommonHeader class object.
419#
420def StoreHeader(TextFile, CommonHeader):
421    CopyRight = CommonHeader.Copyright
422    Abstract = CommonHeader.Abstract
423    Description = CommonHeader.Description
424    License = CommonHeader.License
425
426    Header = "#/** @file\n#\n"
427    Header += "# " + Abstract + "\n#\n"
428    Header += "# " + Description.strip().replace("\n", "\n# ") + "\n"
429    Header += "# " + CopyRight + "\n#\n"
430    Header += "#  " + License.replace("\n", "\n# ").replace("  ", " ")
431    Header += "\n#\n#**/\n\n"
432
433    StoreTextFile(TextFile, Header)
434
435## Store file header to a text file.
436#
437# Write Defines section to a text file. DefinesTupleList determines the content.
438#
439# @param  TextFile           The text file object.
440# @param  DefinesTupleList   The list of (Tag, Value) to be added as one item.
441#
442def StoreDefinesSection(TextFile, DefinesTupleList):
443    Section = "[Defines]\n"
444    for DefineItem in DefinesTupleList:
445        Section += "  %-30s = %s\n" % DefineItem
446
447    Section += "\n\n"
448    StoreTextFile(TextFile, Section)
449
450
451## Return one User Extension section.
452#
453# Read the input UserExtentsions class object and return one section.
454#
455# @param  UserExtensions       An input UserExtensions class object.
456#
457# @retval UserExtensionSection A section representing UserExtensions object.
458#
459def GetUserExtensions(UserExtensions):
460    UserId = UserExtensions.UserID
461    Identifier = UserExtensions.Identifier
462    Content = UserExtensions.Content
463
464    return "[UserExtensions.%s.%s]\n  %s\n\n" % (UserId, Identifier, Content)
465
466## Regular expression to match an equation.
467mReEquation = re.compile(r"\s*(\S+)\s*=\s*(\S*)\s*")
468
469## Return a value tuple matching information in a text fle.
470#
471# Parse the text file and return a value tuple corresponding to an input tag
472# tuple. In case of any error, an tuple of empty strings is returned.
473#
474# @param  FileName           The file name of the text file.
475# @param  TagTuple           A tuple of tags as the key to the value.
476#
477# @param  ValueTupe          The returned tuple corresponding to the tag tuple.
478#
479def GetTextFileInfo(FileName, TagTuple):
480    ValueTuple = [""] * len(TagTuple)
481    try:
482        for Line in open(FileName):
483            Line = Line.split("#", 1)[0]
484            MatchEquation = mReEquation.match(Line)
485            if MatchEquation:
486                Tag = MatchEquation.group(1).upper()
487                Value = MatchEquation.group(2)
488                for Index in range(len(TagTuple)):
489                    if TagTuple[Index] == Tag:
490                        ValueTuple[Index] = Value
491    except:
492        EdkLogger.info("IO Error in reading file %s" % FileName)
493
494    return ValueTuple
495
496
497## Return a value tuple matching information in an XML fle.
498#
499# Parse the XML file and return a value tuple corresponding to an input tag
500# tuple. In case of any error, an tuple of empty strings is returned.
501#
502# @param  FileName           The file name of the XML file.
503# @param  TagTuple           A tuple of tags as the key to the value.
504#
505# @param  ValueTupe          The returned tuple corresponding to the tag tuple.
506#
507def GetXmlFileInfo(FileName, TagTuple):
508    XmlDom = XmlParseFile(FileName)
509    return tuple([XmlElement(XmlDom, XmlTag) for XmlTag in TagTuple])
510
511
512## Parse migration command line options
513#
514# Use standard Python module optparse to parse command line option of this tool.
515#
516# @param  Source             The source file type.
517# @param  Destinate          The destinate file type.
518#
519# @retval Options            A optparse object containing the parsed options.
520# @retval InputFile          Path of an source file to be migrated.
521#
522def MigrationOptionParser(Source, Destinate, ToolName, VersionNumber=1.0):
523    # use clearer usage to override default usage message
524    UsageString = "%s [-a] [-v|-q] [-o <output_file>] <input_file>" % ToolName
525    Version = "%s Version %.2f" % (ToolName, VersionNumber)
526    Copyright = "Copyright (c) 2007, Intel Corporation. All rights reserved."
527
528    Parser = OptionParser(description=Copyright, version=Version, usage=UsageString)
529    Parser.add_option("-o", "--output", dest="OutputFile", help="The name of the %s file to be created." % Destinate)
530    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))
531    Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
532    Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")
533
534    Options, Args = Parser.parse_args()
535
536    # Set logging level
537    if Options.verbose:
538        EdkLogger.setLevel(EdkLogger.VERBOSE)
539    elif Options.quiet:
540        EdkLogger.setLevel(EdkLogger.QUIET)
541    else:
542        EdkLogger.setLevel(EdkLogger.INFO)
543
544    # error check
545    if len(Args) == 0:
546        raise MigrationError(PARAMETER_MISSING, name="Input file", usage=Parser.get_usage())
547    if len(Args) > 1:
548        raise MigrationError(PARAMETER_INVALID, name="Too many input files", usage=Parser.get_usage())
549
550    InputFile = Args[0]
551    if not os.path.exists(InputFile):
552        raise MigrationError(FILE_NOT_FOUND, name=InputFile)
553
554    if Options.OutputFile:
555        if Options.AutoWrite:
556            raise MigrationError(OPTION_CONFLICT, arg1="-o", arg2="-a", usage=Parser.get_usage())
557    else:
558        if Options.AutoWrite:
559            Options.OutputFile = os.path.splitext(InputFile)[0] + "." + Destinate.lower()
560        else:
561            raise MigrationError(OPTION_MISSING, name="-o", usage=Parser.get_usage())
562
563    return Options, InputFile
564
565# This acts like the main() function for the script, unless it is 'import'ed
566# into another script.
567if __name__ == '__main__':
568    pass
569