add audio libraries, and download transitive package requirements

This commit is contained in:
David Rose 2009-10-12 01:50:55 +00:00
parent 787bfc5f94
commit d7b2de8029
10 changed files with 258 additions and 73 deletions

View File

@ -238,16 +238,39 @@ class AppRunner(DirectObject):
packageName, version, hostUrl)
return False
return self.__rInstallPackage(package, [])
def __rInstallPackage(self, package, nested):
""" The recursive implementation of installPackage(). The new
parameter, nested, is a list of packages that we are
recursively calling this from, to avoid recursive loops. """
if not package.downloadDescFile(self.http):
return False
# Now that we've downloaded and read the desc file, we can
# install all of the required packages first.
nested = nested[:] + [self]
for packageName, version, host in package.requires:
if host.downloadContentsFile(self.http):
p2 = host.getPackage(packageName, version)
if not p2:
print "Couldn't find %s %s on %s" % (packageName, version, host.hostUrl)
else:
if p2 not in nested:
self.__rInstallPackage(p2, nested)
# Now that all of the required packages are installed, carry
# on to download and install this package.
if not package.downloadPackage(self.http):
return False
if not package.installPackage(self):
return False
print "Package %s %s installed." % (packageName, version)
print "Package %s %s installed." % (
package.packageName, package.packageVersion)
return True
def getHostWithAlt(self, hostUrl):
""" Returns a suitable HostInfo object for downloading
@ -290,7 +313,6 @@ class AppRunner(DirectObject):
mapped host, which is the one we should actually download
from, see getHostWithAlt(). """
if hostUrl is None:
hostUrl = PandaSystem.getPackageHostUrl()

View File

@ -79,6 +79,7 @@ class PackageInfo:
self.uncompressedArchive = None
self.compressedArchive = None
self.extracts = []
self.requires = []
self.installPlans = None
# This is updated during downloadPackage(). It is in the
@ -253,6 +254,7 @@ class PackageInfo:
self.compressedArchive.loadXml(xcompressedArchive)
# The list of files that should be extracted to disk.
self.extracts = []
xextract = xpackage.FirstChildElement('extract')
while xextract:
file = FileSpec()
@ -260,6 +262,19 @@ class PackageInfo:
self.extracts.append(file)
xextract = xextract.NextSiblingElement('extract')
# The list of additional packages that must be installed for
# this package to function properly.
self.requires = []
xrequires = xpackage.FirstChildElement('requires')
while xrequires:
packageName = xrequires.Attribute('name')
version = xrequires.Attribute('version')
hostUrl = xrequires.Attribute('host')
if packageName and hostUrl:
host = self.host.appRunner.getHostWithAlt(hostUrl)
self.requires.append((packageName, version, host))
xrequires = xrequires.NextSiblingElement('requires')
self.hasDescFile = True
# Now that we've read the desc file, go ahead and use it to

View File

@ -76,6 +76,13 @@ class PackageInstaller(DirectObject):
# getDescFile().
self.downloadEffort = 0
def __cmp__(self, pp):
""" Python comparision function. This makes all
PendingPackages withe same (packageName, version, host)
combination be deemed equivalent. """
return cmp((self.packageName, self.version, self.host),
(pp.packageName, pp.version, pp.host))
def getProgress(self):
""" Returns the download progress of this package in the
range 0..1. """
@ -230,16 +237,37 @@ class PackageInstaller(DirectObject):
self.packageLock.acquire()
try:
self.packages.append(pp)
if not pp.checkDescFile():
# Still need to download the desc file.
self.needsDescFile.append(pp)
if not self.descFileTask:
self.descFileTask = taskMgr.add(
self.__getDescFileTask, 'getDescFile',
taskChain = self.taskChain)
self.__internalAddPackage(pp)
finally:
self.packageLock.release()
elif not pp.package.hasPackage:
def __internalAddPackage(self, pp):
""" Adds the indicated "pending package" to the appropriate
list(s) for downloading and installing. Assumes packageLock
is already held."""
if pp in self.packages:
# Already added.
return
self.packages.append(pp)
if not pp.checkDescFile():
# Still need to download the desc file.
self.needsDescFile.append(pp)
if not self.descFileTask:
self.descFileTask = taskMgr.add(
self.__getDescFileTask, 'getDescFile',
taskChain = self.taskChain)
else:
# The desc file is ready, which means so are the requirements.
for packageName, version, host in pp.package.requires:
pp2 = self.PendingPackage(packageName, version, host)
self.__internalAddPackage(pp2)
# Now that we've added the required packages, add the
# package itself.
if not pp.package.hasPackage:
# The desc file is good, but the package itself needs
# to be downloaded.
self.needsDownload.append(pp)
@ -247,9 +275,6 @@ class PackageInstaller(DirectObject):
else:
# The package is already fully downloaded.
self.earlyDone.append(pp)
finally:
self.packageLock.release()
def donePackages(self):
""" After calling addPackage() for each package to be
@ -494,6 +519,10 @@ class PackageInstaller(DirectObject):
# This package is now ready to be downloaded.
self.packageLock.acquire()
try:
# Also add any packages required by this one.
for packageName, version, host in pp.package.requires:
pp2 = self.PendingPackage(packageName, version, host)
self.__internalAddPackage(pp2)
self.needsDownload.append(pp)
finally:
self.packageLock.release()

View File

@ -1545,15 +1545,15 @@ class Packager:
def requirePackage(self, package):
""" Indicates a dependency on the given package. This
also implicitly requires all of the package's requirements
as well. """
as well (though this transitive requirement happens at
runtime, not here at build time). """
for p2 in package.requires + [package]:
if p2 not in self.requires:
self.requires.append(p2)
for filename in p2.targetFilenames.keys():
self.skipFilenames[filename] = True
for moduleName, mdef in p2.moduleNames.items():
self.skipModules[moduleName] = mdef
if package not in self.requires:
self.requires.append(package)
for filename in package.targetFilenames.keys():
self.skipFilenames[filename] = True
for moduleName, mdef in package.moduleNames.items():
self.skipModules[moduleName] = mdef
# Packager constructor
def __init__(self):

View File

@ -99,7 +99,43 @@ aux-display tinydisplay
plugin-path $PANDA3D_ROOT
default-model-extension .bam
""" + auxDisplays)
class fmod(package):
# This package includes the FMod audio library. This is
# full-featured and robust, but it is closed-source and the
# licensing is cost-free only for non-commercial products.
config(display_name = "FMod audio library")
require('panda3d')
file('libp3fmod_audio.dll')
file('fmod.prc', extract = True, text = """
plugin-path $FMOD_ROOT
audio-library-name p3fmod_audio
""")
class openal(package):
# This package includes the OpenAL audio libraries. This is free
# in both senses, but there are some technical issues, especially
# on certain platforms.
config(display_name = "OpenAL audio library")
require('panda3d')
file('libp3openal_audio.dll')
file('openal.prc', extract = True, text = """
plugin-path $OPENAL_ROOT
audio-library-name p3openal_audio
""")
class audio(package):
# This package includes the best audio library for the given platform.
if platform.startswith('osx'):
require('fmod')
else:
require('openal')
class egg(package):
# This package contains the code for reading and operating on egg

View File

@ -85,6 +85,7 @@ P3DInstance(P3D_request_ready_func *func,
_got_fparams = false;
_got_wparams = false;
_p3d_trusted = false;
_xpackage = NULL;
_p3dcert_package = NULL;
_fparams.set_tokens(tokens, num_tokens);
@ -224,6 +225,11 @@ P3DInstance::
delete _temp_p3d_filename;
_temp_p3d_filename = NULL;
}
if (_xpackage != NULL) {
delete _xpackage;
_xpackage = NULL;
}
#ifdef __APPLE__
if (_frame_timer != NULL) {
@ -761,6 +767,33 @@ handle_event(P3D_event_data event) {
return retval;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::add_package
// Access: Public
// Description: Adds the package to the list of packages used by this
// instance. The instance will share responsibility for
// downloading the package with any of the other
// instances that use the same package.
////////////////////////////////////////////////////////////////////
void P3DInstance::
add_package(const string &name, const string &version, P3DHost *host) {
string alt_host = _fparams.lookup_token("alt_host");
// Look up in the p3d_info.xml file to see if this p3d file has
// a specific alt_host indication for this host_url.
string alt_host_url = find_alt_host_url(host->get_host_url(), alt_host);
if (!alt_host_url.empty()) {
// If it does, we go ahead and switch to that host now,
// instead of bothering to contact the original host.
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
host = inst_mgr->get_host(alt_host_url);
alt_host.clear();
}
P3DPackage *package = host->get_package(name, version, alt_host);
add_package(package);
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::add_package
// Access: Public
@ -1259,13 +1292,15 @@ scan_app_desc_file(TiXmlDocument *doc) {
if (xpackage == NULL) {
return;
}
assert(_xpackage == NULL);
_xpackage = (TiXmlElement *)xpackage->Clone();
const char *log_basename = xpackage->Attribute("log_basename");
const char *log_basename = _xpackage->Attribute("log_basename");
if (log_basename != NULL) {
_log_basename = log_basename;
}
TiXmlElement *xconfig = xpackage->FirstChildElement("config");
TiXmlElement *xconfig = _xpackage->FirstChildElement("config");
if (xconfig != NULL) {
int hidden = 0;
if (xconfig->QueryIntAttribute("hidden", &hidden) == TIXML_SUCCESS) {
@ -1308,9 +1343,7 @@ scan_app_desc_file(TiXmlDocument *doc) {
_wparams.set_window_type(P3D_WT_hidden);
}
string alt_host = _fparams.lookup_token("alt_host");
TiXmlElement *xrequires = xpackage->FirstChildElement("requires");
TiXmlElement *xrequires = _xpackage->FirstChildElement("requires");
while (xrequires != NULL) {
const char *name = xrequires->Attribute("name");
const char *host_url = xrequires->Attribute("host");
@ -1320,20 +1353,7 @@ scan_app_desc_file(TiXmlDocument *doc) {
version = "";
}
P3DHost *host = inst_mgr->get_host(host_url);
string this_alt_host = alt_host;
// Look up in the p3d_info.xml file to see if this p3d file has
// a specific alt_host indication for this host_url.
string alt_host_url = find_alt_host_url(xpackage, host_url, alt_host);
if (!alt_host_url.empty()) {
// If it does, we go ahead and switch to that host now,
// instead of bothering to contact the original host.
host = inst_mgr->get_host(alt_host_url);
this_alt_host.clear();
}
P3DPackage *package = host->get_package(name, version, this_alt_host);
add_package(package);
add_package(name, version, host);
}
xrequires = xrequires->NextSiblingElement("requires");
@ -1348,9 +1368,8 @@ scan_app_desc_file(TiXmlDocument *doc) {
// Returns empty string if there is no match.
////////////////////////////////////////////////////////////////////
string P3DInstance::
find_alt_host_url(TiXmlElement *xpackage,
const string &host_url, const string &alt_host) {
TiXmlElement *xhost = xpackage->FirstChildElement("host");
find_alt_host_url(const string &host_url, const string &alt_host) {
TiXmlElement *xhost = _xpackage->FirstChildElement("host");
while (xhost != NULL) {
const char *url = xhost->Attribute("url");
if (url != NULL && host_url == url) {
@ -1845,6 +1864,14 @@ report_package_info_ready(P3DPackage *package) {
return;
}
// Now that the package's info is ready, we know its set of required
// packages, and we can add these to the list.
P3DPackage::Requires::const_iterator ri;
for (ri = package->_requires.begin(); ri != package->_requires.end(); ++ri) {
const P3DPackage::RequiredPackage &rp = (*ri);
add_package(rp._package_name, rp._package_version, rp._host);
}
if (get_packages_info_ready()) {
// All packages are ready to go. Let's start some download
// action.

View File

@ -90,6 +90,7 @@ public:
inline P3D_request_ready_func *get_request_ready_func() const;
void add_package(const string &name, const string &version, P3DHost *host);
void add_package(P3DPackage *package);
bool get_packages_info_ready() const;
bool get_packages_ready() const;
@ -154,8 +155,7 @@ private:
void mark_p3d_untrusted();
void mark_p3d_trusted();
void scan_app_desc_file(TiXmlDocument *doc);
string find_alt_host_url(TiXmlElement *xpackage,
const string &host_url, const string &alt_host);
string find_alt_host_url(const string &host_url, const string &alt_host);
void send_browser_script_object();
P3D_request *make_p3d_request(TiXmlElement *xrequest);
@ -218,6 +218,7 @@ private:
P3DWindowParams _wparams;
bool _p3d_trusted;
TiXmlElement *_xpackage;
// For downloading the p3dcert authorization program.
P3DPackage *_p3dcert_package;

View File

@ -202,3 +202,18 @@ inline void P3DPackage::InstallStep::
report_step_progress() {
_package->report_progress(this);
}
////////////////////////////////////////////////////////////////////
// Function: P3DPackage::RequiredPackage::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
inline P3DPackage::RequiredPackage::
RequiredPackage(const string &package_name, const string &package_version,
P3DHost *host) :
_package_name(package_name),
_package_version(package_version),
_host(host)
{
}

View File

@ -169,8 +169,8 @@ get_formatted_name() const {
////////////////////////////////////////////////////////////////////
// Function: P3DPackage::add_instance
// Access: Public
// Description: Specifies an instance that may be responsible for
// downloading this package.
// Description: Specifies an instance that that will be using this
// package, and may be responsible for downloading it.
////////////////////////////////////////////////////////////////////
void P3DPackage::
add_instance(P3DInstance *inst) {
@ -182,8 +182,9 @@ add_instance(P3DInstance *inst) {
////////////////////////////////////////////////////////////////////
// Function: P3DPackage::remove_instance
// Access: Public
// Description: Indicates that the given instance will no longer be
// responsible for downloading this package.
// Description: Indicates that the given instance is no longer
// interested in this package and will not be
// responsible for downloading it.
////////////////////////////////////////////////////////////////////
void P3DPackage::
remove_instance(P3DInstance *inst) {
@ -567,26 +568,33 @@ desc_file_download_finished(bool success) {
void P3DPackage::
got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
TiXmlElement *xpackage = doc->FirstChildElement("package");
TiXmlElement *xuncompressed_archive = NULL;
TiXmlElement *xcompressed_archive = NULL;
if (xpackage != NULL) {
xpackage->Attribute("patch_version", &_patch_version);
xuncompressed_archive = xpackage->FirstChildElement("uncompressed_archive");
xcompressed_archive = xpackage->FirstChildElement("compressed_archive");
TiXmlElement *xconfig = xpackage->FirstChildElement("config");
if (xconfig != NULL) {
const char *display_name_cstr = xconfig->Attribute("display_name");
if (display_name_cstr != NULL) {
_package_display_name = display_name_cstr;
}
// Save the config entry within this class for others to query.
_xconfig = (TiXmlElement *)xconfig->Clone();
if (xpackage == NULL) {
nout << _package_name << " desc file contains no <package>\n";
if (!freshly_downloaded) {
download_desc_file();
return;
}
report_done(false);
return;
}
xpackage->Attribute("patch_version", &_patch_version);
TiXmlElement *xconfig = xpackage->FirstChildElement("config");
if (xconfig != NULL) {
const char *display_name_cstr = xconfig->Attribute("display_name");
if (display_name_cstr != NULL) {
_package_display_name = display_name_cstr;
}
// Save the config entry within this class for others to query.
_xconfig = (TiXmlElement *)xconfig->Clone();
}
TiXmlElement *xuncompressed_archive =
xpackage->FirstChildElement("uncompressed_archive");
TiXmlElement *xcompressed_archive =
xpackage->FirstChildElement("compressed_archive");
if (xuncompressed_archive == NULL || xcompressed_archive == NULL) {
// The desc file didn't include the archive file itself, weird.
@ -604,18 +612,37 @@ got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
// Now get all the extractable components.
_unpack_size = 0;
_extracts.clear();
TiXmlElement *extract = xpackage->FirstChildElement("extract");
while (extract != NULL) {
TiXmlElement *xextract = xpackage->FirstChildElement("extract");
while (xextract != NULL) {
FileSpec file;
file.load_xml(extract);
file.load_xml(xextract);
_extracts.push_back(file);
_unpack_size += file.get_size();
extract = extract->NextSiblingElement("extract");
xextract = xextract->NextSiblingElement("extract");
}
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
// Get the required packages.
_requires.clear();
TiXmlElement *xrequires = xpackage->FirstChildElement("requires");
while (xrequires != NULL) {
const char *package_name = xrequires->Attribute("name");
const char *version = xrequires->Attribute("version");
const char *host_url = xrequires->Attribute("host");
if (package_name != NULL && host_url != NULL) {
P3DHost *host = inst_mgr->get_host(host_url);
if (version == NULL) {
version = "";
}
_requires.push_back(RequiredPackage(package_name, version, host));
}
xrequires = xrequires->NextSiblingElement("requires");
}
// Get a list of all of the files in the directory, so we can remove
// files that don't belong.
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
vector<string> contents;
inst_mgr->scan_directory_recursively(_package_dir, contents);

View File

@ -211,6 +211,19 @@ private:
bool is_extractable(FileSpec &file, const string &filename) const;
public:
class RequiredPackage {
public:
inline RequiredPackage(const string &package_name,
const string &package_version,
P3DHost *host);
string _package_name;
string _package_version;
P3DHost *_host;
};
typedef vector<RequiredPackage> Requires;
Requires _requires;
private:
P3DHost *_host;
int _host_contents_seq;