346b09e5a36e413a8f150f886772cece7b122ef8
[people/mcb30/edk2.git] / edk2 / Tools / Python / InstallFar.py
1 #!/usr/bin/env python
2
3 """This is a python script that takes user input from the command line and
4 installs a far (Framework Archive Manifest) file into the workspace."""
5
6 import os, sys, getopt, string, xml.dom.minidom, zipfile, md5
7 from XmlRoutines import *
8 from WorkspaceRoutines import *
9
10 verbose = False
11 force = False
12
13 class Database:
14
15   def __init__(self, filename="Tools/Conf/FrameworkDatabase.db"): 
16
17     # First try to get a lock file.
18     self.DBFile = inWorkspace(filename)
19     self.lockfile = inWorkspace("Tools/Conf/FrameworkDatabase.lock")
20     if os.path.exists(self.lockfile):
21       self.itsMyLockFile = False
22       print "Error: The database file is locked by ", self.lockfile
23       raise OSError("The Database is locked.")
24     else:
25       self.lock = open(self.lockfile, 'w')
26       self.lock.write("pid "+str(os.getpid()))
27       self.itsMyLockFile = True
28
29     self.dom = XmlParseFile(inWorkspace(filename))
30
31     self.installedPackages = {}
32     self.installedPlatforms = {}
33     self.installedFars = {}
34
35     for spdfile in XmlList(self.dom, "/FrameworkDatabase/PackageList/Filename"):
36       filename = str(XmlElementData(spdfile))
37       spd = XmlParseFileSection(inWorkspace(filename), "SpdHeader")
38       self.installedPackages[XmlElement(spd, "/SpdHeader/GuidValue"), XmlElement(spd, "/SpdHeader/Version")] = \
39         XmlElement(spd, "/SpdHeader/PackageName")
40
41     for fpdfile in XmlList(self.dom, "/FrameworkDatabase/PlatformList/Filename"):
42       filename = str(XmlElementData(fpdfile))
43       fpd = XmlParseFileSection(inWorkspace(filename), "PlatformHeader")
44       self.installedPlatforms[XmlElement(fpd, "/PlatformHeader/GuidValue"), XmlElement(fpd, "/PlatformHeader/Version") ] = \
45         XmlElement(fpd, "/PlatformHeader/PlatformName")
46
47     for farfile in  XmlList(self.dom, "/FrameworkDatabase/FarList/Filename"):
48       farGuid = farfile.getAttribute("FarGuid")
49       self.installedFars[farGuid] = XmlElementData(farfile)
50
51     self.packageList = XmlNode(self.dom, "/FrameworkDatabase/PackageList")
52     self.platformList = XmlNode(self.dom, "/FrameworkDatabase/PlatformList")
53     self.farList = XmlNode(self.dom, "/FrameworkDatabase/FarList")
54
55   def __del__(self):
56     if self.itsMyLockFile:
57       self.lock.close()
58       os.unlink(self.lockfile)
59
60   def HasPackage(self, (guid, version)):
61     """Return true iff this package is already installed."""
62     if version == "":
63       # Look for the guid.
64       for (g, v) in self.installedPackages.keys():
65         if g == guid:
66           return True
67     return self.installedPackages.has_key((guid, version))
68
69   def HasPlatform(self, (guid, version)):
70     """Return true iff this platform is already installed."""
71     if version == "":
72       # Look for the guid.
73       for (g, v) in self.installedPlatforms.keys():
74         if g == guid:
75           return True
76     return self.installedPlatforms.has_key((guid, version))
77
78   def HasFar(self, farguid):
79     """Return true iff this far is already installed."""
80     return self.installedFars.has_key(farguid)
81
82   def AddPackage(self, f):
83     filename = self.dom.createElement("Filename")
84     filename.appendChild(self.dom.createTextNode(f))
85     self.packageList.appendChild(filename)
86     
87   def AddPlatform(self, f):
88     filename = self.dom.createElement("Filename")
89     filename.appendChild(self.dom.createTextNode(f))
90     self.platformList.appendChild(filename)
91
92   def AddFar(self, f, guid=""):
93     filename = self.dom.createElement("Filename")
94     filename.setAttribute("FarGuid", guid)
95     filename.appendChild(self.dom.createTextNode(f))
96     self.farList.appendChild(filename)
97
98   def Write(self):
99     if True:
100       XmlSaveFile(self.dom, self.DBFile)
101     else:
102       f=open(self.DBFile, 'w')
103       f.write(self.dom.toprettyxml(2*" "))
104       f.close()
105
106 def ExtractFile(zip, file, workspaceLocation=""):
107
108   if verbose:
109     print "Extracting ", file
110
111   destFile = os.path.join(inWorkspace(workspaceLocation), str(file))
112   destDir = os.path.dirname(destFile)
113
114   mkdir(destDir)
115
116   f = open(destFile, "w")
117   f.write(zip.read(file))
118   f.close()
119
120 def GetFpdGuidVersion(Dom):
121
122   """Get the Guid and version of the fpd from a dom object."""
123
124   return XmlElement(Dom, "/PlatformSurfaceArea/PlatformHeader/GuidValue"), \
125          XmlElement(Dom, "/PlatformSurfaceArea/PlatformHeader/Version")
126
127 def GetSpdGuidVersion(Dom):
128
129   """Get the Guid and version of the spd from a dom object."""
130
131   return XmlElement(Dom, "/PackageSurfaceArea/SpdHeader/GuidValue"), \
132          XmlElement(Dom, "/PackageSurfaceArea/SpdHeader/Version")
133
134 def InstallFar(farfile, workspaceLocation=""):
135
136   far = zipfile.ZipFile(farfile, "r")
137
138   # Use this list to make sure we get everything from the far.
139   zipContents = far.namelist()
140
141   manifest = xml.dom.minidom.parseString(far.read("FrameworkArchiveManifest.xml"))
142   zipContents.remove("FrameworkArchiveManifest.xml")
143   fdb = Database()
144
145   # First we need to make sure that the far will install cleanly.
146
147   installError = False # Let's hope for the best.
148   spdDoms = []
149   farSpds = []
150
151   # Check the packages
152   for farPackage in XmlList(manifest, "/FrameworkArchiveManifest/FarPackageList/FarPackage/FarFilename"):
153     spdfile = str(XmlElementData(farPackage))
154     spd = XmlParseString(far.read(spdfile))
155     packageGV = GetSpdGuidVersion(spd)
156     if fdb.HasPackage(packageGV):
157       print "Error: This package is already installed: ", spdfile
158       installError = True
159
160     # Build up a list of the package guid versions that this far is bringing in.
161     # This is needed to satisfy dependencies of msas that are in the other packages of
162     # this far.
163
164     farSpds.append(packageGV)
165
166     spdDoms.append(spd)
167
168   for spd in spdDoms:
169     # Now we need to get a list of every msa in this spd and check the package dependencies.
170     for msafile in XmlList(spd, "/PackageSurfaceArea/MsaFiles/Filename"):
171       msafilePath = str(os.path.join(os.path.dirname(spdfile), XmlElementData(msafile)))
172
173       msa = XmlParseString(far.read(msafilePath))
174
175       for package in XmlList(msa, "/ModuleSurfaceArea/PackageDependencies/Package"):
176         guid = package.getAttribute("PackageGuid")
177         version = package.getAttribute("PackageVersion")
178
179         if not fdb.HasPackage((guid, version)) and not (guid, version) in farSpds:
180           print "The module %s depends on the package guid % version %s, which is not installed in the workspace." \
181             % (msafilePath, guid, version)
182           installError = True
183
184   # Check the platforms
185   for farPlatform in XmlList(manifest, "/FrameworkArchiveManifest/FarPlatformList/FarPlatform/FarFilename"):
186     fpdfile = str(XmlElementData(farPlatform))
187     fpd = XmlParseString(far.read(fpdfile))
188     if fdb.HasPlatform(GetFpdGuidVersion(fpd)):
189       print "Error: This platform is already installed: ", fpdfile
190       installError = True
191
192   # Check the fars
193   thisFarGuid = XmlElement(manifest, "/FrameworkArchiveManifest/FarHeader/GuidValue")
194   if fdb.HasFar(thisFarGuid):
195     print "Error: There is a far with this guid already installed."
196     installError = True
197
198   # We can not do the install
199   if installError:
200     if force:
201       print "Ignoring previous errors as you requested."
202     else:
203       return False
204
205   # Install the packages
206   for farPackage in XmlList(manifest, "/FrameworkArchiveManifest/FarPackageList/FarPackage"):
207
208     filename = XmlElement(farPackage, "FarPackage/FarFilename")
209     fdb.AddPackage(filename)
210     ExtractFile(far, filename, workspaceLocation)
211     zipContents.remove(filename)
212
213     for content in XmlList(farPackage, "FarPackage/Contents/FarFilename"):
214
215       filename = XmlElementData(content)
216       ExtractFile(far, filename, workspaceLocation)
217       zipContents.remove(filename)
218
219   # Install the platforms
220   for farPlatform in XmlList(manifest, "/FrameworkArchiveManifest/FarPlatformList/FarPlatform"):
221     
222     filename = XmlElement(farPlatform, "FarPlatform/FarFilename")
223     fdb.AddPlatform(filename)
224     ExtractFile(far, filename, workspaceLocation)
225     zipContents.remove(filename)
226
227   # Install the Contents
228   for content in XmlList(manifest, "/FrameworkArchiveManifest/Contents/FarFilename"):
229
230     filename = XmlElementData(content)
231     ExtractFile(far, filename, workspaceLocation)
232     zipContents.remove(filename)
233
234   # What if there are more files in the far?
235   if not zipContents == []:
236     print "There are still files in the far:", zipContents
237
238   fdb.AddFar(farfile, thisFarGuid)
239
240   # If everything has gone well, we can put the manifest file in a safe place...
241   farDir = inWorkspace("Tools/Conf/InstalledFars/")
242   mkdir(farDir)
243   f=open(os.path.join(farDir, thisFarGuid), 'w')
244   f.write(far.read("FrameworkArchiveManifest.xml"))
245   f.close()
246
247   # Write out the new database
248   fdb.Write()
249   
250   far.close()
251
252 # This acts like the main() function for the script, unless it is 'import'ed
253 # into another script.
254 if __name__ == '__main__':
255
256   # Process the command line args.
257   optlist, args = getopt.getopt(sys.argv[1:], '?hvf', ['help', 'verbose', 'force'])
258
259   # First pass through the options list.
260   for o, a in optlist:
261     if o in ["-h", "--help"]:
262       print """
263 Install a far (Framework Archive) into the current workspace.
264 """ % os.path.basename(sys.argv[0])
265
266       sys.exit()
267       optlist.remove((o,a))
268     if o in ["-v", "--verbose"]:
269       verbose = True
270     if o in ["-f", "--force"]:
271       force = True
272
273   for f in args:
274     InstallFar(f)
275   if args == []:
276     print "Please pass a far filename on the command line."