|
@@ -4,7 +4,8 @@ from pandac.PandaModules import *
|
|
|
class PatchMaker:
|
|
class PatchMaker:
|
|
|
""" This class will operate on an existing package install
|
|
""" This class will operate on an existing package install
|
|
|
directory, as generated by the Packager, and create patchfiles
|
|
directory, as generated by the Packager, and create patchfiles
|
|
|
- between versions as needed. """
|
|
|
|
|
|
|
+ between versions as needed. It is also used at runtime, to apply
|
|
|
|
|
+ the downloaded patches. """
|
|
|
|
|
|
|
|
class PackageVersion:
|
|
class PackageVersion:
|
|
|
""" A specific patch version of a package. This is not just
|
|
""" A specific patch version of a package. This is not just
|
|
@@ -12,15 +13,15 @@ class PatchMaker:
|
|
|
particular patch version, which increments independently of
|
|
particular patch version, which increments independently of
|
|
|
the "version". """
|
|
the "version". """
|
|
|
|
|
|
|
|
- def __init__(self, packageName, platform, version, host, hash):
|
|
|
|
|
|
|
+ def __init__(self, packageName, platform, version, host, file):
|
|
|
self.packageName = packageName
|
|
self.packageName = packageName
|
|
|
self.platform = platform
|
|
self.platform = platform
|
|
|
self.version = version
|
|
self.version = version
|
|
|
self.host = host
|
|
self.host = host
|
|
|
- self.hash = hash
|
|
|
|
|
|
|
+ self.file = file
|
|
|
|
|
|
|
|
- # The Package object that produces this version, in the
|
|
|
|
|
- # current form or the base form, respectively.
|
|
|
|
|
|
|
+ # The Package object that produces this version, if this
|
|
|
|
|
+ # is the current form or the base form, respectively.
|
|
|
self.packageCurrent = None
|
|
self.packageCurrent = None
|
|
|
self.packageBase = None
|
|
self.packageBase = None
|
|
|
|
|
|
|
@@ -38,55 +39,108 @@ class PatchMaker:
|
|
|
if self.tempFile:
|
|
if self.tempFile:
|
|
|
self.tempFile.unlink()
|
|
self.tempFile.unlink()
|
|
|
|
|
|
|
|
- def getFile(self):
|
|
|
|
|
- """ Returns the Filename of the archive file associated
|
|
|
|
|
- with this version. If the file doesn't actually exist on
|
|
|
|
|
- disk, a temporary file will be created. Returns None if
|
|
|
|
|
- the file can't be recreated. """
|
|
|
|
|
|
|
+ def getPatchChain(self, startPv):
|
|
|
|
|
+ """ Returns a list of patches that, when applied in
|
|
|
|
|
+ sequence to the indicated patchVersion object, will
|
|
|
|
|
+ produce this patchVersion object. Returns None if no
|
|
|
|
|
+ chain can be found. """
|
|
|
|
|
+
|
|
|
|
|
+ if self is startPv:
|
|
|
|
|
+ # We're already here. A zero-length patch chain is
|
|
|
|
|
+ # therefore the answer.
|
|
|
|
|
+ return []
|
|
|
|
|
|
|
|
|
|
+ bestPatchChain = None
|
|
|
|
|
+ for patchfile in self.fromPatches:
|
|
|
|
|
+ fromPv = patchfile.fromPv
|
|
|
|
|
+ patchChain = fromPv.getPatchChain(startPv)
|
|
|
|
|
+ if patchChain is not None:
|
|
|
|
|
+ # There's a path through this patchfile.
|
|
|
|
|
+ patchChain = patchChain + [patchfile]
|
|
|
|
|
+ if bestPatchChain is None or len(patchChain) < len(bestPatchChain):
|
|
|
|
|
+ bestPatchChain = patchChain
|
|
|
|
|
+
|
|
|
|
|
+ # Return the shortest path found, or None if there were no
|
|
|
|
|
+ # paths found.
|
|
|
|
|
+ return bestPatchChain
|
|
|
|
|
+
|
|
|
|
|
+ def getRecreateFilePlan(self):
|
|
|
|
|
+ """ Returns the tuple (startFile, plan), describing how to
|
|
|
|
|
+ recreate the archive file for this version. startFile is
|
|
|
|
|
+ the Filename of the file to start with, and plan is a list
|
|
|
|
|
+ of tuples (patchfile, pv), listing the patches to apply in
|
|
|
|
|
+ sequence, and the packageVersion object 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, [])
|
|
|
|
|
|
|
|
if self.packageCurrent:
|
|
if self.packageCurrent:
|
|
|
package = self.packageCurrent
|
|
package = self.packageCurrent
|
|
|
- return Filename(package.packageDir, package.currentFile.filename)
|
|
|
|
|
|
|
+ return (Filename(package.packageDir, package.currentFile.filename), [])
|
|
|
if self.packageBase:
|
|
if self.packageBase:
|
|
|
package = self.packageBase
|
|
package = self.packageBase
|
|
|
- return Filename(package.packageDir, package.baseFile.filename)
|
|
|
|
|
|
|
+ return (Filename(package.packageDir, package.baseFile.filename), [])
|
|
|
|
|
|
|
|
# We'll need to re-create the file.
|
|
# We'll need to re-create the file.
|
|
|
|
|
+ bestPlan = None
|
|
|
|
|
+ bestStartFile = None
|
|
|
for patchfile in self.fromPatches:
|
|
for patchfile in self.fromPatches:
|
|
|
fromPv = patchfile.fromPv
|
|
fromPv = patchfile.fromPv
|
|
|
- prevFile = fromPv.getFile()
|
|
|
|
|
- if prevFile:
|
|
|
|
|
- patchFilename = Filename(patchfile.package.packageDir, patchfile.file.filename)
|
|
|
|
|
- result = self.applyPatch(prevFile, patchFilename, patchfile.toHash)
|
|
|
|
|
- if result:
|
|
|
|
|
- self.tempFile = result
|
|
|
|
|
- return result
|
|
|
|
|
-
|
|
|
|
|
- # Couldn't re-create the file.
|
|
|
|
|
- return None
|
|
|
|
|
|
|
+ startFile, plan = fromPv.getRecreateFilePlan()
|
|
|
|
|
+ if plan is not None:
|
|
|
|
|
+ # There's a path through this patchfile.
|
|
|
|
|
+ plan = plan + [(patchfile, self)]
|
|
|
|
|
+ if bestPlan is None or len(plan) < len(bestPlan):
|
|
|
|
|
+ bestPlan = plan
|
|
|
|
|
+ bestStartFile = startFile
|
|
|
|
|
+
|
|
|
|
|
+ # Return the shortest path found, or None if there were no
|
|
|
|
|
+ # paths found.
|
|
|
|
|
+ return (bestStartFile, bestPlan)
|
|
|
|
|
|
|
|
- def applyPatch(self, origFile, patchFilename, targetHash):
|
|
|
|
|
|
|
+ def getFile(self):
|
|
|
|
|
+ """ Returns the Filename of the archive file associated
|
|
|
|
|
+ with this version. If the file doesn't actually exist on
|
|
|
|
|
+ disk, a temporary file will be created. Returns None if
|
|
|
|
|
+ the file can't be recreated. """
|
|
|
|
|
+
|
|
|
|
|
+ startFile, plan = self.getRecreateFilePlan()
|
|
|
|
|
+ if not plan:
|
|
|
|
|
+ # If plan is a zero-length list, we're already
|
|
|
|
|
+ # here--return startFile. If plan is None, there's no
|
|
|
|
|
+ # solution, and startFile is None. In either case, we
|
|
|
|
|
+ # can return startFile.
|
|
|
|
|
+ return startFile
|
|
|
|
|
+
|
|
|
|
|
+ # If plan is a non-empty list, we have to walk the list to
|
|
|
|
|
+ # apply the patch plan.
|
|
|
|
|
+ prevFile = startFile
|
|
|
|
|
+ for patchfile, pv in plan:
|
|
|
|
|
+ fromPv = patchfile.fromPv
|
|
|
|
|
+ patchFilename = Filename(patchfile.package.packageDir, patchfile.file.filename)
|
|
|
|
|
+ result = self.applyPatch(prevFile, patchFilename)
|
|
|
|
|
+ if not result:
|
|
|
|
|
+ # Failure trying to re-create the file.
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+ pv.tempFile = result
|
|
|
|
|
+ prevFile = result
|
|
|
|
|
+
|
|
|
|
|
+ # Successfully patched.
|
|
|
|
|
+ assert pv is self and prevFile is self.tempFile
|
|
|
|
|
+ return prevFile
|
|
|
|
|
+
|
|
|
|
|
+ def applyPatch(self, origFile, patchFilename):
|
|
|
""" Applies the named patch to the indicated original
|
|
""" Applies the named patch to the indicated original
|
|
|
file, storing the results in a temporary file, and returns
|
|
file, storing the results in a temporary file, and returns
|
|
|
that temporary Filename. Returns None on failure. """
|
|
that temporary Filename. Returns None on failure. """
|
|
|
|
|
|
|
|
result = Filename.temporary('', 'patch_')
|
|
result = Filename.temporary('', 'patch_')
|
|
|
- print "patching %s + %s -> %s" % (
|
|
|
|
|
- origFile, patchFilename, result)
|
|
|
|
|
-
|
|
|
|
|
p = Patchfile()
|
|
p = Patchfile()
|
|
|
if not p.apply(patchFilename, origFile, result):
|
|
if not p.apply(patchFilename, origFile, result):
|
|
|
- print "patching failed."
|
|
|
|
|
- return None
|
|
|
|
|
-
|
|
|
|
|
- hv = HashVal()
|
|
|
|
|
- hv.hashFile(result)
|
|
|
|
|
- if hv.asHex() != targetHash:
|
|
|
|
|
- print "patching produced incorrect results."
|
|
|
|
|
- result.unlink()
|
|
|
|
|
|
|
+ print "Internal patching failed: %s" % (patchFilename)
|
|
|
return None
|
|
return None
|
|
|
|
|
|
|
|
return result
|
|
return result
|
|
@@ -113,18 +167,17 @@ class PatchMaker:
|
|
|
self.version = package.version
|
|
self.version = package.version
|
|
|
self.host = None
|
|
self.host = None
|
|
|
|
|
|
|
|
- def getFromKey(self):
|
|
|
|
|
- return (self.packageName, self.platform, self.version, self.host, self.fromHash)
|
|
|
|
|
|
|
+ def getSourceKey(self):
|
|
|
|
|
+ return (self.packageName, self.platform, self.version, self.host, self.sourceFile)
|
|
|
|
|
|
|
|
- def getToKey(self):
|
|
|
|
|
- return (self.packageName, self.platform, self.version, self.host, self.toHash)
|
|
|
|
|
|
|
+ def getTargetKey(self):
|
|
|
|
|
+ return (self.packageName, self.platform, self.version, self.host, self.targetFile)
|
|
|
|
|
|
|
|
- def fromFile(self, packageDir, patchFilename,
|
|
|
|
|
- fromHash, toHash):
|
|
|
|
|
|
|
+ def fromFile(self, packageDir, patchFilename, sourceFile, targetFile):
|
|
|
self.file = FileSpec()
|
|
self.file = FileSpec()
|
|
|
self.file.fromFile(packageDir, patchFilename)
|
|
self.file.fromFile(packageDir, patchFilename)
|
|
|
- self.fromHash = fromHash
|
|
|
|
|
- self.toHash = toHash
|
|
|
|
|
|
|
+ self.sourceFile = sourceFile
|
|
|
|
|
+ self.targetFile = targetFile
|
|
|
|
|
|
|
|
def loadXml(self, xpatch):
|
|
def loadXml(self, xpatch):
|
|
|
self.packageName = xpatch.Attribute('name') or self.packageName
|
|
self.packageName = xpatch.Attribute('name') or self.packageName
|
|
@@ -135,8 +188,15 @@ class PatchMaker:
|
|
|
self.file = FileSpec()
|
|
self.file = FileSpec()
|
|
|
self.file.loadXml(xpatch)
|
|
self.file.loadXml(xpatch)
|
|
|
|
|
|
|
|
- self.fromHash = xpatch.Attribute('from_hash')
|
|
|
|
|
- self.toHash = xpatch.Attribute('to_hash')
|
|
|
|
|
|
|
+ xsource = xpatch.FirstChildElement('source')
|
|
|
|
|
+ if xsource:
|
|
|
|
|
+ self.sourceFile = FileSpec()
|
|
|
|
|
+ self.sourceFile.loadXml(xsource)
|
|
|
|
|
+
|
|
|
|
|
+ xtarget = xpatch.FirstChildElement('target')
|
|
|
|
|
+ if xtarget:
|
|
|
|
|
+ self.targetFile = FileSpec()
|
|
|
|
|
+ self.targetFile.loadXml(xtarget)
|
|
|
|
|
|
|
|
def makeXml(self, package):
|
|
def makeXml(self, package):
|
|
|
xpatch = TiXmlElement('patch')
|
|
xpatch = TiXmlElement('patch')
|
|
@@ -152,8 +212,13 @@ class PatchMaker:
|
|
|
|
|
|
|
|
self.file.storeXml(xpatch)
|
|
self.file.storeXml(xpatch)
|
|
|
|
|
|
|
|
- xpatch.SetAttribute('from_hash', self.fromHash)
|
|
|
|
|
- xpatch.SetAttribute('to_hash', self.toHash)
|
|
|
|
|
|
|
+ xsource = TiXmlElement('source')
|
|
|
|
|
+ self.sourceFile.storeMiniXml(xsource)
|
|
|
|
|
+ xpatch.InsertEndChild(xsource)
|
|
|
|
|
+
|
|
|
|
|
+ xtarget = TiXmlElement('target')
|
|
|
|
|
+ self.targetFile.storeMiniXml(xtarget)
|
|
|
|
|
+ xpatch.InsertEndChild(xtarget)
|
|
|
|
|
|
|
|
return xpatch
|
|
return xpatch
|
|
|
|
|
|
|
@@ -166,16 +231,22 @@ class PatchMaker:
|
|
|
self.packageDesc = packageDesc
|
|
self.packageDesc = packageDesc
|
|
|
self.patchMaker = patchMaker
|
|
self.patchMaker = patchMaker
|
|
|
self.patchVersion = 1
|
|
self.patchVersion = 1
|
|
|
|
|
+ self.currentPv = None
|
|
|
|
|
+ self.basePv = None
|
|
|
|
|
|
|
|
self.doc = None
|
|
self.doc = None
|
|
|
self.anyChanges = False
|
|
self.anyChanges = False
|
|
|
self.patches = []
|
|
self.patches = []
|
|
|
|
|
|
|
|
def getCurrentKey(self):
|
|
def getCurrentKey(self):
|
|
|
- return (self.packageName, self.platform, self.version, self.host, self.currentFile.hash)
|
|
|
|
|
|
|
+ return (self.packageName, self.platform, self.version, self.host, self.currentFile)
|
|
|
|
|
|
|
|
def getBaseKey(self):
|
|
def getBaseKey(self):
|
|
|
- return (self.packageName, self.platform, self.version, self.host, self.baseFile.hash)
|
|
|
|
|
|
|
+ return (self.packageName, self.platform, self.version, self.host, self.baseFile)
|
|
|
|
|
+
|
|
|
|
|
+ def getGenericKey(self, fileSpec):
|
|
|
|
|
+ """ Returns the key that has the indicated FileSpec. """
|
|
|
|
|
+ return (self.packageName, self.platform, self.version, self.host, fileSpec)
|
|
|
|
|
|
|
|
def readDescFile(self):
|
|
def readDescFile(self):
|
|
|
""" Reads the existing package.xml file and stores
|
|
""" Reads the existing package.xml file and stores
|
|
@@ -281,20 +352,44 @@ class PatchMaker:
|
|
|
def __init__(self, installDir):
|
|
def __init__(self, installDir):
|
|
|
self.installDir = installDir
|
|
self.installDir = installDir
|
|
|
self.packageVersions = {}
|
|
self.packageVersions = {}
|
|
|
|
|
+ self.packages = []
|
|
|
|
|
|
|
|
- def run(self):
|
|
|
|
|
|
|
+ def buildPatches(self, packageNames = None):
|
|
|
|
|
+ """ Makes the patches required in a particular directory
|
|
|
|
|
+ structure on disk. If packageNames is None, this makes
|
|
|
|
|
+ patches for all packages; otherwise, it should be a list of
|
|
|
|
|
+ package name strings, limiting the set of packages that are
|
|
|
|
|
+ processed. """
|
|
|
|
|
+
|
|
|
if not self.readContentsFile():
|
|
if not self.readContentsFile():
|
|
|
return False
|
|
return False
|
|
|
self.buildPatchChains()
|
|
self.buildPatchChains()
|
|
|
- self.processPackages()
|
|
|
|
|
|
|
+ if packageNames is None:
|
|
|
|
|
+ self.processAllPackages()
|
|
|
|
|
+ else:
|
|
|
|
|
+ self.processSomePackages(packageNames)
|
|
|
|
|
|
|
|
self.cleanup()
|
|
self.cleanup()
|
|
|
return True
|
|
return True
|
|
|
|
|
|
|
|
def cleanup(self):
|
|
def cleanup(self):
|
|
|
|
|
+ """ Should be called on exit to remove temporary files and
|
|
|
|
|
+ such created during processing. """
|
|
|
|
|
+
|
|
|
for pv in self.packageVersions.values():
|
|
for pv in self.packageVersions.values():
|
|
|
pv.cleanup()
|
|
pv.cleanup()
|
|
|
|
|
|
|
|
|
|
+ def readPackageDescFile(self, descFilename):
|
|
|
|
|
+ """ Reads a desc file associated with a particular package,
|
|
|
|
|
+ and adds the package to self.packageVersions. Returns the
|
|
|
|
|
+ Package object. """
|
|
|
|
|
+
|
|
|
|
|
+ package = self.Package(Filename(descFilename), self)
|
|
|
|
|
+ package.readDescFile()
|
|
|
|
|
+ self.packages.append(package)
|
|
|
|
|
+
|
|
|
|
|
+ return package
|
|
|
|
|
+
|
|
|
def readContentsFile(self):
|
|
def readContentsFile(self):
|
|
|
""" Reads the contents.xml file at the beginning of
|
|
""" Reads the contents.xml file at the beginning of
|
|
|
processing. """
|
|
processing. """
|
|
@@ -306,7 +401,6 @@ class PatchMaker:
|
|
|
print "couldn't read %s" % (contentsFilename)
|
|
print "couldn't read %s" % (contentsFilename)
|
|
|
return False
|
|
return False
|
|
|
|
|
|
|
|
- self.packages = []
|
|
|
|
|
xcontents = doc.FirstChildElement('contents')
|
|
xcontents = doc.FirstChildElement('contents')
|
|
|
if xcontents:
|
|
if xcontents:
|
|
|
xpackage = xcontents.FirstChildElement('package')
|
|
xpackage = xcontents.FirstChildElement('package')
|
|
@@ -328,10 +422,14 @@ class PatchMaker:
|
|
|
""" Returns a shared PackageVersion object for the indicated
|
|
""" Returns a shared PackageVersion object for the indicated
|
|
|
key. """
|
|
key. """
|
|
|
|
|
|
|
|
- pv = self.packageVersions.get(key, None)
|
|
|
|
|
|
|
+ packageName, platform, version, host, file = key
|
|
|
|
|
+
|
|
|
|
|
+ # We actually key on the hash, not the FileSpec itself.
|
|
|
|
|
+ k = (packageName, platform, version, host, file.hash)
|
|
|
|
|
+ pv = self.packageVersions.get(k, None)
|
|
|
if not pv:
|
|
if not pv:
|
|
|
pv = self.PackageVersion(*key)
|
|
pv = self.PackageVersion(*key)
|
|
|
- self.packageVersions[key] = pv
|
|
|
|
|
|
|
+ self.packageVersions[k] = pv
|
|
|
return pv
|
|
return pv
|
|
|
|
|
|
|
|
def buildPatchChains(self):
|
|
def buildPatchChains(self):
|
|
@@ -341,6 +439,10 @@ class PatchMaker:
|
|
|
self.patchFilenames = {}
|
|
self.patchFilenames = {}
|
|
|
|
|
|
|
|
for package in self.packages:
|
|
for package in self.packages:
|
|
|
|
|
+ if not package.baseFile:
|
|
|
|
|
+ # This package doesn't have any versions yet.
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
currentPv = self.getPackageVersion(package.getCurrentKey())
|
|
currentPv = self.getPackageVersion(package.getCurrentKey())
|
|
|
package.currentPv = currentPv
|
|
package.currentPv = currentPv
|
|
|
currentPv.packageCurrent = package
|
|
currentPv.packageCurrent = package
|
|
@@ -356,15 +458,27 @@ class PatchMaker:
|
|
|
""" Adds the indicated patchfile to the patch chains. """
|
|
""" Adds the indicated patchfile to the patch chains. """
|
|
|
self.patchFilenames[patchfile.file.filename] = patchfile
|
|
self.patchFilenames[patchfile.file.filename] = patchfile
|
|
|
|
|
|
|
|
- fromPv = self.getPackageVersion(patchfile.getFromKey())
|
|
|
|
|
|
|
+ fromPv = self.getPackageVersion(patchfile.getSourceKey())
|
|
|
patchfile.fromPv = fromPv
|
|
patchfile.fromPv = fromPv
|
|
|
fromPv.toPatches.append(patchfile)
|
|
fromPv.toPatches.append(patchfile)
|
|
|
|
|
|
|
|
- toPv = self.getPackageVersion(patchfile.getToKey())
|
|
|
|
|
|
|
+ toPv = self.getPackageVersion(patchfile.getTargetKey())
|
|
|
patchfile.toPv = toPv
|
|
patchfile.toPv = toPv
|
|
|
toPv.fromPatches.append(patchfile)
|
|
toPv.fromPatches.append(patchfile)
|
|
|
|
|
|
|
|
- def processPackages(self):
|
|
|
|
|
|
|
+ def processSomePackages(self, packageNames):
|
|
|
|
|
+ """ Builds missing patches only for the named packages. """
|
|
|
|
|
+
|
|
|
|
|
+ remainingNames = packageNames[:]
|
|
|
|
|
+ for package in self.packages:
|
|
|
|
|
+ if package.packageName in remainingNames:
|
|
|
|
|
+ self.processPackage(package)
|
|
|
|
|
+ remainingNames.remove(package.packageName)
|
|
|
|
|
+
|
|
|
|
|
+ if remainingNames:
|
|
|
|
|
+ print "Unknown packages: %s" % (remainingNames,)
|
|
|
|
|
+
|
|
|
|
|
+ def processAllPackages(self):
|
|
|
""" Walks through the list of packages, and builds missing
|
|
""" Walks through the list of packages, and builds missing
|
|
|
patches for each one. """
|
|
patches for each one. """
|
|
|
|
|
|
|
@@ -374,6 +488,10 @@ class PatchMaker:
|
|
|
def processPackage(self, package):
|
|
def processPackage(self, package):
|
|
|
""" Builds missing patches for the indicated package. """
|
|
""" Builds missing patches for the indicated package. """
|
|
|
|
|
|
|
|
|
|
+ if not package.baseFile:
|
|
|
|
|
+ # No versions.
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
# Starting with the package base, how far forward can we go?
|
|
# Starting with the package base, how far forward can we go?
|
|
|
currentPv = package.currentPv
|
|
currentPv = package.currentPv
|
|
|
basePv = package.basePv
|
|
basePv = package.basePv
|
|
@@ -396,8 +514,8 @@ class PatchMaker:
|
|
|
|
|
|
|
|
def buildPatch(self, v1, v2, package, patchFilename):
|
|
def buildPatch(self, v1, v2, package, patchFilename):
|
|
|
""" Builds a patch from PackageVersion v1 to PackageVersion
|
|
""" Builds a patch from PackageVersion v1 to PackageVersion
|
|
|
- v2, and stores it in patchFilename. Returns true on success,
|
|
|
|
|
- false on failure."""
|
|
|
|
|
|
|
+ v2, and stores it in patchFilename.pz. Returns true on
|
|
|
|
|
+ success, false on failure."""
|
|
|
|
|
|
|
|
f1 = v1.getFile()
|
|
f1 = v1.getFile()
|
|
|
f2 = v2.getFile()
|
|
f2 = v2.getFile()
|
|
@@ -406,9 +524,15 @@ class PatchMaker:
|
|
|
if not self.buildPatchFile(f1, f2, pathname):
|
|
if not self.buildPatchFile(f1, f2, pathname):
|
|
|
return False
|
|
return False
|
|
|
|
|
|
|
|
|
|
+ compressedPathname = Filename(pathname + '.pz')
|
|
|
|
|
+ compressedPathname.unlink()
|
|
|
|
|
+ if not compressFile(pathname, compressedPathname, 9):
|
|
|
|
|
+ raise StandardError, "Couldn't compress patch."
|
|
|
|
|
+ pathname.unlink()
|
|
|
|
|
+
|
|
|
patchfile = self.Patchfile(package)
|
|
patchfile = self.Patchfile(package)
|
|
|
- patchfile.fromFile(package.packageDir, patchFilename,
|
|
|
|
|
- v1.hash, v2.hash)
|
|
|
|
|
|
|
+ patchfile.fromFile(package.packageDir, patchFilename + '.pz',
|
|
|
|
|
+ v1.file, v2.file)
|
|
|
package.patches.append(patchfile)
|
|
package.patches.append(patchfile)
|
|
|
package.anyChanges = True
|
|
package.anyChanges = True
|
|
|
|
|
|
|
@@ -425,20 +549,12 @@ class PatchMaker:
|
|
|
# No original version to patch from.
|
|
# No original version to patch from.
|
|
|
return False
|
|
return False
|
|
|
|
|
|
|
|
- print "Building patch from %s to %s" % (origFilename, newFilename)
|
|
|
|
|
|
|
+ print "Building patch to %s" % (newFilename)
|
|
|
patchFilename.unlink()
|
|
patchFilename.unlink()
|
|
|
- p = Patchfile()
|
|
|
|
|
|
|
+ p = Patchfile() # The C++ class
|
|
|
if p.build(origFilename, newFilename, patchFilename):
|
|
if p.build(origFilename, newFilename, patchFilename):
|
|
|
return True
|
|
return True
|
|
|
|
|
|
|
|
# Unable to build a patch for some reason.
|
|
# Unable to build a patch for some reason.
|
|
|
patchFilename.unlink()
|
|
patchFilename.unlink()
|
|
|
return False
|
|
return False
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
-if __name__ == '__main__':
|
|
|
|
|
- pm = PatchMaker(Filename('install'))
|
|
|
|
|
- result = pm.run()
|
|
|
|
|
- print "run returned %s" % (result)
|
|
|
|
|
-
|
|
|