]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/Python/MkFar.py
Import BaseMemoryLibMmx;
[mirror_edk2.git] / Tools / Python / MkFar.py
CommitLineData
e853a9d4 1#!/usr/bin/env python
2
3b7a53b6 3"""This is a python script that takes user input from the command line and
4creates a far (Framework Archive Manifest) file for distribution."""
5
10d6603f 6import os, sys, getopt, string, xml.dom.minidom, zipfile, md5
e853a9d4 7from XmlRoutines import *
8from WorkspaceRoutines import *
9
fb96878e 10class Far:
11 """This class is used to collect arbitrarty data from the template file."""
12 def __init__(far):
13 """Assign the default values for the far fields."""
14 far.FileName = "output.far"
15 far.FarName=""
16 far.Version=""
17 far.License=""
af2efcaf 18 far.Abstract=""
fb96878e 19 far.Description=""
20 far.Copyright=""
af2efcaf 21 far.SpdFiles=[]
22 far.FpdFiles=[]
23 far.ExtraFiles=[]
fb96878e 24
25far = Far()
3b7a53b6 26"""The far object is constructed from the template file the user passed in."""
fb96878e 27
822d4f3a 28def AddToZip(zip, infile):
29
30 """Add a file to a zip file, provided it is not already there."""
31
32 if not infile in zip.namelist():
33 zip.write(inWorkspace(infile), infile)
34
e853a9d4 35def parseMsa(msaFile, spdDir):
36
822d4f3a 37 """Parse an msa file and return a list of all the files that this msa
3b7a53b6 38 includes."""
39
69932b41 40 filelist = [msaFile]
e853a9d4 41
42 msaDir = os.path.dirname(msaFile)
43
10d6603f 44 msa = xml.dom.minidom.parse(inWorkspace(os.path.join(spdDir, msaFile)))
e853a9d4 45
46 xmlPaths = [
10d6603f 47 "/ModuleSurfaceArea/SourceFiles/Filename",
48 "/ModuleSurfaceArea/NonProcessedFiles/Filename" ]
822d4f3a 49
e853a9d4 50 for xmlPath in xmlPaths:
51 for f in XmlList(msa, xmlPath):
52 filelist.append(str(os.path.join(msaDir, XmlElementData(f))))
53
54 return filelist
55
56def parseSpd(spdFile):
57
3b7a53b6 58 """Parse an spd file and return a list of all the files that this spd
59 includes."""
60
10d6603f 61 files = []
e853a9d4 62
63 spdDir = os.path.dirname(spdFile)
64
65 spd = xml.dom.minidom.parse(inWorkspace(spdFile))
66
822d4f3a 67 # We are currently ignoring these hints.
68 readonly = XmlElement(spd, "/PackageSurfaceArea/PackageDefinitions/ReadOnly") != "false"
69 repackage = XmlElement(spd, "/PackageSurfaceArea/PackageDefinitions/RePackage") != "false"
70
e853a9d4 71 xmlPaths = [
72 "/PackageSurfaceArea/LibraryClassDeclarations/LibraryClass/IncludeHeader",
822d4f3a 73 "/PackageSurfaceArea/IndustryStdIncludes/IndustryStdHeader/IncludeHeader" ]
74
75 # These are covered by the Industry Standard Includes.
76 # "/PackageSurfaceArea/PackageHeaders/IncludePkgHeader"
e853a9d4 77
78 for xmlPath in xmlPaths:
79 for f in XmlList(spd, xmlPath):
10d6603f 80 files.append(str(XmlElementData(f)))
e853a9d4 81
d32aaa95 82 for f in XmlList(spd, "/PackageSurfaceArea/MsaFiles/Filename"):
10d6603f 83 msaFile = str(XmlElementData(f))
84 files += parseMsa(msaFile, spdDir)
85
86 cwd = os.getcwd()
87 os.chdir(inWorkspace(spdDir))
88 for root, dirs, entries in os.walk("Include"):
af2efcaf 89 # Some files need to be skipped.
90 for r in ["CVS", ".svn"]:
10d6603f 91 if r in dirs:
92 dirs.remove(r)
93 for entry in entries:
94 files.append(os.path.join(os.path.normpath(root), entry))
95 os.chdir(cwd)
96
97 return files
98
99def makeFarHeader(doc):
100
3b7a53b6 101 """Create a dom tree for the Far Header. It will use information from the
102 template file passed on the command line, if present."""
822d4f3a 103
312ffece 104 header = XmlAppendChildElement(doc.documentElement, "FarHeader")
105
106 XmlAppendChildElement(header, "FarName", far.FarName)
107 XmlAppendChildElement(header, "GuidValue", genguid())
108 XmlAppendChildElement(header, "Version", far.Version)
109 XmlAppendChildElement(header, "Abstract", far.Abstract)
110 XmlAppendChildElement(header, "Description", far.Description)
111 XmlAppendChildElement(header, "Copyright", far.Copyright)
112 XmlAppendChildElement(header, "License", far.License)
113 XmlAppendChildElement(header, "Specification", "FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052")
10d6603f 114
115 return header
116
117def getSpdGuidVersion(spdFile):
e853a9d4 118
3b7a53b6 119 """Returns a tuple (guid, version) which is read from the given spdFile."""
120
10d6603f 121 spd = xml.dom.minidom.parse(inWorkspace(spdFile))
122
123 return (XmlElement(spd, "/PackageSurfaceArea/SpdHeader/GuidValue"),
124 XmlElement(spd, "/PackageSurfaceArea/SpdHeader/Version"))
e853a9d4 125
af2efcaf 126def makeFar(files, farname):
e853a9d4 127
3b7a53b6 128 """Make a far out of the given filelist and writes it to the file farname."""
129
69932b41 130 domImpl = xml.dom.minidom.getDOMImplementation()
131 man = domImpl.createDocument(None, "FrameworkArchiveManifest", None)
132 top_element = man.documentElement
133
10d6603f 134 top_element.appendChild(makeFarHeader(man))
d32aaa95 135
312ffece 136 packList = XmlAppendChildElement(top_element, "FarPackageList")
137 platList = XmlAppendChildElement(top_element, "FarPlatformList")
138 contents = XmlAppendChildElement(top_element, "Contents")
139 XmlAppendChildElement(top_element, "UserExtensions")
10d6603f 140
822d4f3a 141 try:
142 zip = zipfile.ZipFile(farname, "w", zipfile.ZIP_DEFLATED)
143 except:
144 zip = zipfile.ZipFile(farname, "w", zipfile.ZIP_STORED)
af2efcaf 145 for infile in set(files):
d32aaa95 146 if not os.path.exists(inWorkspace(infile)):
5b8acefd 147 print "Error: Non-existent file '%s'." % infile
148 sys.exit()
d32aaa95 149 (_, extension) = os.path.splitext(infile)
e853a9d4 150 if extension == ".spd":
d32aaa95 151 filelist = parseSpd(infile)
10d6603f 152 spdDir = os.path.dirname(infile)
153
154 (spdGuid, spdVersion) = getSpdGuidVersion(infile)
69932b41 155
312ffece 156 package = XmlAppendChildElement(packList, "FarPackage")
157 XmlAppendChildElement(package, "FarFilename", lean(infile), {"Md5Sum": Md5(inWorkspace(infile))})
822d4f3a 158 AddToZip(zip, infile)
312ffece 159 XmlAppendChildElement(package, "GuidValue", spdGuid)
160 XmlAppendChildElement(package, "Version", spdVersion)
161 XmlAppendChildElement(package, "DefaultPath", spdDir)
162 XmlAppendChildElement(package, "FarPlatformList")
163 packContents = XmlAppendChildElement(package, "Contents")
164 XmlAppendChildElement(package, "UserExtensions")
d32aaa95 165
166 for spdfile in filelist:
312ffece 167 XmlAppendChildElement(packContents, "FarFilename", lean(spdfile), {"Md5Sum": Md5(inWorkspace(os.path.join(spdDir, spdfile)))})
822d4f3a 168 AddToZip(zip, os.path.join(spdDir,spdfile))
69932b41 169
e853a9d4 170 elif extension == ".fpd":
d32aaa95 171
312ffece 172 platform = XmlAppendChildElement(platList, "FarPlatform")
173 XmlAppendChildElement(platform, "FarFilename", lean(infile), {"Md5Sum": Md5(inWorkspace(infile))})
822d4f3a 174 AddToZip(zip, infile)
d32aaa95 175
e853a9d4 176 else:
312ffece 177 XmlAppendChildElement(contents, "FarFilename", lean(infile), {"Md5Sum": Md5(inWorkspace(infile))})
822d4f3a 178 AddToZip(zip, infile)
d32aaa95 179
312ffece 180 zip.writestr("FrameworkArchiveManifest.xml", man.toxml('UTF-8'))
e853a9d4 181 zip.close()
182 return
183
d0f7ef3e 184# This acts like the main() function for the script, unless it is 'import'ed
185# into another script.
e853a9d4 186if __name__ == '__main__':
187
188 # Create a pretty printer for dumping data structures in a readable form.
189 # pp = pprint.PrettyPrinter(indent=2)
190
191 # Process the command line args.
312ffece 192 optlist, args = getopt.getopt(sys.argv[1:], 'ho:t:v', [ 'template=', 'output=', 'far=', 'help', 'debug', 'verbose', 'version'])
d0f7ef3e 193
af2efcaf 194 # First pass through the options list.
d0f7ef3e 195 for o, a in optlist:
196 if o in ["-h", "--help"]:
197 print """
198Pass a list of .spd and .fpd files to be placed into a far for distribution.
199You may give the name of the far with a -f or --far option. For example:
200
5b8acefd 201 %s --template far-template --far library.far MdePkg/MdePkg.spd
d0f7ef3e 202
fb96878e 203The file paths of .spd and .fpd are treated as relative to the WORKSPACE
af2efcaf 204environment variable which must be set to a valid workspace root directory.
5b8acefd 205
206A template file may be passed in with the --template option. This template file
207is a text file that allows more contol over the contents of the far.
d0f7ef3e 208""" % os.path.basename(sys.argv[0])
209
210 sys.exit()
af2efcaf 211 optlist.remove((o,a))
fb96878e 212 if o in ["-t", "--template"]:
213 # The template file is processed first, so that command line options can
214 # override it.
215 templateName = a
216 execfile(templateName)
af2efcaf 217 optlist.remove((o,a))
218
219 # Second pass through the options list. These can override the first pass.
220 for o, a in optlist:
312ffece 221 if o in ["-o", "--far", "--output"]:
fb96878e 222 far.FileName = a
e853a9d4 223
af2efcaf 224 # Let's err on the side of caution and not let people blow away data
225 # accidentally.
226 if os.path.exists(far.FileName):
227 print "Error: File %s exists. Not overwriting." % far.FileName
228 sys.exit()
229
230 makeFar(far.SpdFiles + far.FpdFiles + far.ExtraFiles + args, far.FileName)