aggressively delete uncompressed package archive from install dir

This commit is contained in:
David Rose 2009-09-07 02:05:41 +00:00
parent 168cc68e65
commit 61e093a559
2 changed files with 99 additions and 43 deletions

View File

@ -534,15 +534,6 @@ class Packager:
self.multifile.repack() self.multifile.repack()
self.multifile.close() self.multifile.close()
if not self.p3dApplication:
# The "base" package file is the bottom of the patch chain.
packageBaseFullpath = Filename(self.packageFullpath + '.base')
if not packageBaseFullpath.exists() and \
self.packageFullpath.exists():
# There's a previous version of the package file.
# It becomes the "base".
self.packageFullpath.renameTo(packageBaseFullpath)
if not multifileFilename.renameTo(self.packageFullpath): if not multifileFilename.renameTo(self.packageFullpath):
self.notify.error("Cannot move %s to %s" % (multifileFilename, self.packageFullpath)) self.notify.error("Cannot move %s to %s" % (multifileFilename, self.packageFullpath))
@ -556,6 +547,11 @@ class Packager:
self.writeDescFile() self.writeDescFile()
self.writeImportDescFile() self.writeImportDescFile()
# Now that we've written out the desc file, we don't
# need to keep around the uncompressed archive
# anymore.
self.packageFullpath.unlink()
# Replace or add the entry in the contents. # Replace or add the entry in the contents.
pe = Packager.PackageEntry() pe = Packager.PackageEntry()
pe.fromFile(self.packageName, self.platform, self.version, pe.fromFile(self.packageName, self.platform, self.version,
@ -960,8 +956,8 @@ class Packager:
def readDescFile(self): def readDescFile(self):
""" Reads the existing package.xml file before rewriting """ Reads the existing package.xml file before rewriting
it. We need this to preserve the list of patchfiles it. We need this to preserve the list of patches, and
between sessions. """ similar historic data, between sessions. """
self.patchVersion = None self.patchVersion = None
self.patches = [] self.patches = []
@ -989,6 +985,12 @@ class Packager:
if patchVersion: if patchVersion:
self.patchVersion = patchVersion self.patchVersion = patchVersion
# Extract the base_version and patch entries, if any, and
# preserve these entries verbatim for the next version.
xbase = xpackage.FirstChildElement('base_version')
if xbase:
self.patches.append(xbase.Clone())
xpatch = xpackage.FirstChildElement('patch') xpatch = xpackage.FirstChildElement('patch')
while xpatch: while xpatch:
self.patches.append(xpatch.Clone()) self.patches.append(xpatch.Clone())
@ -1035,13 +1037,6 @@ class Packager:
self.packageBasename + '.pz') self.packageBasename + '.pz')
xpackage.InsertEndChild(xcompressedArchive) xpackage.InsertEndChild(xcompressedArchive)
packageBaseFullpath = Filename(self.packageFullpath + '.base')
if packageBaseFullpath.exists():
xbaseVersion = self.getFileSpec(
'base_version', packageBaseFullpath,
self.packageBasename + '.base')
xpackage.InsertEndChild(xbaseVersion)
# Copy in the patch entries read from the previous version # Copy in the patch entries read from the previous version
# of the desc file. # of the desc file.
for xpatch in self.patches: for xpatch in self.patches:
@ -1677,7 +1672,13 @@ class Packager:
""" Call this after calling close(), to build patches for the """ Call this after calling close(), to build patches for the
indicated packages. """ indicated packages. """
packageNames = map(lambda package: package.packageName, packages) # We quietly ignore any p3d applications or solo packages
# passed in the packages list; we only build patches for
# actual Multifile-based packages.
packageNames = []
for package in packages:
if not package.p3dApplication and not package.solo:
packageNames.append(package.packageName)
from PatchMaker import PatchMaker from PatchMaker import PatchMaker
pm = PatchMaker(self.installDir) pm = PatchMaker(self.installDir)

View File

@ -1,5 +1,6 @@
from direct.p3d.FileSpec import FileSpec from direct.p3d.FileSpec import FileSpec
from pandac.PandaModules import * from pandac.PandaModules import *
import copy
class PatchMaker: class PatchMaker:
""" This class will operate on an existing package install """ This class will operate on an existing package install
@ -19,6 +20,7 @@ class PatchMaker:
self.version = version self.version = version
self.host = host self.host = host
self.file = file self.file = file
self.printName = None
# The Package object that produces this version, if this # The Package object that produces this version, if this
# is the current form or the base form, respectively. # is the current form or the base form, respectively.
@ -65,40 +67,48 @@ class PatchMaker:
return bestPatchChain return bestPatchChain
def getRecreateFilePlan(self): def getRecreateFilePlan(self):
""" Returns the tuple (startFile, plan), describing how to """ Returns the tuple (startFile, startPv, plan),
recreate the archive file for this version. startFile is describing how to recreate the archive file for this
the Filename of the file to start with, and plan is a list version. startFile and startPv is the Filename and
of tuples (patchfile, pv), listing the patches to apply in packageVersion of the file to start with, and plan is a
sequence, and the packageVersion object associated with list of tuples (patchfile, pv), listing the patches to
each patch. Returns (None, None) if there is no way to apply in sequence, and the packageVersion object
recreate this archive file. """ associated with each patch. Returns (None, None) if there
is no way to recreate this archive file. """
if self.tempFile: if self.tempFile:
return (self.tempFile, []) return (self.tempFile, self, [])
if self.packageCurrent: if self.packageCurrent:
# This PackageVersion instance represents the current
# version of some package.
package = self.packageCurrent package = self.packageCurrent
return (Filename(package.packageDir, package.currentFile.filename), []) return (Filename(package.packageDir, package.compressedFilename), self, [])
if self.packageBase: if self.packageBase:
# This PackageVersion instance represents the base
# (oldest) version of some package.
package = self.packageBase package = self.packageBase
return (Filename(package.packageDir, package.baseFile.filename), []) return (Filename(package.packageDir, package.baseFile.filename + '.pz'), self, [])
# We'll need to re-create the file. # We'll need to re-create the file.
bestPlan = None bestPlan = None
bestStartFile = None bestStartFile = None
bestStartPv = None
for patchfile in self.fromPatches: for patchfile in self.fromPatches:
fromPv = patchfile.fromPv fromPv = patchfile.fromPv
startFile, plan = fromPv.getRecreateFilePlan() startFile, startPv, plan = fromPv.getRecreateFilePlan()
if plan is not None: if plan is not None:
# There's a path through this patchfile. # There's a path through this patchfile.
plan = plan + [(patchfile, self)] plan = plan + [(patchfile, self)]
if bestPlan is None or len(plan) < len(bestPlan): if bestPlan is None or len(plan) < len(bestPlan):
bestPlan = plan bestPlan = plan
bestStartFile = startFile bestStartFile = startFile
bestStartPv = startPv
# Return the shortest path found, or None if there were no # Return the shortest path found, or None if there were no
# paths found. # paths found.
return (bestStartFile, bestPlan) return (bestStartFile, bestStartPv, bestPlan)
def getFile(self): def getFile(self):
""" Returns the Filename of the archive file associated """ Returns the Filename of the archive file associated
@ -106,7 +116,18 @@ class PatchMaker:
disk, a temporary file will be created. Returns None if disk, a temporary file will be created. Returns None if
the file can't be recreated. """ the file can't be recreated. """
startFile, plan = self.getRecreateFilePlan() startFile, startPv, plan = self.getRecreateFilePlan()
if startFile.getExtension() == 'pz':
# If the starting file is compressed, we have to
# decompress it first.
assert startPv.tempFile is None
startPv.tempFile = Filename.temporary('', 'patch_')
if not decompressFile(startFile, startPv.tempFile):
# Failure trying to decompress the file.
return None
startFile = startPv.tempFile
if not plan: if not plan:
# If plan is a zero-length list, we're already # If plan is a zero-length list, we're already
# here--return startFile. If plan is None, there's no # here--return startFile. If plan is None, there's no
@ -252,6 +273,8 @@ class PatchMaker:
""" Reads the existing package.xml file and stores """ Reads the existing package.xml file and stores
it in this class for later rewriting. """ it in this class for later rewriting. """
self.anyChanges = False
packageDescFullpath = Filename(self.patchMaker.installDir, self.packageDesc) packageDescFullpath = Filename(self.patchMaker.installDir, self.packageDesc)
self.doc = TiXmlDocument(packageDescFullpath.toOsSpecific()) self.doc = TiXmlDocument(packageDescFullpath.toOsSpecific())
if not self.doc.LoadFile(): if not self.doc.LoadFile():
@ -285,19 +308,23 @@ class PatchMaker:
if patchVersion: if patchVersion:
self.patchVersion = int(patchVersion) self.patchVersion = int(patchVersion)
self.patchVersion += 1 self.patchVersion += 1
self.anyChanges = True
self.currentFile = None self.currentFile = None
self.baseFile = None self.baseFile = None
self.compressedFilename = None
xarchive = xpackage.FirstChildElement('uncompressed_archive') xarchive = xpackage.FirstChildElement('uncompressed_archive')
if xarchive: if xarchive:
self.currentFile = FileSpec() self.currentFile = FileSpec()
self.currentFile.loadXml(xarchive) self.currentFile.loadXml(xarchive)
xarchive = xpackage.FirstChildElement('base_version') # We need to know the filename of the compressed archive
# (the uncompressed_archive may not actually exist
# anymore, but the compressed_archive still should).
xarchive = xpackage.FirstChildElement('compressed_archive')
if xarchive: if xarchive:
self.baseFile = FileSpec() self.compressedFilename = xarchive.Attribute('filename')
self.baseFile.loadXml(xarchive)
# Put the patchVersion in the compressed filename, for # Put the patchVersion in the compressed filename, for
# cache-busting. This means when the version changes, its # cache-busting. This means when the version changes, its
@ -317,6 +344,34 @@ class PatchMaker:
compressedFile.fromFile(self.packageDir, newCompressedFilename) compressedFile.fromFile(self.packageDir, newCompressedFilename)
compressedFile.storeXml(xcompressed) compressedFile.storeXml(xcompressed)
self.compressedFilename = newCompressedFilename
# Get the base_version--the bottom (oldest) of the patch
# chain.
xarchive = xpackage.FirstChildElement('base_version')
if xarchive:
self.baseFile = FileSpec()
self.baseFile.loadXml(xarchive)
else:
# If there isn't a base_version yet, we have to make
# one, by duplicating the currentFile.
self.baseFile = copy.copy(self.currentFile)
# Note that the we only store the compressed version
# of base_filename on disk, but we store the md5 of
# the uncompressed version in the xml file. To
# emphasize this, we name it without the .pz extension
# in the xml file, even though the compressed file on
# disk actually has a .pz extension.
self.baseFile.filename += '.base'
# Also duplicate the (compressed) file itself.
if self.compressedFilename:
fromPathname = Filename(self.packageDir, self.compressedFilename)
toPathname = Filename(self.packageDir, self.baseFile.filename + '.pz')
fromPathname.copyTo(toPathname)
self.anyChanges = True
self.patches = [] self.patches = []
xpatch = xpackage.FirstChildElement('patch') xpatch = xpackage.FirstChildElement('patch')
while xpatch: while xpatch:
@ -325,8 +380,6 @@ class PatchMaker:
self.patches.append(patchfile) self.patches.append(patchfile)
xpatch = xpatch.NextSiblingElement('patch') xpatch = xpatch.NextSiblingElement('patch')
self.anyChanges = False
def writeDescFile(self): def writeDescFile(self):
""" Rewrites the desc file with the new patch """ Rewrites the desc file with the new patch
information. """ information. """
@ -464,10 +517,12 @@ class PatchMaker:
currentPv = self.getPackageVersion(package.getCurrentKey()) currentPv = self.getPackageVersion(package.getCurrentKey())
package.currentPv = currentPv package.currentPv = currentPv
currentPv.packageCurrent = package currentPv.packageCurrent = package
currentPv.printName = package.currentFile.filename
basePv = self.getPackageVersion(package.getBaseKey()) basePv = self.getPackageVersion(package.getBaseKey())
package.basePv = basePv package.basePv = basePv
basePv.packageBase = package basePv.packageBase = package
basePv.printName = package.baseFile.filename
for patchfile in package.patches: for patchfile in package.patches:
self.recordPatchfile(patchfile) self.recordPatchfile(patchfile)
@ -483,6 +538,7 @@ class PatchMaker:
toPv = self.getPackageVersion(patchfile.getTargetKey()) toPv = self.getPackageVersion(patchfile.getTargetKey())
patchfile.toPv = toPv patchfile.toPv = toPv
toPv.fromPatches.append(patchfile) toPv.fromPatches.append(patchfile)
toPv.printName = patchfile.file.filename
def processSomePackages(self, packageNames): def processSomePackages(self, packageNames):
""" Builds missing patches only for the named packages. """ """ Builds missing patches only for the named packages. """
@ -535,11 +591,9 @@ class PatchMaker:
v2, and stores it in patchFilename.pz. Returns true on v2, and stores it in patchFilename.pz. Returns true on
success, false on failure.""" success, false on failure."""
f1 = v1.getFile()
f2 = v2.getFile()
pathname = Filename(package.packageDir, patchFilename) pathname = Filename(package.packageDir, patchFilename)
if not self.buildPatchFile(f1, f2, pathname): if not self.buildPatchFile(v1.getFile(), v2.getFile(), pathname,
v1.printName, v2.printName):
return False return False
compressedPathname = Filename(pathname + '.pz') compressedPathname = Filename(pathname + '.pz')
@ -558,7 +612,8 @@ class PatchMaker:
return True return True
def buildPatchFile(self, origFilename, newFilename, patchFilename): def buildPatchFile(self, origFilename, newFilename, patchFilename,
printOrigName, printNewName):
""" Creates a patch file from origFilename to newFilename, """ Creates a patch file from origFilename to newFilename,
storing the result in patchFilename. Returns true on success, storing the result in patchFilename. Returns true on success,
false on failure. """ false on failure. """
@ -567,7 +622,7 @@ class PatchMaker:
# No original version to patch from. # No original version to patch from.
return False return False
print "Building patch to %s" % (newFilename) print "Building patch from %s to %s" % (printOrigName, printNewName)
patchFilename.unlink() patchFilename.unlink()
p = Patchfile() # The C++ class p = Patchfile() # The C++ class
if p.build(origFilename, newFilename, patchFilename): if p.build(origFilename, newFilename, patchFilename):