mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-05 03:15:07 -04:00
steps toward C++ patching
This commit is contained in:
parent
083e7cbe78
commit
81c2514bc4
@ -514,15 +514,7 @@ class PackageInfo:
|
|||||||
from direct.p3d.PatchMaker import PatchMaker
|
from direct.p3d.PatchMaker import PatchMaker
|
||||||
|
|
||||||
patchMaker = PatchMaker(self.packageDir)
|
patchMaker = PatchMaker(self.packageDir)
|
||||||
package = patchMaker.readPackageDescFile(self.descFileBasename)
|
patchChain = patchMaker.getPatchChainToCurrent(self.descFileBasename, fileSpec)
|
||||||
patchMaker.buildPatchChains()
|
|
||||||
fromPv = patchMaker.getPackageVersion(package.getGenericKey(fileSpec))
|
|
||||||
toPv = package.currentPv
|
|
||||||
|
|
||||||
patchChain = None
|
|
||||||
if toPv and fromPv:
|
|
||||||
patchChain = toPv.getPatchChain(fromPv)
|
|
||||||
|
|
||||||
if patchChain is None:
|
if patchChain is None:
|
||||||
# No path.
|
# No path.
|
||||||
patchMaker.cleanup()
|
patchMaker.cleanup()
|
||||||
|
@ -10,15 +10,15 @@ class PatchMaker:
|
|||||||
|
|
||||||
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
|
||||||
the package's "version" number; it also corresponds to the
|
the package's "version" string; it also corresponds to the
|
||||||
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, file):
|
def __init__(self, packageName, platform, version, hostUrl, file):
|
||||||
self.packageName = packageName
|
self.packageName = packageName
|
||||||
self.platform = platform
|
self.platform = platform
|
||||||
self.version = version
|
self.version = version
|
||||||
self.host = host
|
self.hostUrl = hostUrl
|
||||||
self.file = file
|
self.file = file
|
||||||
self.printName = None
|
self.printName = None
|
||||||
|
|
||||||
@ -43,8 +43,8 @@ class PatchMaker:
|
|||||||
|
|
||||||
def getPatchChain(self, startPv):
|
def getPatchChain(self, startPv):
|
||||||
""" Returns a list of patches that, when applied in
|
""" Returns a list of patches that, when applied in
|
||||||
sequence to the indicated patchVersion object, will
|
sequence to the indicated PackageVersion object, will
|
||||||
produce this patchVersion object. Returns None if no
|
produce this PackageVersion object. Returns None if no
|
||||||
chain can be found. """
|
chain can be found. """
|
||||||
|
|
||||||
if self is startPv:
|
if self is startPv:
|
||||||
@ -173,7 +173,7 @@ class PatchMaker:
|
|||||||
if patch.packageName == package.packageName and \
|
if patch.packageName == package.packageName and \
|
||||||
patch.platform == package.platform and \
|
patch.platform == package.platform and \
|
||||||
patch.version == package.version and \
|
patch.version == package.version and \
|
||||||
patch.host == package.host:
|
patch.hostUrl == package.hostUrl:
|
||||||
return patch.toPv
|
return patch.toPv
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@ -186,25 +186,49 @@ class PatchMaker:
|
|||||||
self.packageName = package.packageName
|
self.packageName = package.packageName
|
||||||
self.platform = package.platform
|
self.platform = package.platform
|
||||||
self.version = package.version
|
self.version = package.version
|
||||||
self.host = None
|
self.hostUrl = None
|
||||||
|
|
||||||
|
# FileSpec for the patchfile itself
|
||||||
|
self.file = None
|
||||||
|
|
||||||
|
# FileSpec for the package file that the patch is applied to
|
||||||
|
self.sourceFile = None
|
||||||
|
|
||||||
|
# FileSpec for the package file that the patch generates
|
||||||
|
self.targetFile = None
|
||||||
|
|
||||||
|
# The PackageVersion corresponding to our sourceFile
|
||||||
|
self.fromPv = None
|
||||||
|
|
||||||
|
# The PackageVersion corresponding to our targetFile
|
||||||
|
self.toPv = None
|
||||||
|
|
||||||
def getSourceKey(self):
|
def getSourceKey(self):
|
||||||
return (self.packageName, self.platform, self.version, self.host, self.sourceFile)
|
""" Returns the key for locating the package that this
|
||||||
|
patchfile can be applied to. """
|
||||||
|
return (self.packageName, self.platform, self.version, self.hostUrl, self.sourceFile)
|
||||||
|
|
||||||
def getTargetKey(self):
|
def getTargetKey(self):
|
||||||
return (self.packageName, self.platform, self.version, self.host, self.targetFile)
|
""" Returns the key for locating the package that this
|
||||||
|
patchfile will generate. """
|
||||||
|
return (self.packageName, self.platform, self.version, self.hostUrl, self.targetFile)
|
||||||
|
|
||||||
def fromFile(self, packageDir, patchFilename, sourceFile, targetFile):
|
def fromFile(self, packageDir, patchFilename, sourceFile, targetFile):
|
||||||
|
""" Creates the data structures from an existing patchfile
|
||||||
|
on disk. """
|
||||||
|
|
||||||
self.file = FileSpec()
|
self.file = FileSpec()
|
||||||
self.file.fromFile(packageDir, patchFilename)
|
self.file.fromFile(packageDir, patchFilename)
|
||||||
self.sourceFile = sourceFile
|
self.sourceFile = sourceFile
|
||||||
self.targetFile = targetFile
|
self.targetFile = targetFile
|
||||||
|
|
||||||
def loadXml(self, xpatch):
|
def loadXml(self, xpatch):
|
||||||
|
""" Reads the data structures from an xml file. """
|
||||||
|
|
||||||
self.packageName = xpatch.Attribute('name') or self.packageName
|
self.packageName = xpatch.Attribute('name') or self.packageName
|
||||||
self.platform = xpatch.Attribute('platform') or self.platform
|
self.platform = xpatch.Attribute('platform') or self.platform
|
||||||
self.version = xpatch.Attribute('version') or self.version
|
self.version = xpatch.Attribute('version') or self.version
|
||||||
self.host = xpatch.Attribute('host') or self.host
|
self.hostUrl = xpatch.Attribute('host') or self.hostUrl
|
||||||
|
|
||||||
self.file = FileSpec()
|
self.file = FileSpec()
|
||||||
self.file.loadXml(xpatch)
|
self.file.loadXml(xpatch)
|
||||||
@ -228,8 +252,8 @@ class PatchMaker:
|
|||||||
xpatch.SetAttribute('platform', self.platform)
|
xpatch.SetAttribute('platform', self.platform)
|
||||||
if self.version != package.version:
|
if self.version != package.version:
|
||||||
xpatch.SetAttribute('version', self.version)
|
xpatch.SetAttribute('version', self.version)
|
||||||
if self.host != package.host:
|
if self.hostUrl != package.hostUrl:
|
||||||
xpatch.SetAttribute('host', self.host)
|
xpatch.SetAttribute('host', self.hostUrl)
|
||||||
|
|
||||||
self.file.storeXml(xpatch)
|
self.file.storeXml(xpatch)
|
||||||
|
|
||||||
@ -259,7 +283,7 @@ class PatchMaker:
|
|||||||
self.packageName = None
|
self.packageName = None
|
||||||
self.platform = None
|
self.platform = None
|
||||||
self.version = None
|
self.version = None
|
||||||
self.host = None
|
self.hostUrl = None
|
||||||
self.currentFile = None
|
self.currentFile = None
|
||||||
self.baseFile = None
|
self.baseFile = None
|
||||||
|
|
||||||
@ -268,18 +292,25 @@ class PatchMaker:
|
|||||||
self.patches = []
|
self.patches = []
|
||||||
|
|
||||||
def getCurrentKey(self):
|
def getCurrentKey(self):
|
||||||
return (self.packageName, self.platform, self.version, self.host, self.currentFile)
|
""" Returns the key to locate the current version of this
|
||||||
|
package. """
|
||||||
|
|
||||||
|
return (self.packageName, self.platform, self.version, self.hostUrl, self.currentFile)
|
||||||
|
|
||||||
def getBaseKey(self):
|
def getBaseKey(self):
|
||||||
return (self.packageName, self.platform, self.version, self.host, self.baseFile)
|
""" Returns the key to locate the "base" or oldest version
|
||||||
|
of this package. """
|
||||||
|
|
||||||
|
return (self.packageName, self.platform, self.version, self.hostUrl, self.baseFile)
|
||||||
|
|
||||||
def getGenericKey(self, fileSpec):
|
def getGenericKey(self, fileSpec):
|
||||||
""" Returns the key that has the indicated FileSpec. """
|
""" Returns the key that has the indicated hash. """
|
||||||
return (self.packageName, self.platform, self.version, self.host, fileSpec)
|
return (self.packageName, self.platform, self.version, self.hostUrl, fileSpec)
|
||||||
|
|
||||||
def readDescFile(self):
|
def readDescFile(self):
|
||||||
""" Reads the existing package.xml file and stores
|
""" Reads the existing package.xml file and stores it in
|
||||||
it in this class for later rewriting. """
|
this class for later rewriting. Returns true on success,
|
||||||
|
false on failure. """
|
||||||
|
|
||||||
self.anyChanges = False
|
self.anyChanges = False
|
||||||
|
|
||||||
@ -287,11 +318,11 @@ class PatchMaker:
|
|||||||
self.doc = TiXmlDocument(packageDescFullpath.toOsSpecific())
|
self.doc = TiXmlDocument(packageDescFullpath.toOsSpecific())
|
||||||
if not self.doc.LoadFile():
|
if not self.doc.LoadFile():
|
||||||
print "Couldn't read %s" % (packageDescFullpath)
|
print "Couldn't read %s" % (packageDescFullpath)
|
||||||
return
|
return False
|
||||||
|
|
||||||
xpackage = self.doc.FirstChildElement('package')
|
xpackage = self.doc.FirstChildElement('package')
|
||||||
if not xpackage:
|
if not xpackage:
|
||||||
return
|
return False
|
||||||
self.packageName = xpackage.Attribute('name')
|
self.packageName = xpackage.Attribute('name')
|
||||||
self.platform = xpackage.Attribute('platform')
|
self.platform = xpackage.Attribute('platform')
|
||||||
self.version = xpackage.Attribute('version')
|
self.version = xpackage.Attribute('version')
|
||||||
@ -300,7 +331,7 @@ class PatchMaker:
|
|||||||
# "none" host. TODO: support patching from packages on
|
# "none" host. TODO: support patching from packages on
|
||||||
# other hosts, which means we'll need to fill in a value
|
# other hosts, which means we'll need to fill in a value
|
||||||
# here for those hosts.
|
# here for those hosts.
|
||||||
self.host = None
|
self.hostUrl = None
|
||||||
|
|
||||||
# Get the current patch version. If we have a
|
# Get the current patch version. If we have a
|
||||||
# patch_version attribute, it refers to this particular
|
# patch_version attribute, it refers to this particular
|
||||||
@ -389,6 +420,8 @@ class PatchMaker:
|
|||||||
self.patches.append(patchfile)
|
self.patches.append(patchfile)
|
||||||
xpatch = xpatch.NextSiblingElement('patch')
|
xpatch = xpatch.NextSiblingElement('patch')
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def writeDescFile(self):
|
def writeDescFile(self):
|
||||||
""" Rewrites the desc file with the new patch
|
""" Rewrites the desc file with the new patch
|
||||||
information. """
|
information. """
|
||||||
@ -436,7 +469,7 @@ class PatchMaker:
|
|||||||
fileSpec.fromFile(self.patchMaker.installDir, self.packageDesc)
|
fileSpec.fromFile(self.patchMaker.installDir, self.packageDesc)
|
||||||
fileSpec.storeXml(self.contentsDocPackage)
|
fileSpec.storeXml(self.contentsDocPackage)
|
||||||
|
|
||||||
|
# PatchMaker constructor.
|
||||||
def __init__(self, installDir):
|
def __init__(self, installDir):
|
||||||
self.installDir = installDir
|
self.installDir = installDir
|
||||||
self.packageVersions = {}
|
self.packageVersions = {}
|
||||||
@ -468,15 +501,36 @@ class PatchMaker:
|
|||||||
for pv in self.packageVersions.values():
|
for pv in self.packageVersions.values():
|
||||||
pv.cleanup()
|
pv.cleanup()
|
||||||
|
|
||||||
|
def getPatchChainToCurrent(self, descFilename, fileSpec):
|
||||||
|
""" Reads the package defined in the indicated desc file, and
|
||||||
|
constructs a patch chain from the version represented by
|
||||||
|
fileSpec to the current version of this package, if possible.
|
||||||
|
Returns the patch chain if successful, or None otherwise. """
|
||||||
|
|
||||||
|
package = self.readPackageDescFile(descFilename)
|
||||||
|
if not package:
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.buildPatchChains()
|
||||||
|
fromPv = self.getPackageVersion(package.getGenericKey(fileSpec))
|
||||||
|
toPv = package.currentPv
|
||||||
|
|
||||||
|
patchChain = None
|
||||||
|
if toPv and fromPv:
|
||||||
|
patchChain = toPv.getPatchChain(fromPv)
|
||||||
|
|
||||||
|
return patchChain
|
||||||
|
|
||||||
def readPackageDescFile(self, descFilename):
|
def readPackageDescFile(self, descFilename):
|
||||||
""" Reads a desc file associated with a particular package,
|
""" Reads a desc file associated with a particular package,
|
||||||
and adds the package to self.packageVersions. Returns the
|
and adds the package to self.packages. Returns the Package
|
||||||
Package object. """
|
object, or None on failure. """
|
||||||
|
|
||||||
package = self.Package(Filename(descFilename), self)
|
package = self.Package(Filename(descFilename), self)
|
||||||
package.readDescFile()
|
if not package.readDescFile():
|
||||||
self.packages.append(package)
|
return None
|
||||||
|
|
||||||
|
self.packages.append(package)
|
||||||
return package
|
return package
|
||||||
|
|
||||||
def readContentsFile(self):
|
def readContentsFile(self):
|
||||||
@ -522,10 +576,10 @@ class PatchMaker:
|
|||||||
""" Returns a shared PackageVersion object for the indicated
|
""" Returns a shared PackageVersion object for the indicated
|
||||||
key. """
|
key. """
|
||||||
|
|
||||||
packageName, platform, version, host, file = key
|
packageName, platform, version, hostUrl, file = key
|
||||||
|
|
||||||
# We actually key on the hash, not the FileSpec itself.
|
# We actually key on the hash, not the FileSpec itself.
|
||||||
k = (packageName, platform, version, host, file.hash)
|
k = (packageName, platform, version, hostUrl, file.hash)
|
||||||
pv = self.packageVersions.get(k, None)
|
pv = self.packageVersions.get(k, None)
|
||||||
if not pv:
|
if not pv:
|
||||||
pv = self.PackageVersion(*key)
|
pv = self.PackageVersion(*key)
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
p3dObject.h p3dObject.I \
|
p3dObject.h p3dObject.I \
|
||||||
p3dOsxSplashWindow.h p3dOsxSplashWindow.I \
|
p3dOsxSplashWindow.h p3dOsxSplashWindow.I \
|
||||||
p3dPackage.h p3dPackage.I \
|
p3dPackage.h p3dPackage.I \
|
||||||
|
p3dPatchFinder.h p3dPatchFinder.I \
|
||||||
p3dPythonObject.h \
|
p3dPythonObject.h \
|
||||||
p3dReferenceCount.h p3dReferenceCount.I \
|
p3dReferenceCount.h p3dReferenceCount.I \
|
||||||
p3dSession.h p3dSession.I \
|
p3dSession.h p3dSession.I \
|
||||||
@ -81,6 +82,7 @@
|
|||||||
p3dObject.cxx \
|
p3dObject.cxx \
|
||||||
p3dOsxSplashWindow.cxx \
|
p3dOsxSplashWindow.cxx \
|
||||||
p3dPackage.cxx \
|
p3dPackage.cxx \
|
||||||
|
p3dPatchFinder.cxx \
|
||||||
p3dPythonObject.cxx \
|
p3dPythonObject.cxx \
|
||||||
p3dReferenceCount.cxx \
|
p3dReferenceCount.cxx \
|
||||||
p3dSession.cxx \
|
p3dSession.cxx \
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FileSpec::get_filename
|
// Function: FileSpec::get_filename
|
||||||
// Access: Private
|
// Access: Public
|
||||||
// Description: Returns the relative path to this file on disk,
|
// Description: Returns the relative path to this file on disk,
|
||||||
// within the package root directory.
|
// within the package root directory.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -26,7 +26,7 @@ get_filename() const {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FileSpec::set_filename
|
// Function: FileSpec::set_filename
|
||||||
// Access: Private
|
// Access: Public
|
||||||
// Description: Changes the relative path to this file on disk,
|
// Description: Changes the relative path to this file on disk,
|
||||||
// within the package root directory.
|
// within the package root directory.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -37,7 +37,7 @@ set_filename(const string &filename) {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FileSpec::get_pathname
|
// Function: FileSpec::get_pathname
|
||||||
// Access: Private
|
// Access: Public
|
||||||
// Description: Returns the full path to this file on disk.
|
// Description: Returns the full path to this file on disk.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
inline string FileSpec::
|
inline string FileSpec::
|
||||||
@ -47,7 +47,7 @@ get_pathname(const string &package_dir) const {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FileSpec::get_size
|
// Function: FileSpec::get_size
|
||||||
// Access: Private
|
// Access: Public
|
||||||
// Description: Returns the expected size of this file on disk, in
|
// Description: Returns the expected size of this file on disk, in
|
||||||
// bytes.
|
// bytes.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -56,6 +56,22 @@ get_size() const {
|
|||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: FileSpec::get_actual_file
|
||||||
|
// Access: Public
|
||||||
|
// Description: After a call to quick_verify() or full_verify(), this
|
||||||
|
// method *may* return a pointer to a FileSpec that
|
||||||
|
// represents the actual data read on disk, or it may
|
||||||
|
// return NULL. If this returns a non-NULL value, you
|
||||||
|
// may use it to extract the md5 hash of the existing
|
||||||
|
// file, thus saving the effort of performing the hash
|
||||||
|
// twice.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
inline const FileSpec *FileSpec::
|
||||||
|
get_actual_file() const {
|
||||||
|
return _actual_file;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FileSpec::decode_hexdigit
|
// Function: FileSpec::decode_hexdigit
|
||||||
// Access: Private
|
// Access: Private
|
||||||
|
@ -17,9 +17,11 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <sys/utime.h>
|
#include <sys/utime.h>
|
||||||
@ -44,6 +46,7 @@ FileSpec() {
|
|||||||
_timestamp = 0;
|
_timestamp = 0;
|
||||||
memset(_hash, 0, sizeof(_hash));
|
memset(_hash, 0, sizeof(_hash));
|
||||||
_got_hash = false;
|
_got_hash = false;
|
||||||
|
_actual_file = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -59,6 +62,7 @@ FileSpec(const FileSpec ©) :
|
|||||||
_got_hash(copy._got_hash)
|
_got_hash(copy._got_hash)
|
||||||
{
|
{
|
||||||
memcpy(_hash, copy._hash, sizeof(_hash));
|
memcpy(_hash, copy._hash, sizeof(_hash));
|
||||||
|
_actual_file = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -75,6 +79,18 @@ operator = (const FileSpec ©) {
|
|||||||
_got_hash = copy._got_hash;
|
_got_hash = copy._got_hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: FileSpec::Destructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
FileSpec::
|
||||||
|
~FileSpec() {
|
||||||
|
if (_actual_file != NULL) {
|
||||||
|
delete _actual_file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FileSpec::load_xml
|
// Function: FileSpec::load_xml
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -119,7 +135,12 @@ load_xml(TiXmlElement *xelement) {
|
|||||||
// redownloaded.
|
// redownloaded.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool FileSpec::
|
bool FileSpec::
|
||||||
quick_verify(const string &package_dir) const {
|
quick_verify(const string &package_dir) {
|
||||||
|
if (_actual_file != NULL) {
|
||||||
|
delete _actual_file;
|
||||||
|
_actual_file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
string pathname = get_pathname(package_dir);
|
string pathname = get_pathname(package_dir);
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(pathname.c_str(), &st) != 0) {
|
if (stat(pathname.c_str(), &st) != 0) {
|
||||||
@ -143,7 +164,7 @@ quick_verify(const string &package_dir) const {
|
|||||||
|
|
||||||
// If the size is right but the timestamp is wrong, the file
|
// If the size is right but the timestamp is wrong, the file
|
||||||
// soft-fails. We follow this up with a hash check.
|
// soft-fails. We follow this up with a hash check.
|
||||||
if (!check_hash(pathname)) {
|
if (!priv_check_hash(pathname, st)) {
|
||||||
// Hard fail, the hash is wrong.
|
// Hard fail, the hash is wrong.
|
||||||
//cerr << "hash check wrong: " << _filename << "\n";
|
//cerr << "hash check wrong: " << _filename << "\n";
|
||||||
return false;
|
return false;
|
||||||
@ -174,7 +195,12 @@ quick_verify(const string &package_dir) const {
|
|||||||
// redownloaded.
|
// redownloaded.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool FileSpec::
|
bool FileSpec::
|
||||||
full_verify(const string &package_dir) const {
|
full_verify(const string &package_dir) {
|
||||||
|
if (_actual_file != NULL) {
|
||||||
|
delete _actual_file;
|
||||||
|
_actual_file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
string pathname = get_pathname(package_dir);
|
string pathname = get_pathname(package_dir);
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(pathname.c_str(), &st) != 0) {
|
if (stat(pathname.c_str(), &st) != 0) {
|
||||||
@ -188,7 +214,7 @@ full_verify(const string &package_dir) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!check_hash(pathname)) {
|
if (!priv_check_hash(pathname, st)) {
|
||||||
// Hard fail, the hash is wrong.
|
// Hard fail, the hash is wrong.
|
||||||
//cerr << "hash check wrong: " << _filename << "\n";
|
//cerr << "hash check wrong: " << _filename << "\n";
|
||||||
return false;
|
return false;
|
||||||
@ -218,31 +244,12 @@ full_verify(const string &package_dir) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool FileSpec::
|
bool FileSpec::
|
||||||
check_hash(const string &pathname) const {
|
check_hash(const string &pathname) const {
|
||||||
ifstream stream(pathname.c_str(), ios::in | ios::binary);
|
FileSpec other;
|
||||||
if (!stream) {
|
if (!other.read_hash(pathname)) {
|
||||||
//cerr << "unable to read " << pathname << "\n";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char md[hash_size];
|
return (memcmp(_hash, other._hash, hash_size) == 0);
|
||||||
|
|
||||||
MD5_CTX ctx;
|
|
||||||
MD5_Init(&ctx);
|
|
||||||
|
|
||||||
static const int buffer_size = 4096;
|
|
||||||
char buffer[buffer_size];
|
|
||||||
|
|
||||||
stream.read(buffer, buffer_size);
|
|
||||||
size_t count = stream.gcount();
|
|
||||||
while (count != 0) {
|
|
||||||
MD5_Update(&ctx, buffer, count);
|
|
||||||
stream.read(buffer, buffer_size);
|
|
||||||
count = stream.gcount();
|
|
||||||
}
|
|
||||||
|
|
||||||
MD5_Final(md, &ctx);
|
|
||||||
|
|
||||||
return (memcmp(md, _hash, hash_size) == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -280,6 +287,65 @@ read_hash(const string &pathname) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: FileSpec::compare_hash
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns true if this hash sorts before the other
|
||||||
|
// hash, false otherwise.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool FileSpec::
|
||||||
|
compare_hash(const FileSpec &other) const {
|
||||||
|
return memcmp(_hash, other._hash, hash_size) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: FileSpec::write
|
||||||
|
// Access: Public
|
||||||
|
// Description: Describes the data in the FileSpec.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void FileSpec::
|
||||||
|
write(ostream &out) const {
|
||||||
|
out << "filename: " << _filename << ", " << _size << " bytes, "
|
||||||
|
<< asctime(localtime(&_timestamp));
|
||||||
|
// asctime includes a newline.
|
||||||
|
out << "hash: ";
|
||||||
|
stream_hex(out, _hash, hash_size);
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: FileSpec::output_hash
|
||||||
|
// Access: Public
|
||||||
|
// Description: Writes just the hash code.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void FileSpec::
|
||||||
|
output_hash(ostream &out) const {
|
||||||
|
stream_hex(out, _hash, hash_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: FileSpec::priv_check_hash
|
||||||
|
// Access: Private
|
||||||
|
// Description: Returns true if the file has the expected md5 hash,
|
||||||
|
// false otherwise. Updates _actual_file with the data
|
||||||
|
// read from disk, including the hash, for future
|
||||||
|
// reference.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool FileSpec::
|
||||||
|
priv_check_hash(const string &pathname, const struct stat &st) {
|
||||||
|
assert(_actual_file == NULL);
|
||||||
|
_actual_file = new FileSpec;
|
||||||
|
_actual_file->_filename = pathname;
|
||||||
|
_actual_file->_size = st.st_size;
|
||||||
|
_actual_file->_timestamp = st.st_mtime;
|
||||||
|
|
||||||
|
if (!_actual_file->read_hash(pathname)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (memcmp(_hash, _actual_file->_hash, hash_size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FileSpec::decode_hex
|
// Function: FileSpec::decode_hex
|
||||||
// Access: Private, Static
|
// Access: Private, Static
|
||||||
|
@ -31,6 +31,8 @@ public:
|
|||||||
FileSpec();
|
FileSpec();
|
||||||
FileSpec(const FileSpec ©);
|
FileSpec(const FileSpec ©);
|
||||||
void operator = (const FileSpec ©);
|
void operator = (const FileSpec ©);
|
||||||
|
~FileSpec();
|
||||||
|
|
||||||
void load_xml(TiXmlElement *xelement);
|
void load_xml(TiXmlElement *xelement);
|
||||||
|
|
||||||
inline const string &get_filename() const;
|
inline const string &get_filename() const;
|
||||||
@ -38,13 +40,19 @@ public:
|
|||||||
inline string get_pathname(const string &package_dir) const;
|
inline string get_pathname(const string &package_dir) const;
|
||||||
inline size_t get_size() const;
|
inline size_t get_size() const;
|
||||||
|
|
||||||
bool quick_verify(const string &package_dir) const;
|
bool quick_verify(const string &package_dir);
|
||||||
bool full_verify(const string &package_dir) const;
|
bool full_verify(const string &package_dir);
|
||||||
|
inline const FileSpec *get_actual_file() const;
|
||||||
|
|
||||||
bool check_hash(const string &pathname) const;
|
bool check_hash(const string &pathname) const;
|
||||||
bool read_hash(const string &pathname);
|
bool read_hash(const string &pathname);
|
||||||
|
bool compare_hash(const FileSpec &other) const;
|
||||||
|
|
||||||
|
void write(ostream &out) const;
|
||||||
|
void output_hash(ostream &out) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool priv_check_hash(const string &pathname, const struct stat &st);
|
||||||
static inline int decode_hexdigit(char c);
|
static inline int decode_hexdigit(char c);
|
||||||
static inline char encode_hexdigit(int c);
|
static inline char encode_hexdigit(int c);
|
||||||
|
|
||||||
@ -59,6 +67,8 @@ private:
|
|||||||
time_t _timestamp;
|
time_t _timestamp;
|
||||||
unsigned char _hash[hash_size];
|
unsigned char _hash[hash_size];
|
||||||
bool _got_hash;
|
bool _got_hash;
|
||||||
|
|
||||||
|
FileSpec *_actual_file;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "fileSpec.I"
|
#include "fileSpec.I"
|
||||||
|
@ -1795,7 +1795,7 @@ report_package_info_ready(P3DPackage *package) {
|
|||||||
_download_package_index = 0;
|
_download_package_index = 0;
|
||||||
_total_downloaded = 0;
|
_total_downloaded = 0;
|
||||||
|
|
||||||
nout << "Beginning download of " << _downloading_packages.size()
|
nout << "Beginning install of " << _downloading_packages.size()
|
||||||
<< " packages, total " << _total_download_size
|
<< " packages, total " << _total_download_size
|
||||||
<< " bytes required.\n";
|
<< " bytes required.\n";
|
||||||
|
|
||||||
@ -1844,7 +1844,7 @@ start_next_download() {
|
|||||||
_panda_script_object->set_int_property("downloadPackageSize", package->get_download_size());
|
_panda_script_object->set_int_property("downloadPackageSize", package->get_download_size());
|
||||||
set_install_label("Installing " + name);
|
set_install_label("Installing " + name);
|
||||||
|
|
||||||
nout << "Downloading " << package->get_package_name()
|
nout << "Installing " << package->get_package_name()
|
||||||
<< ", package " << _download_package_index + 1
|
<< ", package " << _download_package_index + 1
|
||||||
<< " of " << _downloading_packages.size()
|
<< " of " << _downloading_packages.size()
|
||||||
<< ", " << package->get_download_size()
|
<< ", " << package->get_download_size()
|
||||||
@ -1999,7 +1999,7 @@ report_package_progress(P3DPackage *package, double progress) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DInstance::
|
void P3DInstance::
|
||||||
report_package_done(P3DPackage *package, bool success) {
|
report_package_done(P3DPackage *package, bool success) {
|
||||||
nout << "Done downloading " << package->get_package_name()
|
nout << "Done installing " << package->get_package_name()
|
||||||
<< ": success = " << success << "\n";
|
<< ": success = " << success << "\n";
|
||||||
|
|
||||||
if (package == _image_package) {
|
if (package == _image_package) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "p3dInstance.h"
|
#include "p3dInstance.h"
|
||||||
#include "p3dMultifileReader.h"
|
#include "p3dMultifileReader.h"
|
||||||
#include "p3dTemporaryFile.h"
|
#include "p3dTemporaryFile.h"
|
||||||
|
#include "p3dPatchFinder.h"
|
||||||
#include "mkdir_complete.h"
|
#include "mkdir_complete.h"
|
||||||
|
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
@ -672,7 +673,7 @@ got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
|
|||||||
} else {
|
} else {
|
||||||
// We need to get the file data still, but at least we know all
|
// We need to get the file data still, but at least we know all
|
||||||
// about it by this point.
|
// about it by this point.
|
||||||
build_install_plans();
|
build_install_plans(doc);
|
||||||
|
|
||||||
if (!_allow_data_download) {
|
if (!_allow_data_download) {
|
||||||
// Not authorized to start downloading yet; just report that
|
// Not authorized to start downloading yet; just report that
|
||||||
@ -712,7 +713,7 @@ clear_install_plans() {
|
|||||||
// to download and install the package.
|
// to download and install the package.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DPackage::
|
void P3DPackage::
|
||||||
build_install_plans() {
|
build_install_plans(TiXmlDocument *doc) {
|
||||||
clear_install_plans();
|
clear_install_plans();
|
||||||
|
|
||||||
if (_instances.empty()) {
|
if (_instances.empty()) {
|
||||||
@ -728,6 +729,8 @@ build_install_plans() {
|
|||||||
_install_plans.push_back(InstallPlan());
|
_install_plans.push_back(InstallPlan());
|
||||||
InstallPlan &plan = _install_plans.back();
|
InstallPlan &plan = _install_plans.back();
|
||||||
|
|
||||||
|
bool needs_redownload = false;
|
||||||
|
|
||||||
InstallStep *step;
|
InstallStep *step;
|
||||||
if (!_uncompressed_archive.quick_verify(_package_dir)) {
|
if (!_uncompressed_archive.quick_verify(_package_dir)) {
|
||||||
// The uncompressed archive is no good.
|
// The uncompressed archive is no good.
|
||||||
@ -735,6 +738,7 @@ build_install_plans() {
|
|||||||
if (!_compressed_archive.quick_verify(_package_dir)) {
|
if (!_compressed_archive.quick_verify(_package_dir)) {
|
||||||
// The compressed archive is no good either. Download a new
|
// The compressed archive is no good either. Download a new
|
||||||
// compressed archive.
|
// compressed archive.
|
||||||
|
needs_redownload = true;
|
||||||
step = new InstallStepDownloadFile(this, _compressed_archive);
|
step = new InstallStepDownloadFile(this, _compressed_archive);
|
||||||
plan.push_back(step);
|
plan.push_back(step);
|
||||||
}
|
}
|
||||||
@ -748,6 +752,35 @@ build_install_plans() {
|
|||||||
// Unpack the uncompressed archive.
|
// Unpack the uncompressed archive.
|
||||||
step = new InstallStepUnpackArchive(this, _unpack_size);
|
step = new InstallStepUnpackArchive(this, _unpack_size);
|
||||||
plan.push_back(step);
|
plan.push_back(step);
|
||||||
|
|
||||||
|
if (needs_redownload) {
|
||||||
|
// Since we need to do some downloading, try to build a plan that
|
||||||
|
// involves downloading patches instead of downloading the whole
|
||||||
|
// file. This will be our first choice, plan A, if we can do it.
|
||||||
|
|
||||||
|
// We'll need the md5 hash of the uncompressed archive currently
|
||||||
|
// on disk.
|
||||||
|
|
||||||
|
// Maybe we've already read the md5 hash and we have it stored here.
|
||||||
|
const FileSpec *on_disk_ptr = _uncompressed_archive.get_actual_file();
|
||||||
|
FileSpec on_disk;
|
||||||
|
if (on_disk_ptr == NULL) {
|
||||||
|
// If not, we have to go read it now.
|
||||||
|
if (on_disk.read_hash(_uncompressed_archive.get_pathname(_package_dir))) {
|
||||||
|
on_disk_ptr = &on_disk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (on_disk_ptr != NULL) {
|
||||||
|
P3DPatchFinder patch_finder;
|
||||||
|
P3DPatchFinder::Patchfiles chain;
|
||||||
|
if (patch_finder.get_patch_chain_to_current(chain, doc, *on_disk_ptr)) {
|
||||||
|
cerr << "got patch chain of length " << chain.size() << "\n";
|
||||||
|
} else {
|
||||||
|
cerr << "No patch chain possible.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -180,7 +180,7 @@ private:
|
|||||||
void got_desc_file(TiXmlDocument *doc, bool freshly_downloaded);
|
void got_desc_file(TiXmlDocument *doc, bool freshly_downloaded);
|
||||||
|
|
||||||
void clear_install_plans();
|
void clear_install_plans();
|
||||||
void build_install_plans();
|
void build_install_plans(TiXmlDocument *doc);
|
||||||
void follow_install_plans(bool download_finished);
|
void follow_install_plans(bool download_finished);
|
||||||
|
|
||||||
class InstallStep;
|
class InstallStep;
|
||||||
|
14
direct/src/plugin/p3dPatchFinder.I
Normal file
14
direct/src/plugin/p3dPatchFinder.I
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Filename: p3dPatchFinder.I
|
||||||
|
// Created by: drose (27Sep09)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the revised BSD
|
||||||
|
// license. You should have received a copy of this license along
|
||||||
|
// with this source code in a file named "LICENSE."
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
439
direct/src/plugin/p3dPatchFinder.cxx
Normal file
439
direct/src/plugin/p3dPatchFinder.cxx
Normal file
@ -0,0 +1,439 @@
|
|||||||
|
// Filename: p3dPatchFinder.cxx
|
||||||
|
// Created by: drose (27Sep09)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the revised BSD
|
||||||
|
// license. You should have received a copy of this license along
|
||||||
|
// with this source code in a file named "LICENSE."
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "p3dPatchFinder.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::PackageVersion::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::PackageVersion::
|
||||||
|
PackageVersion(const PackageVersionKey &key) :
|
||||||
|
_package_name(key._package_name),
|
||||||
|
_platform(key._platform),
|
||||||
|
_version(key._version),
|
||||||
|
_host_url(key._host_url),
|
||||||
|
_file(key._file)
|
||||||
|
{
|
||||||
|
_package_current = NULL;
|
||||||
|
_package_base = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::PackageVersion::get_patch_chain
|
||||||
|
// Access: Public
|
||||||
|
// Description: Fills chain with the list of patches that, when
|
||||||
|
// applied in sequence to the indicated PackageVersion
|
||||||
|
// object, produces this PackageVersion object. Returns
|
||||||
|
// false if no chain can be found.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool P3DPatchFinder::PackageVersion::
|
||||||
|
get_patch_chain(Patchfiles &chain, PackageVersion *start_pv) {
|
||||||
|
chain.clear();
|
||||||
|
if (this == start_pv) {
|
||||||
|
// We're already here. A zero-length patch chain is therefore the
|
||||||
|
// answer.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found_any = false;
|
||||||
|
Patchfiles::iterator pi;
|
||||||
|
for (pi = _from_patches.begin(); pi != _from_patches.end(); ++pi) {
|
||||||
|
Patchfile *patchfile = (*pi);
|
||||||
|
PackageVersion *from_pv = patchfile->_from_pv;
|
||||||
|
assert(from_pv != NULL);
|
||||||
|
Patchfiles this_chain;
|
||||||
|
if (from_pv->get_patch_chain(this_chain, start_pv)) {
|
||||||
|
// There's a path through this patchfile.
|
||||||
|
this_chain.push_back(patchfile);
|
||||||
|
if (!found_any || this_chain.size() < chain.size()) {
|
||||||
|
found_any = true;
|
||||||
|
chain.swap(this_chain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If found_any is true, we've already filled chain with the
|
||||||
|
// shortest path found.
|
||||||
|
return found_any;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::PackageVersionKey::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::PackageVersionKey::
|
||||||
|
PackageVersionKey(const string &package_name,
|
||||||
|
const string &platform,
|
||||||
|
const string &version,
|
||||||
|
const string &host_url,
|
||||||
|
const FileSpec &file) :
|
||||||
|
_package_name(package_name),
|
||||||
|
_platform(platform),
|
||||||
|
_version(version),
|
||||||
|
_host_url(host_url),
|
||||||
|
_file(file)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::PackageVersionKey::operator <
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool P3DPatchFinder::PackageVersionKey::
|
||||||
|
operator < (const PackageVersionKey &other) const {
|
||||||
|
if (_package_name != other._package_name) {
|
||||||
|
return _package_name < other._package_name;
|
||||||
|
}
|
||||||
|
if (_platform != other._platform) {
|
||||||
|
return _platform < other._platform;
|
||||||
|
}
|
||||||
|
if (_version != other._version) {
|
||||||
|
return _version < other._version;
|
||||||
|
}
|
||||||
|
if (_host_url != other._host_url) {
|
||||||
|
return _host_url < other._host_url;
|
||||||
|
}
|
||||||
|
return _file.compare_hash(other._file);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::PackageVersionKey::operator <
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DPatchFinder::PackageVersionKey::
|
||||||
|
output(ostream &out) const {
|
||||||
|
out << "(" << _package_name << ", " << _platform << ", " << _version
|
||||||
|
<< ", " << _host_url << ", ";
|
||||||
|
_file.output_hash(out);
|
||||||
|
out << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::Patchfile::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::Patchfile::
|
||||||
|
Patchfile(Package *package) :
|
||||||
|
_package(package),
|
||||||
|
_from_pv(NULL),
|
||||||
|
_to_pv(NULL)
|
||||||
|
{
|
||||||
|
_package_name = package->_package_name;
|
||||||
|
_platform = package->_platform;
|
||||||
|
_version = package->_version;
|
||||||
|
_host_url = package->_host_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::Patchfile::get_source_key
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns the key for locating the package that this
|
||||||
|
// patchfile can be applied to.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::PackageVersionKey P3DPatchFinder::Patchfile::
|
||||||
|
get_source_key() const {
|
||||||
|
return PackageVersionKey(_package_name, _platform, _version, _host_url, _source_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::Patchfile::get_target_key
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns the key for locating the package that this
|
||||||
|
// patchfile will generate.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::PackageVersionKey P3DPatchFinder::Patchfile::
|
||||||
|
get_target_key() const {
|
||||||
|
return PackageVersionKey(_package_name, _platform, _version, _host_url, _target_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::Patchfile::load_xml
|
||||||
|
// Access: Public
|
||||||
|
// Description: Reads the data structures from an xml file.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DPatchFinder::Patchfile::
|
||||||
|
load_xml(TiXmlElement *xpatch) {
|
||||||
|
const char *package_name_cstr = xpatch->Attribute("name");
|
||||||
|
if (package_name_cstr != NULL && *package_name_cstr) {
|
||||||
|
_package_name = package_name_cstr;
|
||||||
|
}
|
||||||
|
const char *platform_cstr = xpatch->Attribute("platform");
|
||||||
|
if (platform_cstr != NULL && *platform_cstr) {
|
||||||
|
_platform = platform_cstr;
|
||||||
|
}
|
||||||
|
const char *version_cstr = xpatch->Attribute("version");
|
||||||
|
if (version_cstr != NULL && *version_cstr) {
|
||||||
|
_version = version_cstr;
|
||||||
|
}
|
||||||
|
const char *host_url_cstr = xpatch->Attribute("host");
|
||||||
|
if (host_url_cstr != NULL && *host_url_cstr) {
|
||||||
|
_host_url = host_url_cstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
_file.load_xml(xpatch);
|
||||||
|
|
||||||
|
TiXmlElement *xsource = xpatch->FirstChildElement("source");
|
||||||
|
if (xsource != NULL) {
|
||||||
|
_source_file.load_xml(xsource);
|
||||||
|
}
|
||||||
|
TiXmlElement *xtarget = xpatch->FirstChildElement("target");
|
||||||
|
if (xtarget != NULL) {
|
||||||
|
_target_file.load_xml(xtarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::Package::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::Package::
|
||||||
|
Package() {
|
||||||
|
_current_pv = NULL;
|
||||||
|
_base_pv = NULL;
|
||||||
|
_got_base_file = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::Package::get_current_key
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns the key to locate the current version of this
|
||||||
|
// package.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::PackageVersionKey P3DPatchFinder::Package::
|
||||||
|
get_current_key() const {
|
||||||
|
return PackageVersionKey(_package_name, _platform, _version, _host_url, _current_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::Package::get_base_key
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns the key to locate the "base" or oldest
|
||||||
|
// version of this package.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::PackageVersionKey P3DPatchFinder::Package::
|
||||||
|
get_base_key() const {
|
||||||
|
return PackageVersionKey(_package_name, _platform, _version, _host_url, _base_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::Package::get_generic_key
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns the key that has the indicated hash.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::PackageVersionKey P3DPatchFinder::Package::
|
||||||
|
get_generic_key(const FileSpec &file) const {
|
||||||
|
return PackageVersionKey(_package_name, _platform, _version, _host_url, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::Package::read_desc_file
|
||||||
|
// Access: Public
|
||||||
|
// Description: Reads the package's desc file for the package
|
||||||
|
// information. Returns true on success, false on
|
||||||
|
// failure.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool P3DPatchFinder::Package::
|
||||||
|
read_desc_file(TiXmlDocument *doc) {
|
||||||
|
TiXmlElement *xpackage = doc->FirstChildElement("package");
|
||||||
|
if (xpackage == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *package_name_cstr = xpackage->Attribute("name");
|
||||||
|
if (package_name_cstr != NULL && *package_name_cstr) {
|
||||||
|
_package_name = package_name_cstr;
|
||||||
|
}
|
||||||
|
const char *platform_cstr = xpackage->Attribute("platform");
|
||||||
|
if (platform_cstr != NULL && *platform_cstr) {
|
||||||
|
_platform = platform_cstr;
|
||||||
|
}
|
||||||
|
const char *version_cstr = xpackage->Attribute("version");
|
||||||
|
if (version_cstr != NULL && *version_cstr) {
|
||||||
|
_version = version_cstr;
|
||||||
|
}
|
||||||
|
const char *host_url_cstr = xpackage->Attribute("host");
|
||||||
|
if (host_url_cstr != NULL && *host_url_cstr) {
|
||||||
|
_host_url = host_url_cstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current version.
|
||||||
|
TiXmlElement *xarchive = xpackage->FirstChildElement("uncompressed_archive");
|
||||||
|
if (xarchive != NULL) {
|
||||||
|
_current_file.load_xml(xarchive);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the base_version--the bottom (oldest) of the patch chain.
|
||||||
|
xarchive = xpackage->FirstChildElement("base_version");
|
||||||
|
if (xarchive != NULL) {
|
||||||
|
_base_file.load_xml(xarchive);
|
||||||
|
_got_base_file = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_patches.clear();
|
||||||
|
TiXmlElement *xpatch = xpackage->FirstChildElement("patch");
|
||||||
|
while (xpatch != NULL) {
|
||||||
|
Patchfile *patchfile = new Patchfile(this);
|
||||||
|
patchfile->load_xml(xpatch);
|
||||||
|
_patches.push_back(patchfile);
|
||||||
|
xpatch = xpatch->NextSiblingElement("patch");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::
|
||||||
|
P3DPatchFinder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::Destructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::
|
||||||
|
~P3DPatchFinder() {
|
||||||
|
// TODO. Cleanup nicely.
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::get_patch_chain_to_current
|
||||||
|
// Access: Public
|
||||||
|
// Description: Loads the package defined in the indicated desc file,
|
||||||
|
// and constructs a patch chain from the version
|
||||||
|
// represented by file to the current version of this
|
||||||
|
// package, if possible. Returns true if successful,
|
||||||
|
// false otherwise.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool P3DPatchFinder::
|
||||||
|
get_patch_chain_to_current(Patchfiles &chain, TiXmlDocument *doc,
|
||||||
|
const FileSpec &file) {
|
||||||
|
chain.clear();
|
||||||
|
Package *package = read_package_desc_file(doc);
|
||||||
|
if (package == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
build_patch_chains();
|
||||||
|
PackageVersion *from_pv = get_package_version(package->get_generic_key(file));
|
||||||
|
PackageVersion *to_pv = package->_current_pv;
|
||||||
|
|
||||||
|
if (to_pv != NULL && from_pv != NULL) {
|
||||||
|
return to_pv->get_patch_chain(chain, from_pv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::read_package_desc_file
|
||||||
|
// Access: Public
|
||||||
|
// Description: Reads a desc file associated with a particular
|
||||||
|
// package, and adds the package to
|
||||||
|
// _packages. Returns the Package object, or
|
||||||
|
// NULL on failure.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::Package *P3DPatchFinder::
|
||||||
|
read_package_desc_file(TiXmlDocument *doc) {
|
||||||
|
Package *package = new Package;
|
||||||
|
if (!package->read_desc_file(doc)) {
|
||||||
|
delete package;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_packages.push_back(package);
|
||||||
|
return package;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::build_patch_chains
|
||||||
|
// Access: Public
|
||||||
|
// Description: Builds up the chains of PackageVersions and the
|
||||||
|
// patchfiles that connect them.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DPatchFinder::
|
||||||
|
build_patch_chains() {
|
||||||
|
Packages::iterator pi;
|
||||||
|
for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
|
||||||
|
Package *package = (*pi);
|
||||||
|
if (!package->_got_base_file) {
|
||||||
|
// This package doesn't have any versions yet.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageVersion *current_pv = get_package_version(package->get_current_key());
|
||||||
|
package->_current_pv = current_pv;
|
||||||
|
current_pv->_package_current = package;
|
||||||
|
current_pv->_print_name = package->_current_file.get_filename();
|
||||||
|
|
||||||
|
PackageVersion *base_pv = get_package_version(package->get_base_key());
|
||||||
|
package->_base_pv = base_pv;
|
||||||
|
base_pv->_package_base = package;
|
||||||
|
base_pv->_print_name = package->_base_file.get_filename();
|
||||||
|
|
||||||
|
Patchfiles::iterator fi;
|
||||||
|
for (fi = package->_patches.begin(); fi != package->_patches.end(); ++fi) {
|
||||||
|
record_patchfile(*fi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::get_package_version
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns a shared PackageVersion object for the
|
||||||
|
// indicated key.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
P3DPatchFinder::PackageVersion *P3DPatchFinder::
|
||||||
|
get_package_version(const PackageVersionKey &key) {
|
||||||
|
assert(!key._package_name.empty());
|
||||||
|
PackageVersions::const_iterator vi = _package_versions.find(key);
|
||||||
|
if (vi != _package_versions.end()) {
|
||||||
|
return (*vi).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageVersion *pv = new PackageVersion(key);
|
||||||
|
bool inserted = _package_versions.insert(PackageVersions::value_type(key, pv)).second;
|
||||||
|
assert(inserted);
|
||||||
|
return pv;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DPatchFinder::record_patchfile
|
||||||
|
// Access: Public
|
||||||
|
// Description: Adds the indicated patchfile to the patch chains.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DPatchFinder::
|
||||||
|
record_patchfile(Patchfile *patchfile) {
|
||||||
|
PackageVersion *from_pv = get_package_version(patchfile->get_source_key());
|
||||||
|
patchfile->_from_pv = from_pv;
|
||||||
|
from_pv->_to_patches.push_back(patchfile);
|
||||||
|
|
||||||
|
PackageVersion *to_pv = get_package_version(patchfile->get_target_key());
|
||||||
|
patchfile->_to_pv = to_pv;
|
||||||
|
to_pv->_from_patches.push_back(patchfile);
|
||||||
|
to_pv->_print_name = patchfile->_file.get_filename();
|
||||||
|
}
|
180
direct/src/plugin/p3dPatchFinder.h
Normal file
180
direct/src/plugin/p3dPatchFinder.h
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
// Filename: p3dPatchFinder.h
|
||||||
|
// Created by: drose (27Sep09)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the revised BSD
|
||||||
|
// license. You should have received a copy of this license along
|
||||||
|
// with this source code in a file named "LICENSE."
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef P3DPATCHFINDER_H
|
||||||
|
#define P3DPATCHFINDER_H
|
||||||
|
|
||||||
|
#include "p3d_plugin_common.h"
|
||||||
|
#include "fileSpec.h"
|
||||||
|
#include "get_tinyxml.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Class : P3DPatchFinder
|
||||||
|
// Description : This class is used to reconstruct the patch
|
||||||
|
// chain--the chain of patch files needed to generate a
|
||||||
|
// file--for downloading a package via patches, rather
|
||||||
|
// than downloading the entire file.
|
||||||
|
//
|
||||||
|
// It is similar to PatchMaker.py, except it only reads
|
||||||
|
// patches, it does not generate them.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
class P3DPatchFinder {
|
||||||
|
public:
|
||||||
|
class Package;
|
||||||
|
class Patchfile;
|
||||||
|
|
||||||
|
typedef vector<Patchfile *> Patchfiles;
|
||||||
|
|
||||||
|
// This class is used to index into a map to locate PackageVersion
|
||||||
|
// objects, below.
|
||||||
|
class PackageVersionKey {
|
||||||
|
public:
|
||||||
|
PackageVersionKey(const string &package_name,
|
||||||
|
const string &platform,
|
||||||
|
const string &version,
|
||||||
|
const string &host_url,
|
||||||
|
const FileSpec &file);
|
||||||
|
bool operator < (const PackageVersionKey &other) const;
|
||||||
|
void output(ostream &out) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
string _package_name;
|
||||||
|
string _platform;
|
||||||
|
string _version;
|
||||||
|
string _host_url;
|
||||||
|
FileSpec _file;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A specific version of a package. This is not just a package's
|
||||||
|
// "version" string; it also corresponds to the particular patch
|
||||||
|
// version, which increments independently of the "version".
|
||||||
|
class PackageVersion {
|
||||||
|
public:
|
||||||
|
PackageVersion(const PackageVersionKey &key);
|
||||||
|
|
||||||
|
bool get_patch_chain(Patchfiles &chain, PackageVersion *start_pv);
|
||||||
|
|
||||||
|
public:
|
||||||
|
string _package_name;
|
||||||
|
string _platform;
|
||||||
|
string _version;
|
||||||
|
string _host_url;
|
||||||
|
FileSpec _file;
|
||||||
|
string _print_name;
|
||||||
|
|
||||||
|
// The Package object that produces this version if this is the
|
||||||
|
// current form or the base form, respectively.
|
||||||
|
Package *_package_current;
|
||||||
|
Package *_package_base;
|
||||||
|
|
||||||
|
// A list of patchfiles that can produce this version.
|
||||||
|
Patchfiles _from_patches;
|
||||||
|
|
||||||
|
// A list of patchfiles that can start from this version.
|
||||||
|
Patchfiles _to_patches;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A single patchfile for a package.
|
||||||
|
class Patchfile {
|
||||||
|
public:
|
||||||
|
Patchfile(Package *package);
|
||||||
|
|
||||||
|
PackageVersionKey get_source_key() const;
|
||||||
|
PackageVersionKey get_target_key() const;
|
||||||
|
void load_xml(TiXmlElement *xpatch);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Package *_package;
|
||||||
|
string _package_name;
|
||||||
|
string _platform;
|
||||||
|
string _version;
|
||||||
|
string _host_url;
|
||||||
|
|
||||||
|
// The patchfile itself
|
||||||
|
FileSpec _file;
|
||||||
|
|
||||||
|
// The package file that the patch is applied to
|
||||||
|
FileSpec _source_file;
|
||||||
|
|
||||||
|
// The package file that the patch generates
|
||||||
|
FileSpec _target_file;
|
||||||
|
|
||||||
|
// The PackageVersion corresponding to our source_file
|
||||||
|
PackageVersion *_from_pv;
|
||||||
|
|
||||||
|
// The PackageVersion corresponding to our target_file
|
||||||
|
PackageVersion *_to_pv;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is a particular package. This contains all of the
|
||||||
|
// information extracted from the package's desc file.
|
||||||
|
class Package {
|
||||||
|
public:
|
||||||
|
Package();
|
||||||
|
|
||||||
|
PackageVersionKey get_current_key() const;
|
||||||
|
PackageVersionKey get_base_key() const;
|
||||||
|
PackageVersionKey get_generic_key(const FileSpec &file) const;
|
||||||
|
|
||||||
|
bool read_desc_file(TiXmlDocument *doc);
|
||||||
|
|
||||||
|
public:
|
||||||
|
string _package_name;
|
||||||
|
string _platform;
|
||||||
|
string _version;
|
||||||
|
string _host_url;
|
||||||
|
|
||||||
|
PackageVersion *_current_pv;
|
||||||
|
PackageVersion *_base_pv;
|
||||||
|
|
||||||
|
FileSpec _current_file;
|
||||||
|
FileSpec _base_file;
|
||||||
|
bool _got_base_file;
|
||||||
|
|
||||||
|
Patchfiles _patches;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
P3DPatchFinder();
|
||||||
|
~P3DPatchFinder();
|
||||||
|
|
||||||
|
bool get_patch_chain_to_current(Patchfiles &chain, TiXmlDocument *doc,
|
||||||
|
const FileSpec &file);
|
||||||
|
|
||||||
|
Package *read_package_desc_file(TiXmlDocument *doc);
|
||||||
|
void build_patch_chains();
|
||||||
|
PackageVersion *get_package_version(const PackageVersionKey &key);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void record_patchfile(Patchfile *patchfile);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef map<PackageVersionKey, PackageVersion *> PackageVersions;
|
||||||
|
PackageVersions _package_versions;
|
||||||
|
|
||||||
|
typedef vector<Package *> Packages;
|
||||||
|
Packages _packages;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "p3dPatchFinder.I"
|
||||||
|
|
||||||
|
inline ostream &operator << (ostream &out, const P3DPatchFinder::PackageVersionKey &key) {
|
||||||
|
key.output(out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -17,6 +17,7 @@
|
|||||||
#include "p3dObject.cxx"
|
#include "p3dObject.cxx"
|
||||||
#include "p3dOsxSplashWindow.cxx"
|
#include "p3dOsxSplashWindow.cxx"
|
||||||
#include "p3dPackage.cxx"
|
#include "p3dPackage.cxx"
|
||||||
|
#include "p3dPatchFinder.cxx"
|
||||||
#include "p3dPythonObject.cxx"
|
#include "p3dPythonObject.cxx"
|
||||||
#include "p3dReferenceCount.cxx"
|
#include "p3dReferenceCount.cxx"
|
||||||
#include "p3dSession.cxx"
|
#include "p3dSession.cxx"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user