mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -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
|
||||
|
||||
patchMaker = PatchMaker(self.packageDir)
|
||||
package = patchMaker.readPackageDescFile(self.descFileBasename)
|
||||
patchMaker.buildPatchChains()
|
||||
fromPv = patchMaker.getPackageVersion(package.getGenericKey(fileSpec))
|
||||
toPv = package.currentPv
|
||||
|
||||
patchChain = None
|
||||
if toPv and fromPv:
|
||||
patchChain = toPv.getPatchChain(fromPv)
|
||||
|
||||
patchChain = patchMaker.getPatchChainToCurrent(self.descFileBasename, fileSpec)
|
||||
if patchChain is None:
|
||||
# No path.
|
||||
patchMaker.cleanup()
|
||||
|
@ -10,15 +10,15 @@ class PatchMaker:
|
||||
|
||||
class PackageVersion:
|
||||
""" 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
|
||||
the "version". """
|
||||
|
||||
def __init__(self, packageName, platform, version, host, file):
|
||||
def __init__(self, packageName, platform, version, hostUrl, file):
|
||||
self.packageName = packageName
|
||||
self.platform = platform
|
||||
self.version = version
|
||||
self.host = host
|
||||
self.hostUrl = hostUrl
|
||||
self.file = file
|
||||
self.printName = None
|
||||
|
||||
@ -43,8 +43,8 @@ class PatchMaker:
|
||||
|
||||
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
|
||||
sequence to the indicated PackageVersion object, will
|
||||
produce this PackageVersion object. Returns None if no
|
||||
chain can be found. """
|
||||
|
||||
if self is startPv:
|
||||
@ -173,7 +173,7 @@ class PatchMaker:
|
||||
if patch.packageName == package.packageName and \
|
||||
patch.platform == package.platform and \
|
||||
patch.version == package.version and \
|
||||
patch.host == package.host:
|
||||
patch.hostUrl == package.hostUrl:
|
||||
return patch.toPv
|
||||
|
||||
return None
|
||||
@ -186,25 +186,49 @@ class PatchMaker:
|
||||
self.packageName = package.packageName
|
||||
self.platform = package.platform
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
""" Creates the data structures from an existing patchfile
|
||||
on disk. """
|
||||
|
||||
self.file = FileSpec()
|
||||
self.file.fromFile(packageDir, patchFilename)
|
||||
self.sourceFile = sourceFile
|
||||
self.targetFile = targetFile
|
||||
|
||||
def loadXml(self, xpatch):
|
||||
""" Reads the data structures from an xml file. """
|
||||
|
||||
self.packageName = xpatch.Attribute('name') or self.packageName
|
||||
self.platform = xpatch.Attribute('platform') or self.platform
|
||||
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.loadXml(xpatch)
|
||||
@ -228,8 +252,8 @@ class PatchMaker:
|
||||
xpatch.SetAttribute('platform', self.platform)
|
||||
if self.version != package.version:
|
||||
xpatch.SetAttribute('version', self.version)
|
||||
if self.host != package.host:
|
||||
xpatch.SetAttribute('host', self.host)
|
||||
if self.hostUrl != package.hostUrl:
|
||||
xpatch.SetAttribute('host', self.hostUrl)
|
||||
|
||||
self.file.storeXml(xpatch)
|
||||
|
||||
@ -259,7 +283,7 @@ class PatchMaker:
|
||||
self.packageName = None
|
||||
self.platform = None
|
||||
self.version = None
|
||||
self.host = None
|
||||
self.hostUrl = None
|
||||
self.currentFile = None
|
||||
self.baseFile = None
|
||||
|
||||
@ -268,18 +292,25 @@ class PatchMaker:
|
||||
self.patches = []
|
||||
|
||||
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):
|
||||
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):
|
||||
""" Returns the key that has the indicated FileSpec. """
|
||||
return (self.packageName, self.platform, self.version, self.host, fileSpec)
|
||||
""" Returns the key that has the indicated hash. """
|
||||
return (self.packageName, self.platform, self.version, self.hostUrl, fileSpec)
|
||||
|
||||
def readDescFile(self):
|
||||
""" Reads the existing package.xml file and stores
|
||||
it in this class for later rewriting. """
|
||||
""" Reads the existing package.xml file and stores it in
|
||||
this class for later rewriting. Returns true on success,
|
||||
false on failure. """
|
||||
|
||||
self.anyChanges = False
|
||||
|
||||
@ -287,11 +318,11 @@ class PatchMaker:
|
||||
self.doc = TiXmlDocument(packageDescFullpath.toOsSpecific())
|
||||
if not self.doc.LoadFile():
|
||||
print "Couldn't read %s" % (packageDescFullpath)
|
||||
return
|
||||
return False
|
||||
|
||||
xpackage = self.doc.FirstChildElement('package')
|
||||
if not xpackage:
|
||||
return
|
||||
return False
|
||||
self.packageName = xpackage.Attribute('name')
|
||||
self.platform = xpackage.Attribute('platform')
|
||||
self.version = xpackage.Attribute('version')
|
||||
@ -300,7 +331,7 @@ class PatchMaker:
|
||||
# "none" host. TODO: support patching from packages on
|
||||
# other hosts, which means we'll need to fill in a value
|
||||
# here for those hosts.
|
||||
self.host = None
|
||||
self.hostUrl = None
|
||||
|
||||
# Get the current patch version. If we have a
|
||||
# patch_version attribute, it refers to this particular
|
||||
@ -389,6 +420,8 @@ class PatchMaker:
|
||||
self.patches.append(patchfile)
|
||||
xpatch = xpatch.NextSiblingElement('patch')
|
||||
|
||||
return True
|
||||
|
||||
def writeDescFile(self):
|
||||
""" Rewrites the desc file with the new patch
|
||||
information. """
|
||||
@ -436,7 +469,7 @@ class PatchMaker:
|
||||
fileSpec.fromFile(self.patchMaker.installDir, self.packageDesc)
|
||||
fileSpec.storeXml(self.contentsDocPackage)
|
||||
|
||||
|
||||
# PatchMaker constructor.
|
||||
def __init__(self, installDir):
|
||||
self.installDir = installDir
|
||||
self.packageVersions = {}
|
||||
@ -468,15 +501,36 @@ class PatchMaker:
|
||||
for pv in self.packageVersions.values():
|
||||
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):
|
||||
""" Reads a desc file associated with a particular package,
|
||||
and adds the package to self.packageVersions. Returns the
|
||||
Package object. """
|
||||
and adds the package to self.packages. Returns the Package
|
||||
object, or None on failure. """
|
||||
|
||||
package = self.Package(Filename(descFilename), self)
|
||||
package.readDescFile()
|
||||
if not package.readDescFile():
|
||||
return None
|
||||
|
||||
self.packages.append(package)
|
||||
|
||||
return package
|
||||
|
||||
def readContentsFile(self):
|
||||
@ -522,10 +576,10 @@ class PatchMaker:
|
||||
""" Returns a shared PackageVersion object for the indicated
|
||||
key. """
|
||||
|
||||
packageName, platform, version, host, file = key
|
||||
packageName, platform, version, hostUrl, file = key
|
||||
|
||||
# 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)
|
||||
if not pv:
|
||||
pv = self.PackageVersion(*key)
|
||||
|
@ -48,6 +48,7 @@
|
||||
p3dObject.h p3dObject.I \
|
||||
p3dOsxSplashWindow.h p3dOsxSplashWindow.I \
|
||||
p3dPackage.h p3dPackage.I \
|
||||
p3dPatchFinder.h p3dPatchFinder.I \
|
||||
p3dPythonObject.h \
|
||||
p3dReferenceCount.h p3dReferenceCount.I \
|
||||
p3dSession.h p3dSession.I \
|
||||
@ -81,6 +82,7 @@
|
||||
p3dObject.cxx \
|
||||
p3dOsxSplashWindow.cxx \
|
||||
p3dPackage.cxx \
|
||||
p3dPatchFinder.cxx \
|
||||
p3dPythonObject.cxx \
|
||||
p3dReferenceCount.cxx \
|
||||
p3dSession.cxx \
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FileSpec::get_filename
|
||||
// Access: Private
|
||||
// Access: Public
|
||||
// Description: Returns the relative path to this file on disk,
|
||||
// within the package root directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -26,7 +26,7 @@ get_filename() const {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FileSpec::set_filename
|
||||
// Access: Private
|
||||
// Access: Public
|
||||
// Description: Changes the relative path to this file on disk,
|
||||
// within the package root directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -37,7 +37,7 @@ set_filename(const string &filename) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FileSpec::get_pathname
|
||||
// Access: Private
|
||||
// Access: Public
|
||||
// Description: Returns the full path to this file on disk.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline string FileSpec::
|
||||
@ -47,7 +47,7 @@ get_pathname(const string &package_dir) const {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FileSpec::get_size
|
||||
// Access: Private
|
||||
// Access: Public
|
||||
// Description: Returns the expected size of this file on disk, in
|
||||
// bytes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -56,6 +56,22 @@ get_size() const {
|
||||
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
|
||||
// Access: Private
|
||||
|
@ -17,9 +17,11 @@
|
||||
|
||||
#include <fstream>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sys/utime.h>
|
||||
@ -44,6 +46,7 @@ FileSpec() {
|
||||
_timestamp = 0;
|
||||
memset(_hash, 0, sizeof(_hash));
|
||||
_got_hash = false;
|
||||
_actual_file = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -59,6 +62,7 @@ FileSpec(const FileSpec ©) :
|
||||
_got_hash(copy._got_hash)
|
||||
{
|
||||
memcpy(_hash, copy._hash, sizeof(_hash));
|
||||
_actual_file = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -75,6 +79,18 @@ operator = (const FileSpec ©) {
|
||||
_got_hash = copy._got_hash;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FileSpec::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
FileSpec::
|
||||
~FileSpec() {
|
||||
if (_actual_file != NULL) {
|
||||
delete _actual_file;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FileSpec::load_xml
|
||||
// Access: Public
|
||||
@ -119,7 +135,12 @@ load_xml(TiXmlElement *xelement) {
|
||||
// redownloaded.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
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);
|
||||
struct stat st;
|
||||
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
|
||||
// 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.
|
||||
//cerr << "hash check wrong: " << _filename << "\n";
|
||||
return false;
|
||||
@ -174,7 +195,12 @@ quick_verify(const string &package_dir) const {
|
||||
// redownloaded.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
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);
|
||||
struct stat st;
|
||||
if (stat(pathname.c_str(), &st) != 0) {
|
||||
@ -188,7 +214,7 @@ full_verify(const string &package_dir) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_hash(pathname)) {
|
||||
if (!priv_check_hash(pathname, st)) {
|
||||
// Hard fail, the hash is wrong.
|
||||
//cerr << "hash check wrong: " << _filename << "\n";
|
||||
return false;
|
||||
@ -218,31 +244,12 @@ full_verify(const string &package_dir) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool FileSpec::
|
||||
check_hash(const string &pathname) const {
|
||||
ifstream stream(pathname.c_str(), ios::in | ios::binary);
|
||||
if (!stream) {
|
||||
//cerr << "unable to read " << pathname << "\n";
|
||||
FileSpec other;
|
||||
if (!other.read_hash(pathname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char md[hash_size];
|
||||
|
||||
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);
|
||||
return (memcmp(_hash, other._hash, hash_size) == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -280,6 +287,65 @@ read_hash(const string &pathname) {
|
||||
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
|
||||
// Access: Private, Static
|
||||
|
@ -31,6 +31,8 @@ public:
|
||||
FileSpec();
|
||||
FileSpec(const FileSpec ©);
|
||||
void operator = (const FileSpec ©);
|
||||
~FileSpec();
|
||||
|
||||
void load_xml(TiXmlElement *xelement);
|
||||
|
||||
inline const string &get_filename() const;
|
||||
@ -38,13 +40,19 @@ public:
|
||||
inline string get_pathname(const string &package_dir) const;
|
||||
inline size_t get_size() const;
|
||||
|
||||
bool quick_verify(const string &package_dir) const;
|
||||
bool full_verify(const string &package_dir) const;
|
||||
bool quick_verify(const string &package_dir);
|
||||
bool full_verify(const string &package_dir);
|
||||
inline const FileSpec *get_actual_file() const;
|
||||
|
||||
bool check_hash(const string &pathname) const;
|
||||
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:
|
||||
bool priv_check_hash(const string &pathname, const struct stat &st);
|
||||
static inline int decode_hexdigit(char c);
|
||||
static inline char encode_hexdigit(int c);
|
||||
|
||||
@ -59,6 +67,8 @@ private:
|
||||
time_t _timestamp;
|
||||
unsigned char _hash[hash_size];
|
||||
bool _got_hash;
|
||||
|
||||
FileSpec *_actual_file;
|
||||
};
|
||||
|
||||
#include "fileSpec.I"
|
||||
|
@ -1795,7 +1795,7 @@ report_package_info_ready(P3DPackage *package) {
|
||||
_download_package_index = 0;
|
||||
_total_downloaded = 0;
|
||||
|
||||
nout << "Beginning download of " << _downloading_packages.size()
|
||||
nout << "Beginning install of " << _downloading_packages.size()
|
||||
<< " packages, total " << _total_download_size
|
||||
<< " bytes required.\n";
|
||||
|
||||
@ -1844,7 +1844,7 @@ start_next_download() {
|
||||
_panda_script_object->set_int_property("downloadPackageSize", package->get_download_size());
|
||||
set_install_label("Installing " + name);
|
||||
|
||||
nout << "Downloading " << package->get_package_name()
|
||||
nout << "Installing " << package->get_package_name()
|
||||
<< ", package " << _download_package_index + 1
|
||||
<< " of " << _downloading_packages.size()
|
||||
<< ", " << package->get_download_size()
|
||||
@ -1999,7 +1999,7 @@ report_package_progress(P3DPackage *package, double progress) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
report_package_done(P3DPackage *package, bool success) {
|
||||
nout << "Done downloading " << package->get_package_name()
|
||||
nout << "Done installing " << package->get_package_name()
|
||||
<< ": success = " << success << "\n";
|
||||
|
||||
if (package == _image_package) {
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "p3dInstance.h"
|
||||
#include "p3dMultifileReader.h"
|
||||
#include "p3dTemporaryFile.h"
|
||||
#include "p3dPatchFinder.h"
|
||||
#include "mkdir_complete.h"
|
||||
|
||||
#include "zlib.h"
|
||||
@ -672,7 +673,7 @@ got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
|
||||
} else {
|
||||
// We need to get the file data still, but at least we know all
|
||||
// about it by this point.
|
||||
build_install_plans();
|
||||
build_install_plans(doc);
|
||||
|
||||
if (!_allow_data_download) {
|
||||
// Not authorized to start downloading yet; just report that
|
||||
@ -712,7 +713,7 @@ clear_install_plans() {
|
||||
// to download and install the package.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::
|
||||
build_install_plans() {
|
||||
build_install_plans(TiXmlDocument *doc) {
|
||||
clear_install_plans();
|
||||
|
||||
if (_instances.empty()) {
|
||||
@ -728,6 +729,8 @@ build_install_plans() {
|
||||
_install_plans.push_back(InstallPlan());
|
||||
InstallPlan &plan = _install_plans.back();
|
||||
|
||||
bool needs_redownload = false;
|
||||
|
||||
InstallStep *step;
|
||||
if (!_uncompressed_archive.quick_verify(_package_dir)) {
|
||||
// The uncompressed archive is no good.
|
||||
@ -735,6 +738,7 @@ build_install_plans() {
|
||||
if (!_compressed_archive.quick_verify(_package_dir)) {
|
||||
// The compressed archive is no good either. Download a new
|
||||
// compressed archive.
|
||||
needs_redownload = true;
|
||||
step = new InstallStepDownloadFile(this, _compressed_archive);
|
||||
plan.push_back(step);
|
||||
}
|
||||
@ -748,6 +752,35 @@ build_install_plans() {
|
||||
// Unpack the uncompressed archive.
|
||||
step = new InstallStepUnpackArchive(this, _unpack_size);
|
||||
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 clear_install_plans();
|
||||
void build_install_plans();
|
||||
void build_install_plans(TiXmlDocument *doc);
|
||||
void follow_install_plans(bool download_finished);
|
||||
|
||||
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 "p3dOsxSplashWindow.cxx"
|
||||
#include "p3dPackage.cxx"
|
||||
#include "p3dPatchFinder.cxx"
|
||||
#include "p3dPythonObject.cxx"
|
||||
#include "p3dReferenceCount.cxx"
|
||||
#include "p3dSession.cxx"
|
||||
|
Loading…
x
Reference in New Issue
Block a user