per_platform flag, giving better compatibility with old p3d files

This commit is contained in:
David Rose 2012-09-28 20:26:22 +00:00
parent 526159f961
commit a737ebcc90
19 changed files with 247 additions and 89 deletions

View File

@ -104,6 +104,7 @@ class AppRunner(DirectObject):
self.interactiveConsole = False self.interactiveConsole = False
self.initialAppImport = False self.initialAppImport = False
self.trueFileIO = False self.trueFileIO = False
self.respectPerPlatform = None
self.verifyContents = self.P3DVCNone self.verifyContents = self.P3DVCNone
@ -493,7 +494,7 @@ class AppRunner(DirectObject):
hostData = InstalledHostData(host, dirnode) hostData = InstalledHostData(host, dirnode)
if host: if host:
for package in host.getAllPackages(): for package in host.getAllPackages(includeAllPlatforms = True):
packageDir = package.getPackageDir() packageDir = package.getPackageDir()
if not packageDir.exists(): if not packageDir.exists():
continue continue
@ -781,7 +782,7 @@ class AppRunner(DirectObject):
self.deferredEvals = [] self.deferredEvals = []
def setInstanceInfo(self, rootDir, logDirectory, superMirrorUrl, def setInstanceInfo(self, rootDir, logDirectory, superMirrorUrl,
verifyContents, main): verifyContents, main, respectPerPlatform):
""" Called by the browser to set some global information about """ Called by the browser to set some global information about
the instance. """ the instance. """
@ -807,6 +808,9 @@ class AppRunner(DirectObject):
if main is not None: if main is not None:
self.main = main self.main = main
self.respectPerPlatform = respectPerPlatform
#self.notify.info("respectPerPlatform = %s" % (self.respectPerPlatform))
# Now that we have rootDir, we can read the config file. # Now that we have rootDir, we can read the config file.
self.readConfigXml() self.readConfigXml()

View File

@ -28,9 +28,16 @@ class HostInfo:
there. At the moment, mirror folders do not download old there. At the moment, mirror folders do not download old
patch files from the server. patch files from the server.
perPlatform remains for historical reasons, but it is ignored. If you pass perPlatform = True, then files are unpacked into a
Nowadays, all files are always unpacked into platform-specific platform-specific directory, which is appropriate when you
directories, even on the client. """ might be downloading multiple platforms. The default is
perPlatform = False, which means all files are unpacked into
the host directory directly, without an intervening
platform-specific directory name. If asMirror is True, then
the default is perPlatform = True.
Note that perPlatform is also restricted by the individual
package's specification. """
assert appRunner or rootDir or hostDir assert appRunner or rootDir or hostDir
@ -45,7 +52,9 @@ class HostInfo:
self.hostDir = hostDir self.hostDir = hostDir
self.asMirror = asMirror self.asMirror = asMirror
self.perPlatform = True self.perPlatform = perPlatform
if perPlatform is None:
self.perPlatform = asMirror
# Initially false, this is set true when the contents file is # Initially false, this is set true when the contents file is
# successfully read. # successfully read.
@ -372,8 +381,12 @@ class HostInfo:
solo = int(xpackage.Attribute('solo') or '') solo = int(xpackage.Attribute('solo') or '')
except ValueError: except ValueError:
solo = False solo = False
try:
perPlatform = int(xpackage.Attribute('per_platform') or '')
except ValueError:
perPlatform = False
package = self.__makePackage(name, platform, version, solo) package = self.__makePackage(name, platform, version, solo, perPlatform)
package.descFile = FileSpec() package.descFile = FileSpec()
package.descFile.loadXml(xpackage) package.descFile.loadXml(xpackage)
package.setupFilenames() package.setupFilenames()
@ -493,7 +506,7 @@ class HostInfo:
self.altHosts[keyword] = url self.altHosts[keyword] = url
xalthost = xalthost.NextSiblingElement('alt_host') xalthost = xalthost.NextSiblingElement('alt_host')
def __makePackage(self, name, platform, version, solo): def __makePackage(self, name, platform, version, solo, perPlatform):
""" Creates a new PackageInfo entry for the given name, """ Creates a new PackageInfo entry for the given name,
version, and platform. If there is already a matching version, and platform. If there is already a matching
PackageInfo, returns it. """ PackageInfo, returns it. """
@ -507,7 +520,8 @@ class HostInfo:
package = platforms.get(platform, None) package = platforms.get(platform, None)
if not package: if not package:
package = PackageInfo(self, name, version, platform = platform, package = PackageInfo(self, name, version, platform = platform,
solo = solo, asMirror = self.asMirror) solo = solo, asMirror = self.asMirror,
perPlatform = perPlatform)
platforms[platform] = package platforms[platform] = package
return package return package
@ -560,7 +574,7 @@ class HostInfo:
return packages return packages
def getAllPackages(self): def getAllPackages(self, includeAllPlatforms = False):
""" Returns a list of all available packages provided by this """ Returns a list of all available packages provided by this
host. """ host. """
@ -569,7 +583,7 @@ class HostInfo:
items = self.packages.items() items = self.packages.items()
items.sort() items.sort()
for key, platforms in items: for key, platforms in items:
if self.perPlatform: if self.perPlatform or includeAllPlatforms:
# If we maintain a different answer per platform, # If we maintain a different answer per platform,
# return all of them. # return all of them.
pitems = platforms.items() pitems = platforms.items()

View File

@ -78,13 +78,14 @@ class PackageInfo:
return min(float(self.bytesDone) / float(self.bytesNeeded), 1) return min(float(self.bytesDone) / float(self.bytesNeeded), 1)
def __init__(self, host, packageName, packageVersion, platform = None, def __init__(self, host, packageName, packageVersion, platform = None,
solo = False, asMirror = False): solo = False, asMirror = False, perPlatform = False):
self.host = host self.host = host
self.packageName = packageName self.packageName = packageName
self.packageVersion = packageVersion self.packageVersion = packageVersion
self.platform = platform self.platform = platform
self.solo = solo self.solo = solo
self.asMirror = asMirror self.asMirror = asMirror
self.perPlatform = perPlatform
# This will be active while we are in the middle of a download # This will be active while we are in the middle of a download
# cycle. # cycle.
@ -144,11 +145,22 @@ class PackageInfo:
self.packageDir = Filename(self.packageDir, self.packageVersion) self.packageDir = Filename(self.packageDir, self.packageVersion)
if self.host.perPlatform: if self.host.perPlatform:
# The server directory contains the platform name, # If we're running on a special host that wants us to
# though the client directory normally doesn't (unless # include the platform, we include it.
# perPlatform is set true). includePlatform = True
elif self.perPlatform and self.host.appRunner.respectPerPlatform:
# Otherwise, if our package spec wants us to include
# the platform (and our plugin knows about this), then
# we also include it.
includePlatform = True
else:
# Otherwise, we must be running legacy code
# somewhere--either an old package or an old
# plugin--and we therefore shouldn't include the
# platform in the directory hierarchy.
includePlatform = False
if self.platform: if includePlatform and self.platform:
self.packageDir = Filename(self.packageDir, self.platform) self.packageDir = Filename(self.packageDir, self.platform)
return self.packageDir return self.packageDir
@ -346,6 +358,13 @@ class PackageInfo:
except ValueError: except ValueError:
self.patchVersion = None self.patchVersion = None
try:
perPlatform = int(xpackage.Attribute('per_platform') or '')
except ValueError:
perPlatform = False
if perPlatform != self.perPlatform:
self.notify.warning("per_platform disagreement on package %s" % (self.packageName))
self.displayName = None self.displayName = None
xconfig = xpackage.FirstChildElement('config') xconfig = xpackage.FirstChildElement('config')
if xconfig: if xconfig:

View File

@ -41,6 +41,8 @@ class PackageMerger:
self.version = xpackage.Attribute('version') self.version = xpackage.Attribute('version')
solo = xpackage.Attribute('solo') solo = xpackage.Attribute('solo')
self.solo = int(solo or '0') self.solo = int(solo or '0')
perPlatform = xpackage.Attribute('per_platform')
self.perPlatform = int(perPlatform or '0')
self.descFile = FileSpec() self.descFile = FileSpec()
self.descFile.loadXml(xpackage) self.descFile.loadXml(xpackage)
@ -71,6 +73,8 @@ class PackageMerger:
xpackage.SetAttribute('version', self.version) xpackage.SetAttribute('version', self.version)
if self.solo: if self.solo:
xpackage.SetAttribute('solo', '1') xpackage.SetAttribute('solo', '1')
if self.perPlatform:
xpackage.SetAttribute('per_platform', '1')
self.descFile.storeXml(xpackage) self.descFile.storeXml(xpackage)
self.packageSeq.storeXml(xpackage, 'seq') self.packageSeq.storeXml(xpackage, 'seq')

View File

@ -187,12 +187,13 @@ class Packager:
objects uniquely per package. """ objects uniquely per package. """
return (self.packageName, self.platform, self.version) return (self.packageName, self.platform, self.version)
def fromFile(self, packageName, platform, version, solo, def fromFile(self, packageName, platform, version, solo, perPlatform,
installDir, descFilename, importDescFilename): installDir, descFilename, importDescFilename):
self.packageName = packageName self.packageName = packageName
self.platform = platform self.platform = platform
self.version = version self.version = version
self.solo = solo self.solo = solo
self.perPlatform = perPlatform
self.descFile = FileSpec() self.descFile = FileSpec()
self.descFile.fromFile(installDir, descFilename) self.descFile.fromFile(installDir, descFilename)
@ -208,6 +209,8 @@ class Packager:
self.version = xpackage.Attribute('version') self.version = xpackage.Attribute('version')
solo = xpackage.Attribute('solo') solo = xpackage.Attribute('solo')
self.solo = int(solo or '0') self.solo = int(solo or '0')
perPlatform = xpackage.Attribute('per_platform')
self.perPlatform = int(perPlatform or '0')
self.packageSeq = SeqValue() self.packageSeq = SeqValue()
self.packageSeq.loadXml(xpackage, 'seq') self.packageSeq.loadXml(xpackage, 'seq')
@ -235,6 +238,8 @@ class Packager:
xpackage.SetAttribute('version', self.version) xpackage.SetAttribute('version', self.version)
if self.solo: if self.solo:
xpackage.SetAttribute('solo', '1') xpackage.SetAttribute('solo', '1')
if self.perPlatform:
xpackage.SetAttribute('per_platform', '1')
self.packageSeq.storeXml(xpackage, 'seq') self.packageSeq.storeXml(xpackage, 'seq')
self.packageSetVer.storeXml(xpackage, 'set_ver') self.packageSetVer.storeXml(xpackage, 'set_ver')
@ -322,6 +327,9 @@ class Packager:
# platform-specific. # platform-specific.
self.platform = None self.platform = None
# This is always true on modern packages.
self.perPlatform = True
# The arch string, though, is pre-loaded from the system # The arch string, though, is pre-loaded from the system
# arch string, so we can sensibly call otool. # arch string, so we can sensibly call otool.
self.arch = self.packager.arch self.arch = self.packager.arch
@ -722,6 +730,7 @@ class Packager:
else: else:
self.readDescFile() self.readDescFile()
self.packageSeq += 1 self.packageSeq += 1
self.perPlatform = True # always true on modern packages.
self.compressMultifile() self.compressMultifile()
self.writeDescFile() self.writeDescFile()
self.writeImportDescFile() self.writeImportDescFile()
@ -734,7 +743,7 @@ class Packager:
# Replace or add the entry in the contents. # Replace or add the entry in the contents.
pe = Packager.PackageEntry() pe = Packager.PackageEntry()
pe.fromFile(self.packageName, self.platform, self.version, pe.fromFile(self.packageName, self.platform, self.version,
False, self.packager.installDir, False, self.perPlatform, self.packager.installDir,
self.packageDesc, self.packageImportDesc) self.packageDesc, self.packageImportDesc)
pe.packageSeq = self.packageSeq pe.packageSeq = self.packageSeq
pe.packageSetVer = self.packageSetVer pe.packageSetVer = self.packageSetVer
@ -753,6 +762,7 @@ class Packager:
kinds of similar "solo" packages as well. """ kinds of similar "solo" packages as well. """
self.considerPlatform() self.considerPlatform()
self.perPlatform = False # Not true on "solo" packages.
packageDir = self.packageName packageDir = self.packageName
if self.platform: if self.platform:
@ -798,7 +808,7 @@ class Packager:
# Replace or add the entry in the contents. # Replace or add the entry in the contents.
pe = Packager.PackageEntry() pe = Packager.PackageEntry()
pe.fromFile(self.packageName, self.platform, self.version, pe.fromFile(self.packageName, self.platform, self.version,
True, self.packager.installDir, True, self.perPlatform, self.packager.installDir,
Filename(packageDir, file.newName), None) Filename(packageDir, file.newName), None)
peOrig = self.packager.contents.get(pe.getKey(), None) peOrig = self.packager.contents.get(pe.getKey(), None)
if peOrig: if peOrig:
@ -1509,6 +1519,9 @@ class Packager:
if not xpackage: if not xpackage:
return return
perPlatform = xpackage.Attribute('per_platform')
self.perPlatform = int(perPlatform or '0')
self.packageSeq.loadXml(xpackage, 'seq') self.packageSeq.loadXml(xpackage, 'seq')
self.packageSetVer.loadXml(xpackage, 'set_ver') self.packageSetVer.loadXml(xpackage, 'set_ver')
@ -1554,6 +1567,8 @@ class Packager:
xpackage.SetAttribute('platform', self.platform) xpackage.SetAttribute('platform', self.platform)
if self.version: if self.version:
xpackage.SetAttribute('version', self.version) xpackage.SetAttribute('version', self.version)
if self.perPlatform:
xpackage.SetAttribute('per_platform', '1')
if self.patchVersion: if self.patchVersion:
xpackage.SetAttribute('last_patch_version', self.patchVersion) xpackage.SetAttribute('last_patch_version', self.patchVersion)

View File

@ -70,6 +70,7 @@
p3dX11SplashWindow.h p3dX11SplashWindow.I \ p3dX11SplashWindow.h p3dX11SplashWindow.I \
p3dWindowParams.h p3dWindowParams.I \ p3dWindowParams.h p3dWindowParams.I \
plugin_get_x11.h \ plugin_get_x11.h \
xml_helpers.h \
run_p3dpython.h run_p3dpython.h
#define COREAPI_INCLUDED_SOURCES \ #define COREAPI_INCLUDED_SOURCES \
@ -104,7 +105,8 @@
p3dUndefinedObject.cxx \ p3dUndefinedObject.cxx \
p3dWinSplashWindow.cxx \ p3dWinSplashWindow.cxx \
p3dX11SplashWindow.cxx \ p3dX11SplashWindow.cxx \
p3dWindowParams.cxx p3dWindowParams.cxx \
xml_helpers.cxx
#begin lib_target #begin lib_target

View File

@ -89,26 +89,36 @@ set_p3d_url(const string &p3d_url) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::set_tokens // Function: P3DFileParams::set_tokens
// Access: Public // Access: Public
// Description: Specifies the tokens associated with the instance. // Description: Replaces all the tokens associated with the instance.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void P3DFileParams:: void P3DFileParams::
set_tokens(const P3D_token tokens[], size_t num_tokens) { set_tokens(const P3D_token tokens[], size_t num_tokens) {
_tokens.clear(); _tokens.clear();
for (size_t i = 0; i < num_tokens; ++i) { for (size_t i = 0; i < num_tokens; ++i) {
set_token(tokens[i]._keyword, tokens[i]._value);
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DFileParams::set_token
// Access: Public
// Description: Sets an individual token value.
////////////////////////////////////////////////////////////////////
void P3DFileParams::
set_token(const char *keyword, const char *value) {
Token token; Token token;
if (tokens[i]._keyword != NULL) { if (keyword != NULL) {
// Make the token lowercase, since HTML is case-insensitive but // Make the token lowercase, since HTML is case-insensitive but
// we're not. // we're not.
for (const char *p = tokens[i]._keyword; *p; ++p) { for (const char *p = keyword; *p; ++p) {
token._keyword += tolower(*p); token._keyword += tolower(*p);
} }
} }
if (tokens[i]._value != NULL) { if (value != NULL) {
token._value = tokens[i]._value; token._value = value;
} }
_tokens.push_back(token); _tokens.push_back(token);
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -34,6 +34,7 @@ public:
void set_p3d_offset(const int &p3d_offset); void set_p3d_offset(const int &p3d_offset);
void set_p3d_url(const string &p3d_url); void set_p3d_url(const string &p3d_url);
void set_tokens(const P3D_token tokens[], size_t num_tokens); void set_tokens(const P3D_token tokens[], size_t num_tokens);
void set_token(const char *keyword, const char *value);
void set_args(int argc, const char *argv[]); void set_args(int argc, const char *argv[]);
inline const string &get_p3d_filename() const; inline const string &get_p3d_filename() const;

View File

@ -17,6 +17,7 @@
#include "p3dPackage.h" #include "p3dPackage.h"
#include "mkdir_complete.h" #include "mkdir_complete.h"
#include "wstring_encode.h" #include "wstring_encode.h"
#include "xml_helpers.h"
#include "openssl/md5.h" #include "openssl/md5.h"
#include <algorithm> #include <algorithm>
@ -445,12 +446,15 @@ get_package(const string &package_name, const string &package_version,
// Function: P3DHost::choose_suitable_platform // Function: P3DHost::choose_suitable_platform
// Access: Public // Access: Public
// Description: Chooses the most appropriate platform for the // Description: Chooses the most appropriate platform for the
// indicated package (presumably the "panda3d" package), // indicated package based on what this hardware
// based on what this hardware supports and what is // supports and what is actually available. Also fills
// actually available. // in per_platform, which is a boolean value indicating
// whether the directory structure contains the platform
// directory or not.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool P3DHost:: bool P3DHost::
choose_suitable_platform(string &selected_platform, choose_suitable_platform(string &selected_platform,
bool &per_platform,
const string &package_name, const string &package_name,
const string &package_version, const string &package_version,
const string &package_platform) { const string &package_platform) {
@ -482,6 +486,7 @@ choose_suitable_platform(string &selected_platform,
package_version == version) { package_version == version) {
// Here's the matching package definition. // Here's the matching package definition.
selected_platform = platform; selected_platform = platform;
per_platform = parse_bool_attrib(xpackage, "per_platform", false);
return true; return true;
} }
@ -490,7 +495,7 @@ choose_suitable_platform(string &selected_platform,
} }
} }
// Now, we look for an exact match for the current platform. // Now, we look for an exact match for the expected platform.
xpackage = _xcontents->FirstChildElement("package"); xpackage = _xcontents->FirstChildElement("package");
while (xpackage != NULL) { while (xpackage != NULL) {
const char *name = xpackage->Attribute("name"); const char *name = xpackage->Attribute("name");
@ -505,13 +510,15 @@ choose_suitable_platform(string &selected_platform,
package_version == version) { package_version == version) {
// Here's the matching package definition. // Here's the matching package definition.
selected_platform = platform; selected_platform = platform;
per_platform = parse_bool_attrib(xpackage, "per_platform", false);
return true; return true;
} }
xpackage = xpackage->NextSiblingElement("package"); xpackage = xpackage->NextSiblingElement("package");
} }
// Look again, this time looking for a non-platform-specific version. // Look one more time, this time looking for a non-platform-specific
// version.
xpackage = _xcontents->FirstChildElement("package"); xpackage = _xcontents->FirstChildElement("package");
while (xpackage != NULL) { while (xpackage != NULL) {
const char *name = xpackage->Attribute("name"); const char *name = xpackage->Attribute("name");
@ -528,6 +535,7 @@ choose_suitable_platform(string &selected_platform,
*platform == '\0' && *platform == '\0' &&
package_version == version) { package_version == version) {
selected_platform = platform; selected_platform = platform;
per_platform = parse_bool_attrib(xpackage, "per_platform", false);
return true; return true;
} }
@ -561,8 +569,9 @@ get_package_desc_file(FileSpec &desc_file, // out
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
// Scan the contents data for the indicated package. First, we look // Scan the contents data for the indicated package. We expect to
// for a platform-specific version. // match the platform precisely, because we previously called
// choose_suitable_platform().
TiXmlElement *xpackage = _xcontents->FirstChildElement("package"); TiXmlElement *xpackage = _xcontents->FirstChildElement("package");
while (xpackage != NULL) { while (xpackage != NULL) {
const char *name = xpackage->Attribute("name"); const char *name = xpackage->Attribute("name");
@ -593,40 +602,6 @@ get_package_desc_file(FileSpec &desc_file, // out
xpackage = xpackage->NextSiblingElement("package"); xpackage = xpackage->NextSiblingElement("package");
} }
// Look again, this time looking for a non-platform-specific version.
xpackage = _xcontents->FirstChildElement("package");
while (xpackage != NULL) {
const char *name = xpackage->Attribute("name");
const char *platform = xpackage->Attribute("platform");
const char *version = xpackage->Attribute("version");
const char *seq = xpackage->Attribute("seq");
const char *solo = xpackage->Attribute("solo");
if (platform == NULL) {
platform = "";
}
if (version == NULL) {
version = "";
}
if (seq == NULL) {
seq = "";
}
if (name != NULL &&
package_name == name &&
*platform == '\0' &&
package_version == version) {
// Here's the matching package definition.
desc_file.load_xml(xpackage);
package_seq = seq;
package_solo = false;
if (solo != NULL) {
package_solo = (atoi(solo) != 0);
}
return true;
}
xpackage = xpackage->NextSiblingElement("package");
}
// Couldn't find the named package. // Couldn't find the named package.
return false; return false;
} }

View File

@ -58,6 +58,7 @@ public:
const string &package_seq, const string &package_seq,
const string &alt_host = ""); const string &alt_host = "");
bool choose_suitable_platform(string &selected_platform, bool choose_suitable_platform(string &selected_platform,
bool &per_platform,
const string &package_name, const string &package_name,
const string &package_version, const string &package_version,
const string &package_platform); const string &package_platform);

View File

@ -1366,10 +1366,15 @@ make_xml() {
xinstance->SetAttribute("log_directory", inst_mgr->get_log_directory()); xinstance->SetAttribute("log_directory", inst_mgr->get_log_directory());
xinstance->SetAttribute("verify_contents", (int)inst_mgr->get_verify_contents()); xinstance->SetAttribute("verify_contents", (int)inst_mgr->get_verify_contents());
// Tell the Panda process that it was started by a plugin that knows
// about the new per_platform flag.
xinstance->SetAttribute("respect_per_platform", 1);
if (!inst_mgr->get_super_mirror().empty()) { if (!inst_mgr->get_super_mirror().empty()) {
xinstance->SetAttribute("super_mirror", inst_mgr->get_super_mirror()); xinstance->SetAttribute("super_mirror", inst_mgr->get_super_mirror());
} }
TiXmlElement *xfparams = _fparams.make_xml(); TiXmlElement *xfparams = _fparams.make_xml();
xinstance->LinkEndChild(xfparams); xinstance->LinkEndChild(xfparams);

View File

@ -300,6 +300,12 @@ initialize(int api_version, const string &contents_filename,
} }
} }
nout << "Supported platforms:";
for (size_t pi = 0; pi < _supported_platforms.size(); ++pi) {
nout << " " << _supported_platforms[pi];
}
nout << "\n";
return true; return true;
} }

View File

@ -674,7 +674,7 @@ read_log_file(const string &log_pathname,
log.seekg(0, ios::beg); log.seekg(0, ios::beg);
log.read(buffer, full_bytes); log.read(buffer, full_bytes);
streamsize read_bytes = log.gcount(); streamsize read_bytes = log.gcount();
assert(read_bytes < buffer_bytes); assert(read_bytes < (streamsize)buffer_bytes);
buffer[read_bytes] = '\0'; buffer[read_bytes] = '\0';
log_data << "== PandaLog-" << "Full Start"; log_data << "== PandaLog-" << "Full Start";
log_data << " " << "(" << log_leafname << ")" << "\n"; log_data << " " << "(" << log_leafname << ")" << "\n";
@ -688,7 +688,7 @@ read_log_file(const string &log_pathname,
log.seekg(0, ios::beg); log.seekg(0, ios::beg);
log.read(buffer, head_bytes); log.read(buffer, head_bytes);
streamsize read_bytes = log.gcount(); streamsize read_bytes = log.gcount();
assert(read_bytes < buffer_bytes); assert(read_bytes < (streamsize)buffer_bytes);
buffer[read_bytes] = '\0'; buffer[read_bytes] = '\0';
log_data << "== PandaLog-" << "Head Start"; log_data << "== PandaLog-" << "Head Start";
log_data << " " << "(" << log_leafname << ")" << "\n"; log_data << " " << "(" << log_leafname << ")" << "\n";
@ -708,7 +708,7 @@ read_log_file(const string &log_pathname,
log.seekg(file_size - tail_bytes, ios::beg); log.seekg(file_size - tail_bytes, ios::beg);
log.read(buffer, tail_bytes); log.read(buffer, tail_bytes);
streamsize read_bytes = log.gcount(); streamsize read_bytes = log.gcount();
assert(read_bytes < buffer_bytes); assert(read_bytes < (streamsize)buffer_bytes);
buffer[read_bytes] = '\0'; buffer[read_bytes] = '\0';
log_data << "== PandaLog-" << "Tail Start"; log_data << "== PandaLog-" << "Tail Start";
log_data << " " << "(" << log_leafname << ")" << "\n"; log_data << " " << "(" << log_leafname << ")" << "\n";

View File

@ -52,10 +52,8 @@ P3DPackage(P3DHost *host, const string &package_name,
_package_platform(package_platform), _package_platform(package_platform),
_alt_host(alt_host) _alt_host(alt_host)
{ {
_package_fullname = _package_name; set_fullname();
if (!_package_version.empty()) { _per_platform = false;
_package_fullname += string(".") + _package_version;
}
_patch_version = 0; _patch_version = 0;
// This is set true if the package is a "solo", i.e. a single // This is set true if the package is a "solo", i.e. a single
@ -638,24 +636,28 @@ host_got_contents_file() {
// provided. // provided.
assert(_alt_host.empty()); assert(_alt_host.empty());
string new_platform; string new_platform;
if (_host->choose_suitable_platform(new_platform, _package_name, _package_version, _package_platform)) { if (_host->choose_suitable_platform(new_platform, _per_platform,
_package_name, _package_version, _package_platform)) {
if (new_platform != _package_platform) { if (new_platform != _package_platform) {
nout << "Migrating " << get_package_name() << " from platform \"" nout << "Migrating " << get_package_name() << " from platform \""
<< _package_platform << "\" to platform \"" << _package_platform << "\" to platform \""
<< new_platform << "\"\n"; << new_platform << "\"\n";
_package_platform = new_platform; _package_platform = new_platform;
set_fullname();
} }
} else { } else {
nout << "Couldn't find a platform for " << get_package_name() << ".\n"; nout << "Couldn't find a platform for " << get_package_name() << ".\n";
} }
nout << "_per_platform for " << get_package_name() << " = " << _per_platform << "\n";
// Now that we have a valid host and platform, we can define the // Now that we have a valid host and platform, we can define the
// _package_dir. // _package_dir.
_package_dir = _host->get_host_dir() + string("/") + _package_name; _package_dir = _host->get_host_dir() + string("/") + _package_name;
if (!_package_version.empty()) { if (!_package_version.empty()) {
_package_dir += string("/") + _package_version; _package_dir += string("/") + _package_version;
} }
if (!_package_platform.empty()) { if (_per_platform && !_package_platform.empty()) {
_package_dir += string("/") + _package_platform; _package_dir += string("/") + _package_platform;
} }
@ -686,7 +688,7 @@ download_desc_file() {
_package_name, _package_version, _package_name, _package_version,
_package_platform)) { _package_platform)) {
nout << "Couldn't find package " << _package_fullname nout << "Couldn't find package " << _package_fullname
<< "/" << _package_platform << " in contents file.\n"; << " in contents file.\n";
redownload_contents_file(NULL); redownload_contents_file(NULL);
return; return;
} }
@ -702,8 +704,8 @@ download_desc_file() {
} }
// The desc file might have a different path on the host server than // The desc file might have a different path on the host server than
// it has locally, because we strip out the platform directory // it has locally, because we might strip out the platform directory
// locally. // locally (according to _per_platform).
FileSpec local_desc_file = _desc_file; FileSpec local_desc_file = _desc_file;
local_desc_file.set_filename(_desc_file_basename); local_desc_file.set_filename(_desc_file_basename);
_desc_file_pathname = local_desc_file.get_pathname(_package_dir); _desc_file_pathname = local_desc_file.get_pathname(_package_dir);
@ -792,6 +794,16 @@ got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
return; return;
} }
bool per_platform = parse_bool_attrib(xpackage, "per_platform", false);
if (per_platform != _per_platform) {
nout << "Warning! per_platform disagreement for " << get_package_name()
<< "!\n";
// We don't do anything with this warning--the original value for
// _per_platform we got from the contents.xml file has to apply,
// because we're already committed to the _package_dir we're
// using.
}
xpackage->Attribute("patch_version", &_patch_version); xpackage->Attribute("patch_version", &_patch_version);
TiXmlElement *xconfig = xpackage->FirstChildElement("config"); TiXmlElement *xconfig = xpackage->FirstChildElement("config");
@ -1458,6 +1470,23 @@ instance_terminating(P3DInstance *instance) {
return true; return true;
} }
////////////////////////////////////////////////////////////////////
// Function: P3DPackage::set_fullname
// Access: Private
// Description: Assigns _package_fullname to the appropriate
// combination of name, version, and platform.
////////////////////////////////////////////////////////////////////
void P3DPackage::
set_fullname() {
_package_fullname = _package_name;
if (!_package_version.empty()) {
_package_fullname += string(".") + _package_version;
}
if (!_package_platform.empty()) {
_package_fullname += string(".") + _package_platform;
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DPackage::Download::Constructor // Function: P3DPackage::Download::Constructor
// Access: Public // Access: Public

View File

@ -241,6 +241,7 @@ private:
bool is_extractable(FileSpec &file, const string &filename) const; bool is_extractable(FileSpec &file, const string &filename) const;
bool instance_terminating(P3DInstance *instance); bool instance_terminating(P3DInstance *instance);
void set_fullname();
public: public:
class RequiredPackage { class RequiredPackage {
@ -264,6 +265,7 @@ private:
string _package_name; string _package_name;
string _package_version; string _package_version;
string _package_platform; string _package_platform;
bool _per_platform;
int _patch_version; int _patch_version;
string _alt_host; string _alt_host;
bool _package_solo; bool _package_solo;

View File

@ -1252,9 +1252,12 @@ set_instance_info(P3DCInstance *inst, TiXmlElement *xinstance) {
Py_INCREF(main); Py_INCREF(main);
} }
int respect_per_platform = 0;
xinstance->Attribute("respect_per_platform", &respect_per_platform);
PyObject *result = PyObject_CallMethod PyObject *result = PyObject_CallMethod
(_runner, (char *)"setInstanceInfo", (char *)"sssiO", root_dir, (_runner, (char *)"setInstanceInfo", (char *)"sssiOi", root_dir,
log_directory, super_mirror, verify_contents, main); log_directory, super_mirror, verify_contents, main, respect_per_platform);
Py_DECREF(main); Py_DECREF(main);
if (result == NULL) { if (result == NULL) {

View File

@ -30,3 +30,4 @@
#include "p3dWinSplashWindow.cxx" #include "p3dWinSplashWindow.cxx"
#include "p3dX11SplashWindow.cxx" #include "p3dX11SplashWindow.cxx"
#include "p3dWindowParams.cxx" #include "p3dWindowParams.cxx"
#include "xml_helpers.cxx"

View File

@ -0,0 +1,43 @@
// Filename: xml_helpers.cxx
// Created by: drose (28Sep12)
//
////////////////////////////////////////////////////////////////////
//
// 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 "p3d_plugin_common.h"
#include "xml_helpers.h"
////////////////////////////////////////////////////////////////////
// Function: parse_bool_attrib
// Description: Examines the indicated attrib from the XML attrib and
// returns its true or false value. Returns
// default_value if the attrib is not present or is
// empty.
////////////////////////////////////////////////////////////////////
bool
parse_bool_attrib(TiXmlElement *xelem, const string &attrib,
bool default_value) {
const char *value = xelem->Attribute(attrib.c_str());
if (value == NULL || *value == '\0') {
return default_value;
}
char *endptr;
int result = strtol(value, &endptr, 10);
if (*endptr == '\0') {
// A valid integer.
return (result != 0);
}
// An invalid integer.
return default_value;
}

24
direct/src/plugin/xml_helpers.h Executable file
View File

@ -0,0 +1,24 @@
// Filename: xml_helpers.h
// Created by: drose (28Sep12)
//
////////////////////////////////////////////////////////////////////
//
// 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 XML_HELPERS_H
#define XML_HELPERS_H
#include "get_tinyxml.h"
bool parse_bool_attrib(TiXmlElement *xelem, const string &attrib,
bool default_value);
#endif