package dependencies
This commit is contained in:
parent
d426b9179f
commit
687961b626
|
|
@ -24,6 +24,7 @@
|
|||
#include "p3dObject.h"
|
||||
#include "p3dToplevelObject.h"
|
||||
#include "p3dUndefinedObject.h"
|
||||
#include "p3dMultifileReader.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
|
@ -68,6 +69,7 @@ P3DInstance(P3D_request_ready_func *func,
|
|||
INIT_LOCK(_request_lock);
|
||||
|
||||
_session = NULL;
|
||||
_panda3d = NULL;
|
||||
_splash_window = NULL;
|
||||
_instance_window_opened = false;
|
||||
_requested_stop = false;
|
||||
|
|
@ -157,15 +159,25 @@ set_p3d_filename(const string &p3d_filename) {
|
|||
// This also sets up some internal data based on the contents of the
|
||||
// above file and the associated tokens.
|
||||
|
||||
// For the moment, all sessions will be unique.
|
||||
// Extract the application desc file from the p3d file.
|
||||
P3DMultifileReader reader;
|
||||
stringstream sstream;
|
||||
if (!reader.extract_one(p3d_filename, sstream, "p3d_info.xml")) {
|
||||
nout << "No p3d_info.xml file found in " << p3d_filename << "\n";
|
||||
} else {
|
||||
sstream.seekg(0);
|
||||
TiXmlDocument doc;
|
||||
sstream >> doc;
|
||||
scan_app_desc_file(&doc);
|
||||
}
|
||||
|
||||
// For the moment, all sessions will be unique. TODO: support
|
||||
// multiple instances per session.
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
ostringstream strm;
|
||||
strm << inst_mgr->get_unique_id();
|
||||
_session_key = strm.str();
|
||||
|
||||
// TODO.
|
||||
_python_version = "python24";
|
||||
|
||||
// Generate a special notification: onpluginload, indicating the
|
||||
// plugin has read its parameters and is ready to be queried (even
|
||||
// if Python has not yet started).
|
||||
|
|
@ -605,15 +617,62 @@ handle_event(P3D_event_data event) {
|
|||
// Access: Public
|
||||
// Description: Adds the package to the list of packages used by this
|
||||
// instance. The instance will share responsibility for
|
||||
// downloading the package will any of the other
|
||||
// downloading the package with any of the other
|
||||
// instances that use the same package.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
add_package(P3DPackage *package) {
|
||||
assert(find(_packages.begin(), _packages.end(), package) == _packages.end());
|
||||
if (find(_packages.begin(), _packages.end(), package) != _packages.end()) {
|
||||
// Already have this package.
|
||||
return;
|
||||
}
|
||||
|
||||
_packages.push_back(package);
|
||||
package->set_instance(this);
|
||||
|
||||
if (package->get_package_name() == "panda3d") {
|
||||
_panda3d = package;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::get_packages_ready
|
||||
// Access: Public
|
||||
// Description: Returns true if all of the packages required by the
|
||||
// instance (as specified in previous calls to
|
||||
// add_package()) have been fully downloaded and are
|
||||
// ready to run, or false if one or more of them still
|
||||
// requires downloading.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DInstance::
|
||||
get_packages_ready() const {
|
||||
Packages::const_iterator pi;
|
||||
for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
|
||||
if (!(*pi)->get_ready()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::get_packages_failed
|
||||
// Access: Public
|
||||
// Description: Returns true if any of the packages required by the
|
||||
// instance have failed to download (and thus we will
|
||||
// never be ready).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DInstance::
|
||||
get_packages_failed() const {
|
||||
Packages::const_iterator pi;
|
||||
for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
|
||||
if ((*pi)->get_failed()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -700,6 +759,37 @@ make_xml() {
|
|||
return xinstance;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::scan_app_desc_file
|
||||
// Access: Private
|
||||
// Description: Reads the p3d_info.xml file at instance startup, to
|
||||
// determine the set of required packages and so forth.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
scan_app_desc_file(TiXmlDocument *doc) {
|
||||
TiXmlElement *xpackage = doc->FirstChildElement("package");
|
||||
if (xpackage == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
|
||||
TiXmlElement *xrequires = xpackage->FirstChildElement("requires");
|
||||
while (xrequires != NULL) {
|
||||
const char *name = xrequires->Attribute("name");
|
||||
if (name != NULL) {
|
||||
const char *version = xrequires->Attribute("version");
|
||||
if (version == NULL) {
|
||||
version = "";
|
||||
}
|
||||
P3DPackage *package = inst_mgr->get_package(name, version);
|
||||
add_package(package);
|
||||
}
|
||||
|
||||
xrequires = xrequires->NextSiblingElement("requires");
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::send_browser_script_object
|
||||
// Access: Private
|
||||
|
|
@ -1010,31 +1100,42 @@ start_package_download(P3DPackage *package) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::install_progress
|
||||
// Function: P3DInstance::report_package_progress
|
||||
// Access: Private
|
||||
// Description: Notified as the _panda3d package is downloaded.
|
||||
// Description: Notified as a required package is downloaded.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
install_progress(P3DPackage *package, double progress) {
|
||||
report_package_progress(P3DPackage *package, double progress) {
|
||||
if (_splash_window != NULL) {
|
||||
_splash_window->set_install_label("Installing Panda3D");
|
||||
if (!package->get_package_display_name().empty()) {
|
||||
_splash_window->set_install_label("Installing " + package->get_package_display_name());
|
||||
}
|
||||
_splash_window->set_install_progress(progress);
|
||||
}
|
||||
_panda_script_object->set_float_property("downloadProgress", progress);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::package_ready
|
||||
// Function: P3DInstance::report_package_done
|
||||
// Access: Private
|
||||
// Description: Notified when the package is fully downloaded.
|
||||
// Description: Notified when a required package is fully downloaded,
|
||||
// or failed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
package_ready(P3DPackage *package, bool success) {
|
||||
report_package_done(P3DPackage *package, bool success) {
|
||||
if (success) {
|
||||
install_progress(package, 1.0);
|
||||
_panda_script_object->set_bool_property("downloadComplete", true);
|
||||
_panda_script_object->set_string_property("status", "starting");
|
||||
send_notify("ondownloadcomplete");
|
||||
report_package_progress(package, 1.0);
|
||||
|
||||
if (get_packages_ready()) {
|
||||
_panda_script_object->set_bool_property("downloadComplete", true);
|
||||
_panda_script_object->set_string_property("status", "starting");
|
||||
send_notify("ondownloadcomplete");
|
||||
|
||||
// Notify the session also.
|
||||
if (_session != NULL) {
|
||||
_session->report_packages_done(this, success);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ public:
|
|||
inline P3D_request_ready_func *get_request_ready_func() const;
|
||||
|
||||
void add_package(P3DPackage *package);
|
||||
bool get_packages_ready() const;
|
||||
bool get_packages_failed() const;
|
||||
|
||||
void start_download(P3DDownload *download);
|
||||
inline bool is_started() const;
|
||||
|
|
@ -100,6 +102,8 @@ private:
|
|||
P3DInstance *_inst;
|
||||
};
|
||||
|
||||
void scan_app_desc_file(TiXmlDocument *doc);
|
||||
|
||||
void send_browser_script_object();
|
||||
P3D_request *make_p3d_request(TiXmlElement *xrequest);
|
||||
void handle_notify_request(const string &message);
|
||||
|
|
@ -108,8 +112,8 @@ private:
|
|||
bool needs_response, int unique_id);
|
||||
void make_splash_window();
|
||||
void start_package_download(P3DPackage *package);
|
||||
void install_progress(P3DPackage *package, double progress);
|
||||
void package_ready(P3DPackage *package, bool success);
|
||||
void report_package_progress(P3DPackage *package, double progress);
|
||||
void report_package_done(P3DPackage *package, bool progress);
|
||||
|
||||
void paint_window();
|
||||
void add_modifier_flags(unsigned int &swb_flags, int modifiers);
|
||||
|
|
@ -157,6 +161,10 @@ private:
|
|||
typedef vector<P3DPackage *> Packages;
|
||||
Packages _packages;
|
||||
|
||||
// We keep the _panda3d pointer separately because it's so
|
||||
// important, but it's in the above vector also.
|
||||
P3DPackage *_panda3d;
|
||||
|
||||
typedef map<int, P3DDownload *> Downloads;
|
||||
Downloads _downloads;
|
||||
|
||||
|
|
@ -175,6 +183,7 @@ private:
|
|||
friend class P3DSession;
|
||||
friend class SplashDownload;
|
||||
friend class P3DWindowParams;
|
||||
friend class P3DPackage;
|
||||
};
|
||||
|
||||
#include "p3dInstance.I"
|
||||
|
|
|
|||
|
|
@ -352,8 +352,7 @@ wait_request() {
|
|||
// package.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPackage *P3DInstanceManager::
|
||||
get_package(const string &package_name, const string &package_version,
|
||||
const string &package_display_name) {
|
||||
get_package(const string &package_name, const string &package_version) {
|
||||
string package_platform = get_platform();
|
||||
string key = package_name + "_" + package_platform + "_" + package_version;
|
||||
Packages::iterator pi = _packages.find(key);
|
||||
|
|
@ -361,8 +360,8 @@ get_package(const string &package_name, const string &package_version,
|
|||
return (*pi).second;
|
||||
}
|
||||
|
||||
P3DPackage *package = new P3DPackage(package_name, package_platform,
|
||||
package_version, package_display_name);
|
||||
P3DPackage *package =
|
||||
new P3DPackage(package_name, package_platform, package_version);
|
||||
bool inserted = _packages.insert(Packages::value_type(key, package)).second;
|
||||
assert(inserted);
|
||||
|
||||
|
|
|
|||
|
|
@ -66,8 +66,7 @@ public:
|
|||
void wait_request();
|
||||
|
||||
P3DPackage *get_package(const string &package_name,
|
||||
const string &package_version,
|
||||
const string &package_display_name);
|
||||
const string &package_version);
|
||||
bool get_package_desc_file(FileSpec &desc_file,
|
||||
const string &package_name,
|
||||
const string &package_version);
|
||||
|
|
|
|||
|
|
@ -48,11 +48,12 @@ P3DMultifileReader() {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DMultifileReader::extract
|
||||
// Function: P3DMultifileReader::extract_all
|
||||
// Access: Public
|
||||
// Description: Reads the named multifile, and extracts all files
|
||||
// within it to the indicated directory. Returns true
|
||||
// on success, false on failure.
|
||||
// Description: Reads the named multifile, and extracts all the
|
||||
// expected extractable components within it to the
|
||||
// indicated directory. Returns true on success, false
|
||||
// on failure.
|
||||
//
|
||||
// The parameters package, start_progress, and
|
||||
// progress_size are provided to make the appropriate
|
||||
|
|
@ -60,8 +61,95 @@ P3DMultifileReader() {
|
|||
// during this operation.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DMultifileReader::
|
||||
extract(const string &pathname, const string &to_dir,
|
||||
P3DPackage *package, double start_progress, double progress_size) {
|
||||
extract_all(const string &pathname, const string &to_dir,
|
||||
P3DPackage *package, double start_progress, double progress_size) {
|
||||
if (!read_header(pathname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now walk through all of the files, and extract only the ones we
|
||||
// expect to encounter.
|
||||
size_t num_processed = 0;
|
||||
size_t num_expected = _subfiles.size();
|
||||
if (package != NULL) {
|
||||
num_expected = package->_extracts.size();
|
||||
}
|
||||
|
||||
Subfiles::iterator si;
|
||||
for (si = _subfiles.begin(); si != _subfiles.end(); ++si) {
|
||||
const Subfile &s = (*si);
|
||||
if (package != NULL && !package->is_extractable(s._filename)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string output_pathname = to_dir + "/" + s._filename;
|
||||
if (!mkfile_complete(output_pathname, nout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ofstream out(output_pathname.c_str(), ios::out | ios::binary);
|
||||
if (!out) {
|
||||
nout << "Unable to write to " << output_pathname << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!extract_subfile(out, s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the timestamp according to the multifile.
|
||||
out.close();
|
||||
utimbuf utb;
|
||||
utb.actime = time(NULL);
|
||||
utb.modtime = s._timestamp;
|
||||
utime(output_pathname.c_str(), &utb);
|
||||
|
||||
|
||||
++num_processed;
|
||||
if (package != NULL) {
|
||||
double progress = (double)num_processed / (double)num_expected;
|
||||
package->report_progress(start_progress + progress * progress_size);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DMultifileReader::extract_one
|
||||
// Access: Public
|
||||
// Description: Reads the named multifile, and extracts only the
|
||||
// named component to the indicated stream. Returns
|
||||
// true on success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DMultifileReader::
|
||||
extract_one(const string &pathname, ostream &out, const string &filename) {
|
||||
if (!read_header(pathname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look for the named component.
|
||||
Subfiles::iterator si;
|
||||
for (si = _subfiles.begin(); si != _subfiles.end(); ++si) {
|
||||
const Subfile &s = (*si);
|
||||
if (s._filename == filename) {
|
||||
return extract_subfile(out, s);
|
||||
}
|
||||
}
|
||||
|
||||
nout << "Could not extract " << filename << ": not found.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DMultifileReader::read_header
|
||||
// Access: Private
|
||||
// Description: Opens the named multifile and reads the header
|
||||
// information and index, returning true on success,
|
||||
// false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DMultifileReader::
|
||||
read_header(const string &pathname) {
|
||||
_subfiles.clear();
|
||||
|
||||
_in.open(pathname.c_str(), ios::in | ios::binary);
|
||||
|
|
@ -99,64 +187,12 @@ extract(const string &pathname, const string &to_dir,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Now walk through all of the files.
|
||||
size_t num_processed = 0;
|
||||
Subfiles::iterator si;
|
||||
for (si = _subfiles.begin(); si != _subfiles.end(); ++si) {
|
||||
const Subfile &s = (*si);
|
||||
|
||||
string output_pathname = to_dir + "/" + s._filename;
|
||||
if (!mkfile_complete(output_pathname, nout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ofstream out(output_pathname.c_str(), ios::out | ios::binary);
|
||||
if (!out) {
|
||||
nout << "Unable to write to " << output_pathname << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
_in.seekg(s._start);
|
||||
|
||||
static const size_t buffer_size = 1024;
|
||||
char buffer[buffer_size];
|
||||
|
||||
size_t remaining_data = s._length;
|
||||
_in.read(buffer, min(buffer_size, remaining_data));
|
||||
size_t count = _in.gcount();
|
||||
while (count != 0) {
|
||||
remaining_data -= count;
|
||||
out.write(buffer, count);
|
||||
_in.read(buffer, min(buffer_size, remaining_data));
|
||||
count = _in.gcount();
|
||||
}
|
||||
|
||||
if (remaining_data != 0) {
|
||||
nout << "Unable to extract " << s._filename << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the timestamp according to the multifile.
|
||||
out.close();
|
||||
utimbuf utb;
|
||||
utb.actime = time(NULL);
|
||||
utb.modtime = s._timestamp;
|
||||
utime(output_pathname.c_str(), &utb);
|
||||
|
||||
|
||||
++num_processed;
|
||||
if (package != NULL) {
|
||||
double progress = (double)num_processed / (double)_subfiles.size();
|
||||
package->report_progress(start_progress + progress * progress_size);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DMultifileReader::read_index
|
||||
// Access: Public
|
||||
// Access: Private
|
||||
// Description: Assuming the file stream is positioned at the first
|
||||
// record, reads all of the records into the _subfiles
|
||||
// list. Returns true on success, false on failure.
|
||||
|
|
@ -172,10 +208,6 @@ read_index() {
|
|||
s._start = read_uint32();
|
||||
s._length = read_uint32();
|
||||
unsigned int flags = read_uint16();
|
||||
if (flags != 0) {
|
||||
nout << "Unsupported per-subfile options in multifile\n";
|
||||
return false;
|
||||
}
|
||||
s._timestamp = read_uint32();
|
||||
size_t name_length = read_uint16();
|
||||
char *buffer = new char[name_length];
|
||||
|
|
@ -189,7 +221,10 @@ read_index() {
|
|||
s._filename = string(buffer, name_length);
|
||||
delete[] buffer;
|
||||
|
||||
_subfiles.push_back(s);
|
||||
if (flags == 0) {
|
||||
// We can only support subfiles with no particular flags set.
|
||||
_subfiles.push_back(s);
|
||||
}
|
||||
|
||||
_in.seekg(next_entry);
|
||||
next_entry = read_uint32();
|
||||
|
|
@ -200,3 +235,36 @@ read_index() {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DMultifileReader::extract_subfile
|
||||
// Access: Private
|
||||
// Description: Extracts the indicated subfile and writes it to the
|
||||
// indicated stream. Returns true on success, false on
|
||||
// failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DMultifileReader::
|
||||
extract_subfile(ostream &out, const Subfile &s) {
|
||||
_in.seekg(s._start);
|
||||
|
||||
static const size_t buffer_size = 1024;
|
||||
char buffer[buffer_size];
|
||||
|
||||
size_t remaining_data = s._length;
|
||||
_in.read(buffer, min(buffer_size, remaining_data));
|
||||
size_t count = _in.gcount();
|
||||
while (count != 0) {
|
||||
remaining_data -= count;
|
||||
out.write(buffer, count);
|
||||
_in.read(buffer, min(buffer_size, remaining_data));
|
||||
count = _in.gcount();
|
||||
}
|
||||
|
||||
if (remaining_data != 0) {
|
||||
nout << "Unable to extract " << s._filename << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,12 +31,20 @@ class P3DMultifileReader {
|
|||
public:
|
||||
P3DMultifileReader();
|
||||
|
||||
bool extract(const string &pathname, const string &to_dir,
|
||||
P3DPackage *package, double start_progress,
|
||||
double progress_size);
|
||||
bool extract_all(const string &pathname, const string &to_dir,
|
||||
P3DPackage *package, double start_progress,
|
||||
double progress_size);
|
||||
|
||||
bool extract_one(const string &pathname, ostream &out,
|
||||
const string &filename);
|
||||
|
||||
private:
|
||||
class Subfile;
|
||||
|
||||
bool read_header(const string &pathname);
|
||||
bool read_index();
|
||||
bool extract_subfile(ostream &out, const Subfile &s);
|
||||
|
||||
inline unsigned int read_uint16();
|
||||
inline unsigned int read_uint32();
|
||||
|
||||
|
|
|
|||
|
|
@ -37,12 +37,10 @@ static const double extract_portion = 0.05;
|
|||
P3DPackage::
|
||||
P3DPackage(const string &package_name,
|
||||
const string &package_platform,
|
||||
const string &package_version,
|
||||
const string &package_display_name) :
|
||||
const string &package_version) :
|
||||
_package_name(package_name),
|
||||
_package_platform(package_platform),
|
||||
_package_version(package_version),
|
||||
_package_display_name(package_display_name)
|
||||
_package_version(package_version)
|
||||
{
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
|
||||
|
|
@ -87,43 +85,6 @@ P3DPackage::
|
|||
assert(_instances.empty());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::set_callback
|
||||
// Access: Public
|
||||
// Description: Registers a callback on the package. The callback
|
||||
// object will be notified when the package is ready for
|
||||
// use (or when it has failed to download properly).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::
|
||||
set_callback(Callback *callback) {
|
||||
if (_ready || _failed) {
|
||||
// Actually, we're already done. Signal the callback immediately.
|
||||
callback->package_ready(this, _ready);
|
||||
delete callback;
|
||||
} else {
|
||||
// Bootstrap still in progress. Save the callback.
|
||||
_callbacks.push_back(callback);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::cancel_callback
|
||||
// Access: Public
|
||||
// Description: Unregisters a particular callback object. This
|
||||
// object will no longer be notified when the package is
|
||||
// ready.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::
|
||||
cancel_callback(Callback *callback) {
|
||||
Callbacks::iterator ci;
|
||||
ci = find(_callbacks.begin(), _callbacks.end(), callback);
|
||||
if (ci != _callbacks.end()) {
|
||||
_callbacks.erase(ci);
|
||||
} else {
|
||||
nout << "Canceling unknown callback on " << _package_fullname << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::set_instance
|
||||
// Access: Public
|
||||
|
|
@ -334,6 +295,11 @@ got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
|
|||
TiXmlElement *compressed_archive = NULL;
|
||||
|
||||
if (xpackage != NULL) {
|
||||
const char *display_name_cstr = xpackage->Attribute("display_name");
|
||||
if (display_name_cstr != NULL) {
|
||||
_package_display_name = display_name_cstr;
|
||||
}
|
||||
|
||||
uncompressed_archive = xpackage->FirstChildElement("uncompressed_archive");
|
||||
compressed_archive = xpackage->FirstChildElement("compressed_archive");
|
||||
}
|
||||
|
|
@ -351,27 +317,27 @@ got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
|
|||
_uncompressed_archive.load_xml(uncompressed_archive);
|
||||
_compressed_archive.load_xml(compressed_archive);
|
||||
|
||||
// Now get all the components.
|
||||
_components.clear();
|
||||
TiXmlElement *component = xpackage->FirstChildElement("component");
|
||||
while (component != NULL) {
|
||||
// Now get all the extractable components.
|
||||
_extracts.clear();
|
||||
TiXmlElement *extract = xpackage->FirstChildElement("extract");
|
||||
while (extract != NULL) {
|
||||
FileSpec file;
|
||||
file.load_xml(component);
|
||||
_components.push_back(file);
|
||||
component = component->NextSiblingElement("component");
|
||||
file.load_xml(extract);
|
||||
_extracts.push_back(file);
|
||||
extract = extract->NextSiblingElement("extract");
|
||||
}
|
||||
|
||||
// Verify all of the components.
|
||||
bool all_components_ok = true;
|
||||
Components::iterator ci;
|
||||
for (ci = _components.begin(); ci != _components.end(); ++ci) {
|
||||
// Verify all of the extracts.
|
||||
bool all_extracts_ok = true;
|
||||
Extracts::iterator ci;
|
||||
for (ci = _extracts.begin(); ci != _extracts.end(); ++ci) {
|
||||
if (!(*ci).quick_verify(_package_dir)) {
|
||||
all_components_ok = false;
|
||||
all_extracts_ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_components_ok) {
|
||||
if (all_extracts_ok) {
|
||||
// Great, we're ready to begin.
|
||||
report_done(true);
|
||||
|
||||
|
|
@ -589,8 +555,8 @@ void P3DPackage::
|
|||
extract_archive() {
|
||||
string source_pathname = _package_dir + "/" + _uncompressed_archive.get_filename();
|
||||
P3DMultifileReader reader;
|
||||
if (!reader.extract(source_pathname, _package_dir,
|
||||
this, download_portion + uncompress_portion, extract_portion)) {
|
||||
if (!reader.extract_all(source_pathname, _package_dir,
|
||||
this, download_portion + uncompress_portion, extract_portion)) {
|
||||
nout << "Failure extracting " << _uncompressed_archive.get_filename()
|
||||
<< "\n";
|
||||
report_done(false);
|
||||
|
|
@ -604,13 +570,13 @@ extract_archive() {
|
|||
// Function: P3DPackage::report_progress
|
||||
// Access: Private
|
||||
// Description: Reports the indicated install progress to all
|
||||
// listening callbacks.
|
||||
// interested instances.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::
|
||||
report_progress(double progress) {
|
||||
Callbacks::iterator ci;
|
||||
for (ci = _callbacks.begin(); ci != _callbacks.end(); ++ci) {
|
||||
(*ci)->install_progress(this, progress);
|
||||
Instances::iterator ii;
|
||||
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
||||
(*ii)->report_package_progress(this, progress);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -618,8 +584,8 @@ report_progress(double progress) {
|
|||
// Function: P3DPackage::report_done
|
||||
// Access: Private
|
||||
// Description: Transitions the package to "ready" or "failure"
|
||||
// state, and reports this change to all the listening
|
||||
// callbacks.
|
||||
// state, and reports this change to all the interested
|
||||
// instances.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::
|
||||
report_done(bool success) {
|
||||
|
|
@ -631,16 +597,10 @@ report_done(bool success) {
|
|||
_failed = true;
|
||||
}
|
||||
|
||||
Callbacks orig_callbacks;
|
||||
orig_callbacks.swap(_callbacks);
|
||||
Callbacks::iterator ci;
|
||||
for (ci = orig_callbacks.begin(); ci != orig_callbacks.end(); ++ci) {
|
||||
(*ci)->package_ready(this, _ready);
|
||||
delete (*ci);
|
||||
Instances::iterator ii;
|
||||
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
||||
(*ii)->report_package_done(this, success);
|
||||
}
|
||||
|
||||
// We shouldn't have added any more callbacks during the above loop.
|
||||
assert(_callbacks.empty());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -674,30 +634,21 @@ start_download(P3DPackage::DownloadType dtype, const string &url,
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::Callback::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
// Function: P3DPackage::is_extractable
|
||||
// Access: Private
|
||||
// Description: Returns true if the name file is on the extract list,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPackage::Callback::
|
||||
~Callback() {
|
||||
}
|
||||
bool P3DPackage::
|
||||
is_extractable(const string &filename) const {
|
||||
Extracts::const_iterator ci;
|
||||
for (ci = _extracts.begin(); ci != _extracts.end(); ++ci) {
|
||||
if ((*ci).get_filename() == filename) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::Callback::install_progress
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::Callback::
|
||||
install_progress(P3DPackage *package, double progress) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPackage::Callback::package_ready
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPackage::Callback::
|
||||
package_ready(P3DPackage *package, bool success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -38,17 +38,9 @@ class P3DPackage {
|
|||
public:
|
||||
P3DPackage(const string &package_name,
|
||||
const string &package_platform,
|
||||
const string &package_version,
|
||||
const string &package_display_name);
|
||||
const string &package_version);
|
||||
~P3DPackage();
|
||||
|
||||
class Callback {
|
||||
public:
|
||||
virtual ~Callback();
|
||||
virtual void install_progress(P3DPackage *package, double progress);
|
||||
virtual void package_ready(P3DPackage *package, bool success);
|
||||
};
|
||||
|
||||
inline bool get_ready() const;
|
||||
inline bool get_failed() const;
|
||||
inline const string &get_package_dir() const;
|
||||
|
|
@ -56,9 +48,6 @@ public:
|
|||
inline const string &get_package_version() const;
|
||||
inline const string &get_package_display_name() const;
|
||||
|
||||
void set_callback(Callback *callback);
|
||||
void cancel_callback(Callback *callback);
|
||||
|
||||
void set_instance(P3DInstance *inst);
|
||||
void cancel_instance(P3DInstance *inst);
|
||||
|
||||
|
|
@ -102,6 +91,8 @@ private:
|
|||
void start_download(DownloadType dtype, const string &url,
|
||||
const string &pathname, bool allow_partial);
|
||||
|
||||
bool is_extractable(const string &filename) const;
|
||||
|
||||
private:
|
||||
string _package_name;
|
||||
string _package_version;
|
||||
|
|
@ -120,17 +111,14 @@ private:
|
|||
Download *_active_download;
|
||||
bool _partial_download;
|
||||
|
||||
typedef vector<Callback *> Callbacks;
|
||||
Callbacks _callbacks;
|
||||
|
||||
typedef vector<P3DInstance *> Instances;
|
||||
Instances _instances;
|
||||
|
||||
FileSpec _compressed_archive;
|
||||
FileSpec _uncompressed_archive;
|
||||
|
||||
typedef vector<FileSpec> Components;
|
||||
Components _components;
|
||||
typedef vector<FileSpec> Extracts;
|
||||
Extracts _extracts;
|
||||
|
||||
friend class Download;
|
||||
friend class P3DMultifileReader;
|
||||
|
|
|
|||
|
|
@ -65,14 +65,8 @@ P3DSession(P3DInstance *inst) {
|
|||
_output_filename = "/tmp/panda3d.3.log";
|
||||
#endif // _WIN32
|
||||
|
||||
_panda3d_callback = NULL;
|
||||
|
||||
INIT_LOCK(_instances_lock);
|
||||
INIT_THREAD(_read_thread);
|
||||
|
||||
_panda3d = inst_mgr->get_package("panda3d", "dev", "Panda3D");
|
||||
_python_root_dir = _panda3d->get_package_dir();
|
||||
inst->add_package(_panda3d);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -95,12 +89,6 @@ P3DSession::
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
shutdown() {
|
||||
if (_panda3d_callback != NULL) {
|
||||
_panda3d->cancel_callback(_panda3d_callback);
|
||||
delete _panda3d_callback;
|
||||
_panda3d_callback = NULL;
|
||||
}
|
||||
|
||||
if (_p3dpython_running) {
|
||||
// Tell the process we're going away.
|
||||
TiXmlDocument doc;
|
||||
|
|
@ -226,16 +214,14 @@ start_instance(P3DInstance *inst) {
|
|||
send_command(doc);
|
||||
inst->send_browser_script_object();
|
||||
|
||||
if (_panda3d->get_ready()) {
|
||||
if (inst->get_packages_ready()) {
|
||||
// If it's ready immediately, go ahead and start.
|
||||
start_p3dpython();
|
||||
start_p3dpython(inst);
|
||||
|
||||
} else {
|
||||
// Otherwise, set a callback, so we'll know when it is ready.
|
||||
if (_panda3d_callback == NULL) {
|
||||
_panda3d_callback = new PackageCallback(this);
|
||||
_panda3d->set_callback(_panda3d_callback);
|
||||
}
|
||||
inst->start_package_download(_panda3d);
|
||||
// Otherwise, wait for the instance to download itself. We'll
|
||||
// automatically get a callback to report_packages_done() when
|
||||
// it's done.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -644,43 +630,14 @@ drop_p3dobj(int object_id) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::install_progress
|
||||
// Function: P3DSession::report_packages_done
|
||||
// Access: Private
|
||||
// Description: Notified as the _panda3d package is downloaded.
|
||||
// Description: Notified when a child instance is fully downloaded.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
install_progress(P3DPackage *package, double progress) {
|
||||
Instances::iterator ii;
|
||||
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
||||
P3DInstance *inst = (*ii).second;
|
||||
inst->install_progress(package, progress);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::package_ready
|
||||
// Access: Private
|
||||
// Description: Notified when the package is fully downloaded.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
package_ready(P3DPackage *package, bool success) {
|
||||
_panda3d_callback = NULL;
|
||||
|
||||
Instances::iterator ii;
|
||||
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
||||
P3DInstance *inst = (*ii).second;
|
||||
inst->package_ready(package, success);
|
||||
}
|
||||
|
||||
if (package == _panda3d) {
|
||||
if (success) {
|
||||
start_p3dpython();
|
||||
} else {
|
||||
nout << "Failed to install " << package->get_package_name()
|
||||
<< "_" << package->get_package_version() << "\n";
|
||||
}
|
||||
} else {
|
||||
nout << "Unexpected panda3d package: " << package << "\n";
|
||||
report_packages_done(P3DInstance *inst, bool success) {
|
||||
if (success) {
|
||||
start_p3dpython(inst);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -690,7 +647,19 @@ package_ready(P3DPackage *package, bool success) {
|
|||
// Description: Starts Python running in a child process.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
start_p3dpython() {
|
||||
start_p3dpython(P3DInstance *inst) {
|
||||
if (_p3dpython_running) {
|
||||
// Already started.
|
||||
return;
|
||||
}
|
||||
|
||||
if (inst->_panda3d == NULL) {
|
||||
nout << "Couldn't start Python: no panda3d dependency.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
_python_root_dir = inst->_panda3d->get_package_dir();
|
||||
|
||||
string p3dpython = P3D_PLUGIN_P3DPYTHON;
|
||||
if (p3dpython.empty()) {
|
||||
p3dpython = _python_root_dir + "/p3dpython";
|
||||
|
|
@ -1116,44 +1085,3 @@ posix_create_process(const string &program, const string &start_dir,
|
|||
return child;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::PackageCallback::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DSession::PackageCallback::
|
||||
PackageCallback(P3DSession *session) :
|
||||
_session(session)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::PackageCallback::install_progress
|
||||
// Access: Public, Virtual
|
||||
// Description: This callback is received during the download process
|
||||
// to inform us how much has been installed so far.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::PackageCallback::
|
||||
install_progress(P3DPackage *package, double progress) {
|
||||
if (this == _session->_panda3d_callback) {
|
||||
_session->install_progress(package, progress);
|
||||
} else {
|
||||
nout << "Unexpected callback for P3DSession\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DSession::PackageCallback::package_ready
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::PackageCallback::
|
||||
package_ready(P3DPackage *package, bool success) {
|
||||
if (this == _session->_panda3d_callback) {
|
||||
_session->package_ready(package, success);
|
||||
} else {
|
||||
nout << "Unexpected callback for P3DSession\n";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,9 +61,8 @@ public:
|
|||
void drop_p3dobj(int object_id);
|
||||
|
||||
private:
|
||||
void install_progress(P3DPackage *package, double progress);
|
||||
void package_ready(P3DPackage *package, bool success);
|
||||
void start_p3dpython();
|
||||
void report_packages_done(P3DInstance *inst, bool success);
|
||||
void start_p3dpython(P3DInstance *inst);
|
||||
|
||||
void spawn_read_thread();
|
||||
void join_read_thread();
|
||||
|
|
@ -87,23 +86,11 @@ private:
|
|||
HandleStream &pipe_read, HandleStream &pipe_write);
|
||||
#endif
|
||||
|
||||
class PackageCallback : public P3DPackage::Callback {
|
||||
public:
|
||||
PackageCallback(P3DSession *session);
|
||||
|
||||
virtual void install_progress(P3DPackage *package, double progress);
|
||||
virtual void package_ready(P3DPackage *package, bool success);
|
||||
|
||||
protected:
|
||||
P3DSession *_session;
|
||||
};
|
||||
|
||||
private:
|
||||
int _session_id;
|
||||
string _session_key;
|
||||
string _python_version;
|
||||
string _output_filename;
|
||||
|
||||
string _python_root_dir;
|
||||
|
||||
typedef map<int, P3DInstance *> Instances;
|
||||
|
|
@ -123,7 +110,6 @@ private:
|
|||
SentObjects _sent_objects;
|
||||
|
||||
P3DPackage *_panda3d;
|
||||
PackageCallback *_panda3d_callback;
|
||||
|
||||
// Members for communicating with the p3dpython child process.
|
||||
#ifdef _WIN32
|
||||
|
|
@ -146,7 +132,7 @@ private:
|
|||
bool _read_thread_continue;
|
||||
THREAD _read_thread;
|
||||
|
||||
friend class PackageCallback;
|
||||
friend class P3DInstance;
|
||||
};
|
||||
|
||||
#include "p3dSession.I"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import os
|
|||
import glob
|
||||
import marshal
|
||||
import new
|
||||
import string
|
||||
from direct.showbase import Loader
|
||||
from direct.showutil import FreezeTool
|
||||
from direct.directnotify.DirectNotifyGlobal import *
|
||||
|
|
@ -29,7 +30,7 @@ class Packager:
|
|||
|
||||
class PackFile:
|
||||
def __init__(self, filename, newName = None, deleteTemp = False,
|
||||
extract = False):
|
||||
extract = None):
|
||||
assert isinstance(filename, Filename)
|
||||
self.filename = filename
|
||||
self.newName = newName
|
||||
|
|
@ -43,6 +44,7 @@ class Packager:
|
|||
self.version = None
|
||||
self.platform = None
|
||||
self.p3dApplication = False
|
||||
self.displayName = None
|
||||
self.files = []
|
||||
self.compressionLevel = 0
|
||||
self.importedMapsDir = 'imported_maps'
|
||||
|
|
@ -208,13 +210,14 @@ class Packager:
|
|||
if self.version:
|
||||
xpackage.SetAttribute('version', self.version)
|
||||
|
||||
if self.displayName:
|
||||
xpackage.SetAttribute('display_name', self.displayName)
|
||||
|
||||
xpackage.SetAttribute('main_module', self.mainModule)
|
||||
|
||||
for package in self.requires:
|
||||
xrequires = TiXmlElement('requires')
|
||||
xrequires.SetAttribute('name', package.packageName)
|
||||
if package.platform:
|
||||
xrequires.SetAttribute('platform', package.platform)
|
||||
if package.version:
|
||||
xrequires.SetAttribute('version', package.version)
|
||||
xpackage.InsertEndChild(xrequires)
|
||||
|
|
@ -225,7 +228,11 @@ class Packager:
|
|||
# can add it to the multifile.
|
||||
filename = Filename.temporary('', 'p3d_', '.xml')
|
||||
doc.SaveFile(filename.toOsSpecific())
|
||||
self.multifile.addSubfile('p3d_info.xml', filename, self.compressionLevel)
|
||||
|
||||
# It's important not to compress this file: the core API
|
||||
# runtime can't decode compressed subfiles.
|
||||
self.multifile.addSubfile('p3d_info.xml', filename, 0)
|
||||
|
||||
self.multifile.flush()
|
||||
filename.unlink()
|
||||
|
||||
|
|
@ -252,6 +259,9 @@ class Packager:
|
|||
if self.version:
|
||||
xpackage.SetAttribute('version', self.version)
|
||||
|
||||
if self.displayName:
|
||||
xpackage.SetAttribute('display_name', self.displayName)
|
||||
|
||||
xuncompressedArchive = self.getFileSpec(
|
||||
'uncompressed_archive', self.packageFullpath,
|
||||
self.packageBasename)
|
||||
|
|
@ -485,13 +495,13 @@ class Packager:
|
|||
# not further compressible.
|
||||
self.addComponent(file, compressible = False)
|
||||
|
||||
def addComponent(self, file, compressible = True, extract = False):
|
||||
def addComponent(self, file, compressible = True, extract = None):
|
||||
ext = Filename(file.newName).getExtension()
|
||||
if ext in self.packager.uncompressibleExtensions:
|
||||
compressible = False
|
||||
|
||||
extract = file.extract
|
||||
if ext in self.packager.extractExtensions:
|
||||
if extract is None and ext in self.packager.extractExtensions:
|
||||
extract = True
|
||||
|
||||
if ext in self.packager.platformSpecificExtensions:
|
||||
|
|
@ -599,7 +609,7 @@ class Packager:
|
|||
self.musicManager = None
|
||||
|
||||
# This is filled in during readPackageDef().
|
||||
self.packageList = None
|
||||
self.packageList = []
|
||||
|
||||
# A table of all known packages by name.
|
||||
self.packages = {}
|
||||
|
|
@ -636,54 +646,152 @@ class Packager:
|
|||
## # created there
|
||||
## os.chdir(self.persistDir.toOsSpecific())
|
||||
|
||||
def __expandVariable(self, line, p):
|
||||
""" Given that line[p] is a dollar sign beginning a variable
|
||||
reference, advances p to the first dollar sign following the
|
||||
reference, and looks up the variable referenced.
|
||||
|
||||
Returns (value, p) where value is the value of the named
|
||||
variable, and p is the first character following the variable
|
||||
reference. """
|
||||
|
||||
p += 1
|
||||
if p >= len(line):
|
||||
return '', p
|
||||
|
||||
var = ''
|
||||
if line[p] == '{':
|
||||
# Curly braces exactly delimit the variable name.
|
||||
p += 1
|
||||
while p < len(line) and line[p] != '}':
|
||||
var += line[p]
|
||||
p += 1
|
||||
else:
|
||||
# Otherwise, a string of alphanumeric characters,
|
||||
# including underscore, delimits the variable name.
|
||||
var += line[p]
|
||||
p += 1
|
||||
while p < len(line) and (line[p] in string.letters or line[p] in string.digits or line[p] == '_'):
|
||||
var += line[p]
|
||||
p += 1
|
||||
|
||||
return ExecutionEnvironment.getEnvironmentVariable(var), p
|
||||
|
||||
|
||||
def __splitLine(self, line):
|
||||
""" Separates the indicated line into words at whitespace.
|
||||
Quotation marks and escape characters protect spaces. This is
|
||||
designed to be similar to the algorithm employed by the Unix
|
||||
shell. """
|
||||
|
||||
words = []
|
||||
|
||||
p = 0
|
||||
while p < len(line):
|
||||
if line[p] == '#':
|
||||
# A word that begins with a hash mark indicates an
|
||||
# inline comment, and the end of the parsing.
|
||||
break
|
||||
|
||||
# Scan to the end of the word.
|
||||
word = ''
|
||||
while p < len(line) and line[p] not in string.whitespace:
|
||||
if line[p] == '\\':
|
||||
# Output an escaped character.
|
||||
p += 1
|
||||
if p < len(line):
|
||||
word += line[p]
|
||||
p += 1
|
||||
|
||||
elif line[p] == '$':
|
||||
# Output a variable reference.
|
||||
expand, p = self.__expandVariable(line, p)
|
||||
word += expand
|
||||
|
||||
elif line[p] == '"':
|
||||
# Output a double-quoted string.
|
||||
p += 1
|
||||
while p < len(line) and line[p] != '"':
|
||||
if line[p] == '\\':
|
||||
# Output an escaped character.
|
||||
p += 1
|
||||
if p < len(line):
|
||||
word += line[p]
|
||||
p += 1
|
||||
elif line[p] == '$':
|
||||
# Output a variable reference.
|
||||
expand, p = self.__expandVariable(line, p)
|
||||
word += expand
|
||||
else:
|
||||
word += line[p]
|
||||
p += 1
|
||||
|
||||
elif line[p] == "'":
|
||||
# Output a single-quoted string. Escape
|
||||
# characters and dollar signs within single quotes
|
||||
# are not special.
|
||||
p += 1
|
||||
while p < len(line) and line[p] != "'":
|
||||
word += line[p]
|
||||
p += 1
|
||||
|
||||
else:
|
||||
# Output a single character.
|
||||
word += line[p]
|
||||
p += 1
|
||||
|
||||
words.append(word)
|
||||
|
||||
# Scan to the beginning of the next word.
|
||||
while p < len(line) and line[p] in string.whitespace:
|
||||
p += 1
|
||||
|
||||
return words
|
||||
|
||||
def __getNextLine(self, file):
|
||||
""" Extracts the next line from the input file, and splits it
|
||||
into words. Returns the list of words, or None at end of
|
||||
file. """
|
||||
|
||||
line = file.readline()
|
||||
while line:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
# Skip the line, it was just a blank line
|
||||
pass
|
||||
|
||||
elif line[0] == '#':
|
||||
# Eat python-style comments.
|
||||
pass
|
||||
|
||||
else:
|
||||
return self.__splitLine(line)
|
||||
|
||||
line = file.readline()
|
||||
|
||||
# End of file.
|
||||
return None
|
||||
|
||||
def readPackageDef(self, packageDef):
|
||||
""" Reads the lines in the .pdef file named by packageDef and
|
||||
dispatches to the appropriate handler method for each
|
||||
line. Returns the list of package files."""
|
||||
|
||||
assert self.packageList is None
|
||||
self.packageList = []
|
||||
|
||||
self.notify.info('Reading %s' % (packageDef))
|
||||
file = open(packageDef.toOsSpecific())
|
||||
lines = file.readlines()
|
||||
file.close()
|
||||
|
||||
lineNum = [0]
|
||||
def getNextLine(lineNum = lineNum):
|
||||
"""
|
||||
Read in the next line of the packageDef
|
||||
"""
|
||||
while lineNum[0] < len(lines):
|
||||
line = lines[lineNum[0]].strip()
|
||||
lineNum[0] += 1
|
||||
if not line:
|
||||
# Skip the line, it was just a blank line
|
||||
pass
|
||||
elif line[0] == '#':
|
||||
# Eat python-style comments.
|
||||
pass
|
||||
else:
|
||||
# Remove any trailing comment.
|
||||
hash = line.find(' #')
|
||||
if hash != -1:
|
||||
line = line[:hash].strip()
|
||||
# Return the line as an array split at whitespace.
|
||||
return line.split()
|
||||
|
||||
# EOF.
|
||||
return None
|
||||
|
||||
# Now start parsing the packageDef lines
|
||||
try:
|
||||
lineList = getNextLine()
|
||||
while lineList:
|
||||
command = lineList[0]
|
||||
words = self.__getNextLine(file)
|
||||
while words:
|
||||
command = words[0]
|
||||
try:
|
||||
methodName = 'parse_%s' % (command)
|
||||
method = getattr(self, methodName, None)
|
||||
if method:
|
||||
method(lineList)
|
||||
method(words)
|
||||
|
||||
else:
|
||||
message = 'Unknown command %s' % (command)
|
||||
|
|
@ -695,7 +803,7 @@ class Packager:
|
|||
message = '%s command encounted outside of package specification' %(command)
|
||||
raise OutsideOfPackageError, message
|
||||
|
||||
lineList = getNextLine()
|
||||
words = self.__getNextLine(file)
|
||||
|
||||
except PackagerError:
|
||||
# Append the line number and file name to the exception
|
||||
|
|
@ -705,17 +813,17 @@ class Packager:
|
|||
raise
|
||||
|
||||
packageList = self.packageList
|
||||
self.packageList = None
|
||||
self.packageList = []
|
||||
|
||||
return packageList
|
||||
|
||||
def parse_set(self, lineList):
|
||||
def parse_set(self, words):
|
||||
"""
|
||||
set variable=value
|
||||
"""
|
||||
|
||||
try:
|
||||
command, assign = lineList
|
||||
command, assign = words
|
||||
except ValueError:
|
||||
raise ArgumentNumber
|
||||
|
||||
|
|
@ -728,15 +836,15 @@ class Packager:
|
|||
value = ExecutionEnvironment.expandString(value.strip())
|
||||
ExecutionEnvironment.setEnvironmentVariable(variable, value)
|
||||
|
||||
def parse_begin_package(self, lineList):
|
||||
def parse_begin_package(self, words):
|
||||
"""
|
||||
begin_package packageName [version=v]
|
||||
"""
|
||||
|
||||
args = self.parseArgs(lineList, ['version'])
|
||||
args = self.__parseArgs(words, ['version'])
|
||||
|
||||
try:
|
||||
command, packageName = lineList
|
||||
command, packageName = words
|
||||
except ValueError:
|
||||
raise ArgumentNumber
|
||||
|
||||
|
|
@ -744,127 +852,149 @@ class Packager:
|
|||
|
||||
self.beginPackage(packageName, version = version, p3dApplication = False)
|
||||
|
||||
def parse_end_package(self, lineList):
|
||||
def parse_end_package(self, words):
|
||||
"""
|
||||
end_package packageName
|
||||
"""
|
||||
|
||||
try:
|
||||
command, packageName = lineList
|
||||
command, packageName = words
|
||||
except ValueError:
|
||||
raise ArgumentError
|
||||
|
||||
self.endPackage(packageName, p3dApplication = False)
|
||||
|
||||
def parse_begin_p3d(self, lineList):
|
||||
def parse_begin_p3d(self, words):
|
||||
"""
|
||||
begin_p3d appName
|
||||
"""
|
||||
|
||||
try:
|
||||
command, packageName = lineList
|
||||
command, packageName = words
|
||||
except ValueError:
|
||||
raise ArgumentNumber
|
||||
|
||||
self.beginPackage(packageName, p3dApplication = True)
|
||||
|
||||
def parse_end_p3d(self, lineList):
|
||||
def parse_end_p3d(self, words):
|
||||
"""
|
||||
end_p3d appName
|
||||
"""
|
||||
|
||||
try:
|
||||
command, packageName = lineList
|
||||
command, packageName = words
|
||||
except ValueError:
|
||||
raise ArgumentError
|
||||
|
||||
self.endPackage(packageName, p3dApplication = True)
|
||||
|
||||
def parse_require(self, lineList):
|
||||
def parse_display_name(self, words):
|
||||
"""
|
||||
display_name "name"
|
||||
"""
|
||||
|
||||
try:
|
||||
command, displayName = words
|
||||
except ValueError:
|
||||
raise ArgumentError
|
||||
|
||||
if not self.currentPackage:
|
||||
raise OutsideOfPackageError
|
||||
|
||||
self.currentPackage.displayName = displayName
|
||||
|
||||
def parse_require(self, words):
|
||||
"""
|
||||
require packageName [version=v]
|
||||
"""
|
||||
|
||||
args = self.parseArgs(lineList, ['version'])
|
||||
args = self.__parseArgs(words, ['version'])
|
||||
|
||||
try:
|
||||
command, packageName = lineList
|
||||
command, packageName = words
|
||||
except ValueError:
|
||||
raise ArgumentError
|
||||
|
||||
version = args.get('version', None)
|
||||
self.require(packageName, version = version)
|
||||
|
||||
def parse_module(self, lineList):
|
||||
def parse_module(self, words):
|
||||
"""
|
||||
module moduleName [newName]
|
||||
"""
|
||||
newName = None
|
||||
|
||||
try:
|
||||
if len(lineList) == 2:
|
||||
command, moduleName = lineList
|
||||
if len(words) == 2:
|
||||
command, moduleName = words
|
||||
else:
|
||||
command, moduleName, newName = lineList
|
||||
command, moduleName, newName = words
|
||||
except ValueError:
|
||||
raise ArgumentError
|
||||
|
||||
self.module(moduleName, newName = newName)
|
||||
|
||||
def parse_main_module(self, lineList):
|
||||
def parse_main_module(self, words):
|
||||
"""
|
||||
main_module moduleName
|
||||
"""
|
||||
|
||||
try:
|
||||
command, moduleName = lineList
|
||||
command, moduleName = words
|
||||
except ValueError:
|
||||
raise ArgumentError
|
||||
|
||||
self.mainModule(moduleName)
|
||||
|
||||
def parse_freeze_exe(self, lineList):
|
||||
def parse_freeze_exe(self, words):
|
||||
"""
|
||||
freeze_exe path/to/basename
|
||||
"""
|
||||
|
||||
try:
|
||||
command, filename = lineList
|
||||
command, filename = words
|
||||
except ValueError:
|
||||
raise ArgumentError
|
||||
|
||||
self.freeze(filename, compileToExe = True)
|
||||
|
||||
def parse_freeze_dll(self, lineList):
|
||||
def parse_freeze_dll(self, words):
|
||||
"""
|
||||
freeze_dll path/to/basename
|
||||
"""
|
||||
|
||||
try:
|
||||
command, filename = lineList
|
||||
command, filename = words
|
||||
except ValueError:
|
||||
raise ArgumentError
|
||||
|
||||
self.freeze(filename, compileToExe = False)
|
||||
|
||||
def parse_file(self, lineList):
|
||||
def parse_file(self, words):
|
||||
"""
|
||||
file filename [newNameOrDir]
|
||||
file filename [newNameOrDir] [extract=1]
|
||||
"""
|
||||
|
||||
args = self.__parseArgs(words, ['extract'])
|
||||
|
||||
newNameOrDir = None
|
||||
|
||||
try:
|
||||
if len(lineList) == 2:
|
||||
command, filename = lineList
|
||||
if len(words) == 2:
|
||||
command, filename = words
|
||||
else:
|
||||
command, filename, newNameOrDir = lineList
|
||||
command, filename, newNameOrDir = words
|
||||
except ValueError:
|
||||
raise ArgumentError
|
||||
|
||||
self.file(filename, newNameOrDir = newNameOrDir)
|
||||
extract = args.get('extract', None)
|
||||
if extract is not None:
|
||||
extract = int(extract)
|
||||
|
||||
def parse_dir(self, lineList):
|
||||
self.file(Filename.fromOsSpecific(filename),
|
||||
newNameOrDir = newNameOrDir, extract = extract)
|
||||
|
||||
def parse_dir(self, words):
|
||||
"""
|
||||
dir dirname [newDir]
|
||||
"""
|
||||
|
|
@ -872,20 +1002,20 @@ class Packager:
|
|||
newDir = None
|
||||
|
||||
try:
|
||||
if len(lineList) == 2:
|
||||
command, dirname = lineList
|
||||
if len(words) == 2:
|
||||
command, dirname = words
|
||||
else:
|
||||
command, dirname, newDir = lineList
|
||||
command, dirname, newDir = words
|
||||
except ValueError:
|
||||
raise ArgumentError
|
||||
|
||||
self.dir(dirname, newDir = newDir)
|
||||
self.dir(Filename.fromOsSpecific(dirname), newDir = newDir)
|
||||
|
||||
def parseArgs(self, lineList, argList):
|
||||
def __parseArgs(self, words, argList):
|
||||
args = {}
|
||||
|
||||
while len(lineList) > 1:
|
||||
arg = lineList[-1]
|
||||
while len(words) > 1:
|
||||
arg = words[-1]
|
||||
if '=' not in arg:
|
||||
return args
|
||||
|
||||
|
|
@ -901,7 +1031,7 @@ class Packager:
|
|||
|
||||
args[parameter] = value
|
||||
|
||||
del lineList[-1]
|
||||
del words[-1]
|
||||
|
||||
|
||||
def beginPackage(self, packageName, version = None, p3dApplication = False):
|
||||
|
|
@ -1026,11 +1156,11 @@ class Packager:
|
|||
|
||||
def require(self, packageName, version = None):
|
||||
""" Indicates a dependency on the named package, supplied as
|
||||
name.
|
||||
a name.
|
||||
|
||||
Attempts to install this package will implicitly install the
|
||||
named package also. Files already included in the named
|
||||
package will be omitted from this one. """
|
||||
package will be omitted from this one when building it. """
|
||||
|
||||
# A special case for the Panda3D package. We enforce that the
|
||||
# version number matches what we've been compiled with.
|
||||
|
|
@ -1136,14 +1266,13 @@ class Packager:
|
|||
package.mainModule = None
|
||||
|
||||
|
||||
def file(self, filename, newNameOrDir = None):
|
||||
def file(self, filename, newNameOrDir = None, extract = None):
|
||||
""" Adds the indicated arbitrary file to the current package.
|
||||
|
||||
The file is placed in the named directory, or the toplevel
|
||||
directory if no directory is specified.
|
||||
|
||||
The filename may include environment variable references and
|
||||
shell globbing characters.
|
||||
The filename may include shell globbing characters.
|
||||
|
||||
Certain special behavior is invoked based on the filename
|
||||
extension. For instance, .py files may be automatically
|
||||
|
|
@ -1166,10 +1295,10 @@ class Packager:
|
|||
if not self.currentPackage:
|
||||
raise OutsideOfPackageError
|
||||
|
||||
expanded = Filename.expandFrom(filename)
|
||||
files = glob.glob(expanded.toOsSpecific())
|
||||
filename = Filename(filename)
|
||||
files = glob.glob(filename.toOsSpecific())
|
||||
if not files:
|
||||
self.notify.warning("No such file: %s" % (expanded))
|
||||
self.notify.warning("No such file: %s" % (filename))
|
||||
return
|
||||
|
||||
newName = None
|
||||
|
|
@ -1188,9 +1317,9 @@ class Packager:
|
|||
filename = Filename.fromOsSpecific(filename)
|
||||
basename = filename.getBasename()
|
||||
if newName:
|
||||
self.addFile(filename, newName = newName)
|
||||
self.addFile(filename, newName = newName, extract = extract)
|
||||
else:
|
||||
self.addFile(filename, newName = prefix + basename)
|
||||
self.addFile(filename, newName = prefix + basename, extract = extract)
|
||||
|
||||
def dir(self, dirname, newDir = None):
|
||||
|
||||
|
|
@ -1198,8 +1327,6 @@ class Packager:
|
|||
package. The directory hierarchy is walked recursively, and
|
||||
all files that match a known extension are added to the package.
|
||||
|
||||
The dirname may include environment variable references.
|
||||
|
||||
newDir specifies the directory name within the package which
|
||||
the contents of the named directory should be installed to.
|
||||
If it is omitted, the contents of the named directory are
|
||||
|
|
@ -1209,7 +1336,7 @@ class Packager:
|
|||
if not self.currentPackage:
|
||||
raise OutsideOfPackageError
|
||||
|
||||
dirname = Filename.expandFrom(dirname)
|
||||
dirname = Filename(dirname)
|
||||
if not newDir:
|
||||
newDir = ''
|
||||
|
||||
|
|
@ -1242,7 +1369,7 @@ class Packager:
|
|||
if ext in self.knownExtensions:
|
||||
self.addFile(filename, newName = newName)
|
||||
|
||||
def addFile(self, filename, newName = None):
|
||||
def addFile(self, filename, newName = None, extract = None):
|
||||
""" Adds the named file, giving it the indicated name within
|
||||
the package. """
|
||||
|
||||
|
|
@ -1250,4 +1377,4 @@ class Packager:
|
|||
raise OutsideOfPackageError
|
||||
|
||||
self.currentPackage.files.append(
|
||||
self.PackFile(filename, newName = newName))
|
||||
self.PackFile(filename, newName = newName, extract = extract))
|
||||
|
|
|
|||
|
|
@ -23,21 +23,37 @@ Options:
|
|||
import sys
|
||||
import getopt
|
||||
import os
|
||||
|
||||
import direct
|
||||
from pandac.PandaModules import *
|
||||
|
||||
from FileSpec import FileSpec
|
||||
import md5
|
||||
|
||||
class ArgumentError(AttributeError):
|
||||
pass
|
||||
|
||||
class FileSpec:
|
||||
""" Represents a single file in the directory, and its associated
|
||||
timestamp, size, and md5 hash. """
|
||||
|
||||
def __init__(self, filename, pathname):
|
||||
self.filename = filename
|
||||
self.pathname = pathname
|
||||
|
||||
s = os.stat(pathname)
|
||||
self.size = s.st_size
|
||||
self.timestamp = s.st_mtime
|
||||
|
||||
m = md5.new()
|
||||
m.update(open(pathname, 'rb').read())
|
||||
self.hash = m.hexdigest()
|
||||
|
||||
def getParams(self):
|
||||
return 'filename="%s" size="%s" timestamp="%s" hash="%s"' % (
|
||||
self.filename, self.size, self.timestamp, self.hash)
|
||||
|
||||
class ContentsMaker:
|
||||
def __init__(self):
|
||||
self.stageDir = None
|
||||
self.installDir = None
|
||||
|
||||
def build(self):
|
||||
if not self.stageDir:
|
||||
if not self.installDir:
|
||||
raise ArgumentError, "Stage directory not specified."
|
||||
|
||||
self.packages = []
|
||||
|
|
@ -48,9 +64,9 @@ class ContentsMaker:
|
|||
|
||||
# Now write the contents.xml file.
|
||||
contentsFileBasename = 'contents.xml'
|
||||
contentsFilePathname = Filename(self.stageDir, contentsFileBasename)
|
||||
contentsFilePathname = os.path.join(self.installDir, contentsFileBasename)
|
||||
|
||||
f = open(contentsFilePathname.toOsSpecific(), 'w')
|
||||
f = open(contentsFilePathname, 'w')
|
||||
print >> f, '<?xml version="1.0" ?>'
|
||||
print >> f, ''
|
||||
print >> f, '<contents>'
|
||||
|
|
@ -64,7 +80,7 @@ class ContentsMaker:
|
|||
""" Walks through all the files in the stage directory and
|
||||
looks for the package directory xml files. """
|
||||
|
||||
startDir = self.stageDir.toOsSpecific()
|
||||
startDir = self.installDir
|
||||
if startDir.endswith(os.sep):
|
||||
startDir = startDir[:-1]
|
||||
prefix = startDir + os.sep
|
||||
|
|
@ -91,14 +107,14 @@ class ContentsMaker:
|
|||
packageName, packageVersion, junk = localpath.split('/')
|
||||
packagePlatform = None
|
||||
file = FileSpec(localpath + xml,
|
||||
Filename(self.stageDir, localpath + xml))
|
||||
os.path.join(self.installDir, localpath + xml))
|
||||
print file.filename
|
||||
self.packages.append((packageName, packagePlatform, packageVersion, file))
|
||||
|
||||
if localpath.count('/') == 3:
|
||||
packageName, packagePlatform, packageVersion, junk = localpath.split('/')
|
||||
file = FileSpec(localpath + xml,
|
||||
Filename(self.stageDir, localpath + xml))
|
||||
os.path.join(self.installDir, localpath + xml))
|
||||
print file.filename
|
||||
self.packages.append((packageName, packagePlatform, packageVersion, file))
|
||||
|
||||
|
|
@ -107,10 +123,10 @@ def makeContents(args):
|
|||
opts, args = getopt.getopt(args, 'd:h')
|
||||
|
||||
cm = ContentsMaker()
|
||||
cm.stageDir = Filename('.')
|
||||
cm.installDir = '.'
|
||||
for option, value in opts:
|
||||
if option == '-d':
|
||||
cm.stageDir = Filename.fromOsSpecific(value)
|
||||
cm.installDir = value
|
||||
|
||||
elif option == '-h':
|
||||
print __doc__
|
||||
|
|
@ -119,8 +135,9 @@ def makeContents(args):
|
|||
cm.build()
|
||||
|
||||
|
||||
try:
|
||||
makeContents(sys.argv[1:])
|
||||
except ArgumentError, e:
|
||||
print e.args[0]
|
||||
sys.exit(1)
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
makeContents(sys.argv[1:])
|
||||
except ArgumentError, e:
|
||||
print e.args[0]
|
||||
sys.exit(1)
|
||||
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
"""
|
||||
|
||||
This module will pack a Panda application, consisting of a directory
|
||||
This command will pack a Panda application, consisting of a directory
|
||||
tree of .py files and models, into a p3d file for convenient
|
||||
distribution. The resulting p3d file can be run by the Panda3D
|
||||
runtime executable, or by the Panda3D web browser plugin.
|
||||
|
||||
Also see ppackage.py, which can be used to build p3d files more
|
||||
generally, using a pdef description file.
|
||||
|
||||
Usage:
|
||||
|
||||
packp3d.py [opts] app.p3d
|
||||
|
|
@ -14,13 +17,11 @@ Usage:
|
|||
Options:
|
||||
|
||||
-r application_root
|
||||
|
||||
Specify the root directory of the application source; this is a
|
||||
directory tree that contains all of your .py files and models.
|
||||
If this is omitted, the default is the current directory.
|
||||
|
||||
-m main.py
|
||||
|
||||
Names the Python file that begins the application. This should
|
||||
be a file within the root directory. If this is omitted, the
|
||||
default is a file named "main.py", or if there is only one Python
|
||||
|
|
@ -29,313 +30,48 @@ Options:
|
|||
(this is preferable to having the module start itself immediately
|
||||
upon importing).
|
||||
|
||||
-c [py,pyc,pyo]
|
||||
-s search_dir
|
||||
Additional directories to search for previously-built packages.
|
||||
This option may be repeated as necessary.
|
||||
|
||||
Specifies the compilation mode of python files. 'py' means to
|
||||
leave them as source files, 'pyc' and 'pyo' are equivalent, and
|
||||
mean to compile to byte code. pyc files will be written if the
|
||||
interpreter is running in normal debug mode, while pyo files will
|
||||
be written if it is running in optimize mode (-O or -OO).
|
||||
-x
|
||||
If this is specified, a version-independent application is built.
|
||||
This stores source py files instead of compiled pyc files, and
|
||||
egg files instead of bam files. This application can then be run
|
||||
with any version of Panda (provided you are careful not to make
|
||||
any Python or Panda calls that are version-specific). This is
|
||||
not recommended except for very small, simple applications.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import imp
|
||||
import marshal
|
||||
import glob
|
||||
import direct
|
||||
from direct.stdpy.file import open
|
||||
from direct.showbase import Loader
|
||||
from direct.showutil import Packager
|
||||
from pandac.PandaModules import *
|
||||
|
||||
vfs = VirtualFileSystem.getGlobalPtr()
|
||||
|
||||
class ArgumentError(AttributeError):
|
||||
class ArgumentError(StandardError):
|
||||
pass
|
||||
|
||||
class AppPacker:
|
||||
|
||||
compression_level = 6
|
||||
imported_maps = 'imported_maps'
|
||||
|
||||
# Text files that are copied (and compressed) to the multifile
|
||||
# without processing.
|
||||
text_extensions = [ 'prc' ]
|
||||
|
||||
# Binary files that are copied and compressed without processing.
|
||||
binary_extensions = [ 'ttf', 'wav', 'mid' ]
|
||||
|
||||
# Binary files that are considered uncompressible, and are copied
|
||||
# without compression.
|
||||
uncompressible_extensions = [ 'mp3' ]
|
||||
|
||||
# Specifies how or if python files are compiled.
|
||||
compilation_mode = 'pyc'
|
||||
|
||||
def __init__(self, multifile_name):
|
||||
# Make sure any pre-existing file is removed.
|
||||
Filename(multifile_name).unlink()
|
||||
|
||||
self.multifile = Multifile()
|
||||
if not self.multifile.openReadWrite(multifile_name):
|
||||
raise ArgumentError, 'Could not open %s for writing' % (multifile_name)
|
||||
self.imported_textures = {}
|
||||
|
||||
# Get the list of filename extensions that are recognized as
|
||||
# image files.
|
||||
self.image_extensions = []
|
||||
for type in PNMFileTypeRegistry.getGlobalPtr().getTypes():
|
||||
self.image_extensions += type.getExtensions()
|
||||
|
||||
self.loader = Loader.Loader(self)
|
||||
|
||||
def scan(self, root, main):
|
||||
if self.compilation_mode != 'py':
|
||||
if __debug__:
|
||||
self.compilation_mode = 'pyc'
|
||||
else:
|
||||
self.compilation_mode = 'pyo'
|
||||
|
||||
self.root = Filename(root)
|
||||
self.root.makeAbsolute(vfs.getCwd())
|
||||
|
||||
# Check if there is just one .py file.
|
||||
pyFiles = self.findPyFiles(self.root)
|
||||
if main == None:
|
||||
if len(pyFiles) == 1:
|
||||
main = pyFiles[0]
|
||||
else:
|
||||
main = 'main.py'
|
||||
if main not in pyFiles:
|
||||
raise StandardError, 'No file %s in root directory.' % (main)
|
||||
self.main = Filename(self.root, main)
|
||||
|
||||
self._recurse(self.root)
|
||||
|
||||
self.multifile.repack()
|
||||
|
||||
def findPyFiles(self, dirname):
|
||||
""" Returns a list of Python filenames at the root directory
|
||||
level. """
|
||||
|
||||
dirList = vfs.scanDirectory(dirname)
|
||||
pyFiles = []
|
||||
for file in dirList:
|
||||
if file.getFilename().getExtension() == 'py':
|
||||
pyFiles.append(file.getFilename().getBasename())
|
||||
|
||||
return pyFiles
|
||||
|
||||
def _recurse(self, filename):
|
||||
dirList = vfs.scanDirectory(filename)
|
||||
if dirList:
|
||||
# It's a directory name. Recurse.
|
||||
for subfile in dirList:
|
||||
self._recurse(subfile.getFilename())
|
||||
return
|
||||
|
||||
# It's a real file. Is it something we care about?
|
||||
ext = filename.getExtension().lower()
|
||||
outFilename = filename
|
||||
if ext == 'pz':
|
||||
# Strip off an implicit .pz extension.
|
||||
outFilename = Filename(filename)
|
||||
outFilename.setExtension('')
|
||||
outFilename = Filename(outFilename.cStr())
|
||||
ext = outFilename.getExtension().lower()
|
||||
|
||||
if ext == 'py':
|
||||
self.addPyFile(filename)
|
||||
elif ext == 'egg':
|
||||
self.addEggFile(filename, outFilename)
|
||||
elif ext == 'bam':
|
||||
self.addBamFile(filename, outFilename)
|
||||
elif ext in self.image_extensions:
|
||||
self.addTexture(filename)
|
||||
elif ext in self.text_extensions:
|
||||
self.addTextFile(filename)
|
||||
elif ext in self.binary_extensions:
|
||||
self.addBinaryFile(filename)
|
||||
elif ext in self.uncompressible_extensions:
|
||||
self.addUncompressibleFile(filename)
|
||||
|
||||
def addPyFile(self, filename):
|
||||
targetFilename = self.makeRelFilename(filename)
|
||||
|
||||
if filename == self.main:
|
||||
# This one is the "main.py"; the starter file.
|
||||
targetFilename = Filename('main.py')
|
||||
|
||||
if self.compilation_mode == 'py':
|
||||
# Add python files as source files.
|
||||
self.multifile.addSubfile(targetFilename.cStr(), filename, self.compression_level)
|
||||
elif self.compilation_mode == 'pyc' or self.compilation_mode == 'pyo':
|
||||
# Compile it to bytecode.
|
||||
targetFilename.setExtension(self.compilation_mode)
|
||||
source = open(filename, 'r').read()
|
||||
if source and source[-1] != '\n':
|
||||
source = source + '\n'
|
||||
code = compile(source, targetFilename.cStr(), 'exec')
|
||||
data = imp.get_magic() + '\0\0\0\0' + marshal.dumps(code)
|
||||
|
||||
stream = StringStream(data)
|
||||
self.multifile.addSubfile(targetFilename.cStr(), stream, self.compression_level)
|
||||
self.multifile.flush()
|
||||
else:
|
||||
raise StandardError, 'Unsupported compilation mode %s' % (self.compilation_mode)
|
||||
|
||||
def addEggFile(self, filename, outFilename):
|
||||
# Precompile egg files to bam's.
|
||||
np = self.loader.loadModel(filename, okMissing = True)
|
||||
if not np:
|
||||
raise StandardError, 'Could not read egg file %s' % (filename)
|
||||
|
||||
self.addNode(np.node(), outFilename)
|
||||
|
||||
def addBamFile(self, filename, outFilename):
|
||||
# Load the bam file so we can massage its textures.
|
||||
bamFile = BamFile()
|
||||
if not bamFile.openRead(filename):
|
||||
raise StandardError, 'Could not read bam file %s' % (filename)
|
||||
|
||||
if not bamFile.resolve():
|
||||
raise StandardError, 'Could not resolve bam file %s' % (filename)
|
||||
|
||||
node = bamFile.readNode()
|
||||
if not node:
|
||||
raise StandardError, 'Not a model file: %s' % (filename)
|
||||
|
||||
self.addNode(node, outFilename)
|
||||
|
||||
def addNode(self, node, filename):
|
||||
""" Converts the indicated node to a bam stream, and adds the
|
||||
bam file to the multifile under the indicated filename. """
|
||||
|
||||
# Be sure to import all of the referenced textures, and tell
|
||||
# them their new location within the multifile.
|
||||
|
||||
for tex in NodePath(node).findAllTextures():
|
||||
if not tex.hasFullpath() and tex.hasRamImage():
|
||||
# We need to store this texture as a raw-data image.
|
||||
# Clear the filename so this will happen
|
||||
# automatically.
|
||||
tex.clearFilename()
|
||||
tex.clearAlphaFilename()
|
||||
|
||||
else:
|
||||
# We can store this texture as a file reference to its
|
||||
# image. Copy the file into our multifile, and rename
|
||||
# its reference in the texture.
|
||||
if tex.hasFilename():
|
||||
tex.setFilename(self.addTexture(tex.getFullpath()))
|
||||
if tex.hasAlphaFilename():
|
||||
tex.setAlphaFilename(self.addTexture(tex.getAlphaFullpath()))
|
||||
|
||||
# Now generate an in-memory bam file. Tell the bam writer to
|
||||
# keep the textures referenced by their in-multifile path.
|
||||
bamFile = BamFile()
|
||||
stream = StringStream()
|
||||
bamFile.openWrite(stream)
|
||||
bamFile.getWriter().setFileTextureMode(bamFile.BTMUnchanged)
|
||||
bamFile.writeObject(node)
|
||||
bamFile.close()
|
||||
|
||||
# Clean the node out of memory.
|
||||
node.removeAllChildren()
|
||||
|
||||
# Now we have an in-memory bam file.
|
||||
rel = self.makeRelFilename(filename)
|
||||
rel.setExtension('bam')
|
||||
stream.seekg(0)
|
||||
self.multifile.addSubfile(rel.cStr(), stream, self.compression_level)
|
||||
|
||||
# Flush it so the data gets written to disk immediately, so we
|
||||
# don't have to keep it around in ram.
|
||||
self.multifile.flush()
|
||||
|
||||
def addTexture(self, filename):
|
||||
""" Adds the texture to the multifile, if it has not already
|
||||
been added. If it is not within the root directory, copies it
|
||||
in (virtually) into a directory within the multifile named
|
||||
imported_maps. Returns the new filename within the
|
||||
multifile. """
|
||||
|
||||
assert not filename.isLocal()
|
||||
|
||||
filename = Filename(filename)
|
||||
filename.makeAbsolute(vfs.getCwd())
|
||||
filename.makeTrueCase()
|
||||
|
||||
rel = self.imported_textures.get(filename.cStr())
|
||||
if not rel:
|
||||
rel = Filename(filename)
|
||||
if not rel.makeRelativeTo(self.root, False):
|
||||
# Not within the multifile.
|
||||
rel = Filename(self.imported_maps, filename.getBasename())
|
||||
|
||||
# Need to add it now.
|
||||
self.imported_textures[filename.cStr()] = rel
|
||||
filename = Filename(filename)
|
||||
filename.setBinary()
|
||||
self.multifile.addSubfile(rel.cStr(), filename, 0)
|
||||
|
||||
return rel
|
||||
|
||||
def mapTextureFilename(self, filename):
|
||||
""" Returns the filename within the multifile of the
|
||||
already-added texture. """
|
||||
|
||||
filename = Filename(filename)
|
||||
filename.makeAbsolute(vfs.getCwd())
|
||||
filename.makeTrueCase()
|
||||
|
||||
return self.imported_textures[filename.cStr()]
|
||||
|
||||
def addTextFile(self, filename):
|
||||
""" Adds a generic text file to the multifile. """
|
||||
|
||||
rel = self.makeRelFilename(filename)
|
||||
filename = Filename(filename)
|
||||
filename.setText()
|
||||
self.multifile.addSubfile(rel.cStr(), filename, self.compression_level)
|
||||
|
||||
def addBinaryFile(self, filename):
|
||||
""" Adds a generic binary file to the multifile. """
|
||||
|
||||
rel = self.makeRelFilename(filename)
|
||||
filename = Filename(filename)
|
||||
filename.setBinary()
|
||||
self.multifile.addSubfile(rel.cStr(), filename, self.compression_level)
|
||||
|
||||
def addUncompressibleFile(self, filename):
|
||||
""" Adds a generic binary file to the multifile, without compression. """
|
||||
|
||||
rel = self.makeRelFilename(filename)
|
||||
filename = Filename(filename)
|
||||
filename.setBinary()
|
||||
self.multifile.addSubfile(rel.cStr(), filename, 0)
|
||||
|
||||
def makeRelFilename(self, filename):
|
||||
""" Returns the same filename, relative to self.root """
|
||||
rel = Filename(filename)
|
||||
result = rel.makeRelativeTo(self.root, False)
|
||||
assert result
|
||||
return rel
|
||||
|
||||
|
||||
def makePackedApp(args):
|
||||
opts, args = getopt.getopt(args, 'r:m:c:h')
|
||||
opts, args = getopt.getopt(args, 'r:m:s:xh')
|
||||
|
||||
packager = Packager.Packager()
|
||||
|
||||
root = '.'
|
||||
main = None
|
||||
compilation_mode = AppPacker.compilation_mode
|
||||
versionIndependent = False
|
||||
for option, value in opts:
|
||||
if option == '-r':
|
||||
root = value
|
||||
root = Filename.fromOsSpecific(value)
|
||||
elif option == '-m':
|
||||
main = value
|
||||
elif option == '-c':
|
||||
compilation_mode = value
|
||||
elif option == '-s':
|
||||
packager.installSearch.append(Filename.fromOsSpecific(value))
|
||||
elif option == '-x':
|
||||
versionIndependent = True
|
||||
elif option == '-h':
|
||||
print __doc__
|
||||
sys.exit(1)
|
||||
|
|
@ -343,13 +79,43 @@ def makePackedApp(args):
|
|||
if not args:
|
||||
raise ArgumentError, "No destination app specified. Use:\npackp3d.py app.p3d"
|
||||
|
||||
multifile_name = args[0]
|
||||
if len(args) > 1:
|
||||
raise ArgumentError, "Too many arguments."
|
||||
|
||||
p = AppPacker(multifile_name)
|
||||
p.compilation_mode = compilation_mode
|
||||
p.scan(root = root, main = main)
|
||||
appFilename = Filename.fromOsSpecific(args[0])
|
||||
if appFilename.getExtension() != 'p3d':
|
||||
raise ArgumentError, 'Application filename must end in ".p3d".'
|
||||
|
||||
appDir = Filename(appFilename.getDirname())
|
||||
appBase = appFilename.getBasenameWoExtension()
|
||||
|
||||
if not main:
|
||||
main = Filename(root, 'main.py')
|
||||
if main.exists():
|
||||
main = 'main.py'
|
||||
else:
|
||||
main = glob.glob(os.path.join(root.toOsSpecific(), '*.py'))
|
||||
if len(main) == 0:
|
||||
raise ArgumentError, 'No Python files in root directory.'
|
||||
elif len(main) > 1:
|
||||
raise ArgumentError, 'Multiple Python files in root directory; specify the main application with -m "main".'
|
||||
main = os.path.split(main[0])[1]
|
||||
|
||||
main = Filename.fromOsSpecific(main)
|
||||
main.setExtension('')
|
||||
|
||||
mainModule = main.cStr().replace('/', '.')
|
||||
|
||||
packager.installDir = appDir
|
||||
|
||||
packager.setup()
|
||||
packager.beginPackage(appBase, p3dApplication = True)
|
||||
|
||||
packager.require('panda3d')
|
||||
packager.dir(root)
|
||||
packager.mainModule(mainModule)
|
||||
|
||||
packager.endPackage(appBase, p3dApplication = True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ Options:
|
|||
copy this directory structure to a web host where it may be
|
||||
downloaded by the client.
|
||||
|
||||
-s search_dir
|
||||
Additional directories to search for previously-built packages.
|
||||
This option may be repeated as necessary.
|
||||
|
||||
-d persist_dir
|
||||
The full path to a local directory that retains persistant state
|
||||
between publishes. This directory structure keeps files that are
|
||||
|
|
@ -60,6 +64,7 @@ import getopt
|
|||
import os
|
||||
|
||||
from direct.showutil import Packager
|
||||
from direct.showutil import make_contents
|
||||
from pandac.PandaModules import *
|
||||
|
||||
def usage(code, msg = ''):
|
||||
|
|
@ -70,13 +75,15 @@ def usage(code, msg = ''):
|
|||
packager = Packager.Packager()
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'i:d:p:Hh')
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'i:s:d:p:Hh')
|
||||
except getopt.error, msg:
|
||||
usage(1, msg)
|
||||
|
||||
for opt, arg in opts:
|
||||
if opt == '-i':
|
||||
packager.installDir = Filename.fromOsSpecific(arg)
|
||||
elif opt == '-s':
|
||||
packager.installSearch.append(Filename.fromOsSpecific(arg))
|
||||
elif opt == '-d':
|
||||
packager.persistDir = Filename.fromOsSpecific(arg)
|
||||
elif opt == '-p':
|
||||
|
|
@ -101,7 +108,13 @@ packageDef = Filename.fromOsSpecific(args[0])
|
|||
|
||||
if not packager.installDir:
|
||||
packager.installDir = Filename('install')
|
||||
packager.installSearch = [packager.installDir]
|
||||
packager.installSearch = [packager.installDir] + packager.installSearch
|
||||
|
||||
packager.setup()
|
||||
packager.readPackageDef(packageDef)
|
||||
|
||||
# Update the contents.xml at the root of the install directory.
|
||||
cm = make_contents.ContentsMaker()
|
||||
cm.installDir = packager.installDir.toOsSpecific()
|
||||
cm.build()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue