]>
Commit | Line | Data |
---|---|---|
4040421a | 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 | ||
312ffece | 10 | class Flags: |
11 | """Keep track of some command line flags and operating modes.""" | |
12 | def __init__(self): | |
13 | self.verbose = False | |
14 | self.force = False | |
15 | self.reinstall = False | |
4040421a | 16 | |
17 | class Database: | |
18 | ||
312ffece | 19 | """This class encapsulates the FrameworkDatabase file for the workspace we |
20 | are operating on.""" | |
21 | ||
4040421a | 22 | def __init__(self, filename="Tools/Conf/FrameworkDatabase.db"): |
23 | ||
24 | # First try to get a lock file. | |
25 | self.DBFile = inWorkspace(filename) | |
26 | self.lockfile = inWorkspace("Tools/Conf/FrameworkDatabase.lock") | |
27 | if os.path.exists(self.lockfile): | |
28 | self.itsMyLockFile = False | |
29 | print "Error: The database file is locked by ", self.lockfile | |
30 | raise OSError("The Database is locked.") | |
31 | else: | |
32 | self.lock = open(self.lockfile, 'w') | |
33 | self.lock.write("pid "+str(os.getpid())) | |
34 | self.itsMyLockFile = True | |
35 | ||
36 | self.dom = XmlParseFile(inWorkspace(filename)) | |
37 | ||
38 | self.installedPackages = {} | |
39 | self.installedPlatforms = {} | |
40 | self.installedFars = {} | |
41 | ||
42 | for spdfile in XmlList(self.dom, "/FrameworkDatabase/PackageList/Filename"): | |
43 | filename = str(XmlElementData(spdfile)) | |
44 | spd = XmlParseFileSection(inWorkspace(filename), "SpdHeader") | |
312ffece | 45 | self.installedPackages[GetSpdGuidVersion(spd, 1)] = \ |
4040421a | 46 | XmlElement(spd, "/SpdHeader/PackageName") |
47 | ||
48 | for fpdfile in XmlList(self.dom, "/FrameworkDatabase/PlatformList/Filename"): | |
49 | filename = str(XmlElementData(fpdfile)) | |
50 | fpd = XmlParseFileSection(inWorkspace(filename), "PlatformHeader") | |
312ffece | 51 | self.installedPlatforms[GetFpdGuidVersion(fpd, 1)] = \ |
4040421a | 52 | XmlElement(fpd, "/PlatformHeader/PlatformName") |
53 | ||
54 | for farfile in XmlList(self.dom, "/FrameworkDatabase/FarList/Filename"): | |
55 | farGuid = farfile.getAttribute("FarGuid") | |
56 | self.installedFars[farGuid] = XmlElementData(farfile) | |
57 | ||
58 | self.packageList = XmlNode(self.dom, "/FrameworkDatabase/PackageList") | |
59 | self.platformList = XmlNode(self.dom, "/FrameworkDatabase/PlatformList") | |
60 | self.farList = XmlNode(self.dom, "/FrameworkDatabase/FarList") | |
61 | ||
62 | def __del__(self): | |
63 | if self.itsMyLockFile: | |
64 | self.lock.close() | |
65 | os.unlink(self.lockfile) | |
66 | ||
24a86f9a | 67 | def HasPackage(self, (guid, version)): |
4040421a | 68 | """Return true iff this package is already installed.""" |
24a86f9a | 69 | if version == "": |
70 | # Look for the guid. | |
71 | for (g, v) in self.installedPackages.keys(): | |
72 | if g == guid: | |
73 | return True | |
4040421a | 74 | return self.installedPackages.has_key((guid, version)) |
75 | ||
24a86f9a | 76 | def HasPlatform(self, (guid, version)): |
4040421a | 77 | """Return true iff this platform is already installed.""" |
24a86f9a | 78 | if version == "": |
79 | # Look for the guid. | |
80 | for (g, v) in self.installedPlatforms.keys(): | |
81 | if g == guid: | |
82 | return True | |
4040421a | 83 | return self.installedPlatforms.has_key((guid, version)) |
84 | ||
85 | def HasFar(self, farguid): | |
86 | """Return true iff this far is already installed.""" | |
87 | return self.installedFars.has_key(farguid) | |
88 | ||
89 | def AddPackage(self, f): | |
312ffece | 90 | """Put this package in the database""" |
91 | XmlAppendChildElement(self.packageList, "Filename", f) | |
4040421a | 92 | |
93 | def AddPlatform(self, f): | |
312ffece | 94 | """Put this platform in the database""" |
95 | XmlAppendChildElement(self.platformList, "Filename", f) | |
4040421a | 96 | |
97 | def AddFar(self, f, guid=""): | |
312ffece | 98 | """Put this far in the database""" |
99 | XmlAppendChildElement(self.farList, "Filename", f, {"FarGuid":guid} ) | |
4040421a | 100 | |
101 | def Write(self): | |
312ffece | 102 | """Save the Xml tree out to the file.""" |
4040421a | 103 | if True: |
104 | XmlSaveFile(self.dom, self.DBFile) | |
105 | else: | |
106 | f=open(self.DBFile, 'w') | |
107 | f.write(self.dom.toprettyxml(2*" ")) | |
108 | f.close() | |
109 | ||
312ffece | 110 | def ExtractFile(zip, file, defaultDir="", workspaceLocation="", md5sum=""): |
111 | """Unzip a file.""" | |
112 | if flags.verbose: | |
4040421a | 113 | print "Extracting ", file |
114 | ||
115 | destFile = os.path.join(inWorkspace(workspaceLocation), str(file)) | |
116 | destDir = os.path.dirname(destFile) | |
117 | ||
118 | mkdir(destDir) | |
119 | ||
120 | f = open(destFile, "w") | |
312ffece | 121 | contents = zip.read(os.path.join(defaultDir,file)) |
122 | if md5sum and (md5.md5(contents).hexdigest() != md5sum): | |
123 | print "Error: The md5 sum does not match on file %s." % file | |
124 | f.write(contents) | |
4040421a | 125 | f.close() |
126 | ||
312ffece | 127 | def GetFpdGuidVersion(Dom, strip=0): |
24a86f9a | 128 | |
129 | """Get the Guid and version of the fpd from a dom object.""" | |
130 | ||
312ffece | 131 | gpath = ["PlatformSurfaceArea", "PlatformHeader", "GuidValue"] |
132 | vpath = ["PlatformSurfaceArea", "PlatformHeader", "Version"] | |
24a86f9a | 133 | |
312ffece | 134 | return string.lower(XmlElement(Dom, "/".join(gpath[strip:]))), \ |
135 | XmlElement(Dom, "/".join(vpath[strip:])) | |
136 | ||
137 | def GetSpdGuidVersion(Dom, strip=0): | |
24a86f9a | 138 | |
139 | """Get the Guid and version of the spd from a dom object.""" | |
140 | ||
312ffece | 141 | gpath = ["PackageSurfaceArea", "SpdHeader", "GuidValue"] |
142 | vpath = ["PackageSurfaceArea", "SpdHeader", "Version"] | |
143 | ||
144 | return string.lower(XmlElement(Dom, "/".join(gpath[strip:]))), \ | |
145 | XmlElement(Dom, "/".join(vpath[strip:])) | |
24a86f9a | 146 | |
4040421a | 147 | def InstallFar(farfile, workspaceLocation=""): |
148 | ||
312ffece | 149 | """Unpack the far an install it in the workspace. We need to adhere to the |
150 | rules of far handling.""" | |
151 | ||
4040421a | 152 | far = zipfile.ZipFile(farfile, "r") |
153 | ||
154 | # Use this list to make sure we get everything from the far. | |
155 | zipContents = far.namelist() | |
156 | ||
157 | manifest = xml.dom.minidom.parseString(far.read("FrameworkArchiveManifest.xml")) | |
158 | zipContents.remove("FrameworkArchiveManifest.xml") | |
159 | fdb = Database() | |
160 | ||
161 | # First we need to make sure that the far will install cleanly. | |
162 | ||
24a86f9a | 163 | installError = False # Let's hope for the best. |
164 | spdDoms = [] | |
165 | farSpds = [] | |
166 | ||
4040421a | 167 | # Check the packages |
168 | for farPackage in XmlList(manifest, "/FrameworkArchiveManifest/FarPackageList/FarPackage/FarFilename"): | |
169 | spdfile = str(XmlElementData(farPackage)) | |
312ffece | 170 | spd = XmlParseStringSection(far.read(spdfile), "SpdHeader") |
171 | packageGV = GetSpdGuidVersion(spd, 1) | |
24a86f9a | 172 | if fdb.HasPackage(packageGV): |
312ffece | 173 | if not flags.reinstall: |
174 | print "Error: This package is already installed: ", spdfile | |
175 | installError = True | |
4040421a | 176 | |
24a86f9a | 177 | # Build up a list of the package guid versions that this far is bringing in. |
178 | # This is needed to satisfy dependencies of msas that are in the other packages of | |
179 | # this far. | |
24a86f9a | 180 | farSpds.append(packageGV) |
181 | ||
312ffece | 182 | spdDoms.append((spd, spdfile)) |
24a86f9a | 183 | |
312ffece | 184 | for spd, spdfile in spdDoms: |
24a86f9a | 185 | # Now we need to get a list of every msa in this spd and check the package dependencies. |
186 | for msafile in XmlList(spd, "/PackageSurfaceArea/MsaFiles/Filename"): | |
187 | msafilePath = str(os.path.join(os.path.dirname(spdfile), XmlElementData(msafile))) | |
188 | ||
189 | msa = XmlParseString(far.read(msafilePath)) | |
190 | ||
191 | for package in XmlList(msa, "/ModuleSurfaceArea/PackageDependencies/Package"): | |
192 | guid = package.getAttribute("PackageGuid") | |
193 | version = package.getAttribute("PackageVersion") | |
194 | ||
312ffece | 195 | # Does anyone provide this package? |
24a86f9a | 196 | if not fdb.HasPackage((guid, version)) and not (guid, version) in farSpds: |
312ffece | 197 | print ("Error: The module %s depends on the package guid %s version %s, which " + \ |
198 | "is not installed in the workspace, nor is it provided by this far.") \ | |
199 | % (msafilePath, guid, version) | |
24a86f9a | 200 | installError = True |
201 | ||
4040421a | 202 | # Check the platforms |
203 | for farPlatform in XmlList(manifest, "/FrameworkArchiveManifest/FarPlatformList/FarPlatform/FarFilename"): | |
204 | fpdfile = str(XmlElementData(farPlatform)) | |
24a86f9a | 205 | fpd = XmlParseString(far.read(fpdfile)) |
312ffece | 206 | if fdb.HasPlatform(GetFpdGuidVersion(fpd, 0)): |
207 | if not flags.reinstall: | |
208 | print "Error: This platform is already installed: ", fpdfile | |
209 | installError = True | |
210 | ||
211 | # Now we need to check that all the Platforms (and modules?) that are | |
212 | # referenced by this fpd are installed in the workspace or are in this far. | |
213 | packagesNeeded = set() | |
214 | ||
215 | # Go through the dependencies | |
216 | for dependency in XmlList(fpd, "/PlatformSurfaceArea/FrameworkModules/ModuleSA") + \ | |
217 | XmlList(fpd, "/PlatformSurfaceArea/FrameworkModules/ModuleSA/Libraries/Instance"): | |
218 | packagesNeeded.add((string.lower(dependency.getAttribute("PackageGuid")), | |
219 | dependency.getAttribute("PackageVersion"))) | |
220 | ||
221 | # Let's see if all the packages are in the workspace | |
222 | for guid, version in packagesNeeded: | |
223 | # Does anyone provide this package? | |
224 | if not fdb.HasPackage((guid, version)) and not (guid, version) in farSpds: | |
225 | print ("Error: The fpd %s depends on the package guid %s version %s, which " + \ | |
226 | "is not installed in the workspace, nor is it provided by this far.") \ | |
227 | % (fpdfile, guid, version) | |
228 | installError = True | |
4040421a | 229 | |
230 | # Check the fars | |
312ffece | 231 | thisFarGuid = string.lower(XmlElement(manifest, "/FrameworkArchiveManifest/FarHeader/GuidValue")) |
4040421a | 232 | if fdb.HasFar(thisFarGuid): |
312ffece | 233 | if not flags.reinstall: |
234 | print "Error: There is a far with this guid already installed." | |
235 | installError = True | |
4040421a | 236 | |
237 | # We can not do the install | |
238 | if installError: | |
312ffece | 239 | if flags.force: |
240 | print "Warning: Ignoring previous errors as you requested." | |
4040421a | 241 | else: |
242 | return False | |
243 | ||
244 | # Install the packages | |
245 | for farPackage in XmlList(manifest, "/FrameworkArchiveManifest/FarPackageList/FarPackage"): | |
246 | ||
247 | filename = XmlElement(farPackage, "FarPackage/FarFilename") | |
312ffece | 248 | if not flags.reinstall: |
249 | fdb.AddPackage(filename) | |
4040421a | 250 | ExtractFile(far, filename, workspaceLocation) |
251 | zipContents.remove(filename) | |
252 | ||
312ffece | 253 | DefaultPath = XmlElement(farPackage, "FarPackage/DefaultPath") |
254 | ||
4040421a | 255 | for content in XmlList(farPackage, "FarPackage/Contents/FarFilename"): |
256 | ||
257 | filename = XmlElementData(content) | |
312ffece | 258 | ExtractFile(far, filename, DefaultPath, workspaceLocation, md5sum=content.getAttribute("Md5Sum")) |
259 | zipContents.remove(os.path.join(DefaultPath, filename)) | |
4040421a | 260 | |
261 | # Install the platforms | |
262 | for farPlatform in XmlList(manifest, "/FrameworkArchiveManifest/FarPlatformList/FarPlatform"): | |
263 | ||
264 | filename = XmlElement(farPlatform, "FarPlatform/FarFilename") | |
312ffece | 265 | if not flags.reinstall: |
266 | fdb.AddPlatform(filename) | |
267 | ExtractFile(far, filename, "", workspaceLocation) | |
4040421a | 268 | zipContents.remove(filename) |
269 | ||
270 | # Install the Contents | |
271 | for content in XmlList(manifest, "/FrameworkArchiveManifest/Contents/FarFilename"): | |
272 | ||
273 | filename = XmlElementData(content) | |
312ffece | 274 | ExtractFile(far, filename, "", workspaceLocation) |
4040421a | 275 | zipContents.remove(filename) |
276 | ||
277 | # What if there are more files in the far? | |
278 | if not zipContents == []: | |
312ffece | 279 | print "Warning: There are files in the far that were not expected: ", zipContents |
4040421a | 280 | |
312ffece | 281 | if not flags.reinstall: |
282 | fdb.AddFar(farfile, thisFarGuid) | |
4040421a | 283 | |
284 | # If everything has gone well, we can put the manifest file in a safe place... | |
285 | farDir = inWorkspace("Tools/Conf/InstalledFars/") | |
286 | mkdir(farDir) | |
287 | f=open(os.path.join(farDir, thisFarGuid), 'w') | |
288 | f.write(far.read("FrameworkArchiveManifest.xml")) | |
289 | f.close() | |
290 | ||
291 | # Write out the new database | |
312ffece | 292 | if not flags.reinstall: |
293 | fdb.Write() | |
4040421a | 294 | |
295 | far.close() | |
296 | ||
297 | # This acts like the main() function for the script, unless it is 'import'ed | |
298 | # into another script. | |
299 | if __name__ == '__main__': | |
300 | ||
312ffece | 301 | flags = Flags() |
302 | ||
4040421a | 303 | # Process the command line args. |
312ffece | 304 | optlist, args = getopt.getopt(sys.argv[1:], '?hvf', ['help', 'verbose', 'force', 'reinstall']) |
4040421a | 305 | |
306 | # First pass through the options list. | |
307 | for o, a in optlist: | |
312ffece | 308 | if o in ["-h", "-?", "--help"]: |
4040421a | 309 | print """ |
312ffece | 310 | %s: Install a far (Framework Archive) into the current workspace. |
4040421a | 311 | """ % os.path.basename(sys.argv[0]) |
312 | ||
313 | sys.exit() | |
314 | optlist.remove((o,a)) | |
315 | if o in ["-v", "--verbose"]: | |
312ffece | 316 | flags.verbose = True |
4040421a | 317 | if o in ["-f", "--force"]: |
312ffece | 318 | flags.force = True |
319 | if o in ["--reinstall"]: | |
320 | flags.reinstall = True | |
4040421a | 321 | |
322 | for f in args: | |
323 | InstallFar(f) | |
324 | if args == []: | |
325 | print "Please pass a far filename on the command line." |